WVR_StereoRenderer

struct WVR_StereoRenderer

Aggregate the function pointers to support the callbacks of runtime.

Runtime maintains a stereo renderer mode to handle the customized callback at the specific moment. Native application developer implements all the callbacks and delegates the invoking timing to runtime. The optimized algorithm improves the stereoscopic experience in render runtime with single buffer method.

The following is the sequence diagram, which graphs the relations among each of the components.

_images/WVR_StereoRenderer.png

After setting the customized callback set to render runtime with WVR_StartRenderer, the main block maintains a loop to check the presence of stereorenderer in the render runtime via WVR_IsRendererRendering . Render runtime hooks the following callbacks implemented by the developer to achieve the single buffer method.

graphics_init

bool (*graphics_init)()

This initializes the graphics library.

You can enable server-side capabilties, such as doing depth comparisons and updating the depth buffer, specifying the value used for depth buffer comparisons, or specifying whether depth buffer is enabled for writing. Depending on the development requirements, set up the scene objects, frame buffer for sterero render targets, or render models.

Return Value

  • true -

    Succeeded to initialize the graphics library.

  • false -

    Failed to initialize the graphics library.

pre_draw_frame

bool (*pre_draw_frame)()

Called when a new frame is about to be drawn.

Any per-frame operations not specific to a single view should happen here.

Return Value

  • true -

    Succeeded to invoke the function.

  • false -

    Failed to invoke the function.

draw_eye

void (*draw_eye)(WVR_Eye eye)

This requests to draw the contents from the point of view of an eye.

Implementor should draw the framebuffer corresponding to the different eye. In order to submit the content of the view as a texture to the runtime, it is needed to bind the framebuffer, render the scene, and pack the texture id as the arguemnt of WVR_SubmitFrame.

Parameters

  • eye -

    WVR_Eye, eye id.

post_draw_frame

void (*post_draw_frame)( eye)

Called before a frame is finished.

By the time of this call, the frame content have been already drawn. Any rendering in this step is relative to the full surface, not to any single eye view, such as polling the pose of the devices.

How to use

Here is an example for the function:

//single.cpp

MainApplicationSinglebuffer * getPtr();
bool CustGLInit();
bool CustPreDrawFrame();
void CustPostDrawFrame();
void CustDrawEye(WVR_Eye nEye);

int main(int argc, char *argv[]) {
    LOGENTRY();

    if (!getPtr()->initVRSingleBuffer()) {
        getPtr()->shutdownVR();
        return 1;
    }
    WVR_StereoRenderer_t renderer;
    renderer.graphics_init = &CustGLInit;
    renderer.pre_draw_frame = &CustPreDrawFrame;
    renderer.draw_eye = &CustDrawEye;
    renderer.post_draw_frame = &CustPostDrawFrame;

    WVR_StartRenderer(&renderer);
    while (WVR_IsRendererRendering()) {
        sleep(1);
    }
    LOGD("Renderer is terminated");

    getPtr()->shutdownGL();
    getPtr()->shutdownVR();

    return 0;
}

MainApplicationSinglebuffer * getPtr() {
     return MainApplicationSinglebuffer::getInstance();
}

bool CustGLInit() {
    return getPtr()->GLInit();
}

bool CustPreDrawFrame() {
    return getPtr()->PreDrawFrame();
}

void CustDrawEye(WVR_Eye nEye) {
    getPtr()->DrawEye(nEye);
}

void CustPostDrawFrame() {
    getPtr()->PostDrawFrame();
}
//hellovr_singlebuffer.cpp

#include <log.h>
#include <hellovr_singlebuffer.h>
#include <FrameBufferObject.h>
#include <wvr/wvr.h>

MainApplicationSinglebuffer * MainApplicationSinglebuffer::thizMpSb= NULL;
MainApplicationSinglebuffer * MainApplicationSinglebuffer::getInstance() {
    if (thizMpSb != NULL)
        return thizMpSb;

    thizMpSb = new MainApplicationSinglebuffer();
    return thizMpSb;

}

