JUCE and Ogre 3D integration


#1

Hi folks!

I am wondering whether anyone uses JUCE+Ogre3D combination for their cross-platform (at least Mac/Win) projects? I did search the forum and found a couple of few-years-old brief touches on topic. Still I am unclear on how to line up the collaborative arrangement between two beasts. Any glimpses of enlightenment would be much appreciated!


#2

Did you want to use JUCE as the graphic overlay layer, or just use JUCE as the mouse/keyboard management portion with Ogre?


#3

Something like the latter.
My impetus is to start with Juce being a master user interface framework, which embeds Ogre (in one or more of Juce components) to create 3d scenes and provide rendering. So it’s Ogre which gets embedded within Juce, not the other way around.
The problem as I see it, is what exactly is that kind of Juce entity that I pass to the Ogre for the rendering context creation? Ogre allows creating its render window with the option of using external window handle, so on Windows I pass a native Hwnd which I obtain with Juce’s getPeer()->getNativeHandle(). On OSX this doesn’t seem to work - my Ogre window stays empty. Since I am new to OSX programming I suspect that there might be some platform-specific issues which I am not aware of. All this OSX Carbon/Cocoa heterogenic deal and Objective-C/C++ interminglings make my head spin a little and take away my confidence on where to start looking for solutions.
Hence my question in hope that someone on this forum has already went similar path and got the cross-breed Juce/Ogre stuff working.

Actually, using Juce as the graphic overlay layer within the Ogre’s rendering context would be nice to learn about too, but this is not the task of the moment yet.


#4

I’ve done something quite similar to this on Mac and Windows, so i’ll drop you an email off list…


#5

That’d be great. Thanks, Justin!


#6

I spent a day or two trying to embed an Ogre window in juce as well well but didn’t have much success…

justin, is it possible you can share some code-snippets on this?


#7

Thanks to Justin’s great help and after quite a few failed attempts trying to display Ogre inside a Juce window (on Windows), I have finally succeeded. :smiley:

However, I have yet to succeed to actually display other components on top of the Ogre area.

  • Case 1 (with Ogre filling up the entire window area), passing the externalWindowHandle parameter to Ogre Render Window, all other Juce components flicker at each redraw.

  • Case 2 (with Ogre filling up only a defined portion of the window area - lets call it a “badge”), passing the parentWindowHandle parameter to Ogre Render Window, no flickers but all other Juce components appear behind the Ogre “badge”.

What I am looking for is:
[list][]At best, to have Ogre sitting in its own Juce component “badge” with z-order position changeable (no need for alpha transparency).[/]
[]At worst, to have it filling up the entire main window background with any other components appearing on top.[/]
[]But in both cases, having all other Juce components, crossing its boudaries, not flickering.[/][/list]

Have other Juce/Ogre users managed to achieve this? If so, any hints, guidance or light cast on the procedure would be very greatly appreciated. Thanks in advance :slight_smile:

eLeMenCy (ex Montty)


#8

HI, I'm very interested in this too, since I am a 3D interface guy looking to integrate OGRE as a view inside the JUCE framework, but it looks like there's no resolution on this?  Any chance someone could post some snippets or gists on Github?

 

Thanks!


#9

Bump!

Has anyone managed to successfully integrate Ogre3D yet?

Justin, would you care to give some detail on where you got to?  You say you have managed this on an OSX and Windows -- what additional obstacles are there for the mobile platforms and Linux? (if any...)

eLeMenCy, did you finish your project?

Related:

http://www.juce.com/forum/topic/3d-engine-juce-component


#10

My implementation was way before Jules implemented the new OpenGL code.  So it created a real frankenstein using different frameworks!  (Juce for the keyboard and mouse tracking, Ogre for the rendering and NUI for the 2d UI elements).  I can't see why it shouldn't be possible to use JUCE nowadays.

The way I did it was like this... And I wouldn't do it this way now with the new classes, but it should give an idea... I'm embarassed to post this code, as its real hacky... but if it helps people

 

