Merge branch 'main' into SP3-2-Physics

This commit is contained in:
Diren D Bharwani 2022-11-21 20:15:58 +08:00
commit 3baedd8ffa
19 changed files with 172 additions and 32 deletions

BIN
Assets/Fonts/ALGER.shfont Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: ALGER
ID: 182525173
Type: 10

BIN
Assets/Fonts/ALGER.ttf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -45,15 +45,14 @@ void main()
float screenPxDistance = 2 * (sd - 0.5f); float screenPxDistance = 2 * (sd - 0.5f);
float opacity = clamp (screenPxDistance + 0.5f, 0.0f, 2.0f); float opacity = clamp (screenPxDistance + 0.5f, 0.0f, 2.0f);
vec4 fragColor = vec4 (1.0f); vec4 fragColor;
if (opacity > 0.02f && opacity < 1.9f)
{
fragColor = vec4(0.0f, 1.0f, 1.0f, 1.0f);
}
if (opacity < 0.2f)
discard;
else
fragColor = mix(vec4(0.0f), vec4(In2.textColor, 1.0f), min (opacity, 1.0f)); fragColor = mix(vec4(0.0f), vec4(In2.textColor, 1.0f), min (opacity, 1.0f));
// fragColor = vec4 (1.0f);
color = fragColor; color = fragColor;
outEntityID = In2.eid; outEntityID = In2.eid;

Binary file not shown.

View File

@ -68,7 +68,7 @@ void main()
// Generate UV coords and vertex positions // Generate UV coords and vertex positions
Out.uv = CreateQuad(gl_VertexIndex); Out.uv = CreateQuad(gl_VertexIndex);
vec3 vertexPos = vec3(Out.uv, 1.0f); vec3 vertexPos = vec3(Out.uv, 0.0f);
// Get the local matrices // Get the local matrices
mat4 localModel = testPushConstant.worldTransform; mat4 localModel = testPushConstant.worldTransform;
@ -87,16 +87,15 @@ void main()
toFontSpace[2][0] = positionalOffset.x; toFontSpace[2][0] = positionalOffset.x;
toFontSpace[2][1] = positionalOffset.y; toFontSpace[2][1] = positionalOffset.y;
mat4 PVMatrix = cameraData.vpMat;
// Initialize variables for use in FS // Initialize variables for use in FS
//characterIndex = gl_InstanceID; //characterIndex = gl_InstanceID;
// Transform the vertices to font space // Transform the vertices to font space
vertexPos = toFontSpace * vertexPos; vertexPos = toFontSpace * vec3(vertexPos.xy, 1.0f);
Out2.textColor = testPushConstant.textColor; Out2.textColor = testPushConstant.textColor;
// transform the vertex position to font space // transform the vertex position to font space
gl_Position = PVMatrix * localModel * vec4(vertexPos, 1.0f); gl_Position = cameraData.orthoMat * localModel * vec4(vertexPos, 1.0f);
// gl_Position = vec4(vertexPos, 1.0f);
} }

Binary file not shown.

View File

@ -81,6 +81,7 @@ namespace Sandbox
SHSystemManager::CreateSystem<SHUISystem>(); SHSystemManager::CreateSystem<SHUISystem>();
std::system("FontCompiler.exe ../../Assets/Fonts/SegoeUI.ttf"); std::system("FontCompiler.exe ../../Assets/Fonts/SegoeUI.ttf");
std::system("FontCompiler.exe ../../Assets/Fonts/ALGER.ttf");
SHSystemManager::CreateSystem<SHGraphicsSystem>(); SHSystemManager::CreateSystem<SHGraphicsSystem>();
SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>()); SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>());
@ -142,7 +143,7 @@ namespace Sandbox
//SHComponentManager::CreateComponentSparseSet<SHCameraComponent>(); //SHComponentManager::CreateComponentSparseSet<SHCameraComponent>();
SHAssetManager::Load(); SHAssetManager::Load();
auto font = SHAssetManager::GetData<SHFontAsset>(176667660); //auto font = SHAssetManager::GetData<SHFontAsset>(176667660);
SHSystemManager::RegisterRoutine<SHAudioSystem, SHAudioSystem::AudioRoutine>(); SHSystemManager::RegisterRoutine<SHAudioSystem, SHAudioSystem::AudioRoutine>();