bool MainApplicationSinglebuffer::initVRSingleBuffer() {
    LOGENTRY();

    // Loading the WVR Runtime
    WVR_InitError eError = WVR_InitError_None;
    eError = WVR_Init(WVR_AppType_VRContent);

    if (eError != WVR_InitError_None) {
        LOGE("Unable to init VR runtime: %s", WVR_GetInitErrorString(eError));
        return false;
    }

    // Must initialize render runtime before all OpenGL code.
    WVR_RenderInitParams_t param = {WVR_GraphicsApiType_OpenGL, WVR_RenderConfig_Direct_Mode | WVR_RenderConfig_Timewarp_Asynchronous};
    if (WVR_RenderError_None != WVR_RenderInit(&param)) {
        LOGE("Render runtime initialization failed. See log file for details\n");
        return false;
    }

    return true;
}

bool MainApplicationSinglebuffer::GLInit() {
    if (!initGL()) {
        LOGE("%s - Unable to initialize OpenGL!\n", __FUNCTION__);
        return false;
    }

    return true;
}

bool MainApplicationSinglebuffer::PreDrawFrame() {
    if (handleInput())
        return false;

    // Render the controller model
    drawControllers();

    glClearColor(0.30f, 0.30f, 0.37f, 1.0f); // nice background color, but not black
    return true;
}

void MainApplicationSinglebuffer::DrawEye(WVR_Eye eEye) {
    WVR_SubmitError e;
    if (eEye == WVR_Eye_Left) {
        // Left Eye
        mLeftEyeFBO.at(mIndex)->bindFrameBuffer();
        mLeftEyeFBO.at(mIndex)->glViewportFull();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        renderScene(WVR_Eye_Left);
        mLeftEyeFBO.at(mIndex)->unbindFrameBuffer();
        WVR_TextureParams_t leftEyeTexture = {(WVR_Texture_t)mLeftEyeFBO.at(mIndex)->getTextureId()};
        e = WVR_SubmitFrame(WVR_Eye_Left, &leftEyeTexture);
    } else {
        // Right Eye
        mRightEyeFBO.at(mIndex)->bindFrameBuffer();
        mRightEyeFBO.at(mIndex)->glViewportFull();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        renderScene(WVR_Eye_Right);
        mRightEyeFBO.at(mIndex)->unbindFrameBuffer();
        WVR_TextureParams_t rightEyeTexture = {(WVR_Texture_t)mRightEyeFBO.at(mIndex)->getTextureId()};
        e = WVR_SubmitFrame(WVR_Eye_Right, &rightEyeTexture);
    }
}

void MainApplicationSinglebuffer::PostDrawFrame() {
    updateTime();

    // Spew out the controller and pose count whenever they change.
    if (mControllerCount != mControllerCount_Last || mValidPoseCount != mValidPoseCount_Last) {
        mValidPoseCount_Last = mValidPoseCount;
        mControllerCount_Last = mControllerCount;

        LOGD("PoseCount:%d(%s) Controllers:%d\n", mValidPoseCount, mPoseClasses.c_str(), mControllerCount);
    }

    updateHMDMatrixPose();
}
//hellovr_singlebuffer.h

#pragma once
#include <stdio.h>
#include <string>
#include <vector>

#include <GLES3/gl31.h>
#include <hellovr.h>
#include <wvr/wvr_types.h>
#include <wvr/wvr_render.h>
#include "shared/Matrices.h"

class MainApplicationSinglebuffer : public MainApplication
{
public:
    static MainApplicationSinglebuffer * thizMpSb;
    MainApplicationSinglebuffer();
    ~MainApplicationSinglebuffer();
    bool initVRSingleBuffer();
    static MainApplicationSinglebuffer * getInstance();
    static void clear();
    bool GLInit();
    bool PreDrawFrame();
    void DrawEye(WVR_Eye nEye);
    void PostDrawFrame();
};