Skip to content

Instantly share code, notes, and snippets.

@tomwjerry
Last active January 16, 2025 15:15
Show Gist options
  • Save tomwjerry/44cb034d87e6d5c8781eda1b75fae89b to your computer and use it in GitHub Desktop.
Save tomwjerry/44cb034d87e6d5c8781eda1b75fae89b to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2017-2024 The Forge Interactive Inc.
*
* This file is part of The-Forge
* (see https://github.com/ConfettiFX/The-Forge).
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "resources.h.fsl"
STRUCT(VSInput)
{
DATA(float3, Position1, POSITION);
DATA(float3, Normal1, NORMAL);
DATA(float3, Position2, TEXCOORD1);
DATA(float3, Normal2, TEXCOORD3);
DATA(float4, Color1, TEXCOORD0);
DATA(float4, Color2, TEXCOORD2);
};
STRUCT(VSOutput)
{
DATA(float4, Position, SV_Position);
DATA(float4, Color, COLOR);
};
VSOutput VS_MAIN(VSInput In, SV_InstanceID(uint) instanceId)
{
INIT_MAIN;
VSOutput Out;
#if FT_MULTIVIEW
float4x4 tempMat = mul(instanceBuffer[instanceId].mvp[VR_VIEW_ID], instanceBuffer[instanceId].toWorld);
#else
float4x4 tempMat = mul(instanceBuffer[instanceId].mvp, instanceBuffer[instanceId].toWorld);
#endif
// interpolate between two mesh key frames
float InWeight = instanceBuffer[instanceId].geometry_weight.x;
float3 InPosition = lerp(In.Position1, In.Position2, InWeight);
float3 InNormal = lerp(In.Normal1, In.Normal2, InWeight);
float3 InColor = lerp(In.Color1.xyz, In.Color2.xyz, InWeight);
Out.Position = mul(tempMat, float4(InPosition, 1.0f));
float4 normal = normalize(mul(instanceBuffer[instanceId].toWorld, float4(InNormal, 0.0f))); // Assume uniform scaling
float4 pos = mul(instanceBuffer[instanceId].toWorld, float4(InPosition, 1.0f));
float lightIntensity = 1.0f;
float ambientCoeff = 0.1;
float3 lightDir;
if (instanceBuffer[instanceId].color.w < 0.01) // Special case for Sun, so that it is lit from its top
lightDir = float3(0.0f, 1.0f, 0.0f);
else
lightDir = normalize(instanceBuffer[instanceId].lightPosition.xyz - pos.xyz);
float3 baseColor = (instanceBuffer[instanceId].color.rgb + InColor) / 2.0f;
float3 blendedColor = (instanceBuffer[instanceId].lightColor.rgb * baseColor) * lightIntensity;
float3 diffuse = blendedColor * max(dot(normal.xyz, lightDir), 0.0);
float3 ambient = baseColor * ambientCoeff;
Out.Color = float4(diffuse + ambient, 1.0);
RETURN(Out);
}
/*
* Copyright (c) 2017-2024 The Forge Interactive Inc.
*
* This file is part of The-Forge
* (see https://github.com/ConfettiFX/The-Forge).
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
// Unit Test for testing transformations using a solar system.
// Tests the basic mat4 transformations, such as scaling, rotation, and translation.
#define MAX_PLANETS 20 // Does not affect test, just for allocating space in uniform block. Must match with shader.
// Interfaces
#include "Application/Interfaces/IApp.h"
#include "Application/Interfaces/ICameraController.h"
#include "Application/Interfaces/IFont.h"
#include "Application/Interfaces/IProfiler.h"
#include "Application/Interfaces/IScreenshot.h"
#include "Application/Interfaces/IUI.h"
#include "Game/Interfaces/IScripting.h"
#include "Utilities/Interfaces/IFileSystem.h"
#include "Utilities/Interfaces/ILog.h"
#include "Utilities/Interfaces/ITime.h"
#include "Utilities/RingBuffer.h"
// Renderer
#include "Graphics/Interfaces/IGraphics.h"
#include "Resources/ResourceLoader/Interfaces/IResourceLoader.h"
// Math
#include "Utilities/Math/MathTypes.h"
#include "Utilities/Interfaces/IMemory.h"
/// Demo structures
struct PlanetInfoStruct
{
mat4 mTranslationMat;
mat4 mScaleMat;
mat4 mSharedMat; // Matrix to pass down to children
vec4 mColor;
uint mParentIndex;
float mYOrbitSpeed; // Rotation speed around parent
float mZOrbitSpeed;
float mRotationSpeed; // Rotation speed around self
float mMorphingSpeed; // Speed of morphing betwee cube and sphere
};
struct UniformBlock
{
CameraMatrix mProjectView;
//mat4 mToWorldMat[MAX_PLANETS]; // CHANGED
//vec4 mColor[MAX_PLANETS]; // CHANGED
//float mGeometryWeight[MAX_PLANETS][4]; // CHANGED
mat4 mToWorldMat; // CHANGED
vec4 mColor; // CHANGED
float mGeometryWeight[4]; // CHANGED
// Point Light Information
vec4 mLightPosition;
vec4 mLightColor;
};
struct UniformBlockSky
{
CameraMatrix mProjectView;
};
// But we only need Two sets of resources (one in flight and one being used on CPU)
const uint32_t gDataBufferCount = 2;
const uint gNumPlanets = 11; // Sun, Mercury -> Neptune, Pluto, Moon
const uint gTimeOffset = 600000; // For visually better starting locations
const float gRotSelfScale = 0.0004f;
const float gRotOrbitYScale = 0.001f;
const float gRotOrbitZScale = 0.00001f;
Renderer* pRenderer = NULL;
Queue* pGraphicsQueue = NULL;
GpuCmdRing gGraphicsCmdRing = {};
SwapChain* pSwapChain = NULL;
RenderTarget* pDepthBuffer = NULL;
Semaphore* pImageAcquiredSemaphore = NULL;
Shader* pSphereShader = NULL;
Buffer* pSphereVertexBuffer = NULL;
Buffer* pSphereIndexBuffer = NULL;
uint32_t gSphereIndexCount = 0;
Pipeline* pSpherePipeline = NULL;
VertexLayout gSphereVertexLayout = {};
uint32_t gSphereLayoutType = 0;
Shader* pSkyBoxDrawShader = NULL;
Buffer* pSkyBoxVertexBuffer = NULL;
Pipeline* pSkyBoxDrawPipeline = NULL;
RootSignature* pRootSignature = NULL;
Sampler* pSamplerSkyBox = NULL;
Texture* pSkyBoxTextures[6];
DescriptorSet* pDescriptorSetTexture = { NULL };
DescriptorSet* pDescriptorSetUniforms = { NULL };
Buffer* pProjViewUniformBuffer[gDataBufferCount] = { NULL };
Buffer* pSkyboxUniformBuffer[gDataBufferCount] = { NULL };
uint32_t gFrameIndex = 0;
ProfileToken gGpuProfileToken = PROFILE_INVALID_TOKEN;
int gNumberOfSpherePoints;
//UniformBlock gUniformData; // CHANGED
UniformBlock* gUniformData = NULL; // CHANGED
UniformBlockSky gUniformDataSky;
PlanetInfoStruct gPlanetInfoData[gNumPlanets];
ICameraController* pCameraController = NULL;
UIComponent* pGuiWindow = NULL;
uint32_t gFontID = 0;
QueryPool* pPipelineStatsQueryPool[gDataBufferCount] = {};
const char* pSkyBoxImageFileNames[] = { "Skybox_right1.tex", "Skybox_left2.tex", "Skybox_top3.tex",
"Skybox_bottom4.tex", "Skybox_front5.tex", "Skybox_back6.tex" };
FontDrawDesc gFrameTimeDraw;
// Generate sky box vertex buffer
const float gSkyBoxPoints[] = {
10.0f, -10.0f, -10.0f, 6.0f, // -z
-10.0f, -10.0f, -10.0f, 6.0f, -10.0f, 10.0f, -10.0f, 6.0f, -10.0f, 10.0f,
-10.0f, 6.0f, 10.0f, 10.0f, -10.0f, 6.0f, 10.0f, -10.0f, -10.0f, 6.0f,
-10.0f, -10.0f, 10.0f, 2.0f, //-x
-10.0f, -10.0f, -10.0f, 2.0f, -10.0f, 10.0f, -10.0f, 2.0f, -10.0f, 10.0f,
-10.0f, 2.0f, -10.0f, 10.0f, 10.0f, 2.0f, -10.0f, -10.0f, 10.0f, 2.0f,
10.0f, -10.0f, -10.0f, 1.0f, //+x
10.0f, -10.0f, 10.0f, 1.0f, 10.0f, 10.0f, 10.0f, 1.0f, 10.0f, 10.0f,
10.0f, 1.0f, 10.0f, 10.0f, -10.0f, 1.0f, 10.0f, -10.0f, -10.0f, 1.0f,
-10.0f, -10.0f, 10.0f, 5.0f, // +z
-10.0f, 10.0f, 10.0f, 5.0f, 10.0f, 10.0f, 10.0f, 5.0f, 10.0f, 10.0f,
10.0f, 5.0f, 10.0f, -10.0f, 10.0f, 5.0f, -10.0f, -10.0f, 10.0f, 5.0f,
-10.0f, 10.0f, -10.0f, 3.0f, //+y
10.0f, 10.0f, -10.0f, 3.0f, 10.0f, 10.0f, 10.0f, 3.0f, 10.0f, 10.0f,
10.0f, 3.0f, -10.0f, 10.0f, 10.0f, 3.0f, -10.0f, 10.0f, -10.0f, 3.0f,
10.0f, -10.0f, 10.0f, 4.0f, //-y
10.0f, -10.0f, -10.0f, 4.0f, -10.0f, -10.0f, -10.0f, 4.0f, -10.0f, -10.0f,
-10.0f, 4.0f, -10.0f, -10.0f, 10.0f, 4.0f, 10.0f, -10.0f, 10.0f, 4.0f,
};
static unsigned char gPipelineStatsCharArray[2048] = {};
static bstring gPipelineStats = bfromarr(gPipelineStatsCharArray);
void reloadRequest(void*)
{
ReloadDesc reload{ RELOAD_TYPE_SHADER };
requestReload(&reload);
}
const char* gWindowTestScripts[] = { "TestFullScreen.lua", "TestCenteredWindow.lua", "TestNonCenteredWindow.lua", "TestBorderless.lua" };
static void add_attribute(VertexLayout* layout, ShaderSemantic semantic, TinyImageFormat format, uint32_t offset)
{
uint32_t n_attr = layout->mAttribCount++;
VertexAttrib* attr = layout->mAttribs + n_attr;
attr->mSemantic = semantic;
attr->mFormat = format;
attr->mBinding = 0;
attr->mLocation = n_attr;
attr->mOffset = offset;
}
static void copy_attribute(VertexLayout* layout, void* buffer_data, uint32_t offset, uint32_t size, uint32_t vcount, void* data)
{
uint8_t* dst_data = static_cast<uint8_t*>(buffer_data);
uint8_t* src_data = static_cast<uint8_t*>(data);
for (uint32_t i = 0; i < vcount; ++i)
{
memcpy(dst_data + offset, src_data, size);
dst_data += layout->mBindings[0].mStride;
src_data += size;
}
}
static void compute_normal(const float* src, float* dst)
{
float len = sqrtf(src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
if (len == 0)
{
dst[0] = 0;
dst[1] = 0;
dst[2] = 0;
}
else
{
dst[0] = src[0] / len;
dst[1] = src[1] / len;
dst[2] = src[2] / len;
}
}
static void generate_complex_mesh()
{
gSphereVertexLayout = {};
// number of vertices on a quad side, must be >= 2
#define DETAIL_LEVEL 2
// static here to prevent stack overflow
static float verts[6][DETAIL_LEVEL][DETAIL_LEVEL][3];
static float sqNormals[6][DETAIL_LEVEL][DETAIL_LEVEL][3];
static float sphNormals[6][DETAIL_LEVEL][DETAIL_LEVEL][3];
for (int i = 0; i < 6; ++i)
{
for (int x = 0; x < DETAIL_LEVEL; ++x)
{
for (int y = 0; y < DETAIL_LEVEL; ++y)
{
float* vert = verts[i][x][y];
float* sqNorm = sqNormals[i][x][y];
sqNorm[0] = 0;
sqNorm[1] = 0;
sqNorm[2] = 0;
float fx = 2 * (float(x) / float(DETAIL_LEVEL - 1)) - 1;
float fy = 2 * (float(y) / float(DETAIL_LEVEL - 1)) - 1;
switch (i)
{
case 0:
vert[0] = -1, vert[1] = fx, vert[2] = fy;
sqNorm[0] = -1;
break;
case 1:
vert[0] = 1, vert[1] = -fx, vert[2] = fy;
sqNorm[0] = 1;
break;
case 2:
vert[0] = -fx, vert[1] = fy, vert[2] = 1;
sqNorm[2] = 1;
break;
case 3:
vert[0] = fx, vert[1] = fy, vert[2] = -1;
sqNorm[2] = -1;
break;
case 4:
vert[0] = fx, vert[1] = 1, vert[2] = fy;
sqNorm[1] = 1;
break;
case 5:
vert[0] = -fx, vert[1] = -1, vert[2] = fy;
sqNorm[1] = -1;
break;
}
compute_normal(vert, sphNormals[i][x][y]);
}
}
}
static uint8_t sqColors[6][DETAIL_LEVEL][DETAIL_LEVEL][3];
static uint8_t spColors[6][DETAIL_LEVEL][DETAIL_LEVEL][3];
for (int i = 0; i < 6; ++i)
{
for (int x = 0; x < DETAIL_LEVEL; ++x)
{
uint8_t spColorTemplate[3] = {
uint8_t(randomInt(0, 256)),
uint8_t(randomInt(0, 256)),
uint8_t(randomInt(0, 256)),
};
float rx = 1 - abs((float(x) / DETAIL_LEVEL) * 2 - 1);
for (int y = 0; y < DETAIL_LEVEL; ++y)
{
float ry = 1 - abs((float(y) / DETAIL_LEVEL) * 2 - 1);
uint32_t close_ratio = uint32_t(rx * ry * 255);
uint8_t* sq_color = sqColors[i][x][y];
uint8_t* sp_color = spColors[i][x][y];
sq_color[0] = (uint8_t)((randomInt(0, 256) * close_ratio) / 255);
sq_color[1] = (uint8_t)((randomInt(0, 256) * close_ratio) / 255);
sq_color[2] = (uint8_t)((randomInt(0, 256) * close_ratio) / 255);
sp_color[0] = (uint8_t)((spColorTemplate[0] * close_ratio) / 255);
sp_color[1] = (uint8_t)((spColorTemplate[1] * close_ratio) / 255);
sp_color[2] = (uint8_t)((spColorTemplate[2] * close_ratio) / 255);
}
}
}
static uint16_t indices[6][DETAIL_LEVEL - 1][DETAIL_LEVEL - 1][6];
for (int i = 0; i < 6; ++i)
{
uint32_t o = DETAIL_LEVEL * DETAIL_LEVEL * i;
for (int x = 0; x < DETAIL_LEVEL - 1; ++x)
{
for (int y = 0; y < DETAIL_LEVEL - 1; ++y)
{
uint16_t* quadIndices = indices[i][x][y];
#define vid(vx, vy) (o + (vx)*DETAIL_LEVEL + (vy))
quadIndices[0] = (uint16_t)vid(x, y);
quadIndices[1] = (uint16_t)vid(x, y + 1);
quadIndices[2] = (uint16_t)vid(x + 1, y + 1);
quadIndices[3] = (uint16_t)vid(x + 1, y + 1);
quadIndices[4] = (uint16_t)vid(x + 1, y);
quadIndices[5] = (uint16_t)vid(x, y);
#undef vid
}
}
}
#undef DETAIL_LEVEL
void* bufferData = nullptr;
uint32_t vertexCount = sizeof(verts) / 12;
size_t bufferSize;
gSphereVertexLayout.mBindingCount = 1;
switch (gSphereLayoutType)
{
default:
case 0:
{
// 0-12 sq positions,
// 12-16 sq colors
// 16-28 sq normals
// 28-32 sp colors
// 32-44 sp positions + sp normals
gSphereVertexLayout.mBindings[0].mStride = 44;
size_t vsize = vertexCount * gSphereVertexLayout.mBindings[0].mStride;
bufferSize = vsize;
bufferData = tf_calloc(1, bufferSize);
add_attribute(&gSphereVertexLayout, SEMANTIC_POSITION, TinyImageFormat_R32G32B32_SFLOAT, 0);
add_attribute(&gSphereVertexLayout, SEMANTIC_NORMAL, TinyImageFormat_R32G32B32_SFLOAT, 16);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD1, TinyImageFormat_R32G32B32_SFLOAT, 32);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD3, TinyImageFormat_R32G32B32_SFLOAT, 32);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD0, TinyImageFormat_R8G8B8A8_UNORM, 12);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD2, TinyImageFormat_R8G8B8A8_UNORM, 28);
copy_attribute(&gSphereVertexLayout, bufferData, 0, 12, vertexCount, verts);
copy_attribute(&gSphereVertexLayout, bufferData, 12, 3, vertexCount, sqColors);
copy_attribute(&gSphereVertexLayout, bufferData, 16, 12, vertexCount, sqNormals);
copy_attribute(&gSphereVertexLayout, bufferData, 28, 3, vertexCount, spColors);
copy_attribute(&gSphereVertexLayout, bufferData, 32, 12, vertexCount, sphNormals);
}
break;
case 1:
{
// 0-12 sq positions,
// 16-28 sq normals
// 32-34 sq colors
// 36-40 sp colors
// 48-62 sp positions
// 64-76 sp normals
gSphereVertexLayout.mBindings[0].mStride = 80;
size_t vsize = vertexCount * gSphereVertexLayout.mBindings[0].mStride;
bufferSize = vsize;
bufferData = tf_calloc(1, bufferSize);
add_attribute(&gSphereVertexLayout, SEMANTIC_POSITION, TinyImageFormat_R32G32B32_SFLOAT, 0);
add_attribute(&gSphereVertexLayout, SEMANTIC_NORMAL, TinyImageFormat_R32G32B32_SFLOAT, 16);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD1, TinyImageFormat_R32G32B32_SFLOAT, 48);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD3, TinyImageFormat_R32G32B32_SFLOAT, 64);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD0, TinyImageFormat_R8G8B8A8_UNORM, 32);
add_attribute(&gSphereVertexLayout, SEMANTIC_TEXCOORD2, TinyImageFormat_R8G8B8A8_UNORM, 36);
copy_attribute(&gSphereVertexLayout, bufferData, 0, 12, vertexCount, verts);
copy_attribute(&gSphereVertexLayout, bufferData, 16, 12, vertexCount, sqNormals);
copy_attribute(&gSphereVertexLayout, bufferData, 36, 3, vertexCount, spColors);
copy_attribute(&gSphereVertexLayout, bufferData, 32, 3, vertexCount, sqColors);
copy_attribute(&gSphereVertexLayout, bufferData, 48, 12, vertexCount, sphNormals);
copy_attribute(&gSphereVertexLayout, bufferData, 64, 12, vertexCount, sphNormals);
}
break;
}
gSphereIndexCount = sizeof(indices) / sizeof(uint16_t);
BufferLoadDesc sphereVbDesc = {};
sphereVbDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER;
sphereVbDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
sphereVbDesc.mDesc.mSize = bufferSize;
sphereVbDesc.pData = bufferData;
sphereVbDesc.ppBuffer = &pSphereVertexBuffer;
addResource(&sphereVbDesc, nullptr);
BufferLoadDesc sphereIbDesc = {};
sphereIbDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_INDEX_BUFFER;
sphereIbDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
sphereIbDesc.mDesc.mSize = sizeof(indices);
sphereIbDesc.pData = indices;
sphereIbDesc.ppBuffer = &pSphereIndexBuffer;
addResource(&sphereIbDesc, nullptr);
waitForAllResourceLoads();
tf_free(bufferData);
}
class Transformations : public IApp
{
public:
bool Init()
{
// window and renderer setup
RendererDesc settings;
memset(&settings, 0, sizeof(settings));
initGPUConfiguration(settings.pExtendedSettings);
initRenderer(GetName(), &settings, &pRenderer);
// check for init success
if (!pRenderer)
{
ShowUnsupportedMessage("Failed To Initialize renderer!");
return false;
}
setupGPUConfigurationPlatformParameters(pRenderer, settings.pExtendedSettings);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
QueryPoolDesc poolDesc = {};
poolDesc.mQueryCount = 3; // The count is 3 due to quest & multi-view use otherwise 2 is enough as we use 2 queries.
poolDesc.mType = QUERY_TYPE_PIPELINE_STATISTICS;
for (uint32_t i = 0; i < gDataBufferCount; ++i)
{
initQueryPool(pRenderer, &poolDesc, &pPipelineStatsQueryPool[i]);
}
}
QueueDesc queueDesc = {};
queueDesc.mType = QUEUE_TYPE_GRAPHICS;
queueDesc.mFlag = QUEUE_FLAG_INIT_MICROPROFILE;
initQueue(pRenderer, &queueDesc, &pGraphicsQueue);
GpuCmdRingDesc cmdRingDesc = {};
cmdRingDesc.pQueue = pGraphicsQueue;
cmdRingDesc.mPoolCount = gDataBufferCount;
cmdRingDesc.mCmdPerPoolCount = 1;
cmdRingDesc.mAddSyncPrimitives = true;
initGpuCmdRing(pRenderer, &cmdRingDesc, &gGraphicsCmdRing);
initSemaphore(pRenderer, &pImageAcquiredSemaphore);
initResourceLoaderInterface(pRenderer);
// Loads Skybox Textures
for (int i = 0; i < 6; ++i)
{
TextureLoadDesc textureDesc = {};
textureDesc.pFileName = pSkyBoxImageFileNames[i];
textureDesc.ppTexture = &pSkyBoxTextures[i];
// Textures representing color should be stored in SRGB or HDR format
textureDesc.mCreationFlag = TEXTURE_CREATION_FLAG_SRGB;
addResource(&textureDesc, NULL);
}
// Dynamic sampler that is bound at runtime
SamplerDesc samplerDesc = { FILTER_LINEAR,
FILTER_LINEAR,
MIPMAP_MODE_NEAREST,
ADDRESS_MODE_CLAMP_TO_EDGE,
ADDRESS_MODE_CLAMP_TO_EDGE,
ADDRESS_MODE_CLAMP_TO_EDGE };
addSampler(pRenderer, &samplerDesc, &pSamplerSkyBox);
gUniformData = (UniformBlock*)tf_malloc(MAX_PLANETS * sizeof(UniformBlock)); // CHANGED
uint64_t skyBoxDataSize = 4 * 6 * 6 * sizeof(float);
BufferLoadDesc skyboxVbDesc = {};
skyboxVbDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_VERTEX_BUFFER;
skyboxVbDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_GPU_ONLY;
skyboxVbDesc.mDesc.mSize = skyBoxDataSize;
skyboxVbDesc.pData = gSkyBoxPoints;
skyboxVbDesc.ppBuffer = &pSkyBoxVertexBuffer;
addResource(&skyboxVbDesc, NULL);
BufferLoadDesc ubDesc = {};
ubDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_UNIFORM_BUFFER;
ubDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_CPU_TO_GPU;
ubDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_PERSISTENT_MAP_BIT;
ubDesc.pData = NULL;
for (uint32_t i = 0; i < gDataBufferCount; ++i)
{
//ubDesc.mDesc.pName = "ProjViewUniformBuffer"; // CHANGED
//ubDesc.mDesc.mSize = sizeof(UniformBlock); // CHANGED
//ubDesc.ppBuffer = &pProjViewUniformBuffer[i]; // CHANGED
//addResource(&ubDesc, NULL); // CHANGED
ubDesc.mDesc.pName = "SkyboxUniformBuffer";
ubDesc.mDesc.mSize = sizeof(UniformBlockSky);
ubDesc.ppBuffer = &pSkyboxUniformBuffer[i];
addResource(&ubDesc, NULL);
}
// CHANGED BELOW
ubDesc = {};
ubDesc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER;
ubDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_CPU_TO_GPU;
ubDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_PERSISTENT_MAP_BIT;
//ubDesc.mDesc.mMemoryUsage = RESOURCE_MEMORY_USAGE_CPU_ONLY;
//ubDesc.mDesc.mFlags = BUFFER_CREATION_FLAG_NONE;
//ubDesc.mDesc.mStartState = RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
ubDesc.mDesc.mFirstElement = 0;
ubDesc.mDesc.mElementCount = MAX_PLANETS;
ubDesc.mDesc.mStructStride = sizeof(UniformBlock);
ubDesc.mDesc.mSize = MAX_PLANETS * ubDesc.mDesc.mStructStride;
ubDesc.pData = gUniformData;
ubDesc.mDesc.pName = "ProjViewInstanceBuffer"; // CHANGED
for (uint32_t i = 0; i < gDataBufferCount; ++i)
{
ubDesc.ppBuffer = &pProjViewUniformBuffer[i]; // CHANGED
addResource(&ubDesc, NULL); // CHANGED
}
// END CHANGES
// Load fonts
FontDesc font = {};
font.pFontPath = "TitilliumText/TitilliumText-Bold.otf";
fntDefineFonts(&font, 1, &gFontID);
FontSystemDesc fontRenderDesc = {};
fontRenderDesc.pRenderer = pRenderer;
if (!initFontSystem(&fontRenderDesc))
return false; // report?
// Initialize Forge User Interface Rendering
UserInterfaceDesc uiRenderDesc = {};
uiRenderDesc.pRenderer = pRenderer;
initUserInterface(&uiRenderDesc);
// Initialize micro profiler and its UI.
ProfilerDesc profiler = {};
profiler.pRenderer = pRenderer;
initProfiler(&profiler);
// Gpu profiler can only be added after initProfile.
gGpuProfileToken = initGpuProfiler(pRenderer, pGraphicsQueue, "Graphics");
const uint32_t numScripts = TF_ARRAY_COUNT(gWindowTestScripts);
LuaScriptDesc scriptDescs[numScripts] = {};
for (uint32_t i = 0; i < numScripts; ++i)
scriptDescs[i].pScriptFileName = gWindowTestScripts[i];
DEFINE_LUA_SCRIPTS(scriptDescs, numScripts);
waitForAllResourceLoads();
// Setup planets (Rotation speeds are relative to Earth's, some values randomly given)
// Sun
gPlanetInfoData[0].mParentIndex = 0;
gPlanetInfoData[0].mYOrbitSpeed = 0; // Earth years for one orbit
gPlanetInfoData[0].mZOrbitSpeed = 0;
gPlanetInfoData[0].mRotationSpeed = 24.0f; // Earth days for one rotation
gPlanetInfoData[0].mTranslationMat = mat4::identity();
gPlanetInfoData[0].mScaleMat = mat4::scale(vec3(10.0f));
gPlanetInfoData[0].mColor = vec4(0.97f, 0.38f, 0.09f, 0.0f);
gPlanetInfoData[0].mMorphingSpeed = 0.2f;
// Mercury
gPlanetInfoData[1].mParentIndex = 0;
gPlanetInfoData[1].mYOrbitSpeed = 0.5f;
gPlanetInfoData[1].mZOrbitSpeed = 0.0f;
gPlanetInfoData[1].mRotationSpeed = 58.7f;
gPlanetInfoData[1].mTranslationMat = mat4::translation(vec3(10.0f, 0, 0));
gPlanetInfoData[1].mScaleMat = mat4::scale(vec3(1.0f));
gPlanetInfoData[1].mColor = vec4(0.45f, 0.07f, 0.006f, 1.0f);
gPlanetInfoData[1].mMorphingSpeed = 5;
// Venus
gPlanetInfoData[2].mParentIndex = 0;
gPlanetInfoData[2].mYOrbitSpeed = 0.8f;
gPlanetInfoData[2].mZOrbitSpeed = 0.0f;
gPlanetInfoData[2].mRotationSpeed = 243.0f;
gPlanetInfoData[2].mTranslationMat = mat4::translation(vec3(20.0f, 0, 5));
gPlanetInfoData[2].mScaleMat = mat4::scale(vec3(2));
gPlanetInfoData[2].mColor = vec4(0.6f, 0.32f, 0.006f, 1.0f);
gPlanetInfoData[2].mMorphingSpeed = 1;
// Earth
gPlanetInfoData[3].mParentIndex = 0;
gPlanetInfoData[3].mYOrbitSpeed = 1.0f;
gPlanetInfoData[3].mZOrbitSpeed = 0.0f;
gPlanetInfoData[3].mRotationSpeed = 1.0f;
gPlanetInfoData[3].mTranslationMat = mat4::translation(vec3(30.0f, 0, 0));
gPlanetInfoData[3].mScaleMat = mat4::scale(vec3(4));
gPlanetInfoData[3].mColor = vec4(0.07f, 0.028f, 0.61f, 1.0f);
gPlanetInfoData[3].mMorphingSpeed = 1;
// Mars
gPlanetInfoData[4].mParentIndex = 0;
gPlanetInfoData[4].mYOrbitSpeed = 2.0f;
gPlanetInfoData[4].mZOrbitSpeed = 0.0f;
gPlanetInfoData[4].mRotationSpeed = 1.1f;
gPlanetInfoData[4].mTranslationMat = mat4::translation(vec3(40.0f, 0, 0));
gPlanetInfoData[4].mScaleMat = mat4::scale(vec3(3));
gPlanetInfoData[4].mColor = vec4(0.79f, 0.07f, 0.006f, 1.0f);
gPlanetInfoData[4].mMorphingSpeed = 1;
// Jupiter
gPlanetInfoData[5].mParentIndex = 0;
gPlanetInfoData[5].mYOrbitSpeed = 11.0f;
gPlanetInfoData[5].mZOrbitSpeed = 0.0f;
gPlanetInfoData[5].mRotationSpeed = 0.4f;
gPlanetInfoData[5].mTranslationMat = mat4::translation(vec3(50.0f, 0, 0));
gPlanetInfoData[5].mScaleMat = mat4::scale(vec3(8));
gPlanetInfoData[5].mColor = vec4(0.32f, 0.13f, 0.13f, 1);
gPlanetInfoData[5].mMorphingSpeed = 6;
// Saturn
gPlanetInfoData[6].mParentIndex = 0;
gPlanetInfoData[6].mYOrbitSpeed = 29.4f;
gPlanetInfoData[6].mZOrbitSpeed = 0.0f;
gPlanetInfoData[6].mRotationSpeed = 0.5f;
gPlanetInfoData[6].mTranslationMat = mat4::translation(vec3(60.0f, 0, 0));
gPlanetInfoData[6].mScaleMat = mat4::scale(vec3(6));
gPlanetInfoData[6].mColor = vec4(0.45f, 0.45f, 0.21f, 1.0f);
gPlanetInfoData[6].mMorphingSpeed = 1;
// Uranus
gPlanetInfoData[7].mParentIndex = 0;
gPlanetInfoData[7].mYOrbitSpeed = 84.07f;
gPlanetInfoData[7].mZOrbitSpeed = 0.0f;
gPlanetInfoData[7].mRotationSpeed = 0.8f;
gPlanetInfoData[7].mTranslationMat = mat4::translation(vec3(70.0f, 0, 0));
gPlanetInfoData[7].mScaleMat = mat4::scale(vec3(7));
gPlanetInfoData[7].mColor = vec4(0.13f, 0.13f, 0.32f, 1.0f);
gPlanetInfoData[7].mMorphingSpeed = 1;
// Neptune
gPlanetInfoData[8].mParentIndex = 0;
gPlanetInfoData[8].mYOrbitSpeed = 164.81f;
gPlanetInfoData[8].mZOrbitSpeed = 0.0f;
gPlanetInfoData[8].mRotationSpeed = 0.9f;
gPlanetInfoData[8].mTranslationMat = mat4::translation(vec3(80.0f, 0, 0));
gPlanetInfoData[8].mScaleMat = mat4::scale(vec3(8));
gPlanetInfoData[8].mColor = vec4(0.21f, 0.028f, 0.79f, 1.0f);
gPlanetInfoData[8].mMorphingSpeed = 1;
// Pluto - Not a planet XDD
gPlanetInfoData[9].mParentIndex = 0;
gPlanetInfoData[9].mYOrbitSpeed = 247.7f;
gPlanetInfoData[9].mZOrbitSpeed = 1.0f;
gPlanetInfoData[9].mRotationSpeed = 7.0f;
gPlanetInfoData[9].mTranslationMat = mat4::translation(vec3(90.0f, 0, 0));
gPlanetInfoData[9].mScaleMat = mat4::scale(vec3(1.0f));
gPlanetInfoData[9].mColor = vec4(0.45f, 0.21f, 0.21f, 1.0f);
gPlanetInfoData[9].mMorphingSpeed = 1;
// Moon
gPlanetInfoData[10].mParentIndex = 3;
gPlanetInfoData[10].mYOrbitSpeed = 1.0f;
gPlanetInfoData[10].mZOrbitSpeed = 200.0f;
gPlanetInfoData[10].mRotationSpeed = 27.0f;
gPlanetInfoData[10].mTranslationMat = mat4::translation(vec3(5.0f, 0, 0));
gPlanetInfoData[10].mScaleMat = mat4::scale(vec3(1));
gPlanetInfoData[10].mColor = vec4(0.07f, 0.07f, 0.13f, 1.0f);
gPlanetInfoData[10].mMorphingSpeed = 1;
CameraMotionParameters cmp{ 160.0f, 600.0f, 200.0f };
vec3 camPos{ 48.0f, 48.0f, 20.0f };
vec3 lookAt{ vec3(0) };
pCameraController = initFpsCameraController(camPos, lookAt);
pCameraController->setMotionParameters(cmp);
AddCustomInputBindings();
initScreenshotInterface(pRenderer, pGraphicsQueue);
gFrameIndex = 0;
return true;
}
void Exit()
{
exitScreenshotInterface();
exitCameraController(pCameraController);
exitUserInterface();
exitFontSystem();
// Exit profile
exitProfiler();
for (uint32_t i = 0; i < gDataBufferCount; ++i)
{
removeResource(pProjViewUniformBuffer[i]);
removeResource(pSkyboxUniformBuffer[i]);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
exitQueryPool(pRenderer, pPipelineStatsQueryPool[i]);
}
}
removeResource(pSkyBoxVertexBuffer);
for (uint i = 0; i < 6; ++i)
removeResource(pSkyBoxTextures[i]);
removeSampler(pRenderer, pSamplerSkyBox);
exitGpuCmdRing(pRenderer, &gGraphicsCmdRing);
exitSemaphore(pRenderer, pImageAcquiredSemaphore);
tf_free(gUniformData);
gUniformData = NULL;
exitResourceLoaderInterface(pRenderer);
exitQueue(pRenderer, pGraphicsQueue);
exitRenderer(pRenderer);
exitGPUConfiguration();
pRenderer = NULL;
}
bool Load(ReloadDesc* pReloadDesc)
{
if (pReloadDesc->mType & RELOAD_TYPE_SHADER)
{
addShaders();
addRootSignatures();
addDescriptorSets();
}
if (pReloadDesc->mType & (RELOAD_TYPE_RESIZE | RELOAD_TYPE_RENDERTARGET))
{
// we only need to reload gui when the size of window changed
loadProfilerUI(mSettings.mWidth, mSettings.mHeight);
UIComponentDesc guiDesc = {};
guiDesc.mStartPosition = vec2(mSettings.mWidth * 0.01f, mSettings.mHeight * 0.2f);
uiAddComponent(GetName(), &guiDesc, &pGuiWindow);
SliderUintWidget vertexLayoutWidget;
vertexLayoutWidget.mMin = 0;
vertexLayoutWidget.mMax = 1;
vertexLayoutWidget.mStep = 1;
vertexLayoutWidget.pData = &gSphereLayoutType;
UIWidget* pVLw = uiAddComponentWidget(pGuiWindow, "Vertex Layout", &vertexLayoutWidget, WIDGET_TYPE_SLIDER_UINT);
uiSetWidgetOnEditedCallback(pVLw, nullptr, reloadRequest);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
static float4 color = { 1.0f, 1.0f, 1.0f, 1.0f };
DynamicTextWidget statsWidget;
statsWidget.pText = &gPipelineStats;
statsWidget.pColor = &color;
uiAddComponentWidget(pGuiWindow, "Pipeline Stats", &statsWidget, WIDGET_TYPE_DYNAMIC_TEXT);
}
if (!addSwapChain())
return false;
if (!addDepthBuffer())
return false;
}
if (pReloadDesc->mType & (RELOAD_TYPE_SHADER | RELOAD_TYPE_RENDERTARGET))
{
generate_complex_mesh();
addPipelines();
}
prepareDescriptorSets();
UserInterfaceLoadDesc uiLoad = {};
uiLoad.mColorFormat = pSwapChain->ppRenderTargets[0]->mFormat;
uiLoad.mHeight = mSettings.mHeight;
uiLoad.mWidth = mSettings.mWidth;
uiLoad.mLoadType = pReloadDesc->mType;
loadUserInterface(&uiLoad);
FontSystemLoadDesc fontLoad = {};
fontLoad.mColorFormat = pSwapChain->ppRenderTargets[0]->mFormat;
fontLoad.mHeight = mSettings.mHeight;
fontLoad.mWidth = mSettings.mWidth;
fontLoad.mLoadType = pReloadDesc->mType;
loadFontSystem(&fontLoad);
return true;
}
void Unload(ReloadDesc* pReloadDesc)
{
waitQueueIdle(pGraphicsQueue);
unloadFontSystem(pReloadDesc->mType);
unloadUserInterface(pReloadDesc->mType);
if (pReloadDesc->mType & (RELOAD_TYPE_SHADER | RELOAD_TYPE_RENDERTARGET))
{
removePipelines();
removeResource(pSphereVertexBuffer);
removeResource(pSphereIndexBuffer);
}
if (pReloadDesc->mType & (RELOAD_TYPE_RESIZE | RELOAD_TYPE_RENDERTARGET))
{
removeSwapChain(pRenderer, pSwapChain);
removeRenderTarget(pRenderer, pDepthBuffer);
uiRemoveComponent(pGuiWindow);
unloadProfilerUI();
}
if (pReloadDesc->mType & RELOAD_TYPE_SHADER)
{
removeDescriptorSets();
removeRootSignatures();
removeShaders();
}
}
void Update(float deltaTime)
{
if (!uiIsFocused())
{
pCameraController->onMove({ inputGetValue(0, CUSTOM_MOVE_X), inputGetValue(0, CUSTOM_MOVE_Y) });
pCameraController->onRotate({ inputGetValue(0, CUSTOM_LOOK_X), inputGetValue(0, CUSTOM_LOOK_Y) });
pCameraController->onMoveY(inputGetValue(0, CUSTOM_MOVE_UP));
if (inputGetValue(0, CUSTOM_RESET_VIEW))
{
pCameraController->resetView();
}
if (inputGetValue(0, CUSTOM_TOGGLE_FULLSCREEN))
{
toggleFullscreen(pWindow);
}
if (inputGetValue(0, CUSTOM_TOGGLE_UI))
{
uiToggleActive();
}
if (inputGetValue(0, CUSTOM_DUMP_PROFILE))
{
dumpProfileData(GetName());
}
if (inputGetValue(0, CUSTOM_EXIT))
{
requestShutdown();
}
}
pCameraController->update(deltaTime);
/************************************************************************/
// Scene Update
/************************************************************************/
static float currentTime = 0.0f;
currentTime += deltaTime * 1000.0f;
// update camera with time
mat4 viewMat = pCameraController->getViewMatrix();
const float aspectInverse = (float)mSettings.mHeight / (float)mSettings.mWidth;
const float horizontal_fov = PI / 2.0f;
CameraMatrix projMat = CameraMatrix::perspectiveReverseZ(horizontal_fov, aspectInverse, 0.1f, 1000.0f);
// update planet transformations
for (unsigned int i = 0; i < gNumPlanets; i++)
{
gUniformData[i].mProjectView = projMat * viewMat; // CHANGED
// point light parameters
gUniformData[i].mLightPosition = vec4(0, 0, 0, 0); // CHANGED
gUniformData[i].mLightColor = vec4(0.9f, 0.9f, 0.7f, 1.0f); // Pale Yellow // CHANGED
mat4 rotSelf, rotOrbitY, rotOrbitZ, trans, scale, parentMat;
rotSelf = rotOrbitY = rotOrbitZ = parentMat = mat4::identity();
if (gPlanetInfoData[i].mRotationSpeed > 0.0f)
rotSelf = mat4::rotationY(gRotSelfScale * (currentTime + gTimeOffset) / gPlanetInfoData[i].mRotationSpeed);
if (gPlanetInfoData[i].mYOrbitSpeed > 0.0f)
rotOrbitY = mat4::rotationY(gRotOrbitYScale * (currentTime + gTimeOffset) / gPlanetInfoData[i].mYOrbitSpeed);
if (gPlanetInfoData[i].mZOrbitSpeed > 0.0f)
rotOrbitZ = mat4::rotationZ(gRotOrbitZScale * (currentTime + gTimeOffset) / gPlanetInfoData[i].mZOrbitSpeed);
if (gPlanetInfoData[i].mParentIndex > 0)
parentMat = gPlanetInfoData[gPlanetInfoData[i].mParentIndex].mSharedMat;
trans = gPlanetInfoData[i].mTranslationMat;
scale = gPlanetInfoData[i].mScaleMat;
scale[0][0] /= 2;
scale[1][1] /= 2;
scale[2][2] /= 2;
gPlanetInfoData[i].mSharedMat = parentMat * rotOrbitY * trans;
gUniformData[i].mToWorldMat = parentMat * rotOrbitY * rotOrbitZ * trans * rotSelf * scale; // CHANGED
gUniformData[i].mColor = gPlanetInfoData[i].mColor; // CHANGED
float step;
float phase = modf(currentTime * gPlanetInfoData[i].mMorphingSpeed / 2000.f, &step);
if (phase > 0.5f)
phase = 2 - phase * 2;
else
phase = phase * 2;
gUniformData[i].mGeometryWeight[0] = phase; // CHANGED
}
viewMat.setTranslation(vec3(0));
gUniformDataSky = {};
gUniformDataSky.mProjectView = projMat * viewMat;
}
void Draw()
{
if ((bool)pSwapChain->mEnableVsync != mSettings.mVSyncEnabled)
{
waitQueueIdle(pGraphicsQueue);
::toggleVSync(pRenderer, &pSwapChain);
}
uint32_t swapchainImageIndex;
acquireNextImage(pRenderer, pSwapChain, pImageAcquiredSemaphore, NULL, &swapchainImageIndex);
RenderTarget* pRenderTarget = pSwapChain->ppRenderTargets[swapchainImageIndex];
GpuCmdRingElement elem = getNextGpuCmdRingElement(&gGraphicsCmdRing, true, 1);
// Stall if CPU is running "gDataBufferCount" frames ahead of GPU
FenceStatus fenceStatus;
getFenceStatus(pRenderer, elem.pFence, &fenceStatus);
if (fenceStatus == FENCE_STATUS_INCOMPLETE)
waitForFences(pRenderer, 1, &elem.pFence);
// Update uniform buffers
BufferUpdateDesc viewProjCbv = { pProjViewUniformBuffer[gFrameIndex] };
beginUpdateResource(&viewProjCbv);
memcpy(viewProjCbv.pMappedData, gUniformData, 11 * sizeof(UniformBlock)); // CHANGED
endUpdateResource(&viewProjCbv);
BufferUpdateDesc skyboxViewProjCbv = { pSkyboxUniformBuffer[gFrameIndex] };
beginUpdateResource(&skyboxViewProjCbv);
memcpy(skyboxViewProjCbv.pMappedData, &gUniformDataSky, sizeof(gUniformDataSky));
endUpdateResource(&skyboxViewProjCbv);
// Reset cmd pool for this frame
resetCmdPool(pRenderer, elem.pCmdPool);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
QueryData data3D = {};
QueryData data2D = {};
getQueryData(pRenderer, pPipelineStatsQueryPool[gFrameIndex], 0, &data3D);
getQueryData(pRenderer, pPipelineStatsQueryPool[gFrameIndex], 1, &data2D);
bformat(&gPipelineStats,
"\n"
"Pipeline Stats 3D:\n"
" VS invocations: %u\n"
" PS invocations: %u\n"
" Clipper invocations: %u\n"
" IA primitives: %u\n"
" Clipper primitives: %u\n"
"\n"
"Pipeline Stats 2D UI:\n"
" VS invocations: %u\n"
" PS invocations: %u\n"
" Clipper invocations: %u\n"
" IA primitives: %u\n"
" Clipper primitives: %u\n",
data3D.mPipelineStats.mVSInvocations, data3D.mPipelineStats.mPSInvocations, data3D.mPipelineStats.mCInvocations,
data3D.mPipelineStats.mIAPrimitives, data3D.mPipelineStats.mCPrimitives, data2D.mPipelineStats.mVSInvocations,
data2D.mPipelineStats.mPSInvocations, data2D.mPipelineStats.mCInvocations, data2D.mPipelineStats.mIAPrimitives,
data2D.mPipelineStats.mCPrimitives);
}
Cmd* cmd = elem.pCmds[0];
beginCmd(cmd);
cmdBeginGpuFrameProfile(cmd, gGpuProfileToken);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
cmdResetQuery(cmd, pPipelineStatsQueryPool[gFrameIndex], 0, 2);
QueryDesc queryDesc = { 0 };
cmdBeginQuery(cmd, pPipelineStatsQueryPool[gFrameIndex], &queryDesc);
}
RenderTargetBarrier barriers[] = {
{ pRenderTarget, RESOURCE_STATE_PRESENT, RESOURCE_STATE_RENDER_TARGET },
};
cmdResourceBarrier(cmd, 0, NULL, 0, NULL, 1, barriers);
cmdBeginGpuTimestampQuery(cmd, gGpuProfileToken, "Draw Skybox/Planets");
// simply record the screen cleaning command
BindRenderTargetsDesc bindRenderTargets = {};
bindRenderTargets.mRenderTargetCount = 1;
bindRenderTargets.mRenderTargets[0] = { pRenderTarget, LOAD_ACTION_CLEAR };
bindRenderTargets.mDepthStencil = { pDepthBuffer, LOAD_ACTION_CLEAR };
cmdBindRenderTargets(cmd, &bindRenderTargets);
cmdSetViewport(cmd, 0.0f, 0.0f, (float)pRenderTarget->mWidth, (float)pRenderTarget->mHeight, 0.0f, 1.0f);
cmdSetScissor(cmd, 0, 0, pRenderTarget->mWidth, pRenderTarget->mHeight);
const uint32_t skyboxVbStride = sizeof(float) * 4;
// draw skybox
cmdBeginGpuTimestampQuery(cmd, gGpuProfileToken, "Draw Skybox");
cmdSetViewport(cmd, 0.0f, 0.0f, (float)pRenderTarget->mWidth, (float)pRenderTarget->mHeight, 1.0f, 1.0f);
cmdBindPipeline(cmd, pSkyBoxDrawPipeline);
cmdBindDescriptorSet(cmd, 0, pDescriptorSetTexture);
cmdBindDescriptorSet(cmd, gFrameIndex * 2 + 0, pDescriptorSetUniforms);
cmdBindVertexBuffer(cmd, 1, &pSkyBoxVertexBuffer, &skyboxVbStride, NULL);
cmdDraw(cmd, 36, 0);
cmdSetViewport(cmd, 0.0f, 0.0f, (float)pRenderTarget->mWidth, (float)pRenderTarget->mHeight, 0.0f, 1.0f);
cmdEndGpuTimestampQuery(cmd, gGpuProfileToken);
cmdBeginGpuTimestampQuery(cmd, gGpuProfileToken, "Draw Planets");
cmdBindPipeline(cmd, pSpherePipeline);
cmdBindDescriptorSet(cmd, gFrameIndex * 2 + 1, pDescriptorSetUniforms);
cmdBindVertexBuffer(cmd, 1, &pSphereVertexBuffer, &gSphereVertexLayout.mBindings[0].mStride, nullptr);
cmdBindIndexBuffer(cmd, pSphereIndexBuffer, INDEX_TYPE_UINT16, 0);
cmdDrawIndexedInstanced(cmd, gSphereIndexCount, 0, gNumPlanets, 0, 0);
cmdEndGpuTimestampQuery(cmd, gGpuProfileToken);
cmdEndGpuTimestampQuery(cmd, gGpuProfileToken); // Draw Skybox/Planets
cmdBindRenderTargets(cmd, NULL);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
QueryDesc queryDesc = { 0 };
cmdEndQuery(cmd, pPipelineStatsQueryPool[gFrameIndex], &queryDesc);
queryDesc = { 1 };
cmdBeginQuery(cmd, pPipelineStatsQueryPool[gFrameIndex], &queryDesc);
}
cmdBeginGpuTimestampQuery(cmd, gGpuProfileToken, "Draw UI");
bindRenderTargets = {};
bindRenderTargets.mRenderTargetCount = 1;
bindRenderTargets.mRenderTargets[0] = { pRenderTarget, LOAD_ACTION_LOAD };
bindRenderTargets.mDepthStencil = { NULL, LOAD_ACTION_DONTCARE };
cmdBindRenderTargets(cmd, &bindRenderTargets);
gFrameTimeDraw.mFontColor = 0xff00ffff;
gFrameTimeDraw.mFontSize = 18.0f;
gFrameTimeDraw.mFontID = gFontID;
float2 txtSizePx = cmdDrawCpuProfile(cmd, float2(8.f, 15.f), &gFrameTimeDraw);
cmdDrawGpuProfile(cmd, float2(8.f, txtSizePx.y + 75.f), gGpuProfileToken, &gFrameTimeDraw);
cmdDrawUserInterface(cmd);
cmdEndGpuTimestampQuery(cmd, gGpuProfileToken);
cmdBindRenderTargets(cmd, NULL);
barriers[0] = { pRenderTarget, RESOURCE_STATE_RENDER_TARGET, RESOURCE_STATE_PRESENT };
cmdResourceBarrier(cmd, 0, NULL, 0, NULL, 1, barriers);
cmdEndGpuFrameProfile(cmd, gGpuProfileToken);
if (pRenderer->pGpu->mPipelineStatsQueries)
{
QueryDesc queryDesc = { 1 };
cmdEndQuery(cmd, pPipelineStatsQueryPool[gFrameIndex], &queryDesc);
cmdResolveQuery(cmd, pPipelineStatsQueryPool[gFrameIndex], 0, 2);
}
endCmd(cmd);
FlushResourceUpdateDesc flushUpdateDesc = {};
flushUpdateDesc.mNodeIndex = 0;
flushResourceUpdates(&flushUpdateDesc);
Semaphore* waitSemaphores[2] = { flushUpdateDesc.pOutSubmittedSemaphore, pImageAcquiredSemaphore };
QueueSubmitDesc submitDesc = {};
submitDesc.mCmdCount = 1;
submitDesc.mSignalSemaphoreCount = 1;
submitDesc.mWaitSemaphoreCount = TF_ARRAY_COUNT(waitSemaphores);
submitDesc.ppCmds = &cmd;
submitDesc.ppSignalSemaphores = &elem.pSemaphore;
submitDesc.ppWaitSemaphores = waitSemaphores;
submitDesc.pSignalFence = elem.pFence;
queueSubmit(pGraphicsQueue, &submitDesc);
QueuePresentDesc presentDesc = {};
presentDesc.mIndex = (uint8_t)swapchainImageIndex;
presentDesc.mWaitSemaphoreCount = 1;
presentDesc.pSwapChain = pSwapChain;
presentDesc.ppWaitSemaphores = &elem.pSemaphore;
presentDesc.mSubmitDone = true;
queuePresent(pGraphicsQueue, &presentDesc);
flipProfiler();
gFrameIndex = (gFrameIndex + 1) % gDataBufferCount;
}
const char* GetName() { return "01_Transformations"; }
bool addSwapChain()
{
SwapChainDesc swapChainDesc = {};
swapChainDesc.mWindowHandle = pWindow->handle;
swapChainDesc.mPresentQueueCount = 1;
swapChainDesc.ppPresentQueues = &pGraphicsQueue;
swapChainDesc.mWidth = mSettings.mWidth;
swapChainDesc.mHeight = mSettings.mHeight;
swapChainDesc.mImageCount = getRecommendedSwapchainImageCount(pRenderer, &pWindow->handle);
swapChainDesc.mColorFormat = getSupportedSwapchainFormat(pRenderer, &swapChainDesc, COLOR_SPACE_SDR_SRGB);
swapChainDesc.mColorSpace = COLOR_SPACE_SDR_SRGB;
swapChainDesc.mEnableVsync = mSettings.mVSyncEnabled;
swapChainDesc.mFlags = SWAP_CHAIN_CREATION_FLAG_ENABLE_FOVEATED_RENDERING_VR;
::addSwapChain(pRenderer, &swapChainDesc, &pSwapChain);
return pSwapChain != NULL;
}
bool addDepthBuffer()
{
// Add depth buffer
RenderTargetDesc depthRT = {};
depthRT.mArraySize = 1;
depthRT.mClearValue.depth = 0.0f;
depthRT.mClearValue.stencil = 0;
depthRT.mDepth = 1;
depthRT.mFormat = TinyImageFormat_D32_SFLOAT;
depthRT.mStartState = RESOURCE_STATE_DEPTH_WRITE;
depthRT.mHeight = mSettings.mHeight;
depthRT.mSampleCount = SAMPLE_COUNT_1;
depthRT.mSampleQuality = 0;
depthRT.mWidth = mSettings.mWidth;
depthRT.mFlags = TEXTURE_CREATION_FLAG_ON_TILE | TEXTURE_CREATION_FLAG_VR_MULTIVIEW;
addRenderTarget(pRenderer, &depthRT, &pDepthBuffer);
return pDepthBuffer != NULL;
}
void addDescriptorSets()
{
DescriptorSetDesc desc = { pRootSignature, DESCRIPTOR_UPDATE_FREQ_NONE, 1 };
addDescriptorSet(pRenderer, &desc, &pDescriptorSetTexture);
desc = { pRootSignature, DESCRIPTOR_UPDATE_FREQ_PER_FRAME, gDataBufferCount * 2 };
addDescriptorSet(pRenderer, &desc, &pDescriptorSetUniforms);
}
void removeDescriptorSets()
{
removeDescriptorSet(pRenderer, pDescriptorSetTexture);
removeDescriptorSet(pRenderer, pDescriptorSetUniforms);
}
void addRootSignatures()
{
Shader* shaders[2];
uint32_t shadersCount = 0;
shaders[shadersCount++] = pSphereShader;
shaders[shadersCount++] = pSkyBoxDrawShader;
RootSignatureDesc rootDesc = {};
rootDesc.mShaderCount = shadersCount;
rootDesc.ppShaders = shaders;
addRootSignature(pRenderer, &rootDesc, &pRootSignature);
}
void removeRootSignatures() { removeRootSignature(pRenderer, pRootSignature); }
void addShaders()
{
ShaderLoadDesc skyShader = {};
skyShader.mVert.pFileName = "skybox.vert";
skyShader.mFrag.pFileName = "skybox.frag";
ShaderLoadDesc basicShader = {};
basicShader.mVert.pFileName = "basic.vert";
basicShader.mFrag.pFileName = "basic.frag";
addShader(pRenderer, &skyShader, &pSkyBoxDrawShader);
addShader(pRenderer, &basicShader, &pSphereShader);
}
void removeShaders()
{
removeShader(pRenderer, pSphereShader);
removeShader(pRenderer, pSkyBoxDrawShader);
}
void addPipelines()
{
RasterizerStateDesc rasterizerStateDesc = {};
rasterizerStateDesc.mCullMode = CULL_MODE_NONE;
RasterizerStateDesc sphereRasterizerStateDesc = {};
sphereRasterizerStateDesc.mCullMode = CULL_MODE_FRONT;
DepthStateDesc depthStateDesc = {};
depthStateDesc.mDepthTest = true;
depthStateDesc.mDepthWrite = true;
depthStateDesc.mDepthFunc = CMP_GEQUAL;
PipelineDesc desc = {};
desc.mType = PIPELINE_TYPE_GRAPHICS;
GraphicsPipelineDesc& pipelineSettings = desc.mGraphicsDesc;
pipelineSettings.mPrimitiveTopo = PRIMITIVE_TOPO_TRI_LIST;
pipelineSettings.mRenderTargetCount = 1;
pipelineSettings.pDepthState = &depthStateDesc;
pipelineSettings.pColorFormats = &pSwapChain->ppRenderTargets[0]->mFormat;
pipelineSettings.mSampleCount = pSwapChain->ppRenderTargets[0]->mSampleCount;
pipelineSettings.mSampleQuality = pSwapChain->ppRenderTargets[0]->mSampleQuality;
pipelineSettings.mDepthStencilFormat = pDepthBuffer->mFormat;
pipelineSettings.pRootSignature = pRootSignature;
pipelineSettings.pShaderProgram = pSphereShader;
pipelineSettings.pVertexLayout = &gSphereVertexLayout;
pipelineSettings.pRasterizerState = &sphereRasterizerStateDesc;
pipelineSettings.mVRFoveatedRendering = true;
addPipeline(pRenderer, &desc, &pSpherePipeline);
// layout and pipeline for skybox draw
VertexLayout vertexLayout = {};
vertexLayout.mBindingCount = 1;
vertexLayout.mBindings[0].mStride = sizeof(float4);
vertexLayout.mAttribCount = 1;
vertexLayout.mAttribs[0].mSemantic = SEMANTIC_POSITION;
vertexLayout.mAttribs[0].mFormat = TinyImageFormat_R32G32B32A32_SFLOAT;
vertexLayout.mAttribs[0].mBinding = 0;
vertexLayout.mAttribs[0].mLocation = 0;
vertexLayout.mAttribs[0].mOffset = 0;
pipelineSettings.pVertexLayout = &vertexLayout;
pipelineSettings.pDepthState = NULL;
pipelineSettings.pRasterizerState = &rasterizerStateDesc;
pipelineSettings.pShaderProgram = pSkyBoxDrawShader; //-V519
addPipeline(pRenderer, &desc, &pSkyBoxDrawPipeline);
}
void removePipelines()
{
removePipeline(pRenderer, pSkyBoxDrawPipeline);
removePipeline(pRenderer, pSpherePipeline);
}
void prepareDescriptorSets()
{
// Prepare descriptor sets
DescriptorData params[7] = {};
params[0].pName = "RightText";
params[0].ppTextures = &pSkyBoxTextures[0];
params[1].pName = "LeftText";
params[1].ppTextures = &pSkyBoxTextures[1];
params[2].pName = "TopText";
params[2].ppTextures = &pSkyBoxTextures[2];
params[3].pName = "BotText";
params[3].ppTextures = &pSkyBoxTextures[3];
params[4].pName = "FrontText";
params[4].ppTextures = &pSkyBoxTextures[4];
params[5].pName = "BackText";
params[5].ppTextures = &pSkyBoxTextures[5];
params[6].pName = "uSampler0";
params[6].ppSamplers = &pSamplerSkyBox;
updateDescriptorSet(pRenderer, 0, pDescriptorSetTexture, 7, params);
for (uint32_t i = 0; i < gDataBufferCount; ++i)
{
DescriptorData uParams[1] = {};
uParams[0].pName = "uniformBlock";
uParams[0].ppBuffers = &pSkyboxUniformBuffer[i];
updateDescriptorSet(pRenderer, i * 2 + 0, pDescriptorSetUniforms, 1, uParams);
//uParams[0].pName = "uniformBlock"; // CHANGED
uParams[0].pName = "instanceBuffer"; // CAHNGED
uParams[0].ppBuffers = &pProjViewUniformBuffer[i];
updateDescriptorSet(pRenderer, i * 2 + 1, pDescriptorSetUniforms, 1, uParams);
}
}
};
DEFINE_APPLICATION_MAIN(Transformations)
/*
* Copyright (c) 2017-2024 The Forge Interactive Inc.
*
* This file is part of The-Forge
* (see https://github.com/ConfettiFX/The-Forge).
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef RESOURCES_H
#define RESOURCES_H
// UPDATE_FREQ_NONE
RES(Tex2D(float4), RightText, UPDATE_FREQ_NONE, t1, binding = 1);
RES(Tex2D(float4), LeftText, UPDATE_FREQ_NONE, t2, binding = 2);
RES(Tex2D(float4), TopText, UPDATE_FREQ_NONE, t3, binding = 3);
RES(Tex2D(float4), BotText, UPDATE_FREQ_NONE, t4, binding = 4);
RES(Tex2D(float4), FrontText, UPDATE_FREQ_NONE, t5, binding = 5);
RES(Tex2D(float4), BackText, UPDATE_FREQ_NONE, t6, binding = 6);
RES(SamplerState, uSampler0, UPDATE_FREQ_NONE, s0, binding = 7);
// UPDATE_FREQ_PER_FRAME
#ifndef MAX_PLANETS
#define MAX_PLANETS 20
#endif
STRUCT(UniformData)
{
#if FT_MULTIVIEW
DATA(float4x4, mvp[VR_MULTIVIEW_COUNT], None);
#else
DATA(float4x4, mvp, None);
#endif
#if !defined(SKY_SHADER)
DATA(float4x4, toWorld, None);
DATA(float4, color, None);
DATA(float4, geometry_weight, None);
// Point Light Information
DATA(float4, lightPosition, None);
DATA(float4, lightColor, None);
#endif
};
RES(CBUFFER(UniformData), uniformBlock, UPDATE_FREQ_PER_FRAME, b0, binding = 0);
RES(Buffer(UniformData), instanceBuffer, UPDATE_FREQ_PER_FRAME, t7, binding = 8);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment