Remove glTFViewer from samples
Bug: dawn:152 Change-Id: I5bd36f4ae56889bf12652f8a201a7f7be5e2d25d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7360 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
3a8aa31d88
commit
f3f5bf480d
12
BUILD.gn
12
BUILD.gn
|
@ -762,17 +762,6 @@ if (dawn_standalone) {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
dawn_sample("glTFViewer") {
|
|
||||||
sources = [
|
|
||||||
"examples/glTFViewer/Camera.inc",
|
|
||||||
"examples/glTFViewer/glTFViewer.cpp",
|
|
||||||
]
|
|
||||||
deps = [
|
|
||||||
"third_party:glm",
|
|
||||||
"third_party:tiny_gltf_loader",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
group("dawn_samples") {
|
group("dawn_samples") {
|
||||||
deps = [
|
deps = [
|
||||||
":Animometer",
|
":Animometer",
|
||||||
|
@ -780,7 +769,6 @@ if (dawn_standalone) {
|
||||||
":ComputeBoids",
|
":ComputeBoids",
|
||||||
":CppHelloTriangle",
|
":CppHelloTriangle",
|
||||||
":CubeReflection",
|
":CubeReflection",
|
||||||
":glTFViewer",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
DEPS
6
DEPS
|
@ -78,11 +78,7 @@ deps = {
|
||||||
'condition': 'dawn_standalone',
|
'condition': 'dawn_standalone',
|
||||||
},
|
},
|
||||||
|
|
||||||
# Dependencies for samples: stb and GLM
|
# Dependencies for samples: GLM
|
||||||
'third_party/stb': {
|
|
||||||
'url': '{github_git}/nothings/stb.git@c7110588a4d24c4bb5155c184fbb77dd90b3116e',
|
|
||||||
'condition': 'dawn_standalone',
|
|
||||||
},
|
|
||||||
'third_party/glm': {
|
'third_party/glm': {
|
||||||
'url': '{github_git}/g-truc/glm.git@06f084063fd6d9aa2ef6904517650700ae47b63d',
|
'url': '{github_git}/g-truc/glm.git@06f084063fd6d9aa2ef6904517650700ae47b63d',
|
||||||
'condition': 'dawn_standalone',
|
'condition': 'dawn_standalone',
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright 2017 The Dawn Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
class Camera {
|
|
||||||
public:
|
|
||||||
Camera()
|
|
||||||
: _azimuth(glm::radians(45.f)),
|
|
||||||
_altitude(glm::radians(30.f)),
|
|
||||||
_radius(10.f),
|
|
||||||
_center(0, 0, 0),
|
|
||||||
_dirty(true) {
|
|
||||||
recalculate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void rotate(float dAzimuth, float dAltitude) {
|
|
||||||
_dirty = true;
|
|
||||||
_azimuth = glm::mod(_azimuth + dAzimuth, glm::radians(360.f));
|
|
||||||
_altitude = glm::clamp(_altitude + dAltitude, glm::radians(-89.f), glm::radians(89.f));
|
|
||||||
}
|
|
||||||
|
|
||||||
void pan(float dX, float dY) {
|
|
||||||
recalculate();
|
|
||||||
glm::vec3 vX = glm::normalize(glm::cross(-_eyeDir, glm::vec3(0, 1, 0)));
|
|
||||||
glm::vec3 vY = glm::normalize(glm::cross(_eyeDir, vX));
|
|
||||||
_center += vX * dX * _radius + vY * dY * _radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
void zoom(float factor) {
|
|
||||||
_dirty = true;
|
|
||||||
_radius = _radius * glm::exp(-factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 view() {
|
|
||||||
if (_dirty) {
|
|
||||||
recalculate();
|
|
||||||
}
|
|
||||||
return _view;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void recalculate() {
|
|
||||||
glm::vec4 eye4 = glm::vec4(1, 0, 0, 1);
|
|
||||||
eye4 = glm::rotate(glm::mat4(), _altitude, glm::vec3(0, 0, 1)) * eye4;
|
|
||||||
eye4 = glm::rotate(glm::mat4(), _azimuth, glm::vec3(0, 1, 0)) * eye4;
|
|
||||||
_eyeDir = glm::vec3(eye4);
|
|
||||||
|
|
||||||
_view = glm::lookAt(_center + _eyeDir * _radius, _center, glm::vec3(0, -1, 0));
|
|
||||||
_dirty = false;
|
|
||||||
}
|
|
||||||
float _azimuth;
|
|
||||||
float _altitude;
|
|
||||||
float _radius;
|
|
||||||
glm::vec3 _center;
|
|
||||||
glm::vec3 _eyeDir;
|
|
||||||
bool _dirty;
|
|
||||||
glm::mat4 _view;
|
|
||||||
};
|
|
|
@ -1,30 +0,0 @@
|
||||||
# Dawn glTF Viewer
|
|
||||||
|
|
||||||
This is a barebones glTF model viewer using the Dawn API. It is intended as a
|
|
||||||
proof of concept for the API and is not a robust model viewer. It can load
|
|
||||||
basic mesh/texture data from a few
|
|
||||||
[glTF sample models](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/1.0),
|
|
||||||
such as:
|
|
||||||
|
|
||||||
* 2CylinderEngine
|
|
||||||
* BoxWithoutIndices
|
|
||||||
* Cesium Man
|
|
||||||
* Duck
|
|
||||||
* Monster
|
|
||||||
* VC (Virtual City)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
`build/examples/glTFViewer/glTFViewer path/to/Duck.gltf`
|
|
||||||
|
|
||||||
`build/examples/glTFViewer/glTFViewer path/to/Duck.gltf --backend metal`
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
Duck:
|
|
||||||
|
|
||||||
![Duck](img/nxt-gltf-duck.jpg)
|
|
||||||
|
|
||||||
VC (Virtual City):
|
|
||||||
|
|
||||||
![Virtual City](img/nxt-gltf-vc.jpg)
|
|
|
@ -1,686 +0,0 @@
|
||||||
// Copyright 2017 The Dawn Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Enable this before including any headers as we want inttypes.h to define
|
|
||||||
// format macros such as PRId64 that are used in picojson.
|
|
||||||
#ifndef __STDC_FORMAT_MACROS
|
|
||||||
#define __STDC_FORMAT_MACROS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../SampleUtils.h"
|
|
||||||
|
|
||||||
#include "common/Assert.h"
|
|
||||||
#include "common/Math.h"
|
|
||||||
#include "common/Constants.h"
|
|
||||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
|
||||||
#include "utils/DawnHelpers.h"
|
|
||||||
#include "utils/SystemUtils.h"
|
|
||||||
|
|
||||||
#include <bitset>
|
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
||||||
#include <glm/mat4x4.hpp>
|
|
||||||
#include <glm/gtc/matrix_inverse.hpp>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
|
||||||
|
|
||||||
#define TINYGLTF_LOADER_IMPLEMENTATION
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#define PICOJSON_ASSERT ASSERT
|
|
||||||
#undef __STDC_FORMAT_MACROS
|
|
||||||
#include <tinygltfloader/tiny_gltf_loader.h>
|
|
||||||
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
#include "Camera.inc"
|
|
||||||
|
|
||||||
namespace gl {
|
|
||||||
enum {
|
|
||||||
Triangles = 0x0004,
|
|
||||||
UnsignedShort = 0x1403,
|
|
||||||
UnsignedInt = 0x1405,
|
|
||||||
Float = 0x1406,
|
|
||||||
RGBA = 0x1908,
|
|
||||||
Nearest = 0x2600,
|
|
||||||
Linear = 0x2601,
|
|
||||||
NearestMipmapNearest = 0x2700,
|
|
||||||
LinearMipmapNearest = 0x2701,
|
|
||||||
NearestMipmapLinear = 0x2702,
|
|
||||||
LinearMipmapLinear = 0x2703,
|
|
||||||
ArrayBuffer = 0x8892,
|
|
||||||
ElementArrayBuffer = 0x8893,
|
|
||||||
FragmentShader = 0x8B30,
|
|
||||||
VertexShader = 0x8B31,
|
|
||||||
FloatVec2 = 0x8B50,
|
|
||||||
FloatVec3 = 0x8B51,
|
|
||||||
FloatVec4 = 0x8B52,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MaterialInfo {
|
|
||||||
dawn::RenderPipeline pipeline;
|
|
||||||
dawn::BindGroup bindGroup0;
|
|
||||||
std::map<uint32_t, std::string> slotSemantics;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct u_transform_block {
|
|
||||||
glm::mat4 modelViewProj;
|
|
||||||
glm::mat4 modelInvTr;
|
|
||||||
};
|
|
||||||
|
|
||||||
dawn::Device device;
|
|
||||||
dawn::Queue queue;
|
|
||||||
dawn::SwapChain swapchain;
|
|
||||||
dawn::TextureView depthStencilView;
|
|
||||||
|
|
||||||
dawn::Buffer defaultBuffer;
|
|
||||||
std::map<std::string, dawn::Buffer> buffers;
|
|
||||||
std::map<std::string, dawn::CommandBuffer> commandBuffers;
|
|
||||||
std::map<uint32_t, std::string> slotSemantics = {{0, "POSITION"}, {1, "NORMAL"}, {2, "TEXCOORD_0"}};
|
|
||||||
|
|
||||||
std::map<std::string, dawn::Sampler> samplers;
|
|
||||||
std::map<std::string, dawn::TextureView> textures;
|
|
||||||
|
|
||||||
tinygltf::Scene scene;
|
|
||||||
glm::mat4 projection = glm::perspective(glm::radians(60.f), 640.f/480, 0.1f, 2000.f);
|
|
||||||
Camera camera;
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
namespace {
|
|
||||||
std::string getFilePathExtension(const std::string &FileName) {
|
|
||||||
if (FileName.find_last_of(".") != std::string::npos) {
|
|
||||||
return FileName.substr(FileName.find_last_of(".") + 1);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool techniqueParameterTypeToVertexFormat(int type, dawn::VertexFormat *format) {
|
|
||||||
switch (type) {
|
|
||||||
case gl::FloatVec2:
|
|
||||||
*format = dawn::VertexFormat::Float2;
|
|
||||||
return true;
|
|
||||||
case gl::FloatVec3:
|
|
||||||
*format = dawn::VertexFormat::Float3;
|
|
||||||
return true;
|
|
||||||
case gl::FloatVec4:
|
|
||||||
*format = dawn::VertexFormat::Float4;
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialization
|
|
||||||
namespace {
|
|
||||||
void initBuffers() {
|
|
||||||
dawn::BufferDescriptor descriptor;
|
|
||||||
descriptor.size = 256;
|
|
||||||
descriptor.usage = dawn::BufferUsageBit::Vertex | dawn::BufferUsageBit::Index;
|
|
||||||
defaultBuffer = device.CreateBuffer(&descriptor);
|
|
||||||
|
|
||||||
for (const auto& bv : scene.bufferViews) {
|
|
||||||
const auto& iBufferViewID = bv.first;
|
|
||||||
const auto& iBufferView = bv.second;
|
|
||||||
|
|
||||||
dawn::BufferUsageBit usage = dawn::BufferUsageBit::None;
|
|
||||||
switch (iBufferView.target) {
|
|
||||||
case gl::ArrayBuffer:
|
|
||||||
usage |= dawn::BufferUsageBit::Vertex;
|
|
||||||
break;
|
|
||||||
case gl::ElementArrayBuffer:
|
|
||||||
usage |= dawn::BufferUsageBit::Index;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
fprintf(stderr, "TODO: buffer view has no target; skipping\n");
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unsupported buffer view target %d\n", iBufferView.target);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto& iBuffer = scene.buffers.at(iBufferView.buffer);
|
|
||||||
|
|
||||||
size_t iBufferViewSize =
|
|
||||||
iBufferView.byteLength ? iBufferView.byteLength :
|
|
||||||
(iBuffer.data.size() - iBufferView.byteOffset);
|
|
||||||
auto oBuffer = utils::CreateBufferFromData(device, &iBuffer.data.at(iBufferView.byteOffset), static_cast<uint32_t>(iBufferViewSize), usage);
|
|
||||||
buffers[iBufferViewID] = std::move(oBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MaterialInfo& getMaterial(const std::string& iMaterialID, size_t stridePos, size_t strideNor, size_t strideTxc) {
|
|
||||||
static std::map<std::tuple<std::string, size_t, size_t, size_t>, MaterialInfo> materials;
|
|
||||||
auto key = make_tuple(iMaterialID, stridePos, strideNor, strideTxc);
|
|
||||||
auto materialIterator = materials.find(key);
|
|
||||||
if (materialIterator != materials.end()) {
|
|
||||||
return materialIterator->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& iMaterial = scene.materials.at(iMaterialID);
|
|
||||||
const auto& iTechnique = scene.techniques.at(iMaterial.technique);
|
|
||||||
|
|
||||||
bool hasTexture = false;
|
|
||||||
std::string iTextureID;
|
|
||||||
{
|
|
||||||
auto it = iMaterial.values.find("diffuse");
|
|
||||||
if (it != iMaterial.values.end() && !it->second.string_value.empty()) {
|
|
||||||
hasTexture = true;
|
|
||||||
iTextureID = it->second.string_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto oVSModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
|
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(push_constant) uniform u_transform_block {
|
|
||||||
mat4 modelViewProj;
|
|
||||||
mat4 modelInvTr;
|
|
||||||
} u_transform;
|
|
||||||
|
|
||||||
layout(location = 0) in vec4 a_position;
|
|
||||||
layout(location = 1) in vec3 a_normal;
|
|
||||||
layout(location = 2) in vec2 a_texcoord;
|
|
||||||
|
|
||||||
layout(location = 0) out vec3 v_normal;
|
|
||||||
layout(location = 1) out vec2 v_texcoord;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
v_normal = (u_transform.modelInvTr * vec4(normalize(a_normal), 0)).rgb;
|
|
||||||
v_texcoord = a_texcoord;
|
|
||||||
gl_Position = u_transform.modelViewProj * a_position;
|
|
||||||
})");
|
|
||||||
|
|
||||||
auto oFSSourceTextured = R"(
|
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler u_samp;
|
|
||||||
layout(set = 0, binding = 1) uniform texture2D u_tex;
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 v_normal;
|
|
||||||
layout(location = 1) in vec2 v_texcoord;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragcolor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
const vec3 lightdir = normalize(vec3(-1, -2, 3));
|
|
||||||
vec3 normal = normalize(v_normal);
|
|
||||||
float diffuse = abs(dot(lightdir, normal));
|
|
||||||
float diffamb = diffuse * 0.85 + 0.15;
|
|
||||||
vec3 albedo = texture(sampler2D(u_tex, u_samp), v_texcoord).rgb;
|
|
||||||
fragcolor = vec4(diffamb * albedo, 1);
|
|
||||||
})";
|
|
||||||
auto oFSSourceUntextured = R"(
|
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 v_normal;
|
|
||||||
layout(location = 1) in vec2 v_texcoord;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragcolor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
const vec3 lightdir = normalize(vec3(-1, -2, 3));
|
|
||||||
vec3 normal = normalize(v_normal);
|
|
||||||
float diffuse = abs(dot(lightdir, normal));
|
|
||||||
float diffamb = diffuse * 0.85 + 0.15;
|
|
||||||
fragcolor = vec4(vec3(diffamb), 1);
|
|
||||||
})";
|
|
||||||
|
|
||||||
auto oFSModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, hasTexture ? oFSSourceTextured : oFSSourceUntextured);
|
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
|
||||||
descriptor.cInputState.indexFormat = dawn::IndexFormat::Uint16;
|
|
||||||
uint32_t numAttributes = 0;
|
|
||||||
uint32_t numInputs = 0;
|
|
||||||
std::bitset<3> slotsSet;
|
|
||||||
for (const auto& a : iTechnique.attributes) {
|
|
||||||
const auto iAttributeName = a.first;
|
|
||||||
const auto iParameter = iTechnique.parameters.at(a.second);
|
|
||||||
dawn::VertexFormat format;
|
|
||||||
if (!techniqueParameterTypeToVertexFormat(iParameter.type, &format)) {
|
|
||||||
fprintf(stderr, "unsupported technique parameter type %d\n", iParameter.type);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].format = format;
|
|
||||||
|
|
||||||
if (iParameter.semantic == "POSITION") {
|
|
||||||
descriptor.cInputState.cInputs[numInputs].stride = static_cast<uint32_t>(stridePos);
|
|
||||||
numAttributes++;
|
|
||||||
numInputs++;
|
|
||||||
slotsSet.set(0);
|
|
||||||
} else if (iParameter.semantic == "NORMAL") {
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].shaderLocation = 1;
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].inputSlot = 1;
|
|
||||||
descriptor.cInputState.cInputs[numInputs].inputSlot = 1;
|
|
||||||
descriptor.cInputState.cInputs[numInputs].stride = static_cast<uint32_t>(strideNor);
|
|
||||||
numAttributes++;
|
|
||||||
numInputs++;
|
|
||||||
slotsSet.set(1);
|
|
||||||
} else if (iParameter.semantic == "TEXCOORD_0") {
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].shaderLocation = 2;
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].inputSlot = 2;
|
|
||||||
descriptor.cInputState.cInputs[numInputs].inputSlot = 2;
|
|
||||||
descriptor.cInputState.cInputs[numInputs].stride = static_cast<uint32_t>(strideTxc);
|
|
||||||
numAttributes++;
|
|
||||||
numInputs++;
|
|
||||||
slotsSet.set(2);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "unsupported technique attribute semantic %s\n", iParameter.semantic.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < slotsSet.size(); i++) {
|
|
||||||
if (slotsSet[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].shaderLocation = i;
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].inputSlot = i;
|
|
||||||
descriptor.cInputState.cAttributes[numAttributes].format = dawn::VertexFormat::Float4;
|
|
||||||
|
|
||||||
descriptor.cInputState.cInputs[numInputs].inputSlot = i;
|
|
||||||
|
|
||||||
numAttributes++;
|
|
||||||
numInputs++;
|
|
||||||
}
|
|
||||||
descriptor.cInputState.numAttributes = numAttributes;
|
|
||||||
descriptor.cInputState.numInputs = numInputs;
|
|
||||||
|
|
||||||
constexpr dawn::ShaderStageBit kNoStages{};
|
|
||||||
dawn::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
|
|
||||||
device, {
|
|
||||||
{0, hasTexture ? dawn::ShaderStageBit::Fragment : kNoStages,
|
|
||||||
dawn::BindingType::Sampler},
|
|
||||||
{1, hasTexture ? dawn::ShaderStageBit::Fragment : kNoStages,
|
|
||||||
dawn::BindingType::SampledTexture},
|
|
||||||
});
|
|
||||||
|
|
||||||
auto pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
|
|
||||||
|
|
||||||
descriptor.layout = pipelineLayout;
|
|
||||||
descriptor.cVertexStage.module = oVSModule;
|
|
||||||
descriptor.cFragmentStage.module = oFSModule;
|
|
||||||
descriptor.depthStencilState = &descriptor.cDepthStencilState;
|
|
||||||
descriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
|
|
||||||
descriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
|
|
||||||
descriptor.cDepthStencilState.depthWriteEnabled = true;
|
|
||||||
descriptor.cDepthStencilState.depthCompare = dawn::CompareFunction::Less;
|
|
||||||
|
|
||||||
dawn::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
|
|
||||||
|
|
||||||
dawn::BindGroup bindGroup;
|
|
||||||
|
|
||||||
if (hasTexture) {
|
|
||||||
const auto& textureView = textures[iTextureID];
|
|
||||||
const auto& iSamplerID = scene.textures[iTextureID].sampler;
|
|
||||||
bindGroup = utils::MakeBindGroup(device, bindGroupLayout, {
|
|
||||||
{0, samplers[iSamplerID]},
|
|
||||||
{1, textureView}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
bindGroup = utils::MakeBindGroup(device, bindGroupLayout, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialInfo material = {
|
|
||||||
pipeline,
|
|
||||||
bindGroup,
|
|
||||||
std::map<uint32_t, std::string>(),
|
|
||||||
};
|
|
||||||
materials[key] = std::move(material);
|
|
||||||
return materials.at(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initSamplers() {
|
|
||||||
for (const auto& s : scene.samplers) {
|
|
||||||
const auto& iSamplerID = s.first;
|
|
||||||
const auto& iSampler = s.second;
|
|
||||||
|
|
||||||
dawn::SamplerDescriptor desc = utils::GetDefaultSamplerDescriptor();
|
|
||||||
// TODO: wrap modes
|
|
||||||
|
|
||||||
switch (iSampler.magFilter) {
|
|
||||||
case gl::Nearest:
|
|
||||||
desc.magFilter = dawn::FilterMode::Nearest;
|
|
||||||
break;
|
|
||||||
case gl::Linear:
|
|
||||||
desc.magFilter = dawn::FilterMode::Linear;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unsupported magFilter %d\n", iSampler.magFilter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (iSampler.minFilter) {
|
|
||||||
case gl::Nearest:
|
|
||||||
case gl::NearestMipmapNearest:
|
|
||||||
case gl::NearestMipmapLinear:
|
|
||||||
desc.minFilter = dawn::FilterMode::Nearest;
|
|
||||||
break;
|
|
||||||
case gl::Linear:
|
|
||||||
case gl::LinearMipmapNearest:
|
|
||||||
case gl::LinearMipmapLinear:
|
|
||||||
desc.minFilter = dawn::FilterMode::Linear;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unsupported minFilter %d\n", iSampler.magFilter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (iSampler.minFilter) {
|
|
||||||
case gl::NearestMipmapNearest:
|
|
||||||
case gl::LinearMipmapNearest:
|
|
||||||
desc.mipmapFilter = dawn::FilterMode::Nearest;
|
|
||||||
break;
|
|
||||||
case gl::NearestMipmapLinear:
|
|
||||||
case gl::LinearMipmapLinear:
|
|
||||||
desc.mipmapFilter = dawn::FilterMode::Linear;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplers[iSamplerID] = device.CreateSampler(&desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initTextures() {
|
|
||||||
for (const auto& t : scene.textures) {
|
|
||||||
const auto& iTextureID = t.first;
|
|
||||||
const auto& iTexture = t.second;
|
|
||||||
const auto& iImage = scene.images[iTexture.source];
|
|
||||||
|
|
||||||
dawn::TextureFormat format = dawn::TextureFormat::R8G8B8A8Unorm;
|
|
||||||
switch (iTexture.format) {
|
|
||||||
case gl::RGBA:
|
|
||||||
format = dawn::TextureFormat::R8G8B8A8Unorm;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unsupported texture format %d\n", iTexture.format);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dawn::TextureDescriptor descriptor;
|
|
||||||
descriptor.dimension = dawn::TextureDimension::e2D;
|
|
||||||
descriptor.size.width = iImage.width;
|
|
||||||
descriptor.size.height = iImage.height;
|
|
||||||
descriptor.size.depth = 1;
|
|
||||||
descriptor.arrayLayerCount = 1;
|
|
||||||
descriptor.sampleCount = 1;
|
|
||||||
descriptor.format = format;
|
|
||||||
descriptor.mipLevelCount = 1;
|
|
||||||
descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::Sampled;
|
|
||||||
auto oTexture = device.CreateTexture(&descriptor);
|
|
||||||
// TODO: release this texture
|
|
||||||
|
|
||||||
const uint8_t* origData = iImage.image.data();
|
|
||||||
const uint8_t* data = nullptr;
|
|
||||||
std::vector<uint8_t> newData;
|
|
||||||
|
|
||||||
uint32_t width = static_cast<uint32_t>(iImage.width);
|
|
||||||
uint32_t height = static_cast<uint32_t>(iImage.height);
|
|
||||||
uint32_t rowSize = width * 4;
|
|
||||||
uint32_t rowPitch = Align(rowSize, kTextureRowPitchAlignment);
|
|
||||||
|
|
||||||
if (iImage.component == 3 || iImage.component == 4) {
|
|
||||||
if (rowSize != rowPitch || iImage.component == 3) {
|
|
||||||
newData.resize(rowPitch * height);
|
|
||||||
uint32_t pixelsPerRow = rowPitch / 4;
|
|
||||||
for (uint32_t y = 0; y < height; ++y) {
|
|
||||||
for (uint32_t x = 0; x < width; ++x) {
|
|
||||||
size_t oldIndex = x + y * height;
|
|
||||||
size_t newIndex = x + y * pixelsPerRow;
|
|
||||||
if (iImage.component == 4) {
|
|
||||||
newData[4 * newIndex + 0] = origData[4 * oldIndex + 0];
|
|
||||||
newData[4 * newIndex + 1] = origData[4 * oldIndex + 1];
|
|
||||||
newData[4 * newIndex + 2] = origData[4 * oldIndex + 2];
|
|
||||||
newData[4 * newIndex + 3] = origData[4 * oldIndex + 3];
|
|
||||||
} else if (iImage.component == 3) {
|
|
||||||
newData[4 * newIndex + 0] = origData[3 * oldIndex + 0];
|
|
||||||
newData[4 * newIndex + 1] = origData[3 * oldIndex + 1];
|
|
||||||
newData[4 * newIndex + 2] = origData[3 * oldIndex + 2];
|
|
||||||
newData[4 * newIndex + 3] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data = newData.data();
|
|
||||||
} else {
|
|
||||||
data = origData;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "unsupported image.component %d\n", iImage.component);
|
|
||||||
}
|
|
||||||
|
|
||||||
dawn::Buffer staging = utils::CreateBufferFromData(device, data, rowPitch * iImage.height, dawn::BufferUsageBit::TransferSrc);
|
|
||||||
dawn::BufferCopyView bufferCopyView =
|
|
||||||
utils::CreateBufferCopyView(staging, 0, rowPitch, 0);
|
|
||||||
dawn::TextureCopyView textureCopyView =
|
|
||||||
utils::CreateTextureCopyView(oTexture, 0, 0, {0, 0, 0});
|
|
||||||
dawn::Extent3D copySize = {iImage.width, iImage.height, 1};
|
|
||||||
|
|
||||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
||||||
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size);
|
|
||||||
|
|
||||||
dawn::CommandBuffer cmdbuf = encoder.Finish();
|
|
||||||
queue.Submit(1, &cmdbuf);
|
|
||||||
|
|
||||||
textures[iTextureID] = oTexture.CreateDefaultView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
device = CreateCppDawnDevice();
|
|
||||||
|
|
||||||
queue = device.CreateQueue();
|
|
||||||
swapchain = GetSwapChain(device);
|
|
||||||
swapchain.Configure(GetPreferredSwapChainTextureFormat(),
|
|
||||||
dawn::TextureUsageBit::OutputAttachment, 640, 480);
|
|
||||||
|
|
||||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
|
||||||
|
|
||||||
initBuffers();
|
|
||||||
initSamplers();
|
|
||||||
initTextures();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drawing
|
|
||||||
namespace {
|
|
||||||
void drawMesh(dawn::RenderPassEncoder& pass, const tinygltf::Mesh& iMesh, const glm::mat4& model) {
|
|
||||||
for (const auto& iPrim : iMesh.primitives) {
|
|
||||||
if (iPrim.mode != gl::Triangles) {
|
|
||||||
fprintf(stderr, "unsupported primitive mode %d\n", iPrim.mode);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
u_transform_block transforms = {
|
|
||||||
(projection * camera.view() * model),
|
|
||||||
glm::inverseTranspose(model),
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t strides[3] = {0};
|
|
||||||
for (const auto& s : slotSemantics) {
|
|
||||||
if (s.first < 3) {
|
|
||||||
auto it = iPrim.attributes.find(s.second);
|
|
||||||
if (it == iPrim.attributes.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto& iAccessorName = it->second;
|
|
||||||
strides[s.first] = scene.accessors.at(iAccessorName).byteStride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const MaterialInfo& material = getMaterial(iPrim.material, strides[0], strides[1], strides[2]);
|
|
||||||
pass.SetPipeline(material.pipeline);
|
|
||||||
pass.SetBindGroup(0, material.bindGroup0, 0, nullptr);
|
|
||||||
pass.SetPushConstants(dawn::ShaderStageBit::Vertex,
|
|
||||||
0, sizeof(u_transform_block) / sizeof(uint32_t),
|
|
||||||
reinterpret_cast<const uint32_t*>(&transforms));
|
|
||||||
|
|
||||||
uint32_t vertexCount = 0;
|
|
||||||
for (const auto& s : slotSemantics) {
|
|
||||||
uint32_t slot = s.first;
|
|
||||||
auto it = iPrim.attributes.find(s.second);
|
|
||||||
if (it == iPrim.attributes.end()) {
|
|
||||||
uint64_t zero = 0;
|
|
||||||
pass.SetVertexBuffers(slot, 1, &defaultBuffer, &zero);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto& iAccessor = scene.accessors.at(it->second);
|
|
||||||
if (iAccessor.componentType != gl::Float ||
|
|
||||||
(iAccessor.type != TINYGLTF_TYPE_VEC4 && iAccessor.type != TINYGLTF_TYPE_VEC3 && iAccessor.type != TINYGLTF_TYPE_VEC2)) {
|
|
||||||
fprintf(stderr, "unsupported vertex accessor component type %d and type %d\n", iAccessor.componentType, iAccessor.type);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vertexCount == 0) {
|
|
||||||
vertexCount = static_cast<uint32_t>(iAccessor.count);
|
|
||||||
}
|
|
||||||
const auto& oBuffer = buffers.at(iAccessor.bufferView);
|
|
||||||
uint64_t iBufferOffset = static_cast<uint64_t>(iAccessor.byteOffset);
|
|
||||||
pass.SetVertexBuffers(slot, 1, &oBuffer, &iBufferOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!iPrim.indices.empty()) {
|
|
||||||
const auto& iIndices = scene.accessors.at(iPrim.indices);
|
|
||||||
// DrawElements
|
|
||||||
if (iIndices.componentType != gl::UnsignedShort || iIndices.type != TINYGLTF_TYPE_SCALAR) {
|
|
||||||
fprintf(stderr, "unsupported index accessor component type %d and type %d\n", iIndices.componentType, iIndices.type);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto& oIndicesBuffer = buffers.at(iIndices.bufferView);
|
|
||||||
pass.SetIndexBuffer(oIndicesBuffer, static_cast<uint32_t>(iIndices.byteOffset));
|
|
||||||
pass.DrawIndexed(static_cast<uint32_t>(iIndices.count), 1, 0, 0, 0);
|
|
||||||
} else {
|
|
||||||
// DrawArrays
|
|
||||||
pass.Draw(vertexCount, 1, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawNode(dawn::RenderPassEncoder& pass, const tinygltf::Node& node, const glm::mat4& parent = glm::mat4()) {
|
|
||||||
glm::mat4 model;
|
|
||||||
if (node.matrix.size() == 16) {
|
|
||||||
model = glm::make_mat4(node.matrix.data());
|
|
||||||
} else {
|
|
||||||
if (node.scale.size() == 3) {
|
|
||||||
glm::vec3 scale = glm::make_vec3(node.scale.data());
|
|
||||||
model = glm::scale(model, scale);
|
|
||||||
}
|
|
||||||
if (node.rotation.size() == 4) {
|
|
||||||
glm::quat rotation = glm::make_quat(node.rotation.data());
|
|
||||||
model = glm::mat4_cast(rotation) * model;
|
|
||||||
}
|
|
||||||
if (node.translation.size() == 3) {
|
|
||||||
glm::vec3 translation = glm::make_vec3(node.translation.data());
|
|
||||||
model = glm::translate(model, translation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model = parent * model;
|
|
||||||
|
|
||||||
for (const auto& meshID : node.meshes) {
|
|
||||||
drawMesh(pass, scene.meshes[meshID], model);
|
|
||||||
}
|
|
||||||
for (const auto& child : node.children) {
|
|
||||||
drawNode(pass, scene.nodes.at(child), model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void frame() {
|
|
||||||
dawn::Texture backbuffer = swapchain.GetNextTexture();
|
|
||||||
|
|
||||||
const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
|
|
||||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
||||||
{
|
|
||||||
utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultView()},
|
|
||||||
depthStencilView);
|
|
||||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
|
||||||
for (const auto& n : defaultSceneNodes) {
|
|
||||||
const auto& node = scene.nodes.at(n);
|
|
||||||
drawNode(pass, node);
|
|
||||||
}
|
|
||||||
pass.EndPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
dawn::CommandBuffer commands = encoder.Finish();
|
|
||||||
queue.Submit(1, &commands);
|
|
||||||
|
|
||||||
swapchain.Present(backbuffer);
|
|
||||||
DoFlush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse camera control
|
|
||||||
namespace {
|
|
||||||
bool buttons[GLFW_MOUSE_BUTTON_LAST + 1] = {0};
|
|
||||||
|
|
||||||
void mouseButtonCallback(GLFWwindow*, int button, int action, int) {
|
|
||||||
buttons[button] = (action == GLFW_PRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cursorPosCallback(GLFWwindow*, double mouseX, double mouseY) {
|
|
||||||
static double oldX, oldY;
|
|
||||||
float dX = static_cast<float>(mouseX - oldX);
|
|
||||||
float dY = static_cast<float>(mouseY - oldY);
|
|
||||||
oldX = mouseX;
|
|
||||||
oldY = mouseY;
|
|
||||||
|
|
||||||
if (buttons[2] || (buttons[0] && buttons[1])) {
|
|
||||||
camera.pan(-dX * 0.002f, dY * 0.002f);
|
|
||||||
} else if (buttons[0]) {
|
|
||||||
camera.rotate(dX * 0.01f, dY * 0.01f);
|
|
||||||
} else if (buttons[1]) {
|
|
||||||
camera.zoom(dY * -0.005f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void scrollCallback(GLFWwindow*, double, double yoffset) {
|
|
||||||
camera.zoom(static_cast<float>(yoffset) * 0.04f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
|
||||||
if (!InitSample(argc, argv)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "Usage: %s model.gltf [... Dawn Options]\n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tinygltf::TinyGLTFLoader loader;
|
|
||||||
std::string err;
|
|
||||||
std::string input_filename(argv[1]);
|
|
||||||
std::string ext = getFilePathExtension(input_filename);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if (ext.compare("glb") == 0) {
|
|
||||||
// assume binary glTF.
|
|
||||||
ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
|
|
||||||
} else {
|
|
||||||
// assume ascii glTF.
|
|
||||||
ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
|
|
||||||
}
|
|
||||||
if (!err.empty()) {
|
|
||||||
fprintf(stderr, "ERR: %s\n", err.c_str());
|
|
||||||
}
|
|
||||||
if (!ret) {
|
|
||||||
fprintf(stderr, "Failed to load .glTF : %s\n", argv[1]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
GLFWwindow* window = GetGLFWWindow();
|
|
||||||
glfwSetMouseButtonCallback(window, mouseButtonCallback);
|
|
||||||
glfwSetCursorPosCallback(window, cursorPosCallback);
|
|
||||||
glfwSetScrollCallback(window, scrollCallback);
|
|
||||||
|
|
||||||
while (!ShouldQuit()) {
|
|
||||||
frame();
|
|
||||||
utils::USleep(16000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO release stuff
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 93 KiB |
|
@ -353,45 +353,4 @@ if (dawn_standalone) {
|
||||||
|
|
||||||
# GLM is header only but has too many files to list them.
|
# GLM is header only but has too many files to list them.
|
||||||
}
|
}
|
||||||
|
|
||||||
# STB
|
|
||||||
config("stb_public_config") {
|
|
||||||
include_dirs = [ "stb" ]
|
|
||||||
|
|
||||||
if (!is_msvc) {
|
|
||||||
cflags_cc = [ "-Wno-implicit-fallthrough" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
source_set("stb") {
|
|
||||||
public_configs = [ ":stb_public_config" ]
|
|
||||||
sources = [
|
|
||||||
"stb/stb_image.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# PicoJSON
|
|
||||||
config("picojson_public_config") {
|
|
||||||
include_dirs = [ "." ]
|
|
||||||
}
|
|
||||||
source_set("picojson") {
|
|
||||||
public_configs = [ ":picojson_public_config" ]
|
|
||||||
sources = [
|
|
||||||
"picojson/picojson.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Tiny glTF Loader
|
|
||||||
config("tiny_gltf_loader_public_config") {
|
|
||||||
include_dirs = [ "." ]
|
|
||||||
}
|
|
||||||
source_set("tiny_gltf_loader") {
|
|
||||||
public_configs = [ ":tiny_gltf_loader_public_config" ]
|
|
||||||
public_deps = [
|
|
||||||
":picojson",
|
|
||||||
":stb",
|
|
||||||
]
|
|
||||||
sources = [
|
|
||||||
"tinygltfloader/tiny_gltf_loader.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue