mirror of
https://github.com/AlexAltea/nucleus.git
synced 2024-06-12 01:07:35 -04:00
Added text support and multi-pipeline UI renderer
This commit is contained in:
parent
2f1372edca
commit
5780869b12
|
@ -65,7 +65,14 @@ D3D12_COMPARISON_FUNC convertComparisonFunc(gfx::ComparisonFunc comparisonFunc)
|
|||
|
||||
D3D12_FILTER convertFilter(gfx::Filter filter) {
|
||||
switch (filter) {
|
||||
case FILTER_MIN_MAG_MIP_POINT: return D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
case FILTER_MIN_MAG_MIP_POINT: return D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
case FILTER_MIN_MAG_POINT_MIP_LINEAR: return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
case FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT: return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
case FILTER_MIN_POINT_MAG_MIP_LINEAR: return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
|
||||
case FILTER_MIN_LINEAR_MAG_MIP_POINT: return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
case FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR: return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||
case FILTER_MIN_MAG_LINEAR_MIP_POINT: return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
case FILTER_MIN_MAG_MIP_LINEAR: return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
default:
|
||||
assert_always("Unimplemented case");
|
||||
return D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
|
@ -74,10 +81,12 @@ D3D12_FILTER convertFilter(gfx::Filter filter) {
|
|||
|
||||
DXGI_FORMAT convertFormat(gfx::Format format) {
|
||||
switch (format) {
|
||||
case FORMAT_R32G32: return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case FORMAT_R32G32B32: return DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
case FORMAT_R32G32B32A32: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case FORMAT_R32_FLOAT: return DXGI_FORMAT_R32_FLOAT;
|
||||
case FORMAT_R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case FORMAT_R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
case FORMAT_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case FORMAT_R8_UNORM: return DXGI_FORMAT_R8_UNORM;
|
||||
case FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
default:
|
||||
assert_always("Unimplemented case");
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
|
|
|
@ -267,12 +267,11 @@ std::string Direct3D12Shader::getPointer(Literal pointerId) {
|
|||
return idCache[pointerId];
|
||||
}
|
||||
|
||||
std::string pointerString;
|
||||
Instruction* pointerInstr = module->idInstructions[pointerId];
|
||||
Instruction* typeInstr = module->idInstructions[pointerInstr->typeId];
|
||||
assert(typeInstr->opcode == OP_TYPE_POINTER);
|
||||
|
||||
std::string pointerStr;
|
||||
std::string pointerString;
|
||||
switch (typeInstr->operands[0]) {
|
||||
case StorageClass::UNIFORM_CONSTANT:
|
||||
pointerString = "uniform."; break;
|
||||
|
@ -280,6 +279,8 @@ std::string Direct3D12Shader::getPointer(Literal pointerId) {
|
|||
pointerString = "input."; break;
|
||||
case StorageClass::OUTPUT:
|
||||
pointerString = "output."; break;
|
||||
case StorageClass::FUNCTION:
|
||||
break;
|
||||
default:
|
||||
assert_always("Unimplemented");
|
||||
}
|
||||
|
@ -289,9 +290,17 @@ std::string Direct3D12Shader::getPointer(Literal pointerId) {
|
|||
}
|
||||
if (pointerInstr->opcode == OP_ACCESS_CHAIN) {
|
||||
pointerString += format("v%d", pointerInstr->operands[0]);
|
||||
for (size_t i = 1; i < pointerInstr->operands.size(); i++) {
|
||||
std::string constant = getConstant(pointerInstr->operands[i]);
|
||||
pointerString += format(".m%s", constant.c_str());
|
||||
Instruction* varType = module->idInstructions[pointerInstr->operands[0]];
|
||||
Instruction* ptrType = module->idInstructions[varType->typeId];
|
||||
Instruction* underlyingType = module->idInstructions[ptrType->operands[1]];
|
||||
if (underlyingType->opcode == OP_TYPE_STRUCT) {
|
||||
for (size_t i = 1; i < pointerInstr->operands.size(); i++) {
|
||||
std::string constant = getConstant(pointerInstr->operands[i]);
|
||||
pointerString += format(".m%s", constant.c_str());
|
||||
}
|
||||
} else if (underlyingType->opcode == OP_TYPE_VECTOR) {
|
||||
std::string constant = getConstant(pointerInstr->operands[1]);
|
||||
pointerString += format("[%s]", constant.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +389,21 @@ std::string Direct3D12Shader::emitOpStore(Instruction* i) {
|
|||
return format(PADDING "%s = v%d;\n", pointerStr.c_str(), object);
|
||||
}
|
||||
|
||||
std::string Direct3D12Shader::emitOpVariable(hir::Instruction* i) {
|
||||
assert_true(i->operands.size() >= 1);
|
||||
assert_true(i->operands[0] == StorageClass::FUNCTION);
|
||||
|
||||
Literal result = i->resultId;
|
||||
std::string type = getType(i->typeId);
|
||||
return format(PADDING "%s v%d;\n", type.c_str(), result);
|
||||
}
|
||||
|
||||
std::string Direct3D12Shader::emitOpVectorShuffle(hir::Instruction* i) {
|
||||
assert_true(i->operands.size() >= 2);
|
||||
assert_always("Unimplemented");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Direct3D12Shader::compile(Instruction* i) {
|
||||
std::string source;
|
||||
switch (i->opcode) {
|
||||
|
@ -411,12 +435,16 @@ std::string Direct3D12Shader::compile(Instruction* i) {
|
|||
return emitBinaryOp(i, OP_TYPE_INT, '%'); // TODO: Is this correct?
|
||||
case OP_SREM:
|
||||
return emitBinaryOp(i, OP_TYPE_INT, '%'); // TODO: Is this correct?
|
||||
case OP_VECTOR_SHUFFLE:
|
||||
return emitOpVectorShuffle(i);
|
||||
case OP_COMPOSITE_EXTRACT:
|
||||
return emitOpCompositeExtract(i);
|
||||
case OP_COMPOSITE_CONSTRUCT:
|
||||
return emitOpCompositeConstruct(i);
|
||||
case OP_IMAGE_SAMPLE_IMPLICIT_LOD:
|
||||
return emitOpImageSample(i);
|
||||
case OP_VARIABLE:
|
||||
return emitOpVariable(i);
|
||||
case OP_LOAD:
|
||||
return emitOpLoad(i);
|
||||
case OP_STORE:
|
||||
|
|
|
@ -64,6 +64,8 @@ class Direct3D12Shader : public Shader {
|
|||
std::string emitOpImageSample(hir::Instruction* i);
|
||||
std::string emitOpLoad(hir::Instruction* i);
|
||||
std::string emitOpStore(hir::Instruction* i);
|
||||
std::string emitOpVariable(hir::Instruction* i);
|
||||
std::string emitOpVectorShuffle(hir::Instruction* i);
|
||||
|
||||
// Compile HIR components into HLSL
|
||||
std::string compile(hir::Instruction* i);
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
namespace gfx {
|
||||
|
||||
const FormatInfo formatInfo[_FORMAT_COUNT] = {
|
||||
{ FORMAT_R32G32, 8 },
|
||||
{ FORMAT_R32G32B32, 12 },
|
||||
{ FORMAT_R32G32B32A32, 16 },
|
||||
{ FORMAT_R32_FLOAT, 4 },
|
||||
{ FORMAT_R32G32_FLOAT, 8 },
|
||||
{ FORMAT_R32G32B32_FLOAT, 12 },
|
||||
{ FORMAT_R32G32B32A32_FLOAT, 16 },
|
||||
{ FORMAT_R8_UNORM, 1},
|
||||
{ FORMAT_R8G8B8A8_UNORM, 4 },
|
||||
};
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
namespace gfx {
|
||||
|
||||
enum Format {
|
||||
FORMAT_R32G32,
|
||||
FORMAT_R32G32B32,
|
||||
FORMAT_R32G32B32A32,
|
||||
FORMAT_R32_FLOAT,
|
||||
FORMAT_R32G32_FLOAT,
|
||||
FORMAT_R32G32B32_FLOAT,
|
||||
FORMAT_R32G32B32A32_FLOAT,
|
||||
FORMAT_R8_UNORM,
|
||||
FORMAT_R8G8B8A8_UNORM,
|
||||
|
||||
_FORMAT_COUNT,
|
||||
|
|
|
@ -27,6 +27,7 @@ enum StorageClass {
|
|||
UNIFORM_CONSTANT = 0,
|
||||
INPUT = 1,
|
||||
OUTPUT = 3,
|
||||
FUNCTION = 7,
|
||||
};
|
||||
|
||||
enum Dimension {
|
||||
|
|
|
@ -22,7 +22,14 @@ enum ComparisonFunc {
|
|||
};
|
||||
|
||||
enum Filter {
|
||||
FILTER_MIN_MAG_MIP_POINT,
|
||||
FILTER_MIN_MAG_MIP_POINT = 0,
|
||||
FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1,
|
||||
FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4,
|
||||
FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5,
|
||||
FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10,
|
||||
FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11,
|
||||
FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14,
|
||||
FILTER_MIN_MAG_MIP_LINEAR = 0x15,
|
||||
};
|
||||
|
||||
enum TextureAddress {
|
||||
|
|
|
@ -26,35 +26,32 @@ ScreenLogo::ScreenLogo(UI* manager) : Screen(manager) {
|
|||
logo->style.width = 50_pct;
|
||||
logo->style.background = Color{1,0,1,1};
|
||||
|
||||
/*auto* version = new WidgetText("version");
|
||||
auto* version = new WidgetText("version");
|
||||
version->manager = manager;
|
||||
version->update(defaultFont, 12_px, "Version v0.1.0 from 2016-04-01");
|
||||
version->style.margin.top = 10_px;
|
||||
version->style.width = 240_px;
|
||||
version->style.height = 20_px;
|
||||
version->style.background = Color{1,1,0,1};
|
||||
version->update(defaultFont, 30_px, "Version v0.1.0 from 2016-04-01");
|
||||
version->style.margin.top = 0_px;
|
||||
version->style.width = 25_pct;
|
||||
version->style.color = Color{1,1,1,1};
|
||||
|
||||
auto* author = new WidgetText("author");
|
||||
author->manager = manager;
|
||||
author->update(defaultFont, 20_px, "Created by Alexandro Sanchez Bach");
|
||||
author->update(defaultFont, 60_px, "Created by Alexandro Sanchez Bach");
|
||||
author->style.margin.top = 40_px;
|
||||
author->style.width = 400_px;
|
||||
author->style.height = 30_px;
|
||||
author->style.background = Color{1,1,0,1};
|
||||
author->style.width = 40_pct;
|
||||
author->style.color = Color{1,1,1,1};
|
||||
|
||||
auto* license = new WidgetText("license");
|
||||
license->manager = manager;
|
||||
license->update(defaultFont, 20_px, "Licensed under GPL v2.0");
|
||||
license->style.margin.top = 10_px;
|
||||
license->style.width = 300_px;
|
||||
license->style.height = 30_px;
|
||||
license->style.background = Color{1,1,0,1};*/
|
||||
license->update(defaultFont, 60_px, "Licensed under GPL v2.0");
|
||||
license->style.margin.top = 0_px;
|
||||
license->style.width = 30_pct;
|
||||
license->style.color = Color{1,1,1,1};
|
||||
|
||||
// Add widgets
|
||||
body.addElement(logo);
|
||||
/*body.addElement(version);
|
||||
body.addElement(version);
|
||||
body.addElement(author);
|
||||
body.addElement(license);*/
|
||||
body.addElement(license);
|
||||
}
|
||||
|
||||
void ScreenLogo::update() {
|
||||
|
|
|
@ -18,6 +18,31 @@ ScreenMain::ScreenMain(UI* manager) : Screen(manager) {
|
|||
auto* content = new WidgetContainer("content");
|
||||
content->style.padding = 100_px;
|
||||
|
||||
// content->home (@from=header)
|
||||
// content->home->current
|
||||
// content->home->current->window1..windowN
|
||||
// content->home->recent
|
||||
// content->home->recent->app1..appN
|
||||
// content->home->platforms
|
||||
// content->home->platforms->platform1..platformN
|
||||
|
||||
// content->platform (@from=content->home->platforms, dynamic)
|
||||
// content->platform->details
|
||||
// content->platform->apps
|
||||
// content->platform->apps->app1..appN
|
||||
|
||||
// content->profile (@from=header)
|
||||
// content->profile->details
|
||||
// content->profile->messages?
|
||||
// content->profile->achievements?
|
||||
// content->profile->friends?
|
||||
|
||||
// content->settings (@from=header)
|
||||
// content->settings->?
|
||||
|
||||
// content->help (@from=header)
|
||||
// content->help->?
|
||||
|
||||
body.addElement(header);
|
||||
body.addElement(content);
|
||||
}
|
||||
|
|
|
@ -21,13 +21,6 @@ enum AlignVertical {
|
|||
ALIGN_VERTICAL_BOTTOM,
|
||||
};
|
||||
|
||||
enum ProportionMode {
|
||||
PROPORTION_FIXED, // Use the provided width/height dimensions
|
||||
PROPORTION_AUTOWIDTH, // Calculate width based on the given height
|
||||
PROPORTION_AUTOHEIGHT, // Calculate height based on the given width
|
||||
PROPORTION_AUTO, // Calculate width and height
|
||||
};
|
||||
|
||||
struct Color {
|
||||
float r;
|
||||
float g;
|
||||
|
@ -35,6 +28,22 @@ struct Color {
|
|||
float a;
|
||||
};
|
||||
|
||||
/**
|
||||
* Style
|
||||
* =====
|
||||
* ## Box Model
|
||||
* There are four nested boxes: Margin > Border > Padding > Content.
|
||||
* - Content: The actual contents of the object,
|
||||
* - Padding: Clears a transparent area around the content.
|
||||
* - Border: Border that goes around the padding.
|
||||
* - Margin: Clears a transparent area around the border.
|
||||
*
|
||||
* ## Z-Index
|
||||
* Depth index to render an object with. Greater values imply nearer objects and
|
||||
* lower values imply farther objects. This is used to compute object occlusion.
|
||||
* - Valid values are 1 to 255.
|
||||
* - Specify 0 to automatically assign Z-Index based on the object render tree position.
|
||||
*/
|
||||
class Style {
|
||||
private:
|
||||
struct Box {
|
||||
|
@ -63,18 +72,13 @@ public:
|
|||
|
||||
Box padding;
|
||||
Box margin;
|
||||
struct Border {
|
||||
Length top;
|
||||
Length right;
|
||||
Length bottom;
|
||||
Length left;
|
||||
struct Border : Box {
|
||||
Color color;
|
||||
} border;
|
||||
|
||||
Color color;
|
||||
Color background;
|
||||
|
||||
ProportionMode sizeMode = PROPORTION_AUTO;
|
||||
Size zindex = 0;
|
||||
|
||||
float opacity = 1.0;
|
||||
};
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "ui.h"
|
||||
#include "nucleus/core/config.h"
|
||||
#include "nucleus/core/resource.h"
|
||||
#include "nucleus/graphics/frontend/shader_parser.h"
|
||||
#include "nucleus/ui/screens/list.h"
|
||||
#include "nucleus/ui/widgets/list.h"
|
||||
|
||||
|
@ -37,48 +36,13 @@ void UI::task() {
|
|||
const float clearColor[] = {0.157f, 0.157f, 0.360f, 1.0f};
|
||||
cmdBuffer = graphics->createCommandBuffer();
|
||||
|
||||
gfx::ShaderDesc vertDesc = {};
|
||||
gfx::ShaderDesc fragDesc = {};
|
||||
core::Resource resVS(core::RES_SHADER_UI_WIDGET_VS);
|
||||
core::Resource resPS(core::RES_SHADER_UI_WIDGET_PS);
|
||||
vertDesc.type = gfx::SHADER_TYPE_VERTEX;
|
||||
vertDesc.module = gfx::frontend::ShaderParser::parse(reinterpret_cast<const char*>(resVS.data), resVS.size);
|
||||
fragDesc.type = gfx::SHADER_TYPE_PIXEL;
|
||||
fragDesc.module = gfx::frontend::ShaderParser::parse(reinterpret_cast<const char*>(resPS.data), resPS.size);
|
||||
auto* vertShader = graphics->createShader(vertDesc);
|
||||
auto* fragShader = graphics->createShader(fragDesc);
|
||||
|
||||
gfx::PipelineDesc pipelineDesc = {};
|
||||
pipelineDesc.vs = vertShader;
|
||||
pipelineDesc.ps = fragShader;
|
||||
pipelineDesc.iaState.topology = gfx::TOPOLOGY_TRIANGLE_STRIP;
|
||||
pipelineDesc.iaState.inputLayout = {
|
||||
{ 0, gfx::FORMAT_R32G32, 0, 0, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 },
|
||||
{ 1, gfx::FORMAT_R32G32B32A32, 0, 8, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 },
|
||||
{ 2, gfx::FORMAT_R32G32, 0, 24, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 },
|
||||
};
|
||||
pipelineDesc.cbState.colorTarget[0] = {
|
||||
true, false,
|
||||
gfx::BLEND_SRC_ALPHA, gfx::BLEND_INV_SRC_ALPHA, gfx::BLEND_OP_ADD,
|
||||
gfx::BLEND_SRC_ALPHA, gfx::BLEND_INV_SRC_ALPHA, gfx::BLEND_OP_ADD,
|
||||
gfx::LOGIC_OP_NOOP,
|
||||
gfx::COLOR_WRITE_ENABLE_ALL
|
||||
};
|
||||
pipelineDesc.samplers.resize(1);
|
||||
pipelineDesc.samplers[0] = {
|
||||
gfx::FILTER_MIN_MAG_MIP_POINT,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
};
|
||||
gfx::Pipeline* pipeline = graphics->createPipeline(pipelineDesc);
|
||||
pipelineContainers = WidgetContainer::createPipeline(*graphics);
|
||||
pipelineImages = WidgetImage::createPipeline(*graphics);
|
||||
pipelineText = WidgetText::createPipeline(*graphics);
|
||||
|
||||
// Initial screen
|
||||
#if defined(NUCLEUS_PLATFORM_UWP)
|
||||
screens.push_back(std::make_unique<ScreenMain>(this));
|
||||
screens.push_back(std::make_unique<ScreenLogo>(this));
|
||||
#else
|
||||
screens.push_back(std::make_unique<ScreenLogo>(this));
|
||||
#endif
|
||||
|
@ -89,7 +53,6 @@ void UI::task() {
|
|||
const gfx::Rectangle scissor = { 0, 0, surface.getWidth(), surface.getHeight() };
|
||||
|
||||
cmdBuffer->reset();
|
||||
cmdBuffer->cmdBindPipeline(pipeline);
|
||||
|
||||
gfx::ResourceBarrier barrierBegin;
|
||||
barrierBegin.transition.resource = graphics->screenBackBuffer;
|
||||
|
@ -102,10 +65,8 @@ void UI::task() {
|
|||
cmdBuffer->cmdSetScissors(1, &scissor);
|
||||
cmdBuffer->cmdClearColor(graphics->screenBackTarget, clearColor);
|
||||
|
||||
// Vertex buffer
|
||||
widgetVtxBuffer.clear();
|
||||
|
||||
// Display screens
|
||||
// Re-fill vertex buffers
|
||||
clearVtxBuffers();
|
||||
for (auto i = 0ULL; i < screens.size(); i++) {
|
||||
auto& screen = screens[i];
|
||||
screen->prologue();
|
||||
|
@ -117,25 +78,10 @@ void UI::task() {
|
|||
screens.erase(screens.begin() + i--);
|
||||
}
|
||||
}
|
||||
|
||||
// Render widgets
|
||||
if (!widgetVtxBuffer.empty()) {
|
||||
gfx::VertexBufferDesc vtxBufferDesc = {};
|
||||
vtxBufferDesc.size = widgetVtxBuffer.size() * sizeof(WidgetInput);
|
||||
gfx::VertexBuffer* vtxBuffer = graphics->createVertexBuffer(vtxBufferDesc);
|
||||
|
||||
void* bufferAddr = vtxBuffer->map();
|
||||
memcpy(bufferAddr, widgetVtxBuffer.data(), vtxBufferDesc.size);
|
||||
vtxBuffer->unmap();
|
||||
|
||||
U32 offsets[] = {0};
|
||||
U32 strides[] = { sizeof(WidgetInput) / 4 };
|
||||
cmdBuffer->cmdSetPrimitiveTopology(gfx::TOPOLOGY_TRIANGLE_STRIP);
|
||||
cmdBuffer->cmdSetVertexBuffers(0, 1, &vtxBuffer, offsets, strides);
|
||||
for (size_t i = 0; i < widgetVtxBuffer.size(); i++) {
|
||||
cmdBuffer->cmdDraw(4 * i, 4, 0, 1);
|
||||
}
|
||||
}
|
||||
renderContainers();
|
||||
renderImages();
|
||||
renderText();
|
||||
|
||||
// Add new screens
|
||||
while (!newScreens.empty()) {
|
||||
|
@ -163,12 +109,104 @@ void UI::pushScreen(std::unique_ptr<Screen>&& screen) {
|
|||
}
|
||||
|
||||
// Rendering
|
||||
void UI::renderWidget(const WidgetInput& input) {
|
||||
widgetVtxBuffer.push_back(input);
|
||||
void UI::clearVtxBuffers() {
|
||||
dataContainers.clear();
|
||||
dataImages.clear();
|
||||
dataText.clear();
|
||||
}
|
||||
|
||||
void UI::bindImage(const gfx::Texture* texture) {
|
||||
cmdBuffer->cmdSetTexture(0, texture);
|
||||
void UI::renderContainers() {
|
||||
if (dataContainers.empty()) {
|
||||
return;
|
||||
}
|
||||
cmdBuffer->cmdBindPipeline(pipelineContainers);
|
||||
|
||||
gfx::VertexBufferDesc vtxBufferDesc = {};
|
||||
vtxBufferDesc.size = dataContainers.size() * sizeof(WidgetContainerInput);
|
||||
auto* vtxBuffer = graphics->createVertexBuffer(vtxBufferDesc);
|
||||
vtxBufferContainers.reset(vtxBuffer);
|
||||
|
||||
void* bufferAddr = vtxBuffer->map();
|
||||
memcpy(bufferAddr, dataContainers.data(), vtxBufferDesc.size);
|
||||
vtxBuffer->unmap();
|
||||
|
||||
U32 offsets[] = { 0 };
|
||||
U32 strides[] = { sizeof(WidgetContainerInput) / 4 };
|
||||
cmdBuffer->cmdSetPrimitiveTopology(gfx::TOPOLOGY_TRIANGLE_STRIP);
|
||||
cmdBuffer->cmdSetVertexBuffers(0, 1, &vtxBuffer, offsets, strides);
|
||||
for (size_t i = 0; i < dataContainers.size(); i++) {
|
||||
cmdBuffer->cmdDraw(4 * i, 4, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::renderImages() {
|
||||
if (dataImages.empty()) {
|
||||
return;
|
||||
}
|
||||
cmdBuffer->cmdBindPipeline(pipelineImages);
|
||||
|
||||
gfx::VertexBufferDesc vtxBufferDesc = {};
|
||||
vtxBufferDesc.size = dataImages.size() * sizeof(WidgetImageInput);
|
||||
auto* vtxBuffer = graphics->createVertexBuffer(vtxBufferDesc);
|
||||
vtxBufferImages.reset(vtxBuffer);
|
||||
|
||||
void* bufferAddr = vtxBuffer->map();
|
||||
memcpy(bufferAddr, dataImages.data(), vtxBufferDesc.size);
|
||||
vtxBuffer->unmap();
|
||||
|
||||
U32 offsets[] = { 0 };
|
||||
U32 strides[] = { sizeof(WidgetImageInput) / 4 };
|
||||
cmdBuffer->cmdSetPrimitiveTopology(gfx::TOPOLOGY_TRIANGLE_STRIP);
|
||||
cmdBuffer->cmdSetVertexBuffers(0, 1, &vtxBuffer, offsets, strides);
|
||||
gfx::Texture* texture = nullptr;
|
||||
for (size_t i = 0; i < dataImages.size(); i++) {
|
||||
if (texture != textureImages[i]) {
|
||||
texture = textureImages[i];
|
||||
cmdBuffer->cmdSetTexture(0, texture);
|
||||
}
|
||||
cmdBuffer->cmdDraw(4 * i, 4, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::renderText() {
|
||||
if (dataText.empty()) {
|
||||
return;
|
||||
}
|
||||
cmdBuffer->cmdBindPipeline(pipelineText);
|
||||
|
||||
gfx::VertexBufferDesc vtxBufferDesc = {};
|
||||
vtxBufferDesc.size = dataText.size() * sizeof(WidgetTextInput);
|
||||
auto* vtxBuffer = graphics->createVertexBuffer(vtxBufferDesc);
|
||||
vtxBufferText.reset(vtxBuffer);
|
||||
|
||||
void* bufferAddr = vtxBuffer->map();
|
||||
memcpy(bufferAddr, dataText.data(), vtxBufferDesc.size);
|
||||
vtxBuffer->unmap();
|
||||
|
||||
U32 offsets[] = { 0 };
|
||||
U32 strides[] = { sizeof(WidgetTextInput) / 4 };
|
||||
cmdBuffer->cmdSetPrimitiveTopology(gfx::TOPOLOGY_TRIANGLE_STRIP);
|
||||
cmdBuffer->cmdSetVertexBuffers(0, 1, &vtxBuffer, offsets, strides);
|
||||
gfx::Texture* texture = nullptr;
|
||||
for (size_t i = 0; i < dataText.size(); i++) {
|
||||
if (texture != textureText[i]) {
|
||||
texture = textureText[i];
|
||||
cmdBuffer->cmdSetTexture(0, texture);
|
||||
}
|
||||
cmdBuffer->cmdDraw(4 * i, 4, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::pushWidgetContainer(const WidgetContainerInput& input) {
|
||||
dataContainers.push_back(input);
|
||||
}
|
||||
void UI::pushWidgetImage(const WidgetImageInput& input, gfx::Texture* texture) {
|
||||
dataImages.push_back(input);
|
||||
textureImages.push_back(texture);
|
||||
}
|
||||
void UI::pushWidgetText(const WidgetTextInput& input, gfx::Texture* texture) {
|
||||
dataText.push_back(input);
|
||||
textureText.push_back(texture);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -58,23 +58,50 @@ public:
|
|||
void pushScreen(std::unique_ptr<Screen>&& screen);
|
||||
|
||||
public:
|
||||
// Rendering methods
|
||||
std::vector<WidgetInput> widgetVtxBuffer;
|
||||
// Pipelines
|
||||
gfx::Pipeline* pipelineContainers;
|
||||
gfx::Pipeline* pipelineImages;
|
||||
gfx::Pipeline* pipelineText;
|
||||
|
||||
/**
|
||||
* Pushes a new screen to the back of the screen array
|
||||
* @param[in] screen Widget vertices to include in the buffer
|
||||
*/
|
||||
void renderWidget(const WidgetInput& input);
|
||||
// Inputs
|
||||
std::vector<WidgetContainerInput> dataContainers;
|
||||
std::vector<WidgetImageInput> dataImages;
|
||||
std::vector<WidgetTextInput> dataText;
|
||||
std::vector<gfx::Texture*> textureImages;
|
||||
std::vector<gfx::Texture*> textureText;
|
||||
|
||||
// Vertex buffers
|
||||
std::unique_ptr<gfx::VertexBuffer> vtxBufferContainers;
|
||||
std::unique_ptr<gfx::VertexBuffer> vtxBufferImages;
|
||||
std::unique_ptr<gfx::VertexBuffer> vtxBufferText;
|
||||
|
||||
// Clears all UI-related vertex and texture buffers
|
||||
void clearVtxBuffers();
|
||||
|
||||
// Rendering methods
|
||||
void renderContainers();
|
||||
void renderImages();
|
||||
void renderText();
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Pushes a new WidgetContainer input data to the buffer
|
||||
* @param[in] input WidgetContainer vertex data
|
||||
*/
|
||||
void bindImage(const gfx::Texture* texture);
|
||||
void pushWidgetContainer(const WidgetContainerInput& input);
|
||||
|
||||
/**
|
||||
* Pushes a new WidgetImage input data to the buffer
|
||||
* @param[in] input WidgetImage vertex data
|
||||
* @param[in] texture WidgetImage texture
|
||||
*/
|
||||
void pushWidgetImage(const WidgetImageInput& input, gfx::Texture* texture);
|
||||
|
||||
/**
|
||||
* Pushes a new WidgetText input data to the buffer
|
||||
* @param[in] input WidgetText vertex data
|
||||
* @param[in] texture WidgetText texture
|
||||
*/
|
||||
void pushWidgetText(const WidgetTextInput& input, gfx::Texture* texture);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -19,11 +19,42 @@ namespace ui {
|
|||
// Forward declarations
|
||||
class UI;
|
||||
|
||||
// Single-pipeline inputs
|
||||
struct WidgetInput {
|
||||
struct WidgetVertex {
|
||||
struct Vertex {
|
||||
float position[2];
|
||||
float texcoord[2];
|
||||
Color color0;
|
||||
float type;
|
||||
float zindex;
|
||||
float opacity;
|
||||
};
|
||||
};
|
||||
|
||||
// Multi-pipeline inputs
|
||||
struct WidgetContainerInput {
|
||||
struct Vertex {
|
||||
float position[2];
|
||||
Color background;
|
||||
float zindex;
|
||||
float opacity;
|
||||
} vertex[4];
|
||||
};
|
||||
struct WidgetImageInput {
|
||||
struct Vertex {
|
||||
float position[2];
|
||||
float texcoord[2];
|
||||
float zindex;
|
||||
float opacity;
|
||||
} vertex[4];
|
||||
};
|
||||
struct WidgetTextInput {
|
||||
struct Vertex {
|
||||
float position[2];
|
||||
float texcoord[2];
|
||||
Color color;
|
||||
float zindex;
|
||||
float opacity;
|
||||
} vertex[4];
|
||||
};
|
||||
|
||||
|
@ -48,15 +79,29 @@ struct WidgetInput {
|
|||
* | Padding | getPaddingWidth() | getPaddingHeight() |
|
||||
* | Border | getBorderWidth() | getBorderHeight() |
|
||||
* | Margin | getMarginWidth() | getMarginHeight() |
|
||||
*
|
||||
* ## Input
|
||||
* The vertex data input for any Widget consists at least of four vertices (V0, V1, V2, V3)
|
||||
* each provided with a 2D position attribute such that a rectangle is formed.
|
||||
* The standard coordinate system for position-like attributes goes from 0 to 1 in both axis
|
||||
* with the origin starting in the bottom-left corner of the screen.
|
||||
*
|
||||
* (0,1) (1,1)
|
||||
* +--------------------------------------+
|
||||
* | V1 = (x1,y2) V3 = (x2,y2) |
|
||||
* | + - - - - - - - + |
|
||||
* | : \ : |
|
||||
* | : \ : |
|
||||
* | : \ : h |
|
||||
* | : \ : |
|
||||
* | : w \ : |
|
||||
* | + - - - - - - - + |
|
||||
* | V0 = (x1,y1) V2 = (x2,y1) |
|
||||
* +--------------------------------------+
|
||||
* (0,0) (1,0)
|
||||
*/
|
||||
class Widget {
|
||||
protected:
|
||||
// Texture produced after rendering the contents of this widget
|
||||
gfx::Texture* texture;
|
||||
|
||||
// Vertices to be rendered
|
||||
WidgetInput input;
|
||||
|
||||
// Final dimension and size
|
||||
float vertWidth;
|
||||
float vertHeight;
|
||||
|
@ -67,6 +112,7 @@ protected:
|
|||
float compWidth;
|
||||
float compHeight;
|
||||
|
||||
// Transform lengths to our standard coordinate system
|
||||
float getCoord(const Length& length, float pixels);
|
||||
float getCoordX(const Length& length);
|
||||
float getCoordY(const Length& length);
|
||||
|
|
|
@ -5,12 +5,44 @@
|
|||
|
||||
#include "widget_container.h"
|
||||
#include "nucleus/assert.h"
|
||||
#include "nucleus/core/resource.h"
|
||||
#include "nucleus/graphics/frontend/shader_parser.h"
|
||||
#include "nucleus/ui/ui.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace ui {
|
||||
|
||||
gfx::Pipeline* WidgetContainer::createPipeline(gfx::IBackend& backend) {
|
||||
gfx::ShaderDesc vertDesc = {};
|
||||
gfx::ShaderDesc fragDesc = {};
|
||||
core::Resource resVS(core::RES_SHADER_UI_WIDGET_CONTAINER_VS);
|
||||
core::Resource resPS(core::RES_SHADER_UI_WIDGET_CONTAINER_PS);
|
||||
vertDesc.type = gfx::SHADER_TYPE_VERTEX;
|
||||
vertDesc.module = gfx::frontend::ShaderParser::parse(reinterpret_cast<const char*>(resVS.data), resVS.size);
|
||||
fragDesc.type = gfx::SHADER_TYPE_PIXEL;
|
||||
fragDesc.module = gfx::frontend::ShaderParser::parse(reinterpret_cast<const char*>(resPS.data), resPS.size);
|
||||
|
||||
gfx::PipelineDesc pipelineDesc = {};
|
||||
pipelineDesc.vs = backend.createShader(vertDesc);
|
||||
pipelineDesc.ps = backend.createShader(fragDesc);
|
||||
pipelineDesc.iaState.topology = gfx::TOPOLOGY_TRIANGLE_STRIP;
|
||||
pipelineDesc.iaState.inputLayout = {
|
||||
{ 0, gfx::FORMAT_R32G32_FLOAT, 0, 0, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 }, // Position
|
||||
{ 1, gfx::FORMAT_R32G32B32A32_FLOAT, 0, 8, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 }, // Color
|
||||
{ 2, gfx::FORMAT_R32_FLOAT, 0, 24, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 }, // Z-Index
|
||||
{ 3, gfx::FORMAT_R32_FLOAT, 0, 28, 0, 0, gfx::INPUT_CLASSIFICATION_PER_VERTEX, 0 }, // Opacity
|
||||
};
|
||||
pipelineDesc.cbState.colorTarget[0] = {
|
||||
true, false,
|
||||
gfx::BLEND_SRC_ALPHA, gfx::BLEND_INV_SRC_ALPHA, gfx::BLEND_OP_ADD,
|
||||
gfx::BLEND_SRC_ALPHA, gfx::BLEND_INV_SRC_ALPHA, gfx::BLEND_OP_ADD,
|
||||
gfx::LOGIC_OP_NOOP,
|
||||
gfx::COLOR_WRITE_ENABLE_ALL
|
||||
};
|
||||
return backend.createPipeline(pipelineDesc);
|
||||
}
|
||||
|
||||
bool WidgetContainer::addElement(Widget* widget) {
|
||||
assert_true(widget->parent == nullptr, "Widget already has a parent");
|
||||
widget->parent = this;
|
||||
|
@ -97,23 +129,6 @@ void WidgetContainer::render() {
|
|||
auto y1 = +1.0 - 2 * (offsetTop + getPaddingHeight());
|
||||
auto y2 = +1.0 - 2 * (offsetTop);
|
||||
|
||||
/**
|
||||
* Screen
|
||||
* ======
|
||||
* (0,1) (1,1)
|
||||
* +--------------------------------------+
|
||||
* | V1 = (x1,y2) V3 = (x2,y2) |
|
||||
* | + - - - - - - - + |
|
||||
* | : \ : |
|
||||
* | : \ : |
|
||||
* | : \ : h |
|
||||
* | : \ : |
|
||||
* | : w \ : |
|
||||
* | + - - - - - - - + |
|
||||
* | V0 = (x1,y1) V2 = (x2,y1) |
|
||||
* +--------------------------------------+
|
||||
* (0,0) (1,0)
|
||||
*/
|
||||
auto& V0 = input.vertex[0];
|
||||
auto& V1 = input.vertex[1];
|
||||
auto& V2 = input.vertex[2];
|
||||
|
@ -130,7 +145,7 @@ void WidgetContainer::render() {
|
|||
V2.background = style.background;
|
||||
V3.background = style.background;
|
||||
|
||||
manager->renderWidget(input);
|
||||
manager->pushWidgetContainer(input);
|
||||
|
||||
auto childOffsetTop = offsetTop + getCoordY(style.padding.top);
|
||||
auto childOffsetLeft = offsetLeft + getCoordX(style.padding.left);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
namespace ui {
|
||||
|
||||
class WidgetContainer : public Widget {
|
||||
private:
|
||||
// Input
|
||||
WidgetContainerInput input;
|
||||
|
||||
// Elements of the widget
|
||||
std::vector<Widget*> children;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ WidgetImage::~WidgetImage() {
|
|||
stbi_image_free(imBuffer);
|
||||
}
|
||||
|
||||
gfx::Pipeline* WidgetContainer::createPipeline(gfx::IBackend& backend) {
|
||||
gfx::Pipeline* WidgetImage::createPipeline(gfx::IBackend& backend) {
|
||||
gfx::ShaderDesc vertDesc = {};
|
||||
gfx::ShaderDesc fragDesc = {};
|
||||
core::Resource resVS(core::RES_SHADER_UI_WIDGET_IMAGE_VS);
|
||||
|
@ -47,7 +47,7 @@ gfx::Pipeline* WidgetContainer::createPipeline(gfx::IBackend& backend) {
|
|||
};
|
||||
pipelineDesc.samplers.resize(1);
|
||||
pipelineDesc.samplers[0] = {
|
||||
gfx::FILTER_MIN_MAG_MIP_POINT,
|
||||
gfx::FILTER_MIN_MAG_MIP_LINEAR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
|
@ -128,23 +128,6 @@ void WidgetImage::render() {
|
|||
auto y1 = +1.0 - 2 * (offsetTop + getPaddingHeight());
|
||||
auto y2 = +1.0 - 2 * (offsetTop);
|
||||
|
||||
/**
|
||||
* Screen
|
||||
* ======
|
||||
* (0,1) (1,1)
|
||||
* +--------------------------------------+
|
||||
* | V1 = (x1,y2) V3 = (x2,y2) |
|
||||
* | + - - - - - - - + |
|
||||
* | : \ : |
|
||||
* | : \ : |
|
||||
* | : \ : h |
|
||||
* | : \ : |
|
||||
* | : w \ : |
|
||||
* | + - - - - - - - + |
|
||||
* | V0 = (x1,y1) V2 = (x2,y1) |
|
||||
* +--------------------------------------+
|
||||
* (0,0) (1,0)
|
||||
*/
|
||||
auto& V0 = input.vertex[0];
|
||||
auto& V1 = input.vertex[1];
|
||||
auto& V2 = input.vertex[2];
|
||||
|
@ -157,19 +140,13 @@ void WidgetImage::render() {
|
|||
V0.position[2] = V1.position[2] = V2.position[2] = V3.position[2] = 0.0;
|
||||
V0.position[3] = V1.position[3] = V2.position[3] = V3.position[3] = 1.0;
|
||||
|
||||
V0.background = style.background;
|
||||
V1.background = style.background;
|
||||
V2.background = style.background;
|
||||
V3.background = style.background;
|
||||
|
||||
// Texture coordinates assume top-left is (0,0) and bottom-right is (1,1)
|
||||
V0.texcoord[0] = 0.0; V0.texcoord[1] = 1.0;
|
||||
V1.texcoord[0] = 0.0; V1.texcoord[1] = 0.0;
|
||||
V2.texcoord[0] = 1.0; V2.texcoord[1] = 1.0;
|
||||
V3.texcoord[0] = 1.0; V3.texcoord[1] = 0.0;
|
||||
|
||||
manager->bindImage(texture);
|
||||
manager->renderWidget(input);
|
||||
manager->pushWidgetImage(input, texture);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
namespace ui {
|
||||
|
||||
class WidgetImage : public Widget {
|
||||
private:
|
||||
// Input
|
||||
WidgetImageInput input;
|
||||
gfx::Texture* texture;
|
||||
|
||||
// Image
|
||||
unsigned char* imBuffer;
|
||||
int imWidth = 0;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
namespace ui {
|
||||
|
||||
gfx::Pipeline* WidgetContainer::createPipeline(gfx::IBackend& backend) {
|
||||
gfx::Pipeline* WidgetText::createPipeline(gfx::IBackend& backend) {
|
||||
gfx::ShaderDesc vertDesc = {};
|
||||
gfx::ShaderDesc fragDesc = {};
|
||||
core::Resource resVS(core::RES_SHADER_UI_WIDGET_TEXT_VS);
|
||||
|
@ -43,7 +43,7 @@ gfx::Pipeline* WidgetContainer::createPipeline(gfx::IBackend& backend) {
|
|||
};
|
||||
pipelineDesc.samplers.resize(1);
|
||||
pipelineDesc.samplers[0] = {
|
||||
gfx::FILTER_MIN_MAG_MIP_POINT,
|
||||
gfx::FILTER_MIN_MAG_MIP_LINEAR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
gfx::TEXTURE_ADDRESS_MIRROR,
|
||||
|
@ -73,9 +73,11 @@ void WidgetText::update(const Font* fontFamily, const Length& fontSize, const st
|
|||
txWidth += (dx + kern) * scale;
|
||||
}
|
||||
|
||||
// Render characters
|
||||
Size x = 0;
|
||||
Size y = 0;
|
||||
// Render characters leaving a 1-pixel margin
|
||||
Size x = 1;
|
||||
Size y = 1;
|
||||
txWidth += 2;
|
||||
txHeight += 2;
|
||||
txBuffer.clear();
|
||||
txBuffer.resize(txWidth * txHeight);
|
||||
for (Size i = 0; i < text.length(); i++) {
|
||||
|
@ -97,7 +99,7 @@ void WidgetText::update(const Font* fontFamily, const Length& fontSize, const st
|
|||
textureDesc.width = txWidth;
|
||||
textureDesc.height = txHeight;
|
||||
textureDesc.mipmapLevels = 1;
|
||||
textureDesc.format = gfx::FORMAT_R8G8B8A8_UNORM;
|
||||
textureDesc.format = gfx::FORMAT_R8_UNORM;
|
||||
textureDesc.data = txBuffer.data();
|
||||
textureDesc.size = txBuffer.size();
|
||||
|
||||
|
@ -105,18 +107,23 @@ void WidgetText::update(const Font* fontFamily, const Length& fontSize, const st
|
|||
}
|
||||
|
||||
void WidgetText::dimensionalize() {
|
||||
vertWidth = 0.0;
|
||||
vertHeight = 0.0;
|
||||
auto compWidth = getCoordX(Length{ double(txWidth), Length::TYPE_PX });
|
||||
auto compHeight = getCoordY(Length{ double(txHeight), Length::TYPE_PX });
|
||||
|
||||
if (style.width.type == Length::TYPE_UNDEFINED) {
|
||||
vertWidth = getCoordX(Length{ double(txWidth), Length::TYPE_PX });
|
||||
} else {
|
||||
if (style.width.type != Length::TYPE_UNDEFINED) {
|
||||
vertWidth = getCoordX(style.width);
|
||||
}
|
||||
if (style.height.type == Length::TYPE_UNDEFINED) {
|
||||
vertHeight = getCoordY(Length{ double(txHeight), Length::TYPE_PX });
|
||||
} else if (style.height.type != Length::TYPE_UNDEFINED) {
|
||||
vertWidth = compWidth * getCoordY(style.height) / compHeight;
|
||||
} else {
|
||||
vertWidth = compWidth;
|
||||
}
|
||||
|
||||
if (style.height.type != Length::TYPE_UNDEFINED) {
|
||||
vertHeight = getCoordY(style.height);
|
||||
} else if (style.width.type != Length::TYPE_UNDEFINED) {
|
||||
vertHeight = compHeight * getCoordX(style.width) / compWidth;
|
||||
} else {
|
||||
vertHeight = compHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,23 +137,6 @@ void WidgetText::render() {
|
|||
auto y1 = +1.0 - 2 * (offsetTop + getPaddingHeight());
|
||||
auto y2 = +1.0 - 2 * (offsetTop);
|
||||
|
||||
/**
|
||||
* Screen
|
||||
* ======
|
||||
* (0,1) (1,1)
|
||||
* +--------------------------------------+
|
||||
* | V1 = (x1,y2) V3 = (x2,y2) |
|
||||
* | + - - - - - - - + |
|
||||
* | : \ : |
|
||||
* | : \ : |
|
||||
* | : \ : h |
|
||||
* | : \ : |
|
||||
* | : w \ : |
|
||||
* | + - - - - - - - + |
|
||||
* | V0 = (x1,y1) V2 = (x2,y1) |
|
||||
* +--------------------------------------+
|
||||
* (0,0) (1,0)
|
||||
*/
|
||||
auto& V0 = input.vertex[0];
|
||||
auto& V1 = input.vertex[1];
|
||||
auto& V2 = input.vertex[2];
|
||||
|
@ -158,12 +148,18 @@ void WidgetText::render() {
|
|||
V1.position[1] = V3.position[1] = y2;
|
||||
V0.position[2] = V1.position[2] = V2.position[2] = V3.position[2] = 0.0;
|
||||
V0.position[3] = V1.position[3] = V2.position[3] = V3.position[3] = 1.0;
|
||||
V0.background = style.background;
|
||||
V1.background = style.background;
|
||||
V2.background = style.background;
|
||||
V3.background = style.background;
|
||||
V0.color = style.color;
|
||||
V1.color = style.color;
|
||||
V2.color = style.color;
|
||||
V3.color = style.color;
|
||||
|
||||
manager->renderWidget(input);
|
||||
// Texture coordinates assume top-left is (0,0) and bottom-right is (1,1)
|
||||
V0.texcoord[0] = 0.0; V0.texcoord[1] = 1.0;
|
||||
V1.texcoord[0] = 0.0; V1.texcoord[1] = 0.0;
|
||||
V2.texcoord[0] = 1.0; V2.texcoord[1] = 1.0;
|
||||
V3.texcoord[0] = 1.0; V3.texcoord[1] = 0.0;
|
||||
|
||||
manager->pushWidgetText(input, texture);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
namespace ui {
|
||||
|
||||
class WidgetText : public Widget {
|
||||
private:
|
||||
// Input
|
||||
WidgetTextInput input;
|
||||
gfx::Texture* texture;
|
||||
|
||||
// Text
|
||||
std::vector<Byte> txBuffer;
|
||||
Size txWidth = 0;
|
||||
|
|
|
@ -13,6 +13,6 @@ layout (location = 0) out vec4 result;
|
|||
layout (binding = 0) uniform sampler2D s;
|
||||
|
||||
void main() {
|
||||
result = texture(s, iTexcoord.xy);
|
||||
result = texture(s, iTexcoord.xy);
|
||||
//result *= opacity;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,14 @@ layout (binding = 0) uniform sampler2D s;
|
|||
|
||||
void main() {
|
||||
if (iType == TYPE_CONTAINER) {
|
||||
result = iColor;
|
||||
result = iColor;
|
||||
}
|
||||
else if (iType == TYPE_IMAGE) {
|
||||
result = texture(s, iTexcoord.xy);
|
||||
result = texture(s, iTexcoord.xy);
|
||||
}
|
||||
else if (iType == TYPE_TEXT) {
|
||||
result = iColor;
|
||||
result.w = texture(s, iTexcoord.xy).r;
|
||||
result = iColor;
|
||||
result.w = texture(s, iTexcoord.xy).r;
|
||||
}
|
||||
//result *= opacity;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@ layout (location = 0) out vec4 result;
|
|||
layout (binding = 0) uniform sampler2D s;
|
||||
|
||||
void main() {
|
||||
result = iColor;
|
||||
result.w = texture(s, iTexcoord.xy).x;
|
||||
float r = iColor.x;
|
||||
float g = iColor.y;
|
||||
float b = iColor.z;
|
||||
float a = texture(s, iTexcoord.xy).x;
|
||||
result = vec4(r, g, b, a);
|
||||
//result *= opacity;
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -1,10 +1,10 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) in vec2 iPosition;
|
||||
layout (location = 0) in vec2 iTexcoord;
|
||||
layout (location = 1) in vec4 iColor;
|
||||
layout (location = 2) in float iZindex;
|
||||
layout (location = 3) in float iOpacity;
|
||||
layout (location = 1) in vec2 iTexcoord;
|
||||
layout (location = 2) in vec4 iColor;
|
||||
layout (location = 3) in float iZindex;
|
||||
layout (location = 4) in float iOpacity;
|
||||
|
||||
layout (location = 0) out vec2 oTexcoord;
|
||||
layout (location = 1) out vec4 oColor;
|
||||
|
|
Binary file not shown.
|
@ -6,6 +6,7 @@ import re
|
|||
# Directories
|
||||
NUCLEUS_DIR = os.path.abspath("..")
|
||||
NUCLEUS_PROJECT = os.path.join(NUCLEUS_DIR, "nucleus")
|
||||
NUCLEUS_SHADERS = os.path.join(NUCLEUS_DIR, "resources", "shaders")
|
||||
NUCLEUS_TESTS = os.path.join(NUCLEUS_DIR, "tests", "unit")
|
||||
|
||||
|
||||
|
@ -26,10 +27,14 @@ def formatGeneric(codeInput):
|
|||
|
||||
# Search and edit files of the Nucleus project
|
||||
def main():
|
||||
for path in [NUCLEUS_PROJECT, NUCLEUS_TESTS]:
|
||||
included = (".c", ".cc", ".cpp", ".h", ".hpp", ".glsl")
|
||||
excluded = (".l.cpp", ".y.cpp", ".y.hpp")
|
||||
for path in [NUCLEUS_PROJECT, NUCLEUS_SHADERS, NUCLEUS_TESTS]:
|
||||
for root, dirs, files in os.walk(path):
|
||||
for filename in files:
|
||||
if not filename.endswith((".c",".cc",".cpp",".h",".hpp")):
|
||||
if not filename.endswith(included):
|
||||
continue
|
||||
if filename.endswith(excluded):
|
||||
continue
|
||||
|
||||
# Read and format the code
|
||||
|
|
|
@ -214,10 +214,38 @@
|
|||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
<None Include="..\..\resources\shaders\ui_widget_container_ps.spv" />
|
||||
<None Include="..\..\resources\shaders\ui_widget_container_vs.spv" />
|
||||
<None Include="..\..\resources\shaders\ui_widget_image_ps.spv" />
|
||||
<None Include="..\..\resources\shaders\ui_widget_image_vs.spv" />
|
||||
<None Include="..\..\resources\shaders\ui_widget_container_ps.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_container_vs.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_image_ps.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_image_vs.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_ps.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
|
@ -226,8 +254,22 @@
|
|||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_text_ps.spv" />
|
||||
<None Include="..\..\resources\shaders\ui_widget_text_vs.spv" />
|
||||
<None Include="..\..\resources\shaders\ui_widget_text_ps.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_text_vs.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="..\..\resources\shaders\ui_widget_vs.spv">
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
|
||||
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
|
||||
|
|
Loading…
Reference in a new issue