#include <vuAllocTracer.h>
#include <vrMode.h>
#include <vpObject.h>
#include <vsChannel.h>
#include <vrFontFactory.h>
#include <vpApp.h>
// track memory leaks
vuAllocTracer m_allocTracer;
// the main application class. Note that we must derive from
// vsChannel::Subscriber here so that we can inherit the post draw
// notify method
class myApp : public vpApp, public vsChannel::Subscriber {
public:
/**
* Constructor
*/
myApp() : m_object(NULL),
m_bFollow(true)
{}
/**
* Destructor
*/
~myApp()
{
// unreference member variables which cache Vega Prime class instances
m_object->unref();
}
/**
* Configure my app
*/
int configure() {
// pre-configuration
// configure vega prime system first
vpApp::configure();
// post-configuration
// Increase the reference count by one for all member variables which
// cache the Vega Prime class instances.
//
// All VSG/Vega Prime class instances are referenced counted.
// The initial reference count is 0 after the instance is created.
// When the reference count is smaller or equal to 0 in unref(),
// the instance will be deleted automatically. Increasing reference
// count here for all member variables will guarantee that they will
// not be deleted until myApp is deleted.
// cache the object
m_object = vpObject::find("targetObject");
assert(m_object);
m_object->ref();
// create a font to render the text
vrFontFactory *fontFactory = new vrFontFactory();
m_font = (vrFont2D*)fontFactory->read( "system" );
fontFactory->unref();
// set the default text
m_text1.sprintf("object pos (0.0, 0.0, 0.0)");
m_text2.sprintf("screen coordinates (0, 0)");
m_text3.sprintf("This text starts at the 2D point");
// subsribe to post draw events for our channel
vpChannel *channel = *vpChannel::begin();
assert(channel);
channel->addSubscriber(vsChannel::EVENT_POST_DRAW, this);
return vsgu::SUCCESS;
}
virtual void onKeyInput(vrWindow::Key key, int mod)
{
switch (key) {
case vrWindow::KEY_LEFT:
m_object->setTranslateX(-1.0, true);
break;
case vrWindow::KEY_RIGHT:
m_object->setTranslateX(1.0, true);
break;
case vrWindow::KEY_DOWN:
m_object->setTranslateY(-1.0, true);
break;
case vrWindow::KEY_UP:
m_object->setTranslateY(1.0, true);
break;
case vrWindow::KEY_SPACE:
m_bFollow = !m_bFollow;
break;
default:
vpApp::onKeyInput(key, mod);
break;
}
}
/**
* inherited pre / post cull notification method. We have to implement
* this even though we don't care about these events since the method is
* abstract, however, we can just make it a noop.
*/
virtual void notify(vsChannel::Event, const vsChannel *,
vsTraversalCull *) {}
/**
* inherited pre / post draw notification method. Since we're only
* subscribed to post draw events we don't need to bother checking for the
* pre draw events.
*/
virtual void notify(vsChannel::Event, const vsChannel *channel,
vrDrawContext *context) {
// get the world to screen matrix and viewport
int ox, oy, sx, sy;
vuMatrixf world2screen;
channel->getVrChannel()->getViewport(&ox, &oy, &sx, &sy);
world2screen = channel->getVrChannel()->getWorldToScreenMatrix();
// Create a point in world space to transform
//
// Note: it would be better to use getAbsolutePosition() instead of
// getTranslate() if you need to work with additional transforms in
// the scene graph. Also, getting a position in the draw thread
// may not be accurate if the object is moving.
vuVec4f point;
point.set(m_object->getTranslateX(),
m_object->getTranslateY(),
m_object->getTranslateZ(),
1.0f);
// update the text with the object position
m_text1.sprintf("object pos (%.1f, %.1f, %.1f)",
point[0], point[1], point[2]);
// transform the 4d point into clip space
world2screen.transform(&point);
// divide by w
float fx = point[0]/point[3]; // x between [-1,1]
float fy = point[1]/point[3]; // y between [-1,1]
float fz = point[2]/point[3]; // z between [-1,1]
// normalize to [0,1] range
fx = (fx+1.0f)/2.0f;
fy = (fy+1.0f)/2.0f;
fz = (fz+1.0f)/2.0f;
// find the 2d screen location
int x_coord = (int)(ox + fx*sx + 0.5f);
int y_coord = (int)(oy + fy*sy + 0.5f);
// update the text with the screen position
m_text2.sprintf("screen coordinates (%d, %d)", x_coord, y_coord);
// it is recommended that all modifications to state be done via
// vrDrawContext. Although we're not preventing you from accessing
// OpenGL or Direct3D directly, it is much safer to go through state
// manager as it will guarantee that the software representation of
// the hardware graphics state maintained by vrDrawContext stays in sync
// w/ the hardware. If this gets out of sync for some reason, visual
// anomalies can occur which can be very difficult to track down. If
// you do need to drop down to the graphics library layer, you need to
// make sure that the graphics library hardware is in the same state
// when you leave the function as when you enter it.
// reset all of the graphics state elements to their default values.
// Note that this also resets the model view matrix to identity, so
// all vertex information, etc. will be specified relative to that
context->pushElements(true);
// need to disable the depth buffer since it's enabled by default
vrDepthTest::Element depthTestElement;
depthTestElement.m_enable = false;
context->setElement(vrDepthTest::Element::Id, &depthTestElement);
// set up an orthographic projection. In this case we'll just map the
// channel viewport to 0 to 1 both horizontally and vertically.
vrTransform::ElementProjection projectionElement;
projectionElement.makeOrthographic(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
context->setElement(vrTransform::ElementProjection::Id,
&projectionElement);
// draw the text
vuVec4<float> color(1.0f, 1.0f, 1.0f, 1.0f);
m_font->displayStringAt(context, m_text1.c_str(), color, 0.01f, 0.05f);
m_font->displayStringAt(context, m_text2.c_str(), color, 0.01f, 0.02f);
// draw the following text only if the object is in the frustum
if(m_bFollow && (fz > 0.0f) && (fz < 1.0f) &&
(fx > 0.0f) && (fx < 1.0f) &&
(fy > 0.0f) && (fy < 1.0f))
m_font->displayStringAt(context, m_text3.c_str(), color, fx, fy);
// restore all of the graphics state elements to their previous value
context->popElements();
}
private:
vuField<vrFont2D *> m_font;
vuString m_text1;
vuString m_text2;
vuString m_text3;
bool m_bFollow;
vpObject *m_object;
};
int main(int argc, char *argv[])
{
// initialize vega prime
vp::initialize(argc, argv);
// create my app instance
myApp *app = new myApp;
// load acf file
if (argc <= 1)
app->define("vp_wor