diff options
| author | Yong He <yonghe@outlook.com> | 2021-01-06 12:58:57 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-06 12:58:57 -0800 |
| commit | 92636513abe72d2da0c45f0e2c1235415e0671c3 (patch) | |
| tree | 234136e9d89006df9d6775e8bcd07e91ae344af7 /tools/gfx | |
| parent | 706d4f91e269d473c963d31792fb2c8320933c9b (diff) | |
Refactor GUI/Window utils out of gfx library (#1649)
Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'tools/gfx')
| -rw-r--r-- | tools/gfx/cuda/render-cuda.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/d3d/d3d-util.h | 6 | ||||
| -rw-r--r-- | tools/gfx/d3d11/render-d3d11.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/d3d12/circular-resource-heap-d3d12.h | 6 | ||||
| -rw-r--r-- | tools/gfx/d3d12/descriptor-heap-d3d12.h | 4 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/d3d12/resource-d3d12.h | 2 | ||||
| -rw-r--r-- | tools/gfx/gui.cpp | 415 | ||||
| -rw-r--r-- | tools/gfx/gui.h | 28 | ||||
| -rw-r--r-- | tools/gfx/model.cpp | 564 | ||||
| -rw-r--r-- | tools/gfx/model.h | 77 | ||||
| -rw-r--r-- | tools/gfx/nvapi/nvapi-util.h | 4 | ||||
| -rw-r--r-- | tools/gfx/render.h | 2 | ||||
| -rw-r--r-- | tools/gfx/vector-math.h | 15 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-api.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-module.h | 4 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-swap-chain.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-swap-chain.h | 2 | ||||
| -rw-r--r-- | tools/gfx/window.h | 122 | ||||
| -rw-r--r-- | tools/gfx/windows/win-window.cpp | 398 |
21 files changed, 20 insertions, 1641 deletions
diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp index cf77e4ef6..f12e8ee89 100644 --- a/tools/gfx/cuda/render-cuda.cpp +++ b/tools/gfx/cuda/render-cuda.cpp @@ -4,7 +4,7 @@ #include "../render.h" #include <cuda.h> #include <cuda_runtime_api.h> -#include "../../source/core/slang-std-writers.h" +#include "core/slang-std-writers.h" #include "slang.h" #endif diff --git a/tools/gfx/d3d/d3d-util.h b/tools/gfx/d3d/d3d-util.h index fd7a31d3a..37c277832 100644 --- a/tools/gfx/d3d/d3d-util.h +++ b/tools/gfx/d3d/d3d-util.h @@ -3,10 +3,10 @@ #include <stdint.h> -#include "../../slang-com-helper.h" +#include "slang-com-helper.h" -#include "../../slang-com-ptr.h" -#include "../../source/core/slang-list.h" +#include "slang-com-ptr.h" +#include "core/slang-list.h" #include "../flag-combiner.h" diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp index 48cf7770d..5c04eccf1 100644 --- a/tools/gfx/d3d11/render-d3d11.cpp +++ b/tools/gfx/d3d11/render-d3d11.cpp @@ -16,7 +16,7 @@ //#include <slang.h> -#include "../../slang-com-ptr.h" +#include "slang-com-ptr.h" #include "../flag-combiner.h" // We will be rendering with Direct3D 11, so we need to include diff --git a/tools/gfx/d3d12/circular-resource-heap-d3d12.h b/tools/gfx/d3d12/circular-resource-heap-d3d12.h index bf9f412cf..7eacf9572 100644 --- a/tools/gfx/d3d12/circular-resource-heap-d3d12.h +++ b/tools/gfx/d3d12/circular-resource-heap-d3d12.h @@ -1,8 +1,8 @@ #pragma once -#include "../../slang-com-ptr.h" -#include "../../source/core/slang-list.h" -#include "../../source/core/slang-free-list.h" +#include "slang-com-ptr.h" +#include "core/slang-list.h" +#include "core/slang-free-list.h" #include "resource-d3d12.h" diff --git a/tools/gfx/d3d12/descriptor-heap-d3d12.h b/tools/gfx/d3d12/descriptor-heap-d3d12.h index a546395d8..642ff59db 100644 --- a/tools/gfx/d3d12/descriptor-heap-d3d12.h +++ b/tools/gfx/d3d12/descriptor-heap-d3d12.h @@ -4,8 +4,8 @@ #include <dxgi.h> #include <d3d12.h> -#include "../../slang-com-ptr.h" -#include "../../source/core/slang-list.h" +#include "slang-com-ptr.h" +#include "core/slang-list.h" namespace gfx { diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index d3f030b88..0376ee304 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -35,7 +35,7 @@ struct ID3D12GraphicsCommandList1 {}; # include "../nvapi/nvapi-include.h" #endif -#include "../../slang-com-ptr.h" +#include "slang-com-ptr.h" #include "../flag-combiner.h" #include "resource-d3d12.h" diff --git a/tools/gfx/d3d12/resource-d3d12.h b/tools/gfx/d3d12/resource-d3d12.h index 9e3c3262b..7a26854ff 100644 --- a/tools/gfx/d3d12/resource-d3d12.h +++ b/tools/gfx/d3d12/resource-d3d12.h @@ -10,7 +10,7 @@ #include <dxgi1_4.h> #include <d3d12.h> -#include "../../slang-com-ptr.h" +#include "slang-com-ptr.h" #include "../d3d/d3d-util.h" namespace gfx { diff --git a/tools/gfx/gui.cpp b/tools/gfx/gui.cpp deleted file mode 100644 index 8208bd606..000000000 --- a/tools/gfx/gui.cpp +++ /dev/null @@ -1,415 +0,0 @@ -// gui.cpp -#include "gui.h" - -#ifdef _WIN32 -#include <windows.h> -#include "external/imgui/examples/imgui_impl_win32.h" -IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -#endif - - -namespace gfx { - -#ifdef _WIN32 -LRESULT CALLBACK guiWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - LRESULT handled = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam); - if(handled) return handled; - ImGuiIO& io = ImGui::GetIO(); - - switch( msg ) - { - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - if(io.WantCaptureMouse) handled = 1; - break; - - case WM_KEYDOWN: - case WM_KEYUP: - if(io.WantCaptureKeyboard) handled = 1; - break; - } - - return handled; -} -void setNativeWindowHook(Window* window, WNDPROC proc); -#endif - - -GUI::GUI(Window* window, Renderer* inRenderer) - : renderer(inRenderer) -{ - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - -#ifdef _WIN32 - ImGui_ImplWin32_Init(getPlatformWindowHandle(window)); - - setNativeWindowHook(window, &guiWindowProc); -#endif - - // Let's do the initialization work required for our graphics API - // abstraction layer, so that we can pipe all IMGUI rendering - // through the same interface as other work. - // - - static const char* shaderCode = - "cbuffer U { float4x4 mvp; }; \ - Texture2D t; \ - SamplerState s; \ - struct AssembledVertex { \ - float2 pos; \ - float2 uv; \ - float4 col; \ - }; \ - struct CoarseVertex { \ - float4 col; \ - float2 uv; \ - }; \ - struct VSOutput { \ - CoarseVertex cv : U; \ - float4 pos : SV_Position; \ - }; \ - void vertexMain( \ - AssembledVertex i : U, \ - out VSOutput o) \ - { \ - o.cv.col = i.col; \ - o.cv.uv = i.uv; \ - o.pos = mul(mvp, \ - float4(i.pos.xy, 0.f, 1.f)); \ - } \ - float4 fragmentMain( \ - CoarseVertex i : U) \ - : SV_target \ - { \ - return i.col * t.Sample(s, i.uv); \ - } \ - "; - - SlangSession* slangSession = spCreateSession(nullptr); - SlangCompileRequest* slangRequest = spCreateCompileRequest(slangSession); - - // TODO: These two lines need to change based on what the target graphics API - // is, so we need a way for a `Renderer` to pass back its prefeerred code - // format and profile name... - // - int targetIndex = spAddCodeGenTarget(slangRequest, SLANG_DXBC); - spSetTargetProfile(slangRequest, targetIndex, spFindProfile(slangSession, "sm_4_0")); - - int translationUnitIndex = spAddTranslationUnit(slangRequest, SLANG_SOURCE_LANGUAGE_SLANG, nullptr); - spAddTranslationUnitSourceString(slangRequest, translationUnitIndex, "gui.cpp.slang", shaderCode); - - char const* vertexEntryPointName = "vertexMain"; - char const* fragmentEntryPointName = "fragmentMain"; - int vertexIndex = spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, SLANG_STAGE_VERTEX); - int fragmentIndex = spAddEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, SLANG_STAGE_FRAGMENT); - - const SlangResult compileRes = spCompile(slangRequest); - if(auto diagnostics = spGetDiagnosticOutput(slangRequest)) - { - reportError("%s", diagnostics); - } - if(SLANG_FAILED(compileRes)) - { - spDestroyCompileRequest(slangRequest); - spDestroySession(slangSession); - assert(!"unexpected"); - return; - } - - ISlangBlob* vertexShaderBlob = nullptr; - spGetEntryPointCodeBlob(slangRequest, vertexIndex, 0, &vertexShaderBlob); - - ISlangBlob* fragmentShaderBlob = nullptr; - spGetEntryPointCodeBlob(slangRequest, fragmentIndex, 0, &fragmentShaderBlob); - - char const* vertexCode = (char const*) vertexShaderBlob->getBufferPointer(); - char const* vertexCodeEnd = vertexCode + vertexShaderBlob->getBufferSize(); - - char const* fragmentCode = (char const*) fragmentShaderBlob->getBufferPointer(); - char const* fragmentCodeEnd = fragmentCode + fragmentShaderBlob->getBufferSize(); - - spDestroyCompileRequest(slangRequest); - spDestroySession(slangSession); - - gfx::ShaderProgram::KernelDesc kernelDescs[] = - { - { gfx::StageType::Vertex, vertexCode, vertexCodeEnd }, - { gfx::StageType::Fragment, fragmentCode, fragmentCodeEnd }, - }; - - gfx::ShaderProgram::Desc programDesc; - programDesc.pipelineType = gfx::PipelineType::Graphics; - programDesc.kernels = &kernelDescs[0]; - programDesc.kernelCount = 2; - - auto program = renderer->createProgram(programDesc); - - vertexShaderBlob->release(); - fragmentShaderBlob->release(); - - InputElementDesc inputElements[] = { - {"U", 0, Format::RG_Float32, offsetof(ImDrawVert, pos) }, - {"U", 1, Format::RG_Float32, offsetof(ImDrawVert, uv) }, - {"U", 2, Format::RGBA_Unorm_UInt8, offsetof(ImDrawVert, col) }, - }; - auto inputLayout = renderer->createInputLayout( - &inputElements[0], - SLANG_COUNT_OF(inputElements)); - - // - - List<DescriptorSetLayout::SlotRangeDesc> descriptorSetRanges; - descriptorSetRanges.add(DescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::UniformBuffer)); - descriptorSetRanges.add(DescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::SampledImage)); - descriptorSetRanges.add(DescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::Sampler)); - - DescriptorSetLayout::Desc descriptorSetLayoutDesc; - descriptorSetLayoutDesc.slotRangeCount = descriptorSetRanges.getCount(); - descriptorSetLayoutDesc.slotRanges = descriptorSetRanges.getBuffer(); - - descriptorSetLayout = renderer->createDescriptorSetLayout(descriptorSetLayoutDesc); - - List<PipelineLayout::DescriptorSetDesc> pipelineDescriptorSets; - pipelineDescriptorSets.add(PipelineLayout::DescriptorSetDesc(descriptorSetLayout)); - - PipelineLayout::Desc pipelineLayoutDesc; - pipelineLayoutDesc.descriptorSetCount = pipelineDescriptorSets.getCount(); - pipelineLayoutDesc.descriptorSets = pipelineDescriptorSets.getBuffer(); - pipelineLayoutDesc.renderTargetCount = 1; - - pipelineLayout = renderer->createPipelineLayout(pipelineLayoutDesc); - - TargetBlendDesc targetBlendDesc; - targetBlendDesc.color.srcFactor = BlendFactor::SrcAlpha; - targetBlendDesc.color.dstFactor = BlendFactor::InvSrcAlpha; - targetBlendDesc.alpha.srcFactor = BlendFactor::InvSrcAlpha; - targetBlendDesc.alpha.dstFactor = BlendFactor::Zero; - - GraphicsPipelineStateDesc pipelineDesc; - pipelineDesc.renderTargetCount = 1; - pipelineDesc.program = program; - pipelineDesc.pipelineLayout = pipelineLayout; - pipelineDesc.inputLayout = inputLayout; - pipelineDesc.blend.targets = &targetBlendDesc; - pipelineDesc.blend.targetCount = 1; - pipelineDesc.rasterizer.cullMode = CullMode::None; - - // Set up the pieces of fixed-function state that we care about - pipelineDesc.depthStencil.depthTestEnable = false; - - // TODO: need to set up blending state... - - pipelineState = renderer->createGraphicsPipelineState(pipelineDesc); - - // Initialize the texture atlas - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - - { - gfx::TextureResource::Desc desc; - desc.init2D(Resource::Type::Texture2D, Format::RGBA_Unorm_UInt8, width, height, 1); - desc.setDefaults(Resource::Usage::PixelShaderResource); - - - ptrdiff_t mipRowStrides[] = { ptrdiff_t(width * 4 * sizeof(unsigned char)) }; - void* subResourceData[] = { pixels }; - TextureResource::Data initData; - initData.mipRowStrides = mipRowStrides; - initData.numMips = 1; - initData.numSubResources = 1; - initData.subResources = subResourceData; - - auto texture = renderer->createTextureResource(Resource::Usage::PixelShaderResource, desc, &initData); - - gfx::ResourceView::Desc viewDesc; - viewDesc.format = desc.format; - viewDesc.type = ResourceView::Type::ShaderResource; - auto textureView = renderer->createTextureView(texture, viewDesc); - - io.Fonts->TexID = (void*) textureView.detach(); - } - - { - SamplerState::Desc desc; - samplerState = renderer->createSamplerState(desc); - } -} - - - -void GUI::beginFrame() -{ -#ifdef _WIN32 - ImGui_ImplWin32_NewFrame(); -#endif - ImGui::NewFrame(); -} - -void GUI::endFrame() -{ - ImGui::Render(); - - ImDrawData* draw_data = ImGui::GetDrawData(); - auto vertexCount = draw_data->TotalVtxCount; - auto indexCount = draw_data->TotalIdxCount; - int commandListCount = draw_data->CmdListsCount; - - if(!vertexCount) return; - if(!indexCount) return; - if(!commandListCount) return; - - // Allocate transient vertex/index buffers to hold the data for this frame. - - gfx::BufferResource::Desc vertexBufferDesc; - vertexBufferDesc.init(vertexCount * sizeof(ImDrawVert)); - vertexBufferDesc.setDefaults(Resource::Usage::VertexBuffer); - vertexBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write; - auto vertexBuffer = renderer->createBufferResource( - Resource::Usage::VertexBuffer, - vertexBufferDesc); - - gfx::BufferResource::Desc indexBufferDesc; - indexBufferDesc.init(indexCount * sizeof(ImDrawIdx)); - indexBufferDesc.setDefaults(Resource::Usage::IndexBuffer); - indexBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write; - auto indexBuffer = renderer->createBufferResource( - Resource::Usage::IndexBuffer, - indexBufferDesc); - - { - ImDrawVert* dstVertex = (ImDrawVert*) renderer->map(vertexBuffer, MapFlavor::WriteDiscard); - ImDrawIdx* dstIndex = (ImDrawIdx*) renderer->map(indexBuffer, MapFlavor::WriteDiscard); - - for(int ii = 0; ii < commandListCount; ++ii) - { - const ImDrawList* commandList = draw_data->CmdLists[ii]; - memcpy(dstVertex, commandList->VtxBuffer.Data, commandList->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(dstIndex, commandList->IdxBuffer.Data, commandList->IdxBuffer.Size * sizeof(ImDrawIdx)); - dstVertex += commandList->VtxBuffer.Size; - dstIndex += commandList->IdxBuffer.Size; - } - - renderer->unmap(vertexBuffer); - renderer->unmap(indexBuffer); - } - - // Allocate a transient constant buffer for projection matrix - gfx::BufferResource::Desc constantBufferDesc; - constantBufferDesc.init(sizeof(glm::mat4x4)); - constantBufferDesc.setDefaults(Resource::Usage::ConstantBuffer); - constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write; - auto constantBuffer = renderer->createBufferResource( - Resource::Usage::ConstantBuffer, - constantBufferDesc); - - { - glm::mat4x4* dstMVP = (glm::mat4x4*) renderer->map(constantBuffer, MapFlavor::WriteDiscard); - - float L = draw_data->DisplayPos.x; - float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; - float T = draw_data->DisplayPos.y; - float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; - float mvp[4][4] = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.5f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, - }; - memcpy(dstMVP, mvp, sizeof(mvp)); - - renderer->unmap(constantBuffer); - } - - gfx::Viewport viewport; - viewport.originX = 0; - viewport.originY = 0; - viewport.extentY = draw_data->DisplaySize.y; - viewport.extentX = draw_data->DisplaySize.x; - viewport.extentY = draw_data->DisplaySize.y; - viewport.minZ = 0; - viewport.maxZ = 1; - - renderer->setViewport(viewport); - - auto pipelineType = PipelineType::Graphics; - renderer->setPipelineState(pipelineType, pipelineState); - - renderer->setVertexBuffer(0, vertexBuffer, sizeof(ImDrawVert)); - renderer->setIndexBuffer(indexBuffer, sizeof(ImDrawIdx) == 2 ? Format::R_UInt16 : Format::R_UInt32); - renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList); - - UInt vertexOffset = 0; - UInt indexOffset = 0; - ImVec2 pos = draw_data->DisplayPos; - for(int ii = 0; ii < commandListCount; ++ii) - { - auto commandList = draw_data->CmdLists[ii]; - auto commandCount = commandList->CmdBuffer.Size; - for(int jj = 0; jj < commandCount; jj++) - { - auto command = &commandList->CmdBuffer[jj]; - if(auto userCallback = command->UserCallback) - { - userCallback(commandList, command); - } - else - { - ScissorRect rect = - { - (Int)(command->ClipRect.x - pos.x), - (Int)(command->ClipRect.y - pos.y), - (Int)(command->ClipRect.z - pos.x), - (Int)(command->ClipRect.w - pos.y) - }; - renderer->setScissorRect(rect); - - // TODO: This should be a dynamic/transient descriptor set... - auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout); - descriptorSet->setConstantBuffer(0, 0, constantBuffer); - descriptorSet->setResource(1, 0, - (gfx::ResourceView*) command->TextureId); - descriptorSet->setSampler(2, 0, - samplerState); - - renderer->setDescriptorSet( - pipelineType, - pipelineLayout, - 0, - descriptorSet); - - renderer->drawIndexed(command->ElemCount, indexOffset, vertexOffset); - } - indexOffset += command->ElemCount; - } - vertexOffset += commandList->VtxBuffer.Size; - } -} - -GUI::~GUI() -{ - auto& io = ImGui::GetIO(); - - { - RefPtr<ResourceView> textureView; - textureView.attach((ResourceView*) io.Fonts->TexID); - textureView = nullptr; - } - -#ifdef _WIN32 - ImGui_ImplWin32_Shutdown(); -#endif - - ImGui::DestroyContext(); -} - -} // gfx - -#include "external/imgui/imgui.cpp" -#include "external/imgui/imgui_draw.cpp" -#ifdef _WIN32 -#include "external/imgui/examples/imgui_impl_win32.cpp" -#endif diff --git a/tools/gfx/gui.h b/tools/gfx/gui.h deleted file mode 100644 index cbec5796f..000000000 --- a/tools/gfx/gui.h +++ /dev/null @@ -1,28 +0,0 @@ -// gui.h -#pragma once - -#include "render.h" -#include "vector-math.h" -#include "window.h" - -#include "external/imgui/imgui.h" - -namespace gfx { - -struct GUI : RefObject -{ - GUI(Window* window, Renderer* renderer); - ~GUI(); - - void beginFrame(); - void endFrame(); - -private: - RefPtr<Renderer> renderer; - RefPtr<PipelineState> pipelineState; - RefPtr<DescriptorSetLayout> descriptorSetLayout; - RefPtr<PipelineLayout> pipelineLayout; - RefPtr<SamplerState> samplerState; -}; - -} // gfx diff --git a/tools/gfx/model.cpp b/tools/gfx/model.cpp deleted file mode 100644 index ce176727b..000000000 --- a/tools/gfx/model.cpp +++ /dev/null @@ -1,564 +0,0 @@ -// model.cpp -#include "model.h" - -#define TINYOBJLOADER_IMPLEMENTATION -#include "../../external/tinyobjloader/tiny_obj_loader.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "../../external/stb/stb_image.h" - -#define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "../../external/stb/stb_image_resize.h" - -#include "../../external/glm/glm/glm.hpp" -#include "../../external/glm/glm/gtc/matrix_transform.hpp" -#include "../../external/glm/glm/gtc/constants.hpp" - -#include <memory> -#include <unordered_map> -#include <unordered_set> - -namespace gfx { - -// TinyObj provides a tuple type that bundles up indices, but doesn't -// provide equality comparison or hashing for that type. We'd like -// to have a hash function so that we can unique indices. -// -// In the simplest case, we could define hashing and operator== operations -// directly on `tinobj::index_t`, but that would create problems if they -// revise their API. -// -// We will instead define our own wrapper type that supports equality -// comparisons. -// -struct ObjIndexKey -{ - tinyobj::index_t index; -}; - -bool operator==(ObjIndexKey const& left, ObjIndexKey const& right) -{ - return left.index.vertex_index == right.index.vertex_index - && left.index.normal_index == right.index.normal_index - && left.index.texcoord_index == right.index.texcoord_index; -} - -struct Hasher -{ - template<typename T> - void add(T const& v) - { - state ^= std::hash<T>()(v) + 0x9e3779b9 + (state << 6) + (state >> 2); - } - size_t state = 0; -}; - -struct SmoothingGroupVertexID -{ - size_t smoothingGroup; - size_t positionID; -}; -bool operator==(SmoothingGroupVertexID const& left, SmoothingGroupVertexID const& right) -{ - return left.smoothingGroup == right.smoothingGroup - && left.positionID == right.positionID; -} - -} - -namespace std -{ - template<> struct hash<gfx::ObjIndexKey> - { - size_t operator()(gfx::ObjIndexKey const& key) const - { - gfx::Hasher hasher; - hasher.add(key.index.vertex_index); - hasher.add(key.index.normal_index); - hasher.add(key.index.texcoord_index); - return hasher.state; - } - }; - - template<> struct hash<gfx::SmoothingGroupVertexID> - { - size_t operator()(gfx::SmoothingGroupVertexID const& id) const - { - gfx::Hasher hasher; - hasher.add(id.smoothingGroup); - hasher.add(id.positionID); - return hasher.state; - } - }; -} - -namespace gfx -{ - -RefPtr<TextureResource> loadTextureImage( - Renderer* renderer, - char const* path) -{ - int extentX = 0; - int extentY = 0; - int originalChannelCount = 0; - int requestedChannelCount = 4; // force to 4-component result - stbi_uc* data = stbi_load( - path, - &extentX, - &extentY, - &originalChannelCount, - requestedChannelCount); - if(!data) - return nullptr; - - int channelCount = requestedChannelCount ? requestedChannelCount : originalChannelCount; - - Format format; - switch(channelCount) - { - default: - return nullptr; - - case 4: format = Format::RGBA_Unorm_UInt8; - - // TODO: handle other cases here if/when we stop forcing 4-component - // results when loading the image with stb_image. - } - - std::vector<void*> subresourceInitData; - std::vector<ptrdiff_t> mipRowStrides; - - ptrdiff_t stride = extentX * channelCount * sizeof(stbi_uc); - - subresourceInitData.push_back(data); - mipRowStrides.push_back(stride); - - // create down-sampled images for the different mip levels - bool generateMips = true; - if(generateMips) - { - int prevExtentX = extentX; - int prevExtentY = extentY; - stbi_uc* prevData = data; - int prevStride = int(stride); - - for(;;) - { - if(prevExtentX == 1 && prevExtentY == 1) - break; - - int newExtentX = prevExtentX / 2; - int newExtentY = prevExtentY / 2; - - if(!newExtentX) newExtentX = 1; - if(!newExtentY) newExtentY = 1; - - stbi_uc* newData = (stbi_uc*) malloc(newExtentX * newExtentY * channelCount * sizeof(stbi_uc)); - int newStride = int(newExtentX * channelCount * sizeof(stbi_uc)); - - stbir_resize_uint8_srgb( - prevData, prevExtentX, prevExtentY, prevStride, - newData, newExtentX, newExtentY, newStride, - channelCount, - STBIR_ALPHA_CHANNEL_NONE, - STBIR_FLAG_ALPHA_PREMULTIPLIED); - - subresourceInitData.push_back(newData); - mipRowStrides.push_back(newStride); - - prevExtentX = newExtentX; - prevExtentY = newExtentY; - prevData = newData; - prevStride = newStride; - } - } - - int mipCount = (int) mipRowStrides.size(); - - TextureResource::Desc desc; - desc.init2D(Resource::Type::Texture2D, format, extentX, extentY, mipCount); - - TextureResource::Data initData; - initData.numSubResources = mipCount; - initData.numMips = mipCount; - initData.subResources = &subresourceInitData[0]; - initData.mipRowStrides = &mipRowStrides[0]; - - auto texture = renderer->createTextureResource( - Resource::Usage::PixelShaderResource, - desc, - &initData); - - free(data); - - return texture; -} - -static std::string makeString(const char* start, const char* end) -{ - return std::string(start, size_t(end - start)); -} - -Result ModelLoader::load( - char const* inputPath, - void** outModel) -{ - // TODO: need to actually allocate/load the data - - tinyobj::attrib_t objVertexAttributes; - std::vector<tinyobj::shape_t> objShapes; - std::vector<tinyobj::material_t> objMaterials; - - std::string baseDir; - if( auto lastSlash = strrchr(inputPath, '/') ) - { - baseDir = makeString(inputPath, lastSlash); - } - - std::string diagnostics; - bool shouldTriangulate = true; - bool success = tinyobj::LoadObj( - &objVertexAttributes, - &objShapes, - &objMaterials, - &diagnostics, - inputPath, - baseDir.size() ? baseDir.c_str() : nullptr, - shouldTriangulate); - - if(!diagnostics.empty()) - { - log("%s", diagnostics.c_str()); - } - if(!success) - { - return SLANG_FAIL; - } - - // Translate each material imported by TinyObj into a format that - // we can actually use for rendering. - // - std::vector<void*> materials; - for(auto& objMaterial : objMaterials) - { - MaterialData materialData; - - materialData.diffuseColor = glm::vec3( - objMaterial.diffuse[0], - objMaterial.diffuse[1], - objMaterial.diffuse[2]); - - materialData.specularColor = glm::vec3( - objMaterial.specular[0], - objMaterial.specular[1], - objMaterial.specular[2]); - - materialData.specularity = objMaterial.shininess; - - // load any referenced textures here - if(objMaterial.diffuse_texname.length()) - { - materialData.diffuseMap = loadTextureImage( - renderer, - objMaterial.diffuse_texname.c_str()); - } - - auto material = callbacks->createMaterial(materialData); - materials.push_back(material); - } - - // Flip the winding order on all faces if we are asked to... - // - if(loadFlags & LoadFlag::FlipWinding) - { - for(auto& objShape : objShapes) - { - size_t objIndexCounter = 0; - size_t objFaceCounter = 0; - for(auto objFaceVertexCount : objShape.mesh.num_face_vertices) - { - size_t beginIndex = objIndexCounter; - size_t endIndex = beginIndex + objFaceVertexCount; - objIndexCounter = endIndex; - - size_t halfCount = objFaceVertexCount / 2; - for(size_t ii = 0; ii < halfCount; ++ii) - { - std::swap( - objShape.mesh.indices[beginIndex + ii], - objShape.mesh.indices[endIndex - (ii + 1)]); - } - } - } - - } - - // Identify cases where a face has a vertex without a normal, and in that - // case remember that the given vertex needs to be "smoothed" as part of - // the smoothing group for that face. Note that it is possible for the - // same vertex (position) to be part of faces in distinct smoothing groups. - // - std::unordered_map<SmoothingGroupVertexID, size_t> smoothedVertexNormals; - size_t firstSmoothedNormalID = objVertexAttributes.normals.size() / 3; - size_t flatFaceCounter = 0; - for(auto& objShape : objShapes) - { - size_t objIndexCounter = 0; - size_t objFaceCounter = 0; - for(auto objFaceVertexCount : objShape.mesh.num_face_vertices) - { - const size_t flatFaceIndex = flatFaceCounter++; - const size_t objFaceIndex = objFaceCounter++; - size_t smoothingGroup = objShape.mesh.smoothing_group_ids[objFaceIndex]; - if(!smoothingGroup) - { - smoothingGroup = ~flatFaceIndex; - } - - for(size_t objFaceVertex = 0; objFaceVertex < objFaceVertexCount; ++objFaceVertex) - { - tinyobj::index_t& objIndex = objShape.mesh.indices[objIndexCounter++]; - - if(objIndex.normal_index < 0) - { - SmoothingGroupVertexID smoothVertexID; - smoothVertexID.positionID = objIndex.vertex_index; - smoothVertexID.smoothingGroup = smoothingGroup; - - if(smoothedVertexNormals.find(smoothVertexID) == smoothedVertexNormals.end()) - { - size_t normalID = objVertexAttributes.normals.size() / 3; - objVertexAttributes.normals.push_back(0); - objVertexAttributes.normals.push_back(0); - objVertexAttributes.normals.push_back(0); - - smoothedVertexNormals.insert(std::make_pair(smoothVertexID, normalID)); - - objIndex.normal_index = int(normalID); - } - } - } - } - } - // - // Having identified which vertices we need to smooth, we will make another - // pass to compute face normals and apply them to the vertices that belong - // to the same smoothing group. - // - flatFaceCounter = 0; - for(auto& objShape : objShapes) - { - size_t objIndexCounter = 0; - size_t objFaceCounter = 0; - for(auto objFaceVertexCount : objShape.mesh.num_face_vertices) - { - const size_t flatFaceIndex = flatFaceCounter++; - const size_t objFaceIndex = objFaceCounter++; - size_t smoothingGroup = objShape.mesh.smoothing_group_ids[objFaceIndex]; - if(!smoothingGroup) - { - smoothingGroup = ~flatFaceIndex; - } - - glm::vec3 faceNormal; - if(objFaceVertexCount >= 3) - { - glm::vec3 v[3]; - for(size_t objFaceVertex = 0; objFaceVertex < 3; ++objFaceVertex) - { - tinyobj::index_t objIndex = objShape.mesh.indices[objIndexCounter + objFaceVertex]; - if(objIndex.vertex_index >= 0) - { - v[objFaceVertex] = glm::vec3( - objVertexAttributes.vertices[3 * objIndex.vertex_index + 0], - objVertexAttributes.vertices[3 * objIndex.vertex_index + 1], - objVertexAttributes.vertices[3 * objIndex.vertex_index + 2]); - } - } - faceNormal = cross(v[1] - v[0], v[2] - v[0]); - } - - // Add this face normal to any to-be-smoothed vertex on the face. - for(size_t objFaceVertex = 0; objFaceVertex < objFaceVertexCount; ++objFaceVertex) - { - tinyobj::index_t objIndex = objShape.mesh.indices[objIndexCounter++]; - - SmoothingGroupVertexID smoothVertexID; - smoothVertexID.positionID = objIndex.vertex_index; - smoothVertexID.smoothingGroup = smoothingGroup; - - auto ii = smoothedVertexNormals.find(smoothVertexID); - if(ii != smoothedVertexNormals.end()) - { - size_t normalID = ii->second; - objVertexAttributes.normals[normalID * 3 + 0] += faceNormal.x; - objVertexAttributes.normals[normalID * 3 + 1] += faceNormal.y; - objVertexAttributes.normals[normalID * 3 + 2] += faceNormal.z; - } - } - } - } - // - // Once we've added all contributions from each smoothing group, - // we can normalize the normals to compute the area-weighted average. - // - size_t normalCount = objVertexAttributes.normals.size() / 3; - for(size_t ii = firstSmoothedNormalID; ii < normalCount; ++ii) - { - glm::vec3 normal = glm::vec3( - objVertexAttributes.normals[3 * ii + 0], - objVertexAttributes.normals[3 * ii + 1], - objVertexAttributes.normals[3 * ii + 2]); - - normal = normalize(normal); - - objVertexAttributes.normals[3 * ii + 0] = normal.x; - objVertexAttributes.normals[3 * ii + 1] = normal.y; - objVertexAttributes.normals[3 * ii + 2] = normal.z; - } - - // TODO: we should sort the faces to group faces with - // the same material ID together, in case they weren't - // grouped in the original file. - - // We need to undo the .obj indexing stuff so that we have - // standard position/normal/etc. data in a single flat array - - std::unordered_map<ObjIndexKey, Index> mapObjIndexToFlatIndex; - std::vector<Vertex> flatVertices; - std::vector<Index> flatIndices; - - MeshData* currentMesh = nullptr; - MeshData currentMeshStorage; - - std::vector<void*> meshes; - - void* defaultMaterial = nullptr; - - for(auto& objShape : objShapes) - { - size_t objIndexCounter = 0; - size_t objFaceCounter = 0; - for(auto objFaceVertexCount : objShape.mesh.num_face_vertices) - { - size_t objFaceIndex = objFaceCounter++; - int faceMaterialID = objShape.mesh.material_ids[objFaceIndex]; - void* faceMaterial = nullptr; - if( faceMaterialID < 0 ) - { - if( !defaultMaterial ) - { - MaterialData defaultMaterialData; - defaultMaterialData.diffuseColor = glm::vec3(0.5, 0.5, 0.5); - defaultMaterial = callbacks->createMaterial(defaultMaterialData); - } - faceMaterial = defaultMaterial; - } - else - { - faceMaterial = materials[faceMaterialID]; - } - - if(!currentMesh || (faceMaterial != currentMesh->material)) - { - // finish old mesh. - if(currentMesh) - { - meshes.push_back(callbacks->createMesh(*currentMesh)); - } - - // Need to start a new mesh. - currentMesh = ¤tMeshStorage; - currentMesh->material = faceMaterial; - currentMesh->firstIndex = (int)flatIndices.size(); - currentMesh->indexCount = 0; - } - - for(size_t objFaceVertex = 0; objFaceVertex < objFaceVertexCount; ++objFaceVertex) - { - tinyobj::index_t objIndex = objShape.mesh.indices[objIndexCounter++]; - ObjIndexKey objIndexKey; objIndexKey.index = objIndex; - - - Index flatIndex = Index(-1); - auto iter = mapObjIndexToFlatIndex.find(objIndexKey); - if(iter != mapObjIndexToFlatIndex.end()) - { - flatIndex = iter->second; - } - else - { - Vertex flatVertex; - if(objIndex.vertex_index >= 0) - { - flatVertex.position = scale * glm::vec3( - objVertexAttributes.vertices[3 * objIndex.vertex_index + 0], - objVertexAttributes.vertices[3 * objIndex.vertex_index + 1], - objVertexAttributes.vertices[3 * objIndex.vertex_index + 2]); - } - if(objIndex.normal_index >= 0) - { - flatVertex.normal = glm::vec3( - objVertexAttributes.normals[3 * objIndex.normal_index + 0], - objVertexAttributes.normals[3 * objIndex.normal_index + 1], - objVertexAttributes.normals[3 * objIndex.normal_index + 2]); - } - if(objIndex.texcoord_index >= 0) - { - flatVertex.uv = glm::vec2( - objVertexAttributes.texcoords[2 * objIndex.texcoord_index + 0], - objVertexAttributes.texcoords[2 * objIndex.texcoord_index + 1]); - } - - flatIndex = uint32_t(flatVertices.size()); - mapObjIndexToFlatIndex.insert(std::make_pair(objIndexKey, flatIndex)); - flatVertices.push_back(flatVertex); - } - - flatIndices.push_back(flatIndex); - currentMesh->indexCount++; - } - } - } - - // finish last mesh. - if(currentMesh) - { - meshes.push_back(callbacks->createMesh(*currentMesh)); - } - - ModelData modelData; - - modelData.vertexCount = (int)flatVertices.size(); - modelData.indexCount = (int)flatIndices.size(); - - modelData.meshCount = int(meshes.size()); - modelData.meshes = meshes.data(); - - BufferResource::Desc vertexBufferDesc; - vertexBufferDesc.init(modelData.vertexCount * sizeof(Vertex)); - vertexBufferDesc.setDefaults(Resource::Usage::VertexBuffer); - - modelData.vertexBuffer = renderer->createBufferResource( - Resource::Usage::VertexBuffer, - vertexBufferDesc, - flatVertices.data()); - if(!modelData.vertexBuffer) return SLANG_FAIL; - - BufferResource::Desc indexBufferDesc; - indexBufferDesc.init(modelData.indexCount * sizeof(Index)); - vertexBufferDesc.setDefaults(Resource::Usage::IndexBuffer); - - modelData.indexBuffer = renderer->createBufferResource( - Resource::Usage::IndexBuffer, - indexBufferDesc, - flatIndices.data()); - if(!modelData.indexBuffer) return SLANG_FAIL; - - *outModel = callbacks->createModel(modelData); - - return SLANG_OK; -} - -} // gfx diff --git a/tools/gfx/model.h b/tools/gfx/model.h deleted file mode 100644 index 17b16510e..000000000 --- a/tools/gfx/model.h +++ /dev/null @@ -1,77 +0,0 @@ -// model.h -#pragma once - -#include "render.h" -#include "vector-math.h" - -#include <vector> -#include <string> - -namespace gfx { - -struct ModelLoader -{ - struct MaterialData - { - glm::vec3 diffuseColor; - glm::vec3 specularColor; - float specularity; - - RefPtr<TextureResource> diffuseMap; - }; - - struct Vertex - { - glm::vec3 position; - glm::vec3 normal; - glm::vec2 uv; - }; - - typedef uint32_t Index; - - struct MeshData - { - int firstIndex; - int indexCount; - - void* material; - }; - - struct ModelData - { - RefPtr<BufferResource> vertexBuffer; - RefPtr<BufferResource> indexBuffer; - PrimitiveTopology primitiveTopology; - int vertexCount; - int indexCount; - int meshCount; - void* const* meshes; - }; - - struct ICallbacks - { - typedef ModelLoader::MaterialData MaterialData; - typedef ModelLoader::MeshData MeshData; - typedef ModelLoader::ModelData ModelData; - - virtual void* createMaterial(MaterialData const& data) = 0; - virtual void* createMesh(MeshData const& data) = 0; - virtual void* createModel(ModelData const& data) = 0; - }; - - typedef uint32_t LoadFlags; - enum LoadFlag : LoadFlags - { - FlipWinding = 1 << 0, - }; - - ICallbacks* callbacks = nullptr; - RefPtr<Renderer> renderer; - LoadFlags loadFlags = 0; - float scale = 1.0f; - - Result load(char const* inputPath, void** outModel); -}; - - -} // gfx diff --git a/tools/gfx/nvapi/nvapi-util.h b/tools/gfx/nvapi/nvapi-util.h index 704f4ede4..0bcab7d36 100644 --- a/tools/gfx/nvapi/nvapi-util.h +++ b/tools/gfx/nvapi/nvapi-util.h @@ -1,8 +1,8 @@ // nvapi-util.h #pragma once -#include "../../slang-com-helper.h" -#include "../../slang-com-ptr.h" +#include "slang-com-helper.h" +#include "slang-com-ptr.h" namespace gfx { diff --git a/tools/gfx/render.h b/tools/gfx/render.h index fb9e10724..ab9af8afb 100644 --- a/tools/gfx/render.h +++ b/tools/gfx/render.h @@ -1,8 +1,6 @@ // render.h #pragma once -#include "window.h" - //#include "shader-input-layout.h" #include <float.h> diff --git a/tools/gfx/vector-math.h b/tools/gfx/vector-math.h deleted file mode 100644 index e35cb46ac..000000000 --- a/tools/gfx/vector-math.h +++ /dev/null @@ -1,15 +0,0 @@ -// vector-math.h -#pragma once - -// We will use the GLM library for our vector math types, just for simplicity. - -#include "../../external/glm/glm/glm.hpp" -#include "../../external/glm/glm/gtc/matrix_transform.hpp" -#include "../../external/glm/glm/gtc/constants.hpp" -#include "../../external/glm/glm/gtc/quaternion.hpp" - -namespace gfx { - -using namespace glm; - -} // gfx diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index 0f6e3cdaa..80393904c 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -5,7 +5,7 @@ #include "../render.h" #include "../render-graphics-common.h" -#include "../../source/core/slang-smart-pointer.h" +#include "core/slang-smart-pointer.h" #include "vk-api.h" #include "vk-util.h" diff --git a/tools/gfx/vulkan/vk-api.cpp b/tools/gfx/vulkan/vk-api.cpp index 50f80aa26..9b51b644c 100644 --- a/tools/gfx/vulkan/vk-api.cpp +++ b/tools/gfx/vulkan/vk-api.cpp @@ -1,7 +1,7 @@ // vk-api.cpp #include "vk-api.h" -#include "../../source/core/slang-list.h" +#include "core/slang-list.h" namespace gfx { using namespace Slang; diff --git a/tools/gfx/vulkan/vk-module.h b/tools/gfx/vulkan/vk-module.h index 4d18823ca..7ddd5da45 100644 --- a/tools/gfx/vulkan/vk-module.h +++ b/tools/gfx/vulkan/vk-module.h @@ -1,9 +1,9 @@ // vk-module.h #pragma once -#include "../../slang.h" +#include "slang.h" -#include "../../slang-com-helper.h" +#include "slang-com-helper.h" #if SLANG_WINDOWS_FAMILY # define VK_USE_PLATFORM_WIN32_KHR 1 diff --git a/tools/gfx/vulkan/vk-swap-chain.cpp b/tools/gfx/vulkan/vk-swap-chain.cpp index d9b3a495d..21460ce61 100644 --- a/tools/gfx/vulkan/vk-swap-chain.cpp +++ b/tools/gfx/vulkan/vk-swap-chain.cpp @@ -3,7 +3,7 @@ #include "vk-util.h" -#include "../../source/core/slang-list.h" +#include "core/slang-list.h" #include <stdlib.h> #include <stdio.h> diff --git a/tools/gfx/vulkan/vk-swap-chain.h b/tools/gfx/vulkan/vk-swap-chain.h index 9b4dfc2c1..893910ea6 100644 --- a/tools/gfx/vulkan/vk-swap-chain.h +++ b/tools/gfx/vulkan/vk-swap-chain.h @@ -6,7 +6,7 @@ #include "../render.h" -#include "../../source/core/slang-list.h" +#include "core/slang-list.h" namespace gfx { diff --git a/tools/gfx/window.h b/tools/gfx/window.h deleted file mode 100644 index e6f886f42..000000000 --- a/tools/gfx/window.h +++ /dev/null @@ -1,122 +0,0 @@ -// window.h -#pragma once - -#include <stdint.h> - -namespace gfx { - -struct Window; - -enum class KeyCode -{ - Unknown, - - // TODO: extend this to cover at least a standard US-English keyboard - - A, B, C, D, E, F, G, H, I, J, - K, L, M, N, O, P, Q, R, S, T, - U, V, W, X, Y, Z, - - Space, -}; - -enum class EventCode : uint32_t -{ - MouseDown, - MouseUp, - MouseMoved, - KeyDown, - KeyUp, -}; - -struct Event -{ - EventCode code; - Window* window; - union - { - struct - { - float x; - float y; - } mouse; - - KeyCode key; - } u; -}; - -typedef void (*EventHandler)(Event const&); - -struct WindowDesc -{ - char const* title = nullptr; - void* userData = nullptr; - int width = 0; - int height = 0; - EventHandler eventHandler = nullptr; -}; - -Window* createWindow(WindowDesc const& desc); -void showWindow(Window* window); - -void* getPlatformWindowHandle(Window* window); -void* getUserData(Window* window); - -/// Opaque state provided by platform for a running application. -typedef struct ApplicationContext ApplicationContext; - -/// User-defined application entry-point function. -typedef void(*ApplicationFunc)(ApplicationContext* context); - -/// Dispatch any pending events for application. -/// -/// @returns `true` if application should keep running. -bool dispatchEvents(ApplicationContext* context); - -/// Exit the application with a given result code -void exitApplication(ApplicationContext* context, int resultCode); - -/// Log a message to an appropriate logging destination. -void log(char const* message, ...); - -/// Report an error to an appropriate logging destination. -int reportError(char const* message, ...); - -uint64_t getCurrentTime(); - -uint64_t getTimerFrequency(); - -/// Run an application given the specified callback and command-line arguments. -int runApplication( - ApplicationFunc func, - int argc, - char const* const* argv); - -#define GFX_CONSOLE_MAIN(APPLICATION_ENTRY) \ - int main(int argc, char** argv) { \ - return gfx::runApplication(&(APPLICATION_ENTRY), argc, argv); \ - } - -#ifdef _WIN32 - -int runWindowsApplication( - ApplicationFunc func, - void* instance, - int showCommand); - -#define GFX_UI_MAIN(APPLICATION_ENTRY) \ - int __stdcall WinMain( \ - void* instance, \ - void* /* prevInstance */, \ - void* /* commandLine */, \ - int showCommand) { \ - return gfx::runWindowsApplication(&(APPLICATION_ENTRY), instance, showCommand); \ - } - -#else - -#define GFX_UI_MAIN(APPLICATION_ENTRY) GFX_CONSOLE_MAIN(APPLICATION_ENTRY) - -#endif - -} // gfx diff --git a/tools/gfx/windows/win-window.cpp b/tools/gfx/windows/win-window.cpp deleted file mode 100644 index 45315a27a..000000000 --- a/tools/gfx/windows/win-window.cpp +++ /dev/null @@ -1,398 +0,0 @@ -// win-window.cpp -#include "../window.h" - -#include <stdio.h> - -#ifdef _MSC_VER -#include <stddef.h> -#if (_MSC_VER < 1900) -#define snprintf sprintf_s -#endif -#endif - -#include <stdint.h> - -#if _WIN32 -#include <Windows.h> -#include <Windowsx.h> -#else -#error "The slang-graphics library currently only supports Windows platforms" -#endif - -namespace gfx { - -#if _WIN32 - -struct OSString -{ - OSString(char const* begin, char const* end) - { - _initialize(begin, end - begin); - } - - OSString(char const* begin) - { - _initialize(begin, strlen(begin)); - } - - ~OSString() - { - free(mBegin); - } - - operator WCHAR const*() - { - return mBegin; - } - -private: - WCHAR* mBegin; - WCHAR* mEnd; - - void _initialize(char const* input, size_t inputSize) - { - const DWORD dwFlags = 0; - int outputCodeUnitCount = ::MultiByteToWideChar(CP_UTF8, dwFlags, input, int(inputSize), nullptr, 0); - - WCHAR* buffer = (WCHAR*)malloc(sizeof(WCHAR) * (outputCodeUnitCount + 1)); - - ::MultiByteToWideChar(CP_UTF8, dwFlags, input, int(inputSize), buffer, outputCodeUnitCount); - buffer[outputCodeUnitCount] = 0; - - mBegin = buffer; - mEnd = buffer + outputCodeUnitCount; - } -}; - -struct ApplicationContext -{ - HINSTANCE instance; - int showCommand = SW_SHOWDEFAULT; - int resultCode = 0; -}; - -static uint64_t gTimerFrequency; - - -static void initApplication(ApplicationContext* context) -{ - LARGE_INTEGER timerFrequency; - QueryPerformanceFrequency(&timerFrequency); - gTimerFrequency = timerFrequency.QuadPart; -} - -/// Run an application given the specified callback and command-line arguments. -int runApplication( - ApplicationFunc func, - int argc, - char const* const* argv) -{ - ApplicationContext context; - context.instance = (HINSTANCE) GetModuleHandle(0); - initApplication(&context); - func(&context); - return context.resultCode; -} - -int runWindowsApplication( - ApplicationFunc func, - void* instance, - int showCommand) -{ - ApplicationContext context; - context.instance = (HINSTANCE) instance; - context.showCommand = showCommand; - initApplication(&context); - func(&context); - return context.resultCode; -} - -struct Window -{ - HWND handle; - WNDPROC nativeHook; - EventHandler eventHandler; - void* userData; -}; - -void setNativeWindowHook(Window* window, WNDPROC proc) -{ - window->nativeHook = proc; -} - -static KeyCode translateKeyCode(int vkey) -{ - switch( vkey ) - { - default: - return KeyCode::Unknown; - -#define CASE(FROM, TO) case FROM: return KeyCode::TO; - CASE('A', A); CASE('B', B); CASE('C', C); CASE('D', D); CASE('E', E); - CASE('F', F); CASE('G', G); CASE('H', H); CASE('I', I); CASE('J', J); - CASE('K', K); CASE('L', M); CASE('M', M); CASE('N', N); CASE('O', O); - CASE('P', P); CASE('Q', Q); CASE('R', R); CASE('S', S); CASE('T', T); - CASE('U', U); CASE('V', V); CASE('W', W); CASE('X', X); CASE('Y', Y); - CASE('Z', Z); -#undef CASE - -#define CASE(FROM, TO) case VK_##FROM: return KeyCode::TO; - CASE(SPACE, Space); -#undef CASE - } -} - -static LRESULT CALLBACK windowProc( - HWND windowHandle, - UINT message, - WPARAM wParam, - LPARAM lParam) -{ - Window* window = (Window*) GetWindowLongPtrW(windowHandle, GWLP_USERDATA); - - // Give the installed filter a chance to intercept messages. - // (This is used for ImGui) - if( window ) - { - if(auto nativeHook = window->nativeHook) - { - auto result = nativeHook(windowHandle, message, wParam, lParam); - if(result) - return result; - } - } - - auto eventHandler = window ? window->eventHandler : nullptr; - - switch (message) - { - case WM_CREATE: - { - auto createInfo = (CREATESTRUCTW*) lParam; - window = (Window*) createInfo->lpCreateParams; - window->handle = windowHandle; - - SetWindowLongPtrW(windowHandle, GWLP_USERDATA, (LONG_PTR) window); - } - break; - - case WM_KEYDOWN: - case WM_KEYUP: - { - int virtualKey = (int) wParam; - auto keyCode = translateKeyCode(virtualKey); - if(eventHandler) - { - Event event; - event.window = window; - event.code = message == WM_KEYDOWN ? EventCode::KeyDown : EventCode::KeyUp; - event.u.key = keyCode; - eventHandler(event); - } - } - break; - - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - { - if(eventHandler) - { - Event event; - event.window = window; - event.code = message == WM_LBUTTONDOWN ? EventCode::MouseDown : EventCode::MouseUp; - event.u.mouse.x = (float) GET_X_LPARAM(lParam); - event.u.mouse.y = (float) GET_Y_LPARAM(lParam); - eventHandler(event); - } - } - break; - - case WM_MOUSEMOVE: - { - if(eventHandler) - { - Event event; - event.window = window; - event.code = EventCode::MouseMoved; - event.u.mouse.x = (float) GET_X_LPARAM(lParam); - event.u.mouse.y = (float) GET_Y_LPARAM(lParam); - eventHandler(event); - } - } - break; - - case WM_CLOSE: - PostQuitMessage(0); - return 0; - } - - - return DefWindowProcW(windowHandle, message, wParam, lParam); -} - - -static ATOM createWindowClassAtom() -{ - WNDCLASSEXW windowClassDesc; - windowClassDesc.cbSize = sizeof(windowClassDesc); - windowClassDesc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; - windowClassDesc.lpfnWndProc = &windowProc; - windowClassDesc.cbClsExtra = 0; - windowClassDesc.cbWndExtra = 0; - windowClassDesc.hInstance = (HINSTANCE) GetModuleHandle(0); - windowClassDesc.hIcon = 0; - windowClassDesc.hCursor = 0; - windowClassDesc.hbrBackground = 0; - windowClassDesc.lpszMenuName = 0; - windowClassDesc.lpszClassName = L"SlangGraphicsWindow"; - windowClassDesc.hIconSm = 0; - ATOM windowClassAtom = RegisterClassExW(&windowClassDesc); - return windowClassAtom; -} - -static ATOM getWindowClassAtom() -{ - static ATOM windowClassAtom = createWindowClassAtom(); - return windowClassAtom; -} - -Window* createWindow(WindowDesc const& desc) -{ - Window* window = new Window(); - window->handle = nullptr; - window->nativeHook = nullptr; - window->eventHandler = desc.eventHandler; - window->userData = desc.userData; - - OSString windowTitle(desc.title); - - DWORD windowExtendedStyle = 0; - DWORD windowStyle = 0; - - HINSTANCE instance = (HINSTANCE) GetModuleHandle(0); - - HWND windowHandle = CreateWindowExW( - windowExtendedStyle, - (LPWSTR) getWindowClassAtom(), - windowTitle, - windowStyle, - 0, 0, // x, y - desc.width, desc.height, - NULL, // parent - NULL, // menu - instance, - window); - - if(!windowHandle) - { - delete window; - return nullptr; - } - - window->handle = windowHandle; - return window; -} - -void showWindow(Window* window) -{ - ShowWindow(window->handle, SW_SHOW); -} - -void* getPlatformWindowHandle(Window* window) -{ - return window->handle; -} - -void* getUserData(Window* window) -{ - return window->userData; -} - -bool dispatchEvents(ApplicationContext* context) -{ - for(;;) - { - MSG message; - - int result = PeekMessageW(&message, NULL, 0, 0, PM_REMOVE); - if (result != 0) - { - if (message.message == WM_QUIT) - { - context->resultCode = (int)message.wParam; - return false; - } - - TranslateMessage(&message); - DispatchMessageW(&message); - } - else - { - return true; - } - } - -} - -void exitApplication(ApplicationContext* context, int resultCode) -{ - ExitProcess(resultCode); -} - -void log(char const* message, ...) -{ - va_list args; - va_start(args, message); - - static const int kBufferSize = 1024; - char messageBuffer[kBufferSize]; - vsnprintf(messageBuffer, kBufferSize - 1, message, args); - messageBuffer[kBufferSize - 1] = 0; - - va_end(args); - - fputs(messageBuffer, stderr); - - OSString wideMessageBuffer(messageBuffer); - OutputDebugStringW(wideMessageBuffer); -} - -int reportError(char const* message, ...) -{ - va_list args; - va_start(args, message); - - static const int kBufferSize = 1024; - char messageBuffer[kBufferSize]; - vsnprintf(messageBuffer, kBufferSize - 1, message, args); - messageBuffer[kBufferSize - 1] = 0; - - va_end(args); - - fputs(messageBuffer, stderr); - - OSString wideMessageBuffer(messageBuffer); - OutputDebugStringW(wideMessageBuffer); - - return 1; -} - -uint64_t getCurrentTime() -{ - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - return counter.QuadPart; -} - -uint64_t getTimerFrequency() -{ - return gTimerFrequency; -} - -#else - -// TODO: put an SDL version here - -#endif - -} // gfx |
