# Mixed 2d and 3d drawing with Cinder-WMFPlayer

**URL:** https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486
**Category:** CinderBlocks
**Created:** [April 16, 2019, 6:31pm UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486 "2019-04-16T18:31:54Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![morphogencc](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@morphogencc](https://discourse.libcinder.org/u/morphogencc)
#### Post date: [April 16, 2019, 6:31pm UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486/1 "2019-04-16T18:31:54Z")

</div>

Hey all –

I’m trying to use the popular WMFPlayer block to playback video and texture map objects with video. However, I’m finding that drawing the video on top of a 3d scene (to show what the source material looks like) is slightly problematic.

My mixed drawing looks like:

```
void cinderTestApp::draw() {
	gl::clear( Color( 0, 0, 0 ) );

	gl::enableDepthRead();
	gl::enableDepthWrite();

	mCamera.lookAt( ... );
	ci::gl::setMatrices(mCamera);

	{
            auto lambert = gl::ShaderDef().lambert();
	    auto shader = gl::getStockShader(lambert);
	    shader->bind();

	    for (auto box : mBoxes) {
		gl::color(255, 255, 255);
		box->draw();
             }
	}

	gl::disableDepthWrite();
	gl::disableDepthRead();

	gl::setMatricesWindow(ci::app::getWindowSize());
        mWMFVideoPlayer->draw(0, 0);
}

```

With this code, I just get a white rectangle the size of the video drawn on top of my 3d scene.

If I replace the last line with a `gl::draw` call with a reference texture, that draws fine:

```
	gl::draw(gl::Texture::create(*mReferenceTexture)); // loaded as a surface with ci::loadImage()

```

I even thought that maybe there was something from the 3d calls that wasn’t falling out of scope, so I tried drawing the video to a FBO and then drawing the FBO on top of 3d scene:

```
void visualizationTestApp::update() {
	if (mVideoPlayer) {
		mVideoPlayer->update();
		std::cout << "Video position : " << mVideoPlayer->getPosition() << std::endl;
	}

	{
		gl::ScopedFramebuffer fboScope(mFbo);
		gl::ScopedViewport scpVp(ivec2(0), mFbo->getSize());
		gl::clear(Color(1, 1, 1));

		gl::ScopedColor white(1, 1, 1);
		//mVideoPlayer->draw(0, 0, mFbo->getWidth(), mFbo->getHeight());
		gl::draw(gl::Texture::create(*mReferenceTexture));
	}
}

```

and then drawing the FBO in `draw()`; but even within the FBO, the `gl::draw` call draws the texture properly, but WMFPlayer doesn’t render the image properly!

Can anyone help me understand what’s going on here?

thanks!

---

<div class="post-metadata">

### Author: ![gabor\_papp](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/gabor_papp/32/769_2.png) [@gabor\_papp](https://discourse.libcinder.org/u/gabor_papp)
#### Post date: [April 16, 2019, 7:01pm UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486/2 "2019-04-16T19:01:30Z")

</div>

Hi,

Can you draw the viideo texture on the screen without any 3d?

-Gabor

---

<div class="post-metadata">

### Author: ![morphogencc](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@morphogencc](https://discourse.libcinder.org/u/morphogencc)
#### Post date: [April 16, 2019, 8:23pm UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486/3 "2019-04-16T20:23:23Z")

</div>

Yes, I can. It draws just fine if my draw loop only contains `ciWMFPlayer::draw`. In fact, it’s only when I get into the drawing of the 3d where the issue occurs…

…and, trying a few things, it looks like if I switch to using a scoped shader, then it fixes the problem.

The working draw loop is:

```
void visualizationTestApp::draw() {
	gl::clear( Color( 0, 0, 0 ) );

	gl::enableDepthRead();
	gl::enableDepthWrite();

	mCamera.lookAt( ... );
	ci::gl::setMatrices(mCamera);
	
	{
	    gl::ScopedGlslProg shader(gl::getStockShader(gl::ShaderDef().lambert()));
	    gl::ScopedColor(1,1,1);

            for (auto box : mBoxes) {
                gl::color(255, 255, 255);
	        box->draw();
            }
	}

	gl::disableDepthWrite();
	gl::disableDepthRead();

	gl::setMatricesWindow(ci::app::getWindowSize());
	gl::draw(mFbo->getColorTexture(), Rectf(0, 0, 320, 240)); // draw from Fbo
	//mVideoPlayer->draw(0, 0); // this also works
}
```

---

<div class="post-metadata">

### Author: ![gabor\_papp](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/gabor_papp/32/769_2.png) [@gabor\_papp](https://discourse.libcinder.org/u/gabor_papp)
#### Post date: [April 16, 2019, 9:06pm UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486/4 "2019-04-16T21:06:17Z")

</div>

Good that you have found the solution. Now that you have edited the post with the 3d drawing part of the code it shows that you left the lambert shader bound. which won’t work with the texture because it does not have normals.

---

<div class="post-metadata">

### Author: ![lithium](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/lithium/32/38_2.png) [@lithium](https://discourse.libcinder.org/u/lithium)
#### Post date: [April 17, 2019, 1:31am UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486/5 "2019-04-17T01:31:22Z")

</div>

Something to be aware of, the WMF video player uses the [WGL\_NV\_DX\_interop2](https://www.khronos.org/registry/OpenGL/extensions/NV/WGL_NV_DX_interop2.txt) extension to share a texture from DirectX with OpenGL. This means that the texture needs to be locked when drawn, which is handled by the `ciWMFPlayer::draw` function, but not when you’re drawing it directly with cinder. My solution has been to write a `FrameLease` class that holds the lock on the texture and releases it when it goes out of scope. Something like:

```cpp
class FrameLease
{
public:
    FrameLease ( VideoPlayer& player ) : _player(player) { _player.Lock(); }
    ~FrameLease ( ) { _player.Unlock(); };
    
    operator bool ( ) const { return _player._currentFrame != nullptr; }
    operator ci::gl::TextureRef ( ) const { return _player._currentFrame; };
    
protected:
    
    VideoPlayer& _player;
};

```

I’ve written a small abstraction layer over the WMFPlayer and cinder’s native AVF based player on mac which provides a common interface because WMFPlayer inexplicably didn’t follow the API, but that’s where the `Lock`/`Unlock` calls come into it. The `VideoPlayer` has a `GetCurrentFrame` method that returns a `FrameLease`, which you can directly `gl::draw()`. Anyway this is one possible solution to the issue you’re seeing, and this way you don’t have to think to much about how you’re using the texture or where it came from.

A

---

<div class="post-metadata">

### Author: ![morphogencc](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@morphogencc](https://discourse.libcinder.org/u/morphogencc)
#### Post date: [April 22, 2019, 3:03pm UTC](https://discourse.libcinder.org/t/mixed-2d-and-3d-drawing-with-cinder-wmfplayer/1486/6 "2019-04-22T15:03:11Z")

</div>

@lithium interesting – doesn’t the latest version of WMFPlayer correct this? It looks like in the `ScopedVideoTextureBind` class, the constructor and destructor use:

```auto
ciWMFVideoPlayer::ScopedVideoTextureBind::ScopedVideoTextureBind( const ciWMFVideoPlayer& video, uint8_t textureUnit )
	: mCtx( gl::context() )
	, mTarget( video.mTex->getTarget() )
	, mTextureUnit( textureUnit )
	, mPlayer( video.mPlayer ) {
	mPlayer->mEVRPresenter->lockSharedTexture();
	mCtx->pushTextureBinding( mTarget, video.mTex->getId(), mTextureUnit );
}

ciWMFVideoPlayer::ScopedVideoTextureBind::~ScopedVideoTextureBind() {
	mCtx->popTextureBinding( mTarget, mTextureUnit );
	mPlayer->mEVRPresenter->unlockSharedTexture();
}

```

Which seems to lock and unlock the texture. Is there something additional that needs to be done to make sure the texture can be drawn outside of the player’s `draw()` call?
