Minor update on my end regarding my two questions:
1. From more reading, my understanding is that a portion of NoesisGui functionality is determined to be 'not core' and therefore not a part of the main Noesis library. I wasn't aware until now that all of the 'separate application code' also compiles into a separate library (NoesisApp.lib), which makes the integration easier. That being said, it's somewhat unclear what folders to include for easy integration. For example, to run the 'Hello World' example, two Noesis application parts are need - the GL factory and the Theme provider.
The GLFactory and associated files is found here "Src\Packages\Render\GLRenderDevice\Include", where as the theme provider is found here "Src\Packages\App\Theme\Include". I was a bit surprised to see the Render folder being outside of the App folder. Perhaps there's no deeper meaning to this.
2. Having built the NoesisApp library I can now compile and run my application linked with NoesisGui - Yay success!. Unfortunately, I've yet to actually render anything from NoesisGui. LibCinder which I use as the application framework sets up a 'standard' viewport allowing me to get a rectangle rendered into the active framebuffer with this simple code:
ci::gl::clear( ci::Color::black() );
ci::gl::color( ci::Color::white() );
ci::gl::drawSolidRect( ci::Rectf(100, 100, 300, 300) );
This rectangle vanishes when I call the following function:
_view->GetRenderer()->Init( NoesisApp::GLFactory::CreateDevice( true ) );
Clearly the OpenGL context is being altered but despite the white rectangle disappearing, I unfortunately, don't see anything from NoesisGUI. The log doesn't show any errors, I'm hoping perhaps someone can point out something silly I'm doing. I acknowledge that the code itself doesn't reveal how Cinder sets up its rendering, but it should be writing straight into the standard framebuffer as I can get it to render that white rectangle.
Any and all advice is much appreciated. My full application code is as follows:
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Log.h"
#include "NoesisPCH.h"
#include "NsRender/RenderDevice.h"
// NoesisApp
#include "NsApp/ThemeProviders.h"
#include "NsRender/GLFactory.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class CinderProjectApp : public App {
public:
void setup() override;
void mouseDown( MouseEvent event ) override;
void update() override;
void draw() override;
private:
Noesis::IView* _view;
};
void CinderProjectApp::setup()
{
bool appendToLog = true;
ci::log::LogManager::instance()->clearLoggers();
ci::log::makeLogger<ci::log::LoggerFile>( "Sandbox.log", appendToLog );
CI_LOG_I( "Setting up NoesisGUI" );
Noesis::SetLogHandler( []( const char*, uint32_t, uint32_t level, const char*, const char* msg )
{
// [TRACE] [DEBUG] [INFO] [WARNING] [ERROR]
const char* prefixes[] = { "T", "D", "I", "W", "E" };
printf( "[NOESIS/%s] %s\n", prefixes[level], msg );
switch (level)
{
case 0: // Trace
CI_LOG_V(msg);
break;
case 1: // Debug
CI_LOG_D( msg );
break;
case 2: // Info
CI_LOG_I(msg);
break;
case 3: // Warning
CI_LOG_W( msg );
break;
case 4: // Error
CI_LOG_E( msg );
break;
}
} );
Noesis::GUI::SetLicense( "monkey", "key" );
Noesis::GUI::Init();
// Setup theme
NoesisApp::SetThemeProviders();
Noesis::GUI::LoadApplicationResources( "Theme/NoesisTheme.DarkBlue.xaml" );
// For simplicity purposes we are not using resource providers in this sample. ParseXaml() is
// enough if there is no extra XAML dependencies
Noesis::Ptr<Noesis::Grid> xaml( Noesis::GUI::ParseXaml<Noesis::Grid>( R"(
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<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>
<Viewbox>
<StackPanel Margin="50">
<Button Content="Hello World!" Margin="0,30,0,0"/>
<Rectangle Height="5" Margin="-10,20,-10,0">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Offset="0" Color="#40000000"/>
<GradientStop Offset="1" Color="#00000000"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
</StackPanel>
</Viewbox>
</Grid>
)" ) );
// View creation to render and interact with the user interface
// We transfer the ownership to a global pointer instead of a Ptr<> because there is no way
// in GLUT to do shutdown and we don't want the Ptr<> to be released at global time
_view = Noesis::GUI::CreateView( xaml ).GiveOwnership();
_view->SetFlags( Noesis::RenderFlags_PPAA | Noesis::RenderFlags_LCD );
// Renderer initialization with an OpenGL device
_view->GetRenderer()->Init( NoesisApp::GLFactory::CreateDevice( true ) );
}
void CinderProjectApp::mouseDown( MouseEvent event )
{
}
void CinderProjectApp::update()
{
// Update view (layout, animations, ...)
//_view->Update( glutGet( GLUT_ELAPSED_TIME ) / 1000.0 );
_view->Update( App::getElapsedSeconds() );
// Offscreen rendering phase populates textures needed by the on-screen rendering
_view->GetRenderer()->UpdateRenderTree();
_view->GetRenderer()->RenderOffscreen();
}
void CinderProjectApp::draw()
{
// Draws a clear white rect...
ci::gl::clear( ci::Color::black() );
ci::gl::color( ci::Color::white() );
ci::gl::drawSolidRect( ci::Rectf(100, 100, 300, 300) );
_view->GetRenderer()->Render();
//// 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, glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT ) );
//glClearColor( 0.0f, 0.0f, 0.25f, 0.0f );
//glClearStencil( 0 );
//glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
//// Rendering is done in the active framebuffer
//_view->GetRenderer()->Render();
//glutSwapBuffers();
//glutPostRedisplay();
}
// Enable stencil-buffer
auto options = ci::app::RendererGl::Options().stencil();
CINDER_APP( CinderProjectApp, ci::app::RendererGl( options ) )