Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

How to send data from C++ in to GUI?

21 May 2017, 12:18

I looked in to this tutorials:
Tutorial 3: Events
Tutorial 11: Extending NoesisGUI
Tutorial 12: Data Binding
Tutorial 2: UserControl example
Tutorial 3: CustomControl example

but any of one is not explaining how to send data from C++ in to Noesis. Or I something overlook? They are written in strange way, like for someone have experience with WPF and C#. I looked in to WPF and xaml tutorials but they are oriented most on GUI elements and if there is code behind action, it is only for C#.

What I don't understand is, when I create class for extend control, how can I send data in to this class? I guess, class is created by Noesis engine with NsRegisterReflection(0, true), then how can I reach to created class and pass data in to it?
For example, I want create function inside class (which extend gui control) like this: (to display mouse position in to text label)
void getMousePos(int x, int y) { /*send x to TextLabel; send y to TextLabel */ }
I have only one idea, and that is use global functions or variables and use it inside class.
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: How to send data from C++ in to GUI?

21 May 2017, 17:56

I forgot about non-code-behind acces in to Noesis, it is mentioned in Tutorial 3: Events and first C++ example. With this I careated my own function where I pass data from GLFW in to Noesis and display mouse position.
I have problem with code-behind possibilities.
 
User avatar
jsantos
Site Admin
Posts: 2904
Joined: 20 Jan 2012, 17:18
Contact:

Re: How to send data from C++ in to GUI?

22 May 2017, 04:09

Hi, could you please elaborate a bit about what you mean with "send data from C++" ? Or better yet, could you tell me exactly what do you need to do in your UI? I will provide you a code snipped doing that.

Thanks!
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: How to send data from C++ in to GUI?

22 May 2017, 11:11

Hi, I mean, when I have some my own class only for store data, like path to files or options for running program. And want send this data in to GUI, display path for files, display stored options, etc.. And main reason display realtime data like waveform of audio, or volume display = when audio is playing, it will be displayed on "volume meter" realtime.
Or better yet, could you tell me exactly what do you need to do in your UI? I will provide you a code snipped doing that.
Thanks, now I trying create my own class where will be stored paths to folders as string data, and some options to manipulate with files, and display this paths with options in ListBox. But I want it to be dynamic = user can delete or add new paths (as one ListBoxItem). Each 2 paths are displayed inside grid and that grid is inside ListBox as one ListBoxItem. Another 2 paths are on another Grid with ListBoxItem. All paths in Grid will be as button and when User click on button, can change path. And path will be displayed on this button.

I need only some code sample how to send the string from my class (class must be separated from GUI code) in to GUI and create, and delete ListBoxItem with Grid and manipulate with Grid.


Btw for future will be good if in class documentation will be more detailed explanation what is what and how to use it, with simple and short code.
For example in WPF ListBoxItem can be created with this code:
ListBox listBox = new ListBox();
listBox.ItemsPanel = panelTemplate;
listBox.Items.Add("Mon");
And when I try do something similar in C++ with Noesis, I can't acces to Items, but inside class documentation it is there, then How to use Item when I cant access to it? I think this is needed in documention how to get access to ItemsControl and how to use it.
 
User avatar
jsantos
Site Admin
Posts: 2904
Joined: 20 Jan 2012, 17:18
Contact:

Re: How to send data from C++ in to GUI?

23 May 2017, 01:23

Hi, I mean, when I have some my own class only for store data, like path to files or options for running program. And want send this data in to GUI, display path for files, display stored options, etc.. And main reason display realtime data like waveform of audio, or volume display = when audio is playing, it will be displayed on "volume meter" realtime.
The correct way to do this is using data binding. Make sure you understand the tutorial about it. You can do many things with data binding without extending Noesis with new classes. It is a really powerful mechanism. We are aware that NoesisGUI is tough at the beginning (specially the C++ API), but please be patient because it is a really powerful API, and it is compatible with WPF. This means, you can also use many of the documentation on internet about it and in many cases what you read will also be valid for NoesisGUI.
Btw for future will be good if in class documentation will be more detailed explanation what is what and how to use it, with simple and short code.
For example in WPF ListBoxItem can be created with this code:
ListBox listBox = new ListBox();
listBox.ItemsPanel = panelTemplate;
listBox.Items.Add("Mon");
And when I try do something similar in C++ with Noesis, I can't acces to Items, but inside class documentation it is there, then How to use Item when I cant access to it? I think this is needed in documention how to get access to ItemsControl and how to use it.
Our class documentation try to be API agnostic. There are concepts in C# that don't directly translate to C++ and vicecersa. There are no properties in C++, you need to manually call the Get() or Set() function corresponding to each property. So for example, for the ItemsPanel it would be:
listBox->SetItemsPanel(itemsPanel.GetPtr());
Note also, that our class documentation normally provide a link to the equivalent class in WPF where you can read more about it.
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: How to send data from C++ in to GUI?

24 May 2017, 19:13

Before I start learning it, I want be sure we understand each others.

From DataBindings tutorial, it uses derived class from Noesis (for all C++ examples), and dont see how send data from class, variable etc.. without use noesis. That is I am looking for. For example
class Data
{
public:
     string getName()
     {
          return data1;
     }
private:
     string data1;
};

class Name: public BaseComponent, public INotifyPropertyChanged
{
     void SetName(string sName)
     {
          Name = sName.c_str();
     }
private:
     NsString Name;
};
// How then I do this?
Name name;
Data data;
name.SetName(data.getName());
// when class Name is registered with NsRegisterReflection(0, true); ?
How can I use function from class derived and registered by Noesis inside C++ code? (as I show in example)
 
nikobarli
Posts: 178
Joined: 26 Apr 2017, 06:23

Re: How to send data from C++ in to GUI?

25 May 2017, 04:41

I think you need to start with a working example and play around with data binding.

You can start with Src\Samples\D3D11\Tutorial05\Tutorials.sln included in the SDK.
Then replace PasswordBox.xaml and Tutorial05.cpp with the followings:

PasswordBox.xaml
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Grid.Resources>
    <DataModel x:Name="dataModel" />
  </Grid.Resources>
  
  <Viewbox   DataContext="{StaticResource dataModel}" Margin="150">
  
    <GroupBox Padding="30" FontSize="21" Background="#C0B0B6BB">
        <GroupBox.Header>
            <TextBlock Text="{Binding First}" FontSize="32" Margin="10"/>
        </GroupBox.Header>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Path Grid.Row="0" Panel.ZIndex="10" Data="M8,8 L0,20 20,20 12,8 A6,6 0 1 0 8,8" Fill="#FFB0B6BB" VerticalAlignment="Center" Margin="8,2,0,0" IsHitTestVisible="False"/>
            <TextBlock x:Name="userText" Grid.Row="0" Panel.ZIndex="10" Foreground="#FFB0B6BB" FontSize="18" Text="USERNAME" VerticalAlignment="Center" Margin="36,0,0,0" IsHitTestVisible="False"/>
            <TextBox Grid.Row="0" Width="250" Padding="36,2,2,2" FontSize="24" Foreground="#FFB0B6BB">
                <TextBox.Triggers>
                    <EventTrigger RoutedEvent="UIElement.GotFocus">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.2" To="Transparent" Storyboard.TargetName="userText" Storyboard.TargetProperty="Foreground.Color"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </TextBox.Triggers>
            </TextBox>
            <Path x:Name="passIcon" Grid.Row="1" Panel.ZIndex="10" Data="M16,8 L0,8 0,20 20,20 20,8 18,8 A8,10 0 1 0 2,7 L4,7 A6,8 0 1 1 16,8" Fill="#FFB0B6BB" VerticalAlignment="Center" Margin="8,2,0,0" IsHitTestVisible="False"/>
            <TextBlock x:Name="passText" Grid.Row="1" Panel.ZIndex="10" Foreground="#FFB0B6BB" FontSize="18" Text="PASSWORD" VerticalAlignment="Center" Margin="36,0,0,0" IsHitTestVisible="False"/>
            <PasswordBox x:Name="pass" Grid.Row="1" Width="250" Padding="36,2,2,2" FontSize="24" Margin="0,20" Foreground="#FFB0B6BB">
                <PasswordBox.Triggers>
                    <EventTrigger RoutedEvent="UIElement.GotFocus">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.2" To="#FFB0B6BB" Storyboard.TargetName="passIcon" Storyboard.TargetProperty="Fill.Color"/>
                                    <ColorAnimation Duration="0:0:0.2" To="Transparent" Storyboard.TargetName="passText" Storyboard.TargetProperty="Foreground.Color"/>
                                    <ColorAnimation Duration="0:0:0.2" To="#FFB0B6BB" Storyboard.TargetName="pass" Storyboard.TargetProperty="Foreground.Color"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </PasswordBox.Triggers>
            </PasswordBox>
            <Button Grid.Row="2" Content="LOGIN" FontSize="22">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.3" To="Red" Storyboard.TargetName="passIcon" Storyboard.TargetProperty="Fill.Color"/>
                                    <ColorAnimation Duration="0:0:0.3" To="Red" Storyboard.TargetName="pass" Storyboard.TargetProperty="Foreground.Color"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
        </Grid>
    </GroupBox>
    
  </Viewbox>

</Grid>
Tutorial05.cpp
//--------------------------------------------------------------------------------------
// File: Tutorial05.cpp
//
// This application demonstrates animation using matrix transformations
//
// http://msdn.microsoft.com/en-us/library/windows/apps/ff729722.aspx
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "pch.h"
#include <windows.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>
#include "resource.h"


using namespace DirectX;

//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
    XMFLOAT3 Pos;
    XMFLOAT4 Color;
};


struct ConstantBuffer
{
    XMMATRIX mWorld;
    XMMATRIX mView;
    XMMATRIX mProjection;
};


//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE               g_hInst = nullptr;
HWND                    g_hWnd = nullptr;
D3D_DRIVER_TYPE         g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL       g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device*           g_pd3dDevice = nullptr;
ID3D11Device1*          g_pd3dDevice1 = nullptr;
ID3D11DeviceContext*    g_pImmediateContext = nullptr;
ID3D11DeviceContext1*   g_pImmediateContext1 = nullptr;
IDXGISwapChain*         g_pSwapChain = nullptr;
IDXGISwapChain1*        g_pSwapChain1 = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11Texture2D*        g_pDepthStencil = nullptr;
ID3D11DepthStencilView* g_pDepthStencilView = nullptr;
ID3D11VertexShader*     g_pVertexShader = nullptr;
ID3D11PixelShader*      g_pPixelShader = nullptr;
ID3D11InputLayout*      g_pVertexLayout = nullptr;
ID3D11Buffer*           g_pVertexBuffer = nullptr;
ID3D11Buffer*           g_pIndexBuffer = nullptr;
ID3D11Buffer*           g_pConstantBuffer = nullptr;
XMMATRIX                g_World1;
XMMATRIX                g_World2;
XMMATRIX                g_View;
XMMATRIX                g_Projection;
UINT                    g_Width;
UINT                    g_Height;


//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);
HRESULT InitDevice();
HRESULT Resize(UINT width, UINT height);
void CleanupDevice();
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
void Render();


//--------------------------------------------------------------------------------------
// NoesisGUI
//--------------------------------------------------------------------------------------
#ifdef NOESIS_GUI

// All NoesisGUI API is under Noesis namespace
using namespace Noesis;

// This is the main view that displays the content
Ptr<Noesis::IView> g_XamlView;

// Error handler are invoked for fatal errors. You must never return from here
void NoesisErrorHandler(const NsChar* filename, NsSize line, const NsChar* desc, NsBool fatal)
{
    MessageBoxA(0, desc, "NoesisGUI Fatal Error", MB_ICONERROR);
}

// Map translation from windows keycodes to Noesis enums
Noesis::Key g_KeyMap[256];

void SetupKeyMap()
{
    memset(g_KeyMap, 0, sizeof(g_KeyMap));

    g_KeyMap[VK_BACK] = Key_Back;
    g_KeyMap[VK_TAB] = Key_Tab;
    g_KeyMap[VK_CLEAR] = Key_Clear;
    g_KeyMap[VK_RETURN] = Key_Return;
    g_KeyMap[VK_PAUSE] = Key_Pause;

    g_KeyMap[VK_SHIFT] = Key_LeftShift;
    g_KeyMap[VK_CONTROL] = Key_LeftCtrl;
    g_KeyMap[VK_MENU] = Key_LeftAlt;

    g_KeyMap[VK_ESCAPE] = Key_Escape;

    g_KeyMap[VK_SPACE] = Key_Space;
    g_KeyMap[VK_PRIOR] = Key_Prior;
    g_KeyMap[VK_NEXT] = Key_Next;
    g_KeyMap[VK_END] = Key_End;
    g_KeyMap[VK_HOME] = Key_Home;
    g_KeyMap[VK_LEFT] = Key_Left;
    g_KeyMap[VK_UP] = Key_Up;
    g_KeyMap[VK_RIGHT] = Key_Right;
    g_KeyMap[VK_DOWN] = Key_Down;
    g_KeyMap[VK_SELECT] = Key_Select;
    g_KeyMap[VK_PRINT] = Key_Print;
    g_KeyMap[VK_EXECUTE] = Key_Execute;
    g_KeyMap[VK_SNAPSHOT] = Key_Snapshot;
    g_KeyMap[VK_INSERT] = Key_Insert;
    g_KeyMap[VK_DELETE] = Key_Delete;
    g_KeyMap[VK_HELP] = Key_Help;

    g_KeyMap['0'] = Key_D0;
    g_KeyMap['1'] = Key_D1;
    g_KeyMap['2'] = Key_D2;
    g_KeyMap['3'] = Key_D3;
    g_KeyMap['4'] = Key_D4;
    g_KeyMap['5'] = Key_D5;
    g_KeyMap['6'] = Key_D6;
    g_KeyMap['7'] = Key_D7;
    g_KeyMap['8'] = Key_D8;
    g_KeyMap['9'] = Key_D9;

    g_KeyMap[VK_NUMPAD0] = Key_NumPad0;
    g_KeyMap[VK_NUMPAD1] = Key_NumPad1;
    g_KeyMap[VK_NUMPAD2] = Key_NumPad2;
    g_KeyMap[VK_NUMPAD3] = Key_NumPad3;
    g_KeyMap[VK_NUMPAD4] = Key_NumPad4;
    g_KeyMap[VK_NUMPAD5] = Key_NumPad5;
    g_KeyMap[VK_NUMPAD6] = Key_NumPad6;
    g_KeyMap[VK_NUMPAD7] = Key_NumPad7;
    g_KeyMap[VK_NUMPAD8] = Key_NumPad8;
    g_KeyMap[VK_NUMPAD9] = Key_NumPad9;

    g_KeyMap[VK_MULTIPLY] = Key_Multiply;
    g_KeyMap[VK_ADD] = Key_Add;
    g_KeyMap[VK_SEPARATOR] = Key_Separator;
    g_KeyMap[VK_SUBTRACT] = Key_Subtract;
    g_KeyMap[VK_DECIMAL] = Key_Decimal;
    g_KeyMap[VK_DIVIDE] = Key_Divide;

    g_KeyMap['A'] = Key_A;
    g_KeyMap['B'] = Key_B;
    g_KeyMap['C'] = Key_C;
    g_KeyMap['D'] = Key_D;
    g_KeyMap['E'] = Key_E;
    g_KeyMap['F'] = Key_F;
    g_KeyMap['G'] = Key_G;
    g_KeyMap['H'] = Key_H;
    g_KeyMap['I'] = Key_I;
    g_KeyMap['J'] = Key_J;
    g_KeyMap['K'] = Key_K;
    g_KeyMap['L'] = Key_L;
    g_KeyMap['M'] = Key_M;
    g_KeyMap['N'] = Key_N;
    g_KeyMap['O'] = Key_O;
    g_KeyMap['P'] = Key_P;
    g_KeyMap['Q'] = Key_Q;
    g_KeyMap['R'] = Key_R;
    g_KeyMap['S'] = Key_S;
    g_KeyMap['T'] = Key_T;
    g_KeyMap['U'] = Key_U;
    g_KeyMap['V'] = Key_V;
    g_KeyMap['W'] = Key_W;
    g_KeyMap['X'] = Key_X;
    g_KeyMap['Y'] = Key_Y;
    g_KeyMap['Z'] = Key_Z;

    g_KeyMap[VK_F1] = Key_F1;
    g_KeyMap[VK_F2] = Key_F2;
    g_KeyMap[VK_F3] = Key_F3;
    g_KeyMap[VK_F4] = Key_F4;
    g_KeyMap[VK_F5] = Key_F5;
    g_KeyMap[VK_F6] = Key_F6;
    g_KeyMap[VK_F7] = Key_F7;
    g_KeyMap[VK_F8] = Key_F8;
    g_KeyMap[VK_F9] = Key_F9;
    g_KeyMap[VK_F10] = Key_F10;
    g_KeyMap[VK_F11] = Key_F11;
    g_KeyMap[VK_F12] = Key_F12;
    g_KeyMap[VK_F13] = Key_F13;
    g_KeyMap[VK_F14] = Key_F14;
    g_KeyMap[VK_F15] = Key_F15;
    g_KeyMap[VK_F16] = Key_F16;
    g_KeyMap[VK_F17] = Key_F17;
    g_KeyMap[VK_F18] = Key_F18;
    g_KeyMap[VK_F19] = Key_F19;
    g_KeyMap[VK_F20] = Key_F20;
    g_KeyMap[VK_F21] = Key_F21;
    g_KeyMap[VK_F22] = Key_F22;
    g_KeyMap[VK_F23] = Key_F23;
    g_KeyMap[VK_F24] = Key_F24;

    g_KeyMap[VK_NUMLOCK] = Key_NumLock;
    g_KeyMap[VK_SCROLL] = Key_Scroll;
}
#endif


NS_DECLARE_SYMBOL(First);
NS_DECLARE_SYMBOL(Last);

class DataModel : public BaseComponent, public INotifyPropertyChanged
{
public:
    NS_IMPLEMENT_INTERFACE_FIXUP

public:
    const NsChar* GetFirst() const
    {
        return _first.c_str();
    }

    void SetFirst(const NsChar* first)
    {
        if (_first != first)
        {
            _first = first;
            _propertyChanged(this, NSS(First));
        }
    }

    const NsChar* GetLast() const
    {
        return _last.c_str();
    }

    void SetLast(const NsChar* last)
    {
        if (_last != last)
        {
            _last = last;
            _propertyChanged(this, NSS(Last));
        }
    }

    PropertyChangedEventHandler& PropertyChanged()
    {
        return _propertyChanged;
    }

private:
    NsString _first = "First";
    NsString _last = "Last";

    PropertyChangedEventHandler _propertyChanged;

    NS_IMPLEMENT_INLINE_REFLECTION(DataModel, BaseComponent)
    {
        NsMeta<TypeId>("DataModel");
        NsImpl<INotifyPropertyChanged>();
        NsProp("First", &DataModel::GetFirst, &DataModel::SetFirst);
        NsProp("Last", &DataModel::GetLast, &DataModel::SetLast);

    }

};

////////////////////////////////////////////////////////////////////////////////////////////////////
extern "C" NS_DLL_EXPORT
void NsRegisterReflection(ComponentFactory* factory, NsBool registerComponents)
{
    NS_REGISTER_COMPONENT(DataModel);
}




//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing 
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    if (FAILED(InitWindow(hInstance, nCmdShow)))
        return 0;

    if (FAILED(InitDevice()))
    {
        CleanupDevice();
        return 0;
    }

#ifdef NOESIS_GUI
    {
        SetupKeyMap();

        // NoesisGUI is initialized here. Resources will be loaded from current working directory
        Noesis::GUI::Init(NoesisErrorHandler);
        Noesis::GUI::SetResourceProvider(".");

        // Register own classes
        NsRegisterReflection(0, true);

        // Loads XAML and creates a view with it
        Ptr<FrameworkElement> xaml = Noesis::GUI::LoadXaml<FrameworkElement>("PasswordBox.xaml");
        g_XamlView = Noesis::GUI::CreateView(xaml.GetPtr());
        g_XamlView->SetSize(g_Width, g_Height);
        g_XamlView->SetAntialiasingMode(Noesis::Gui::AntialiasingMode_PPAA);

        // Initializes renderer. This could be done in a render thread
        Ptr<RenderDevice> device = *new D3D11RenderDevice(g_pImmediateContext);
        Ptr<VGContext> context = Noesis::GUI::CreateVGContext(device.GetPtr(), Noesis::VGOptions());
        g_XamlView->GetRenderer()->Init(context.GetPtr());
    }
#endif

    // Main message loop
    MSG msg = { 0 };
    while (WM_QUIT != msg.message)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            ::Render();
        }
    }

    CleanupDevice();

#ifdef NOESIS_GUI
    {
        // Free global resources and shutdown kernel
        g_XamlView.Reset();
        Noesis::GUI::Shutdown();
    }
#endif

    return (int)msg.wParam;
}


//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{
    // Register class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = nullptr;
    wcex.lpszClassName = L"TutorialWindowClass";
    wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_TUTORIAL1);
    if (!RegisterClassEx(&wcex))
        return E_FAIL;

    // Create window
    g_hInst = hInstance;
    RECT rc = { 0, 0, 800, 600 };
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
    g_hWnd = CreateWindow(L"TutorialWindowClass", L"Direct3D 11 Tutorial 5", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,
        nullptr);
    if (!g_hWnd)
        return E_FAIL;

    ShowWindow(g_hWnd, nCmdShow);

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DCompile
//
// With VS 11, we could load up prebuilt .cso files instead...
//--------------------------------------------------------------------------------------
HRESULT CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
    HRESULT hr = S_OK;

    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
    // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
    // Setting this flag improves the shader debugging experience, but still allows 
    // the shaders to be optimized and to run exactly the way they will run in 
    // the release configuration of this program.
    dwShaderFlags |= D3DCOMPILE_DEBUG;

    // Disable optimizations to further improve shader debugging
    dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif

    ID3DBlob* pErrorBlob = nullptr;
    hr = D3DCompileFromFile(szFileName, nullptr, nullptr, szEntryPoint, szShaderModel,
        dwShaderFlags, 0, ppBlobOut, &pErrorBlob);
    if (FAILED(hr))
    {
        if (pErrorBlob)
        {
            OutputDebugStringA(reinterpret_cast<const char*>(pErrorBlob->GetBufferPointer()));
            pErrorBlob->Release();
        }
        return hr;
    }
    if (pErrorBlob) pErrorBlob->Release();

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
    HRESULT hr = S_OK;

    RECT rc;
    GetClientRect(g_hWnd, &rc);
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    UINT createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT numDriverTypes = ARRAYSIZE(driverTypes);

    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };
    UINT numFeatureLevels = ARRAYSIZE(featureLevels);

    for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
    {
        g_driverType = driverTypes[driverTypeIndex];
        hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
            D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);

        if (hr == E_INVALIDARG)
        {
            // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
            hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
                D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);
        }

        if (SUCCEEDED(hr))
            break;
    }
    if (FAILED(hr))
        return hr;

    // Obtain DXGI factory from device (since we used nullptr for pAdapter above)
    IDXGIFactory1* dxgiFactory = nullptr;
    {
        IDXGIDevice* dxgiDevice = nullptr;
        hr = g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
        if (SUCCEEDED(hr))
        {
            IDXGIAdapter* adapter = nullptr;
            hr = dxgiDevice->GetAdapter(&adapter);
            if (SUCCEEDED(hr))
            {
                hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory));
                adapter->Release();
            }
            dxgiDevice->Release();
        }
    }
    if (FAILED(hr))
        return hr;

    // Create swap chain
    IDXGIFactory2* dxgiFactory2 = nullptr;
    hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2));
    if (dxgiFactory2)
    {
        // DirectX 11.1 or later
        hr = g_pd3dDevice->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast<void**>(&g_pd3dDevice1));
        if (SUCCEEDED(hr))
        {
            (void)g_pImmediateContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&g_pImmediateContext1));
        }

        DXGI_SWAP_CHAIN_DESC1 sd;
        ZeroMemory(&sd, sizeof(sd));
        sd.Width = width;
        sd.Height = height;
        sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.BufferCount = 1;

        hr = dxgiFactory2->CreateSwapChainForHwnd(g_pd3dDevice, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1);
        if (SUCCEEDED(hr))
        {
            hr = g_pSwapChain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast<void**>(&g_pSwapChain));
        }

        dxgiFactory2->Release();
    }
    else
    {
        // DirectX 11.0 systems
        DXGI_SWAP_CHAIN_DESC sd;
        ZeroMemory(&sd, sizeof(sd));
        sd.BufferCount = 1;
        sd.BufferDesc.Width = width;
        sd.BufferDesc.Height = height;
        sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.BufferDesc.RefreshRate.Numerator = 60;
        sd.BufferDesc.RefreshRate.Denominator = 1;
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.OutputWindow = g_hWnd;
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
        sd.Windowed = TRUE;

        hr = dxgiFactory->CreateSwapChain(g_pd3dDevice, &sd, &g_pSwapChain);
    }

    dxgiFactory->Release();

    if (FAILED(hr))
        return hr;

    hr = Resize(width, height);
    if (FAILED(hr))
        return hr;

    // Compile the vertex shader
    ID3DBlob* pVSBlob = nullptr;
    hr = CompileShaderFromFile(L"Tutorial05.fx", "VS", "vs_4_0", &pVSBlob);
    if (FAILED(hr))
    {
        MessageBox(nullptr,
            L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
        return hr;
    }

    // Create the vertex shader
    hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader);
    if (FAILED(hr))
    {
        pVSBlob->Release();
        return hr;
    }

    // Define the input layout
    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
    UINT numElements = ARRAYSIZE(layout);

    // Create the input layout
    hr = g_pd3dDevice->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(),
        pVSBlob->GetBufferSize(), &g_pVertexLayout);
    pVSBlob->Release();
    if (FAILED(hr))
        return hr;

    // Set the input layout
    g_pImmediateContext->IASetInputLayout(g_pVertexLayout);

    // Compile the pixel shader
    ID3DBlob* pPSBlob = nullptr;
    hr = CompileShaderFromFile(L"Tutorial05.fx", "PS", "ps_4_0", &pPSBlob);
    if (FAILED(hr))
    {
        MessageBox(nullptr,
            L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
        return hr;
    }

    // Create the pixel shader
    hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader);
    pPSBlob->Release();
    if (FAILED(hr))
        return hr;

    // Create vertex buffer
    SimpleVertex vertices[] =
    {
        { XMFLOAT3(-1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
        { XMFLOAT3(1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
        { XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) },
        { XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
        { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
        { XMFLOAT3(1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
        { XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
        { XMFLOAT3(-1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
    };
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(SimpleVertex) * 8;
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData;
    ZeroMemory(&InitData, sizeof(InitData));
    InitData.pSysMem = vertices;
    hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pVertexBuffer);
    if (FAILED(hr))
        return hr;

    // Set vertex buffer
    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;
    g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);

    // Create index buffer
    WORD indices[] =
    {
        3, 1, 0,
        2, 1, 3,

        0, 5, 4,
        1, 5, 0,

        3, 4, 7,
        0, 4, 3,

        1, 6, 5,
        2, 6, 1,

        2, 7, 6,
        3, 7, 2,

        6, 4, 5,
        7, 4, 6,
    };
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(WORD) * 36;        // 36 vertices needed for 12 triangles in a triangle list
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = 0;
    InitData.pSysMem = indices;
    hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pIndexBuffer);
    if (FAILED(hr))
        return hr;

    // Set index buffer
    g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);

    // Set primitive topology
    g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // Create the constant buffer
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(ConstantBuffer);
    bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bd.CPUAccessFlags = 0;
    hr = g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pConstantBuffer);
    if (FAILED(hr))
        return hr;

    // Initialize the world matrix
    g_World1 = XMMatrixIdentity();
    g_World2 = XMMatrixIdentity();

    // Initialize the view matrix
    XMVECTOR Eye = XMVectorSet(0.0f, 1.0f, -5.0f, 0.0f);
    XMVECTOR At = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
    XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
    g_View = XMMatrixLookAtLH(Eye, At, Up);

    return S_OK;
}

//--------------------------------------------------------------------------------------
// Resize
//--------------------------------------------------------------------------------------
HRESULT Resize(UINT width, UINT height)
{
    HRESULT hr = S_OK;

    g_Width = width;
    g_Height = height;

    // // Release all outstanding references to the swap chain's buffers
    if (g_pDepthStencil) g_pDepthStencil->Release();
    if (g_pDepthStencilView) g_pDepthStencilView->Release();
    if (g_pRenderTargetView) g_pRenderTargetView->Release();

    g_pImmediateContext->OMSetRenderTargets(0, 0, 0);

    hr = g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
    if (FAILED(hr))
        return hr;

    // Create a render target view
    ID3D11Texture2D* pBackBuffer = nullptr;
    hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
    if (FAILED(hr))
        return hr;

    hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
    pBackBuffer->Release();
    if (FAILED(hr))
        return hr;

    // Create depth stencil texture
    D3D11_TEXTURE2D_DESC descDepth;
    ZeroMemory(&descDepth, sizeof(descDepth));
    descDepth.Width = width;
    descDepth.Height = height;
    descDepth.MipLevels = 1;
    descDepth.ArraySize = 1;
    descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    descDepth.SampleDesc.Count = 1;
    descDepth.SampleDesc.Quality = 0;
    descDepth.Usage = D3D11_USAGE_DEFAULT;
    descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    descDepth.CPUAccessFlags = 0;
    descDepth.MiscFlags = 0;
    hr = g_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil);
    if (FAILED(hr))
        return hr;

    // Create the depth stencil view
    D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
    ZeroMemory(&descDSV, sizeof(descDSV));
    descDSV.Format = descDepth.Format;
    descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    descDSV.Texture2D.MipSlice = 0;
    hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencil, &descDSV, &g_pDepthStencilView);
    if (FAILED(hr))
        return hr;

    g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);

    // Setup the viewport
    D3D11_VIEWPORT vp;
    vp.Width = (FLOAT)width;
    vp.Height = (FLOAT)height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pImmediateContext->RSSetViewports(1, &vp);

    // Initialize the projection matrix
    g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, width / (FLOAT)height, 0.01f, 100.0f);

#ifdef NOESIS_GUI
    if (g_XamlView != 0)
    {
        g_XamlView->SetSize(g_Width, g_Height);
    }
#endif

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
    if (g_pImmediateContext) g_pImmediateContext->ClearState();

    if (g_pConstantBuffer) g_pConstantBuffer->Release();
    if (g_pVertexBuffer) g_pVertexBuffer->Release();
    if (g_pIndexBuffer) g_pIndexBuffer->Release();
    if (g_pVertexLayout) g_pVertexLayout->Release();
    if (g_pVertexShader) g_pVertexShader->Release();
    if (g_pPixelShader) g_pPixelShader->Release();
    if (g_pDepthStencil) g_pDepthStencil->Release();
    if (g_pDepthStencilView) g_pDepthStencilView->Release();
    if (g_pRenderTargetView) g_pRenderTargetView->Release();
    if (g_pSwapChain1) g_pSwapChain1->Release();
    if (g_pSwapChain) g_pSwapChain->Release();
    if (g_pImmediateContext1) g_pImmediateContext1->Release();
    if (g_pImmediateContext) g_pImmediateContext->Release();
    if (g_pd3dDevice1) g_pd3dDevice1->Release();
    if (g_pd3dDevice) g_pd3dDevice->Release();
}


//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            EndPaint(hWnd, &ps);
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        case WM_SIZE:
            if (g_pSwapChain)
            {
                RECT rc;
                GetClientRect(hWnd, &rc);
                Resize(rc.right - rc.left, rc.bottom - rc.top);
            }
            break;

#ifdef NOESIS_GUI
        case WM_KEYDOWN:
            if (g_XamlView != 0)
            {
                g_XamlView->KeyDown(wParam < 256 ? g_KeyMap[wParam] : Noesis::Key_None);
            }
            break;

        case WM_KEYUP:
            if (g_XamlView != 0)
            {
                g_XamlView->KeyUp(wParam < 256 ? g_KeyMap[wParam] : Noesis::Key_None);
            }
            break;

        case WM_CHAR:
            if (g_XamlView != 0)
            {
                g_XamlView->Char(NsUInt32(wParam));
            }
            break;

        case WM_MOUSEMOVE:
            if (g_XamlView != 0)
            {
                g_XamlView->MouseMove(LOWORD(lParam), HIWORD(lParam));
            }
            break;

        case WM_LBUTTONDOWN:
            if (g_XamlView != 0)
            {
                g_XamlView->MouseButtonDown(LOWORD(lParam), HIWORD(lParam), MouseButton_Left);
            }
            break;

        case WM_LBUTTONUP:
            if (g_XamlView != 0)
            {
                g_XamlView->MouseButtonUp(LOWORD(lParam), HIWORD(lParam), MouseButton_Left);
            }
            break;

        case WM_MOUSEWHEEL:
            if (g_XamlView != 0)
            {
                POINT point;
                point.x = LOWORD(lParam);
                point.y = HIWORD(lParam);
                ::ScreenToClient(hWnd, &point);

                g_XamlView->MouseWheel(point.x, point.y, GET_WHEEL_DELTA_WPARAM(wParam));
            }
            break;
#endif

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}


//--------------------------------------------------------------------------------------
// Render a frame
//--------------------------------------------------------------------------------------
void Render()
{
    // Update our time
    static float t = 0.0f;
    if (g_driverType == D3D_DRIVER_TYPE_REFERENCE)
    {
        t += (float)XM_PI * 0.0125f;
    }
    else
    {
        static ULONGLONG timeStart = 0;
        ULONGLONG timeCur = GetTickCount64();
        if (timeStart == 0)
            timeStart = timeCur;
        t = (timeCur - timeStart) / 1000.0f;
    }

    // 1st Cube: Rotate around the origin
    g_World1 = XMMatrixRotationY(t);

    // 2nd Cube:  Rotate around origin
    XMMATRIX mSpin = XMMatrixRotationZ(-t);
    XMMATRIX mOrbit = XMMatrixRotationY(-t * 2.0f);
    XMMATRIX mTranslate = XMMatrixTranslation(-4.0f, 0.0f, 0.0f);
    XMMATRIX mScale = XMMatrixScaling(0.3f, 0.3f, 0.3f);

    g_World2 = mScale * mSpin * mTranslate * mOrbit;

#ifdef NOESIS_GUI
    // Updates view passing global time
    g_XamlView->Update(t);

    // Performs rendering operations. Note that the renderer associated to a view is intended
    // to be used in the render thread. In this simple application it is the main thread
    Noesis::IRenderer* renderer = g_XamlView->GetRenderer();

    // Applies changes to the render tree
    renderer->UpdateRenderTree();

    // Renders offscreen textures. This step must be done before binding the main render target
    if (renderer->NeedsOffscreen())
    {
        renderer->RenderOffscreen();
    }

    // Restore state. This must be done per frame because NoesisGUI modifies the GPU state
    // TODO: improve this by adding a SaveState() and RestoreState() to D3D11RenderDevice
    g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
    g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;
    g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
    g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
    g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    g_pImmediateContext->OMSetDepthStencilState(0, 0);
    g_pImmediateContext->RSSetState(0);
    g_pImmediateContext->OMSetBlendState(0, 0, 0xffffffff);

    D3D11_VIEWPORT vp = { 0.0f, 0.0f, (FLOAT)g_Width, (FLOAT)g_Height, 0.0f, 1.0f};
    g_pImmediateContext->RSSetViewports(1, &vp);
#endif

    //
    // Clear the back buffer
    //
    g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, DirectX::Colors::MidnightBlue);

    //
    // Clear the depth buffer to 1.0 (max depth)
    //
    g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

    //
    // Update variables for the first cube
    //
    ConstantBuffer cb1;
    cb1.mWorld = XMMatrixTranspose(g_World1);
    cb1.mView = XMMatrixTranspose(g_View);
    cb1.mProjection = XMMatrixTranspose(g_Projection);
    g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb1, 0, 0);

    //
    // Render the first cube
    //
    g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
    g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
    g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
    g_pImmediateContext->DrawIndexed(36, 0, 0);

    //
    // Update variables for the second cube
    //
    ConstantBuffer cb2;
    cb2.mWorld = XMMatrixTranspose(g_World2);
    cb2.mView = XMMatrixTranspose(g_View);
    cb2.mProjection = XMMatrixTranspose(g_Projection);
    g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb2, 0, 0);

    //
    // Render the second cube
    //
    g_pImmediateContext->DrawIndexed(36, 0, 0);


