Implemented rotating cube.
This commit is contained in:
parent
bcdabba916
commit
5f8a4656fe
BIN
assets/bitmaps/cube.png
Normal file
BIN
assets/bitmaps/cube.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
12
assets/meshes/cube.mtl
Normal file
12
assets/meshes/cube.mtl
Normal file
@ -0,0 +1,12 @@
|
||||
# Blender 4.1.1 MTL File: 'None'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Material
|
||||
Ns 250.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.800000 0.800000 0.800000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
23
assets/shaders/glsl/textured_3dtriangles_from_buffer.vert
Normal file
23
assets/shaders/glsl/textured_3dtriangles_from_buffer.vert
Normal file
@ -0,0 +1,23 @@
|
||||
#version 460
|
||||
|
||||
layout(set = 1, binding = 0)
|
||||
uniform Parameters
|
||||
{
|
||||
mat4 u_worldToView;
|
||||
mat4 u_viewToClip;
|
||||
};
|
||||
|
||||
layout(location = 0)
|
||||
in vec3 i_position;
|
||||
|
||||
layout(location = 1)
|
||||
in vec2 i_texCoord;
|
||||
|
||||
layout(location = 0)
|
||||
out vec2 o_texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_viewToClip * u_worldToView * vec4(i_position, 1.0);
|
||||
o_texCoord = i_texCoord;
|
||||
}
|
2
external/scons-plus-plus
vendored
2
external/scons-plus-plus
vendored
@ -1 +1 @@
|
||||
Subproject commit fe8f329b3852b0492cee6fc3c7d5ed71cf761c07
|
||||
Subproject commit c74fbb8798a78227d4f53b508c079eae6245246d
|
176
private/sdl_gpu_test/2_textured_cube/app.cpp
Normal file
176
private/sdl_gpu_test/2_textured_cube/app.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
#include "./app.hpp"
|
||||
|
||||
#include "../util/mesh.hpp"
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "../util/mesh.hpp"
|
||||
|
||||
namespace sdl_gpu_test
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct VertexShaderParameters
|
||||
{
|
||||
glm::mat4 worldToView;
|
||||
glm::mat4 viewToClip;
|
||||
};
|
||||
}
|
||||
|
||||
void TexturedCubeApp::init(const AppInitArgs& args)
|
||||
{
|
||||
Application::init(args);
|
||||
|
||||
// create shaders
|
||||
const sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/textured_3dtriangles_from_buffer.vert.spv", {
|
||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||
.stage = sdlpp::GPUShaderStage::VERTEX,
|
||||
.numUniformBuffers = 1
|
||||
});
|
||||
const sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", {
|
||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||
.stage = sdlpp::GPUShaderStage::FRAGMENT,
|
||||
.numSamplers = 1,
|
||||
.numUniformBuffers = 1
|
||||
});
|
||||
|
||||
// create depth buffer
|
||||
mDepthBuffer.create(mDevice, {
|
||||
.format = sdlpp::GPUTextureFormat::D16_UNORM,
|
||||
.usage = sdlpp::GPUTextureUsageFlags{.depthStencilTarget = true},
|
||||
.width = 1280,
|
||||
.height = 720
|
||||
});
|
||||
|
||||
// create graphics pipeline
|
||||
std::array colorTargetsDescs = {
|
||||
sdlpp::GPUColorTargetDescription{
|
||||
.format = mDevice.getSwapchainTextureFormat(mWindow),
|
||||
.blendState = {
|
||||
.enableBlend = true,
|
||||
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
|
||||
.dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = sdlpp::GPUBlendOp::ADD,
|
||||
.srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE,
|
||||
.dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO,
|
||||
.alphaBlendOp = sdlpp::GPUBlendOp::ADD
|
||||
}
|
||||
}
|
||||
};
|
||||
std::array vertexBindings = {
|
||||
sdlpp::GPUVertexBinding{
|
||||
.index = 0,
|
||||
.pitch = sizeof(Vertex)
|
||||
}
|
||||
};
|
||||
std::array vertexAttributes = {
|
||||
sdlpp::GPUVertexAttribute{
|
||||
.location = 0,
|
||||
.bindingIndex = 0,
|
||||
.format = sdlpp::GPUVertexElementFormat::FLOAT3,
|
||||
.offset = offsetof(Vertex, pos)
|
||||
},
|
||||
sdlpp::GPUVertexAttribute{
|
||||
.location = 1,
|
||||
.bindingIndex = 0,
|
||||
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
|
||||
.offset = offsetof(Vertex, texcoord)
|
||||
}
|
||||
};
|
||||
mPipeline.create(mDevice, {
|
||||
.vertexShader = vertexShader,
|
||||
.fragmentShader = fragmentShader,
|
||||
.vertexInputState = {
|
||||
.vertexBindings = vertexBindings,
|
||||
.vertexAttributes = vertexAttributes
|
||||
},
|
||||
.rasterizerState = {
|
||||
.cullMode = sdlpp::GPUCullMode::BACK
|
||||
},
|
||||
.targetInfo = {
|
||||
.colorTargetDescriptions = colorTargetsDescs,
|
||||
.depthStencilFormat = sdlpp::GPUTextureFormat::D16_UNORM
|
||||
}
|
||||
});
|
||||
|
||||
// load the mesh
|
||||
const Mesh mesh = loadMesh(mFileSystem.getPath("meshes/cube.obj"));
|
||||
mNumVertices = static_cast<Uint32>(mesh.vertices.size());
|
||||
|
||||
// create vertex buffer
|
||||
mVertexBuffer.create(mDevice, {
|
||||
.usage = {.vertex = true},
|
||||
.size = static_cast<Uint32>(mesh.vertices.size() * sizeof(Vertex))
|
||||
});
|
||||
uploadVertexData(mVertexBuffer, std::span(mesh.vertices.begin(), mesh.vertices.end()));
|
||||
|
||||
// create texture and sampler
|
||||
sdlpp::GPUTextureCreateArgs textureArgs = {
|
||||
.format = sdlpp::GPUTextureFormat::R8G8B8A8_UNORM_SRGB,
|
||||
.usage = {.sampler = true}
|
||||
};
|
||||
mTexture = loadTexture("bitmaps/cube.png", textureArgs);
|
||||
mSampler.create(mDevice, {});
|
||||
}
|
||||
|
||||
void TexturedCubeApp::update(const AppUpdateArgs& args)
|
||||
{
|
||||
Application::update(args);
|
||||
|
||||
sdlpp::GPUCommandBuffer cmdBuffer = mDevice.acquireCommandBuffer();
|
||||
Uint32 swapchainWidth = 0, swapchainHeight = 0;
|
||||
const sdlpp::GPUTexture swapchainTexture = cmdBuffer.acquireSwapchainTexture(mWindow, swapchainWidth, swapchainHeight);
|
||||
|
||||
if (swapchainWidth != mLastSwapchainWidth || swapchainHeight != mLastSwapchainHeight)
|
||||
{
|
||||
mDepthBuffer.destroy();
|
||||
mDepthBuffer.create(mDevice, {
|
||||
.format = sdlpp::GPUTextureFormat::D16_UNORM,
|
||||
.usage = sdlpp::GPUTextureUsageFlags{.depthStencilTarget = true},
|
||||
.width = swapchainWidth,
|
||||
.height = swapchainHeight
|
||||
});
|
||||
mLastSwapchainWidth = swapchainWidth;
|
||||
mLastSwapchainHeight = swapchainHeight;
|
||||
}
|
||||
|
||||
const VertexShaderParameters vertexShaderParameters = {
|
||||
.worldToView = glm::lookAt(glm::vec3(2.f, 1.5f, 2.f), glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 1.f, 0.f))
|
||||
* glm::rotate(glm::mat4(1.f), glm::radians(40.f * args.secondsSinceStart), glm::vec3(0.f, 1.f, 0.f)),
|
||||
.viewToClip = glm::perspectiveFov(
|
||||
/* fov = */ glm::radians(90.f),
|
||||
/* width = */ static_cast<float>(swapchainWidth),
|
||||
/* height = */ static_cast<float>(swapchainHeight),
|
||||
/* zNear = */ 0.1f,
|
||||
/* zFar = */ 100.f
|
||||
)
|
||||
};
|
||||
|
||||
std::array colorTargets = {sdlpp::GPUColorTargetInfo{
|
||||
.texture = swapchainTexture,
|
||||
.clearColor = {.r = 0.f, .g = 0.f, .b = 0.f, .a = 1.f},
|
||||
.loadOp = sdlpp::GPULoadOp::CLEAR,
|
||||
}};
|
||||
sdlpp::GPURenderPass renderPass = cmdBuffer.beginRenderPass({
|
||||
.colorTargetInfos = colorTargets,
|
||||
.depthStencilTargetInfo = sdlpp::GPUDepthStencilTargetInfo{
|
||||
.texture = mDepthBuffer,
|
||||
.loadOp = sdlpp::GPULoadOp::CLEAR
|
||||
}
|
||||
});
|
||||
static const glm::vec4 WHITE(1.f, 1.f, 1.f, 1.f);
|
||||
cmdBuffer.pushFragmentUniformData(0, std::span(&WHITE, 1));
|
||||
cmdBuffer.pushVertexUniformData(0, std::span(&vertexShaderParameters, 1));
|
||||
renderPass.bindFragmentSampler({.texture = mTexture, .sampler = mSampler});
|
||||
renderPass.bindGraphicsPipeline(mPipeline);
|
||||
renderPass.bindVertexBuffer({.buffer = mVertexBuffer});
|
||||
renderPass.drawPrimitives({.numVertices = mNumVertices});
|
||||
renderPass.end();
|
||||
cmdBuffer.submit();
|
||||
}
|
||||
}
|
28
private/sdl_gpu_test/2_textured_cube/app.hpp
Normal file
28
private/sdl_gpu_test/2_textured_cube/app.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_2_TEXTURED_CUBE_APP_HPP_INCLUDED)
|
||||
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_2_TEXTURED_CUBE_APP_HPP_INCLUDED 1
|
||||
|
||||
#include "../application.hpp"
|
||||
|
||||
namespace sdl_gpu_test
|
||||
{
|
||||
class TexturedCubeApp : public Application
|
||||
{
|
||||
private:
|
||||
sdlpp::GPUBuffer mVertexBuffer;
|
||||
sdlpp::GPUTexture mDepthBuffer;
|
||||
sdlpp::GPUGraphicsPipeline mPipeline;
|
||||
sdlpp::GPUTexture mTexture;
|
||||
sdlpp::GPUSampler mSampler;
|
||||
Uint32 mNumVertices = 0;
|
||||
Uint32 mLastSwapchainWidth = 1280;
|
||||
Uint32 mLastSwapchainHeight = 720;
|
||||
public:
|
||||
void init(const AppInitArgs& args) override;
|
||||
void update(const AppUpdateArgs& args) override;
|
||||
};
|
||||
} // namespace sdl_gpu_test
|
||||
|
||||
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_2_TEXTURED_CUBE_APP_HPP_INCLUDED)
|
@ -6,9 +6,11 @@ src_files = Split("""
|
||||
|
||||
application.cpp
|
||||
util/bitmap.cpp
|
||||
util/mesh.cpp
|
||||
|
||||
0_triangle_with_texcoords/app.cpp
|
||||
1_textured_quad/app.cpp
|
||||
2_textured_cube/app.cpp
|
||||
""")
|
||||
|
||||
shader_files = env.Glob("#assets/shaders/glsl/*.frag") \
|
||||
@ -27,7 +29,8 @@ prog_app = env.UnityProgram(
|
||||
}
|
||||
},
|
||||
'spdlog': {},
|
||||
'stb': {}
|
||||
'stb': {},
|
||||
'tinyobjloader': {}
|
||||
}
|
||||
)
|
||||
env.Default(prog_app)
|
||||
|
@ -1,6 +1,8 @@
|
||||
|
||||
#include "./application.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <mijin/util/variant.hpp>
|
||||
#include <mijin/virtual_filesystem/relative.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
@ -48,9 +50,12 @@ void Application::update(const AppUpdateArgs&)
|
||||
|
||||
void Application::run(std::span<const char*> args)
|
||||
{
|
||||
using clock_t = std::chrono::steady_clock;
|
||||
init({
|
||||
.programArgs = args
|
||||
});
|
||||
|
||||
const clock_t::time_point startTime = clock_t::now();
|
||||
while (mRunning)
|
||||
{
|
||||
std::optional<sdlpp::sdl_event_t> event;
|
||||
@ -61,7 +66,11 @@ void Application::run(std::span<const char*> args)
|
||||
[](const auto&) {} // default handler
|
||||
}, *event);
|
||||
}
|
||||
update({});
|
||||
|
||||
const clock_t::time_point frameTime = clock_t::now();
|
||||
update({
|
||||
.secondsSinceStart = std::chrono::duration_cast<std::chrono::duration<float>>(frameTime - startTime).count()
|
||||
});
|
||||
}
|
||||
cleanup({});
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct AppCleanupArgs
|
||||
|
||||
struct AppUpdateArgs
|
||||
{
|
||||
|
||||
float secondsSinceStart = 0.f;
|
||||
};
|
||||
|
||||
class Application
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
#include "./0_triangle_with_texcoords/app.hpp"
|
||||
#include "./1_textured_quad/app.hpp"
|
||||
#include "./2_textured_cube/app.hpp"
|
||||
|
||||
#include <mijin/debug/stacktrace.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
@ -23,7 +24,8 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
// make sure app is destructed before shutting down SDL
|
||||
// std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TriangleWithTexcoordsApp>();
|
||||
std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TexturedQuadApp>();
|
||||
// std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TexturedQuadApp>();
|
||||
std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TexturedCubeApp>();
|
||||
app->run(std::span(const_cast<const char**>(argv), argc));
|
||||
}
|
||||
catch (std::exception& exception)
|
||||
|
@ -433,7 +433,6 @@ static_assert(sizeof(GPUColorTargetDescription) == sizeof(SDL_GPUColorTargetDesc
|
||||
struct GPUGraphicsPipelineTargetInfo
|
||||
{
|
||||
std::span<const GPUColorTargetDescription> colorTargetDescriptions;
|
||||
bool hasDepthStencilTarget = false;
|
||||
GPUTextureFormat depthStencilFormat = GPUTextureFormat::INVALID;
|
||||
|
||||
explicit operator SDL_GpuGraphicsPipelineTargetInfo() const noexcept
|
||||
@ -441,7 +440,7 @@ struct GPUGraphicsPipelineTargetInfo
|
||||
return {
|
||||
.color_target_descriptions = std::bit_cast<const SDL_GPUColorTargetDescription*>(colorTargetDescriptions.data()),
|
||||
.num_color_targets = static_cast<Uint32>(colorTargetDescriptions.size()),
|
||||
.has_depth_stencil_target = hasDepthStencilTarget,
|
||||
.has_depth_stencil_target = depthStencilFormat != GPUTextureFormat::INVALID,
|
||||
.depth_stencil_format = static_cast<SDL_GPUTextureFormat>(depthStencilFormat)
|
||||
};
|
||||
}
|
||||
@ -843,6 +842,17 @@ public:
|
||||
return texture;
|
||||
}
|
||||
|
||||
template<typename TData>
|
||||
void pushVertexUniformData(Uint32 slotIndex, std::span<const TData> data) const noexcept
|
||||
{
|
||||
SDL_PushGPUVertexUniformData(
|
||||
/* command_buffer = */ mHandle,
|
||||
/* slot_index = */ slotIndex,
|
||||
/* data = */ data.data(),
|
||||
/* length = */ data.size_bytes()
|
||||
);
|
||||
}
|
||||
|
||||
template<typename TData>
|
||||
void pushFragmentUniformData(Uint32 slotIndex, std::span<const TData> data) const noexcept
|
||||
{
|
||||
|
75
private/sdl_gpu_test/util/mesh.cpp
Normal file
75
private/sdl_gpu_test/util/mesh.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
|
||||
#include "./mesh.hpp"
|
||||
|
||||
#include <tiny_obj_loader.h>
|
||||
|
||||
namespace sdl_gpu_test
|
||||
{
|
||||
Mesh loadMesh(const mijin::PathReference& path)
|
||||
{
|
||||
std::unique_ptr<mijin::Stream> stream;
|
||||
mijin::throwOnError(path.open(mijin::FileOpenMode::READ, stream));
|
||||
mijin::IOStreamAdapter adapter(*stream);
|
||||
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string warning;
|
||||
std::string error;
|
||||
|
||||
const bool success = tinyobj::LoadObj(
|
||||
/* attrib = */ &attrib,
|
||||
/* shapes = */ &shapes,
|
||||
/* materials = */ &materials,
|
||||
/* warn = */ &warning,
|
||||
/* err = */ &error,
|
||||
/* inStream = */ &adapter
|
||||
);
|
||||
mijin::ensure(success, "Parsing OBJ file failed.");
|
||||
|
||||
Mesh mesh;
|
||||
for (const tinyobj::shape_t& shape : shapes)
|
||||
{
|
||||
std::size_t indexOffset = 0;
|
||||
for (const std::size_t faceVertices : shape.mesh.num_face_vertices)
|
||||
{
|
||||
if (faceVertices != 3)
|
||||
{
|
||||
// we only deal with triangles
|
||||
indexOffset += faceVertices;
|
||||
continue;
|
||||
}
|
||||
for (int vertexIdx = 0; vertexIdx < 3; ++vertexIdx)
|
||||
{
|
||||
const tinyobj::index_t& index = shape.mesh.indices[indexOffset + vertexIdx];
|
||||
mesh.vertices.push_back({
|
||||
.pos = {
|
||||
attrib.vertices[3 * index.vertex_index + 0],
|
||||
attrib.vertices[3 * index.vertex_index + 1],
|
||||
attrib.vertices[3 * index.vertex_index + 2]
|
||||
},
|
||||
.normal = {
|
||||
attrib.normals[3 * index.normal_index + 0],
|
||||
attrib.normals[3 * index.normal_index + 1],
|
||||
attrib.normals[3 * index.normal_index + 2]
|
||||
},
|
||||
.texcoord = {
|
||||
attrib.texcoords[2 * index.texcoord_index + 0],
|
||||
1.f - attrib.texcoords[2 * index.texcoord_index + 1] // obj UV is weird
|
||||
},
|
||||
.color = {
|
||||
attrib.colors[3 * index.vertex_index + 0],
|
||||
attrib.colors[3 * index.vertex_index + 1],
|
||||
attrib.colors[3 * index.vertex_index + 2],
|
||||
1.f
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
indexOffset += 3;
|
||||
}
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
}
|
34
private/sdl_gpu_test/util/mesh.hpp
Normal file
34
private/sdl_gpu_test/util/mesh.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_MESH_HPP_INCLUDED)
|
||||
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_MESH_HPP_INCLUDED 1
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <mijin/io/stlstream.hpp>
|
||||
#include <mijin/virtual_filesystem/filesystem.hpp>
|
||||
|
||||
namespace sdl_gpu_test
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec3 pos;
|
||||
glm::vec3 normal;
|
||||
glm::vec2 texcoord;
|
||||
glm::vec4 color;
|
||||
};
|
||||
|
||||
struct Mesh
|
||||
{
|
||||
std::vector<Vertex> vertices;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
Mesh loadMesh(const mijin::PathReference& path);
|
||||
} // namespace sdl_gpu_test
|
||||
|
||||
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_MESH_HPP_INCLUDED)
|
Loading…
x
Reference in New Issue
Block a user