View File

@ -22,6 +22,14 @@ namespace SHADE
return nullptr; return nullptr;
} }
// Attempt to load font geometry for advance data
auto ttfFilePath = path.string();
ttfFilePath = ttfFilePath.substr(0, ttfFilePath.find_last_of('.'));
ttfFilePath += TTF_EXTENSION.data();
msdfgen::FontHandle* fontHandle = nullptr;
fontHandle = msdfgen::loadFont(SHFreetypeInstance::GetFreetypeHandle(), ttfFilePath.c_str());
newFontAsset->fontGeometry.loadCharset(fontHandle, 1.0f, msdf_atlas::Charset::ASCII);
uint32_t numGlyphs = 0; uint32_t numGlyphs = 0;
// read how many glyphs we have // read how many glyphs we have

View File

@ -496,4 +496,52 @@ namespace SHADE
} }
ImGui::PopID(); ImGui::PopID();
} }
template<>
static void DrawComponent(SHTextRendererComponent* component)
{
if (!component)
return;
ImGui::PushID(SHFamilyID<SHComponent>::GetID<SHTextRendererComponent>());
const auto componentType = rttr::type::get(*component);
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
ImGui::SameLine();
if (ImGui::CollapsingHeader(componentType.get_name().data()))
{
DrawContextMenu(component);
Handle<SHFont> const& font = component->GetFont();
const auto FONT_NAME = SHResourceManager::GetAssetName<SHFont>(font).value_or("");
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Font", FONT_NAME, [component]()
{
Handle<SHFont> const& font = component->GetFont();
return SHResourceManager::GetAssetID<SHFont>(font).value_or(0);
},
[component](AssetID const& id)
{
if (SHAssetManager::GetType(id) != AssetType::FONT)
{
SHLOG_WARNING("Attempted to assign non font asset to TextRendererComponent Font property!")
return;
}
component->SetFont(SHResourceManager::LoadOrGet<SHFont>(id));
SHResourceManager::FinaliseChanges();
}, SHDragDrop::DRAG_RESOURCE);
SHEditorWidgets::InputText("Text",
[component](void)
{
return component->GetText();
},
[component](std::string const& val)
{
component->SetText(val);
}
);
}
else
{
DrawContextMenu(component);
}
ImGui::PopID();
}
} }

View File

