Roest
Topic Author
Posts: 26
Joined: 15 Jan 2020, 15:30

Re: Some pre beginning questions

23 Jan 2020, 11:32

Well your example isn't trying to use a Qt5 QOpenGLWindow. As my luck goes renderdoc refuses to start.

If you don't mind I could create a VS solution with a minimal example but you'd need Qt installed so that's probably not an option.

Not really sure how to go from here because it actually seemed to work correctly and renders all stuff without the glBindFramebuffer(GL_FRAMEBUFFER, 0); which is not the correct way apparently and may lead to the lock up with TextBox.

With your recommended correct way using the glBindFramebuffer it's not rendering anything even if I remove all other stuff and just use the minimum calls required to render the gui.

And it was going so well :)

Edit: Renderdoc is running now, there was a conflict with installed Qt versions. Though I have no idea what I'm looking at. The errors and warnings tab at least is empty.

Edit2: Changed the QOpenGLWidget to a QOpenGLWindow now the render function looks like that
// Update view (layout, animations, ...)
		double time = std::chrono::system_clock::now().time_since_epoch().count();
		m_view->Update( time );

		// Offscreen rendering phase populates textures needed by the on-screen rendering
		m_view->GetRenderer()->UpdateRenderTree();
		m_view->GetRenderer()->RenderOffscreen();

		// If you are going to render here with your own engine you need to restore the GPU state
		// because noesis changes it. In this case only framebuffer and viewport need to be restored
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		glViewport(0, 0, this->width(), this->height() );

		{
			QOpenGLVertexArrayObject::Binder vaoBinder( &m_vao );

			glViewport(0, 0, this->width(), this->height() );
	
			glClearColor( 0.0, 0.0, 0.0, 0.0 );
			glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		
			glEnable( GL_BLEND );
			glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
			//glEnable( GL_DEPTH_TEST );
			glDepthFunc( GL_LEQUAL );
	
			if( m_shader )	
			{
				m_shader->bind();	
		
				m_shader->setUniformValue( "transform", m_projectionMatrix );

				glDrawArraysInstancedBaseInstance( GL_TRIANGLES, 0, 18, 1, 0 );	

				m_shader->release();
			}
		}

		// Rendering is done in the active framebuffer
		m_view->GetRenderer()->Render();
	}
and it renders both the menu and my background. It still locks up when I click into a TextBox and when I uncomment
//glEnable( GL_DEPTH_TEST );
I won't see my background.

Edit3: turns out
double time = std::chrono::system_clock::now().time_since_epoch().count(); 
is the culprit for the lock up, what exactly is expected there? milliseconds since last frame or just a rising counter?
 
Roest
Topic Author
Posts: 26
Joined: 15 Jan 2020, 15:30

Re: Some pre beginning questions

23 Jan 2020, 20:37

Another thing that is not working as expected:

I now set the KeyDown and KeyUp events. That works, I can tab select all the elements, move selected sliders with the arrow keys and so on. Now typing in a TextBox doesn't work, or lets say it works partly. I can move the cursor with arrow left and right, I can delete characters with backspace and I can add spaces with space bar. That's it, no other character showing up.
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Some pre beginning questions

24 Jan 2020, 00:03

what exactly is expected there? milliseconds since last frame or just a rising counter?
The Update function expects time in seconds since the start of the application.
I now set the KeyDown and KeyUp events... Now typing in a TextBox doesn't work
There is another event related to text input you are probably missing. The view->Char() event expects the unicode character translated from the physical key (in Win32 corresponds to the WM_CHAR message). That event is used by TextBox to add normal letters to the control.
 
Roest
Topic Author
Posts: 26
Joined: 15 Jan 2020, 15:30

Re: Some pre beginning questions

25 Jan 2020, 12:40

I guess when I'm done this will be a great collection of all the traps one can stumble into.

Right now my most pressing question is, is it possible to have multiple ViewModels as in having one per xaml class? Because having one view model for the whole menu and later for the game is really getting big. Tried calling SetDataContext in the xaml class for a menu sub page with a different view model class but that lead to all kinds of error messages. So what would be the correct way to implement this?

Another thing I'm trying to wrap my head around is to how to connect the GUI with the existing game. Building a main menu and several settings windows was easy. Load in an existing state and all changes happen in the gui. Thus everything goes through the getters and setters in the ViewModel. What I haven't really understood yet is how to get states that changed outside of that into the gui.

As a simple example lets say I have a bool somewhere in a manager class that controls showing the main menu. The view model getter reads that and returns "Visible" or "Hidden" depending on the state. In the xaml the Visibility of an object is bound to that getter. Testing with setting the variable on start up to true or false shows it is used and the object is on or off. Now if I toggle that variable with a key press I need to notify the GUI that the variable has changed. In the ViewModel this works by calling OnPropertyChanged. Is there a way for that?
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Some pre beginning questions

29 Jan 2020, 10:29

Right now my most pressing question is, is it possible to have multiple ViewModels as in having one per xaml class? Because having one view model for the whole menu and later for the game is really getting big. Tried calling SetDataContext in the xaml class for a menu sub page with a different view model class but that lead to all kinds of error messages. So what would be the correct way to implement this?
Yes, you can have as many ViewModels as you want. They can be set in the code-behind of each user control, or you can pass them to inner controls via bindings in the xaml.
For example you can have a MainViewModel and a SettingsViewModel, exposed in the first one as a property "Settings". Then in xaml you can do:
<Window x:Class="Test.MainWindow" ...>
  ...
  <test:SettingsDialog DataContext="{Binding Settings}"/>
  ...
</Window>
This is something that also happens when you bind a list of items, where each item is a ViewModel in its own, and each of the list item containers gets bounds to that view model automatically.
<ListBox ItemsSource="{Binding Players}" ItemTemplate="{StaticResource PlayerSelectionTemplate}" .../>
Another thing I'm trying to wrap my head around is to how to connect the GUI with the existing game. Building a main menu and several settings windows was easy. Load in an existing state and all changes happen in the gui. Thus everything goes through the getters and setters in the ViewModel. What I haven't really understood yet is how to get states that changed outside of that into the gui.
Everything should be feasible via bindings to the view model.
If you want to keep track of state changes you can probably bind directly to the appropriate properties in the view model (SelectedItem="{Binding SelectedPlayer}").
If you want to perform actions, you should expose Commands in your view model. Commands can be set in Button or MenuItem Command property, or you can use interactivity triggers to call an InvokeCommandAction.
As a simple example lets say I have a bool somewhere in a manager class that controls showing the main menu. The view model getter reads that and returns "Visible" or "Hidden" depending on the state. In the xaml the Visibility of an object is bound to that getter. Testing with setting the variable on start up to true or false shows it is used and the object is on or off. Now if I toggle that variable with a key press I need to notify the GUI that the variable has changed. In the ViewModel this works by calling OnPropertyChanged. Is there a way for that?
You can use a KeyTrigger to call a command in the ViewModel that will toggle the menu visibility:
<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
  <i:Interaction.Triggers>
    <ei:KeyTrigger FiredOn="KeyDown" Key="Escape">
      <i:InvokeCommandAction Command="{Binding ShowHideMenu}" />
    </ei:KeyTrigger>
  <i:Interaction.Triggers>
  ...
</UserControl>
 
Roest
Topic Author
Posts: 26
Joined: 15 Jan 2020, 15:30

Re: Some pre beginning questions

31 Jan 2020, 15:13

Ok I was a bit too dense. It's clearer now. But I still have two serious problems that might void all effort so far if I can't solve them.

First is with triggers. The problem is that the trigger only fires if an object has the mouse or keyboard focus. Which means if the menu is hidden it can't come back, also not good in a game where you want to have keyboard commands. It doesn't matter at all if I set ActiveOnFocus="False" or "True" or omit it. Can't be a general problem else someone else would have mentioned it, so what am I doing wrong this time?
<Page
	x:Class="IngnomiaGUI.MainMenu"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
	xmlns:local="clr-namespace:IngnomiaGUI"
    xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
	FontFamily="./#Hermeneus One"
	x:Name="MainMenu">
		
	<ei:KeyTrigger FiredOn="KeyDown" Key="Escape" ActiveOnFocus="False">
		<i:InvokeCommandAction Command="{Binding Back}" />
	</ei:KeyTrigger>
	</i:Interaction.Triggers>
	
	<Viewbox>
		<Grid x:Name="MenuGrid" Width="1900" Height="1000" Visibility="{Binding ShowMainMenu}">
			<Grid.Background>
				<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
					<GradientStop Offset="0" Color="#FF123F61"/>
					<GradientStop Offset="0.6" Color="#FF0E4B79"/>
					<GradientStop Offset="0.7" Color="#FF106097"/>
				</LinearGradientBrush>
			</Grid.Background>

			<Grid.RowDefinitions>
				<RowDefinition Height="1*"/>
				<RowDefinition Height="9*"/>
				<RowDefinition Height="1*"/>
			</Grid.RowDefinitions>
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="1*"/>
				<ColumnDefinition Width="5*"/>
				<ColumnDefinition Width="1*"/>
			</Grid.ColumnDefinitions>
			<local:MainPage     x:Name="MainPage"     Grid.Row="1" Grid.Column="1"/>
			<local:SettingsPage x:Name="SettingsPage" Grid.Row="1" Grid.Column="1" Visibility="Hidden"/>
			<local:LoadGamePage x:Name="LoadGamePage" Grid.Row="1" Grid.Column="1" Visibility="Hidden"/>
			<local:NewGamePage  x:Name="NewGamePage"  Grid.Row="1" Grid.Column="1" Visibility="Hidden"/>
		</Grid>
	</Viewbox>
</Page>

The other problem is with the depth buffer. So as in the integration example, I place my render code between view->GetRenderer()->RenderOffscreen(); and view->GetRenderer()->Render();

I restore my render context
	glViewport(0, 0, this->width(), this->height() );
	glBindFramebuffer( GL_FRAMEBUFFER, 0 );
	
	glClearStencil( 0 );
	glClearColor( 0.0, 0.0, 0.5, 1.0 );
	glClearDepth( 1 );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
	
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glEnable( GL_DEPTH_TEST );
	glDepthFunc( GL_LEQUAL );
and draw some triangles. The problem is that even though I explicitly set glClearDepth( 1 ); I can see in RenderDoc that the depth buffer is zero for all pixels. The color buffer gets cleared correctly as I can see with the above code that the background is a dark blue. I also don't need to call any Noesis render function per frame. The depth buffer breaks after the call
m_view->GetRenderer()->Init( NoesisApp::GLFactory::CreateDevice() );
in the init function.

Edit: Ok, with the help of the RenderDoc creator I solved the second part. It is because glDepthMask is off after that function, which also prevents the glClear to write to the depth buffer. That might be something worth mentioning somewhere.
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Some pre beginning questions

05 Feb 2020, 10:19

What you need is a root xaml that is always visible, with a root node that is Focusable so keyboard can always go through that node and key bindings will work fine. All Controls are focusable by default except for the UserControl/Page, so you should explicitly set that property to true if you want to use it as root:
<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
  Focusable="True" IsTabStop="False">
  <i:Interaction.Triggers>
        <ei:KeyTrigger Key="Esc" ActiveOnFocus="False">
            <i:InvokeCommandAction Command="{Binding ShowHideMenu}" />
        </ei:KeyTrigger>
    </i:Interaction.Triggers>
  ...
</UserControl>
This root xaml would be the Content of the IView. Inside that xaml you can add other pages (user controls) that can be made visible/hidden as you want, for example the main menu.

Who is online

Users browsing this forum: No registered users and 1 guest