class SMOgreView : public Component

    {

public:

        SMOgreView();

        virtual ~SMOgreView();

        

        void initOgre();

        

        Ogre::RenderWindow *getRenderWindow();

        

        void resized();

        void makeOgreCurrent(); // need to do this before loading any textures or rendering (any gl calls)

        

private:

        void *ogreView; // Type is OgreView on mac (an NSView sub class)

        void *ogreContext;

    };

Then it did something like this(this was the mac implementation of void SMOgreView::initOgre())


// I just throw a regular old NSView in...

    ogreView=[[OgreView alloc]initWithFrame:NSMakeRect(0, 0, getWidth(),getHeight())];

    

    ComponentPeer *componentPeer=getPeer();

    jassert(componentPeer);

    NSView* const peer = (NSView*) (componentPeer->getNativeHandle());

    if (peer != 0)

    {

        [peer addSubview: (OgreView*)ogreView];

    }

    

// Before CreateRenderWindow is called, it MUST be in a window.

// If I use an NSViewComponent then is starts calling resize...

    

    Ogre::NameValuePairList misc;

    misc["macAPI"] = "cocoa";

    misc["externalWindowHandle"] = Ogre::StringConverter::toString((size_t)ogreView);

    

// Create the window and load the params

    Ogre::Root::getSingleton().createRenderWindow("LaunchPad", 0, 0, false, &misc);

 

On windows it was just....

 

void SMOgreView::initOgre()

{

// maybe I put a JUCE openGL component in here and external context it?

// http://www.ogre3d.org/docs/api/html/classOgre_1_1Root.html

   

    ComponentPeer *componentPeer=getPeer();

    jassert(componentPeer);

    HWND windowHandle=(HWND)(componentPeer->getNativeHandle());

    

// Before CreateRenderWindow is called, it MUST be in a window.

    

    Ogre::NameValuePairList misc;

    misc["externalWindowHandle"] = Ogre::StringConverter::toString((size_t)windowHandle);

    

// Create the window and load the params

    ogreView=Ogre::Root::getSingleton().createRenderWindow("Launch Pad", 0, 0, false, &misc);


    ogreContext = wglGetCurrentContext(); //If the calling thread has a current OpenGL rendering context, wglGetCurrentContext returns a handle to that rendering context. Otherwise, the return value is NULL -- The current OpenGL rendering context of a thread is associated with a device context by means of the wglMakeCurrent function. You can use the wglGetCurrentDC function to obtain a handle to the device context associated with the current OpenGL rendering context

    jassert(ogreContext);

    winDC=wglGetCurrentDC();//obtains a handle to the device context that is associated with the current OpenGL rendering context of the calling thread...If the calling thread has a current OpenGL rendering context, the function returns a handle to the device context associated with that rendering context by means of the wglMakeCurrent function. Otherwise, the return value is NULL.

    jassert(winDC);

}

 

This view pimpl was then added to this Component...

 

class SMOgreComponent : public Component,  public Ogre::FrameListener, private Timer,public ApplicationCommandTarget, public Ogre::RenderTargetListener, public SMNotificationListener, public ActionListener

 

Then I had to manually fix rendering after Ogre was done with the context...

 

void SMOgreComponent::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)

{


#if defined(_MACOSX_)

    GLboolean appleStorage;

glGetBooleanv(GL_UNPACK_CLIENT_STORAGE_APPLE,&appleStorage);

#endif

#if 1

glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);

glPushAttrib(GL_ALL_ATTRIB_BITS);

glPolygonMode(GL_FRONT, GL_FILL);

#endif

    

glPushMatrix();

    

    Ogre::RenderSystem *d_renderSystem=Ogre::Root::getSingleton().getRenderSystem();

// initialise render settings

#if 1

    d_renderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY);

    d_renderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY);

    d_renderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY);

#endif

    d_renderSystem->setLightingEnabled(false);

    d_renderSystem->_setDepthBufferParams(false, false);

    d_renderSystem->_setDepthBias(0, 0);

    d_renderSystem->_setCullingMode(Ogre::CULL_NONE);

    d_renderSystem->_setFog(Ogre::FOG_NONE);

    d_renderSystem->_setColourBufferWriteEnabled(true, true, true, true);

    d_renderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM);

    d_renderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM);

    d_renderSystem->setShadingType(Ogre::SO_GOURAUD);

    //d_renderSystem->_setPolygonMode(Ogre::PM_SOLID);

    

    // enable alpha blending

    d_renderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA,

                                      Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);

    