@ -22,6 +22,7 @@
#include "UI/SHCanvasComponent.h" #include "UI/SHCanvasComponent.h"
#include "SHEditorComponentView.h" #include "SHEditorComponentView.h"
#include "AudioSystem/SHAudioListenerComponent.h" #include "AudioSystem/SHAudioListenerComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRendererComponent.h"
namespace SHADE namespace SHADE
{ {
@ -144,6 +145,10 @@ namespace SHADE
{ {
DrawComponent(uiComponent); DrawComponent(uiComponent);
} }
if (auto textRendererComponent = SHComponentManager::GetComponent_s<SHTextRendererComponent>(eid))
{
DrawComponent(textRendererComponent);
}
ImGui::Separator(); ImGui::Separator();
// Render Scripts // Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
@ -162,6 +167,7 @@ namespace SHADE
DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHTextRendererComponent, SHTransformComponent>(eid);
ImGui::EndMenu(); ImGui::EndMenu();

View File

@ -117,13 +117,14 @@ namespace SHADE
// Create generic command buffer // Create generic command buffer
graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
SHAssetManager::CompileAsset("../../Assets/Shaders/Text_VS.glsl", false); SHFreetypeInstance::Init();
SHAssetManager::CompileAsset("../../Assets/Shaders/Text_FS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/UI_VS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Shaders/UI_FS.glsl", false);
SHAssetManager::CompileAsset("../../Assets/Models/Quad.gltf", false); //SHAssetManager::CompileAsset("../../Assets/Shaders/Text_VS.glsl", false);
//SHAssetManager::CompileAsset("../../Assets/Shaders/Text_FS.glsl", false);
//SHAssetManager::CompileAsset("../../Assets/Shaders/TestCube_VS.glsl", false);
//SHAssetManager::CompileAsset("../../Assets/Shaders/UI_VS.glsl", false);
//SHAssetManager::CompileAsset("../../Assets/Shaders/UI_FS.glsl", false);
//SHAssetManager::CompileAsset("../../Assets/Models/Quad.gltf", false);
// Load Built In Shaders // Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT); static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
@ -135,7 +136,6 @@ namespace SHADE
static constexpr AssetID SSAO_BLUR = 39760835; ssaoBlurShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(SSAO_BLUR); static constexpr AssetID SSAO_BLUR = 39760835; ssaoBlurShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(SSAO_BLUR);
static constexpr AssetID TEXT_VS = 39816727; textVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_VS); static constexpr AssetID TEXT_VS = 39816727; textVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_VS);
static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_FS); static constexpr AssetID TEXT_FS = 38024754; textFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TEXT_FS);
static constexpr AssetID SEGOE_UI_FONT = 176667660; testFont = SHResourceManager::LoadOrGet<SHFont>(SEGOE_UI_FONT);
} }
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -379,7 +379,6 @@ namespace SHADE
screenRenderer->BindDescSet(cmdBuffer, frameIndex); screenRenderer->BindDescSet(cmdBuffer, frameIndex);
}); });
SHFreetypeInstance::Init();
} }
void SHGraphicsSystem::InitBuiltInResources(void) void SHGraphicsSystem::InitBuiltInResources(void)
@ -1041,7 +1040,8 @@ namespace SHADE
worldViewport->SetWidth(static_cast<float>(resizeWidth)); worldViewport->SetWidth(static_cast<float>(resizeWidth));
worldViewport->SetHeight(static_cast<float>(resizeHeight)); worldViewport->SetHeight(static_cast<float>(resizeHeight));
worldCamera->SetPerspective(90.0f, static_cast<float>(resizeWidth), static_cast<float>(resizeHeight), 0.0f, 100.0f); //worldCamera->SetPerspective(90.0f, static_cast<float>(resizeWidth), static_cast<float>(resizeHeight), 0.0f, 100.0f);
//screenCamera->SetOrthographic(static_cast<float>(resizeWidth), static_cast<float>(resizeHeight), 0.01f, 100.0f);
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>(); auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
#ifdef SHEDITOR #ifdef SHEDITOR
@ -1053,8 +1053,6 @@ namespace SHADE
for (auto& semaHandle : graphSemaphores) for (auto& semaHandle : graphSemaphores)
semaHandle = device->CreateSemaphore(); semaHandle = device->CreateSemaphore();
} }
void SHGraphicsSystem::AwaitGraphicsExecution() void SHGraphicsSystem::AwaitGraphicsExecution()

View File

@ -24,7 +24,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHTextRendererComponent::OnCreate(void) void SHTextRendererComponent::OnCreate(void)
{ {
text = "Text"; text = "My name is Brandon.";
requiresRecompute = true; requiresRecompute = true;
// Default white color. // Default white color.
@ -58,6 +58,7 @@ namespace SHADE
void SHTextRendererComponent::SetFont(Handle<SHFont> font) noexcept void SHTextRendererComponent::SetFont(Handle<SHFont> font) noexcept
{ {
fontHandle = font; fontHandle = font;
MakeDirty();
} }
/***************************************************************************/ /***************************************************************************/
@ -76,4 +77,19 @@ namespace SHADE
return text; return text;
} }
Handle<SHFont> SHTextRendererComponent::GetFont(void) const noexcept
{
return fontHandle;
}
}
namespace rttr
{
RTTR_REGISTRATION
{
using namespace SHADE;
registration::class_<SHTextRendererComponent>("Text Renderer Component");
};
} }

View File

@ -5,6 +5,7 @@
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Math/SHColour.h" #include "Math/SHColour.h"
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include <rttr/registration>
namespace SHADE namespace SHADE
{ {
@ -53,9 +54,12 @@ namespace SHADE
void SetFont (Handle<SHFont> font) noexcept; void SetFont (Handle<SHFont> font) noexcept;
std::string const& GetText (void) const noexcept; std::string const& GetText (void) const noexcept;
Handle<SHFont> GetFont (void) const noexcept;
friend class SHTextRenderingSubSystem; friend class SHTextRenderingSubSystem;
RTTR_ENABLE()
}; };
} }

View File

@ -16,7 +16,7 @@ namespace SHADE
{ {
void SHTextRenderingSubSystem::RecomputePositions(SHTextRendererComponent& textComp) noexcept void SHTextRenderingSubSystem::RecomputePositions(SHTextRendererComponent& textComp) noexcept
{ {
if (textComp.text.empty() || textComp.fontHandle) if (textComp.text.empty() || !textComp.fontHandle)
return; return;
// Create the buffer // Create the buffer
@ -24,7 +24,7 @@ namespace SHADE
textComp.indexingDataBuffer = logicalDevice->CreateBuffer(SHTextRendererComponent::MAX_CHARACTERS * sizeof(uint32_t), nullptr, SHTextRendererComponent::MAX_CHARACTERS * sizeof(uint32_t), vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); textComp.indexingDataBuffer = logicalDevice->CreateBuffer(SHTextRendererComponent::MAX_CHARACTERS * sizeof(uint32_t), nullptr, SHTextRendererComponent::MAX_CHARACTERS * sizeof(uint32_t), vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT);
if (!textComp.charPositionDataBuffer) if (!textComp.charPositionDataBuffer)
textComp.indexingDataBuffer = logicalDevice->CreateBuffer(SHTextRendererComponent::MAX_CHARACTERS * sizeof(SHVec4), nullptr, SHTextRendererComponent::MAX_CHARACTERS * sizeof(SHVec4), vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); textComp.charPositionDataBuffer = logicalDevice->CreateBuffer(SHTextRendererComponent::MAX_CHARACTERS * sizeof(SHVec4), nullptr, SHTextRendererComponent::MAX_CHARACTERS * sizeof(SHVec4), vk::BufferUsageFlagBits::eVertexBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT);
// For indexing font transformation in the shader // For indexing font transformation in the shader
std::vector <SHTextRendererComponent::TextIndexingType> indexingData; std::vector <SHTextRendererComponent::TextIndexingType> indexingData;
@ -115,8 +115,8 @@ namespace SHADE
SHVertexInputState vertexInputState; SHVertexInputState vertexInputState;
// Configure vertex attributes // Configure vertex attributes
vertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_4D) }); // location = 0 (character position data) vertexInputState.AddBinding(true, false, { SHVertexAttribute(SHAttribFormat::FLOAT_4D) }); // location = 0 (character position data)
vertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::UINT32_1D) }); // location = 1 (glyph index to index matrices) vertexInputState.AddBinding(true, false, { SHVertexAttribute(SHAttribFormat::UINT32_1D) }); // location = 1 (glyph index to index matrices)
// Set vertex state for new pipeline // Set vertex state for new pipeline
pipeline->GetPipelineState().SetVertexInputState(vertexInputState); pipeline->GetPipelineState().SetVertexInputState(vertexInputState);
@ -146,6 +146,13 @@ namespace SHADE
pipeline->GetPipelineState().SetColorBlenState(colorBlendState); pipeline->GetPipelineState().SetColorBlenState(colorBlendState);
SHInputAssemblyState inputAssembly{};
inputAssembly.topology = vk::PrimitiveTopology::eTriangleFan;
pipeline->GetPipelineState().SetInputAssemblyState(inputAssembly);
SHRasterizationState rasterState{};
rasterState.frontFacingOrientation = vk::FrontFace::eClockwise;
pipeline->GetPipelineState().SetRasterizationState(rasterState);
// Construct pipeline // Construct pipeline
pipeline->ConstructPipeline(); pipeline->ConstructPipeline();