#ifdef NOESIS_GUI
    // Renders UI to active render target in the active viewport
    renderer->Render();
#endif

    //
    // Present our back buffer to our front buffer
    //
    g_pSwapChain->Present(0, 0);
}
You can look at the diff of the two files to find out what I have changed to demonstrate data binding:

1. In PasswordBox.xaml, I changed the text "Sign In" to use data binding to property "First" of the data context. Data Context is set to a DataModel instance (You should be able to set the data context programmatically as well. Here the XAML will create the instance of DataModel class for you).

2. DataModel class is defined inside Tutorial05.cpp, and it contains "First" and "Last" property (well, not really property). Note that it derives from BaseComponent and implements INotifyPropertyChanged. You can also see where you should register the component for reflection.

To @jsantos, @sfernandes,

Please consider adding more C++ working samples in the SDK package. This will help people like us who is considering NoesisGUI to learn faster. Copy pasting codes from this forum is counter productive considering the chances that the codes may be obsoleted in later releases. The samples should be as easy as open the solution file, build, then run it. Thus the user can immediately play with the code to check his understanding.

Thanks. (I know you are busy though ;) )
 
User avatar
jsantos
Site Admin
Posts: 2904
Joined: 20 Jan 2012, 17:18
Contact:

Re: How to send data from C++ in to GUI?

25 May 2017, 22:12

Thanks for your great post!
Please consider adding more C++ working samples in the SDK package. This will help people like us who is considering NoesisGUI to learn faster. Copy pasting codes from this forum is counter productive considering the chances that the codes may be obsoleted in later releases. The samples should be as easy as open the solution file, build, then run it. Thus the user can immediately play with the code to check his understanding.
This is high priority right now. We are working in a multiplatform application framework and we plan to provide all the samples in the Downloads section for all platforms. And of course, we will include more and more samples to that section. Thanks a lot for your feedback!
 
Wanderer
Topic Author
Posts: 168
Joined: 08 May 2017, 18:36

Re: How to send data from C++ in to GUI?

29 May 2017, 13:56

Thanks nikobarli for sample.

I was read DataBinding and try nikobarli's sample. It is more clear to me now. But I have few questions:

1. What and when is good to use it (DataBinding), when I can set TextBox from c++ without use lot of code?
// this is pseudo code
TextBox * tb = xamlView->findTextBox("nameOfTextBox");
tb->SetText("my text");
The result is same as with nikobarli's code or samples from DataBindings. I see advantage only with last example in DataBinding tutorial for display more data in to Listbox.

2. Tutorial DataBinding use Serialize and Unserialize, because nikobarli use similar code from DataBinding, but there is no serialize function and code is working. For new tutorials, please include more explanation with some examples in usage for what it is (and what it doing).

3. And I am still don't know how to send data from my class in to class created with Noesis derivation. How can I sen data from:
class Data
{
     String name = "none";
public:
     String GetName() { return name; }
     // ...
};
Data Person;
DataModelClass.SetFirst(Person.GetName());
How can pass the name from my Data class in to class derived and registered for Noesis? It is good idea? Or It is better do it way as I describe in point 1. ? Like this:
class Data
{
     String name = "none";
public:
     String GetName() { return name; }
     void  DisplayName()
     {
          TextBlock * tTextBlock = xaml->FindName<TextBlock>("name");
          tTextBlock->SetText(name.c_str());
     }
}
 
User avatar
sfernandez
Site Admin
Posts: 1912
Joined: 22 Dec 2011, 19:20

Re: How to send data from C++ in to GUI?

29 May 2017, 20:06

1. Using MVVM pattern allows you to decouple the View (xaml) from the the Model (code). This way you can totally redesign your UI without changing your application logic and data.
On the other hand, using the TextBlock instance to set its text requires that you know that the xaml contains a TextBlock with a specific name. This only might have sense when designing some user controls where logic depens on the xaml contents.

2. Serialize/Unserialize methods are deprecated since NoesisGUI 2.0. We will fix DataBinding tutorial as soon as possible because it has code from a previous version.

3. The ViewModel which exposes the data from the application, should inherit from Noesis classes (BaseComponent and INotifyPropertyChange). The application is responsible to keep in sync its data with ViewModel properties. And also update application data if user modifies ViewModel through the interface.

Who is online

Users browsing this forum: No registered users and 1 guest