#if 1

Ogre::TextureUnitState::UVWAddressingMode d_uvwAddressMode;

    d_uvwAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP;

    d_uvwAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP;

    d_uvwAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP;

    

    Ogre::LayerBlendModeEx d_colourBlendMode;

    d_colourBlendMode.blendType    = Ogre::LBT_COLOUR;

    d_colourBlendMode.source1    = Ogre::LBS_TEXTURE;

    d_colourBlendMode.source2    = Ogre::LBS_DIFFUSE;

    d_colourBlendMode.operation    = Ogre::LBX_MODULATE;

    

    Ogre::LayerBlendModeEx d_alphaBlendMode;

    d_alphaBlendMode.blendType    = Ogre::LBT_ALPHA;

    d_alphaBlendMode.source1    = Ogre::LBS_TEXTURE;

    d_alphaBlendMode.source2    = Ogre::LBS_DIFFUSE;

    d_alphaBlendMode.operation    = Ogre::LBX_MODULATE;

    

    d_renderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE);

    d_renderSystem->_setTextureCoordSet(0, 0);

    d_renderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_POINT);

    d_renderSystem->_setTextureAddressingMode(0, d_uvwAddressMode);

    d_renderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY);

    d_renderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false);

    d_renderSystem->_setTextureBlendMode(0, d_colourBlendMode);

    d_renderSystem->_setTextureBlendMode(0, d_alphaBlendMode);

    d_renderSystem->_disableTextureUnitsFrom(1);

#endif

    

if (nuiBridge)

    {    

#if JUCE_MAC

        // on windows i just killed vbo

        glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); // works with 1.5

#endif

        nuiBridge->callDisplay(); // THIS RENDERS the 2d UI elements!

    }

glPopMatrix();

#if 1

glPopAttrib();

glPopClientAttrib();

#endif

#if defined(_MACOSX_)

glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, appleStorage);

#endif


}

#11

Could you/someone elaborate on this:

My implementation was way before Jules implemented the new OpenGL code.

?

What is this 'new OpenGL code' and how might it simplify the process?

This looks very daunting... There is considerable difference between Windows and OS X. So I can only imagine the remaining three platforms will also require some specific handling.

Are you using a precompiled Ogre lib, or including&compiling the Ogre source?


#12

JUCE's layer is more abstract now, and multi-threaded.  So I would let JUCE generate the context and then supply that to Ogre(that code above is platform specific and still applicable).

 

I compiled the Ogre source separately.  And just linked it in.

So probably something like... (just typed not tested!) maybe it'll help... Hopefully if you come up with anything, you'll share!

 

Constructor : public OpenGLRenderer, public Ogre::RenderTargetListener, public Ogre::FrameListener

{
Constructor
{
 glContext.setComponentPaitingEnabled(true);
glContext.setRenderer(this);
glContext.attachTo(*this);
glContext.setContinuousRepainting(true);
}
void newOpenGLContextCreated()
{
 // Platform specific... tell ogre the context if this is possible... (Ogre::Root::getSingleton().createRenderWindow...  it used to be "externalWindowHandle", but i'm sure there's a context way now...
}
void openGLContextClosing()
{
}
void renderOpenGL()
{
glViewport(0,0,getWidth(),getHeight());
OpenGLHelpers::clear(Colours::white);
Ogre::Root::getSingleton().renderOneFrame();
}
void resized()
{
 // you would need to be careful here, this would be called on the main thread, so make sure not rendering!
Ogre::RenderWindow *window = // platform specific way to get the window, it may not exist yet if the context wasn't created, or the context may be invalid.
if (window)
{window->resize(getWidth(),getHeight());
window->windowMovedOrResized();
}

}
private:

OpenGLContext glContext;

}

 

This could be useful for use JUCE's context directly in Ogre...(all that externalWindow stuff above)

 

http://www.ogre3d.org/forums/viewtopic.php?f=2&t=33065