View File

@ -211,6 +211,7 @@ namespace SHADE
AddComponentToComponentNode<SHLightComponent>(components, eid); AddComponentToComponentNode<SHLightComponent>(components, eid);
AddComponentToComponentNode<SHRigidBodyComponent>(components, eid); AddComponentToComponentNode<SHRigidBodyComponent>(components, eid);
AddConvComponentToComponentNode<SHColliderComponent>(components, eid); AddConvComponentToComponentNode<SHColliderComponent>(components, eid);
AddConvComponentToComponentNode<SHTextRendererComponent>(components, eid);
node[ComponentsNode] = components; node[ComponentsNode] = components;
@ -262,6 +263,7 @@ namespace SHADE
AddComponentID<SHRigidBodyComponent>(componentIDList, componentsNode); AddComponentID<SHRigidBodyComponent>(componentIDList, componentsNode);
AddComponentID<SHLightComponent>(componentIDList, componentsNode); AddComponentID<SHLightComponent>(componentIDList, componentsNode);
AddComponentID<SHColliderComponent>(componentIDList, componentsNode); AddComponentID<SHColliderComponent>(componentIDList, componentsNode);
AddComponentID<SHTextRendererComponent>(componentIDList, componentsNode);
return componentIDList; return componentIDList;
} }
@ -338,6 +340,7 @@ namespace SHADE
SHSerializationHelper::InitializeComponentFromNode<SHRigidBodyComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHRigidBodyComponent>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHRenderable>(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent<SHRenderable>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHColliderComponent>(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent<SHColliderComponent>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHTextRendererComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid);
} }
} }

View File

@ -12,6 +12,9 @@
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Physics/Interface/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRendererComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h"
namespace YAML namespace YAML
{ {
using namespace SHADE; using namespace SHADE;
@ -326,4 +329,45 @@ namespace YAML
return true; return true;
} }
}; };
template<>
struct convert<SHTextRendererComponent>
{
static constexpr std::string_view TEXT_YAML_TAG = "Text";
static constexpr std::string_view FONT_YAML_TAG = "Font";
static YAML::Node encode(SHTextRendererComponent const& rhs)
{
YAML::Node node;
node[TEXT_YAML_TAG.data()] = rhs.GetText();
auto font = rhs.GetFont();
if (font)
{
node[FONT_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHFont>(rhs.GetFont()).value_or(0);
}
else
{
node[FONT_YAML_TAG.data()] = 0;
}
return node;
}
static bool decode(YAML::Node const& node, SHTextRendererComponent& rhs)
{
if (node[TEXT_YAML_TAG.data()].IsDefined())
{
rhs.SetText(node[TEXT_YAML_TAG.data()].as<std::string>());
}
if (node[FONT_YAML_TAG.data()].IsDefined())
{
// Temporarily, use default material
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (!gfxSystem)
return false;
rhs.SetFont(SHResourceManager::LoadOrGet<SHFont>(node[TEXT_YAML_TAG.data()].as<AssetID>()));
}
return true;
}
};
} }

View File

@ -62,7 +62,11 @@ project "SHADE_Managed"
disablewarnings disablewarnings
{ {
"4251" "4251",
"4633",
"4634",
"4635",
"4638"
} }
defines defines