用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十四课

  • 简介

NeHe教程在这节课中向我们介绍了如何读取显卡支持的OpenGL的扩展,如何使用Targa(TGA)图像文件作为纹理,以及如何利用OpenGL的剪裁区域来滚动屏幕文字。osg支持tga格式的文件读取,因此不需要像NeHe课程那样解析TGA格式,有兴趣的读者可以查看osgPlugins库中的ReaderWriterTGA.cpp文件了解osg是如何读取TGA图片格式的。

用纹理贴图来创建字体在第十七课中已经使用过了,过程相对比较繁琐,本课的主要目的是学习如何查看OpenGL的扩展,为了简便,本课使用osgText来显示字体。

  • 实现

本课中NeHe使用的是坐标原点在左上角的坐标系统,但是在osg中设置同样的投影坐标系会导致文字反转,在osg论坛中对此也有描述:osgText::Text and screen

按照帖子中修改之后发现字体消失,希望知道的读者指点一下。为此本课还是采用坐标原点在左下角的坐标系统,定义了TX和TY宏以便于使用NeHe中的位置数据

#define TX(x) (x)
#define TY(y) (480-(y))
首先定义创建字体的函数:(字体位置和颜色以及文字内容)

osg::Group* createText(int xPos, int yPos, osg::Vec4 colors, const char *contents)
{
	osgText::Text *text = new osgText::Text;
	text->setText(contents);
	text->setFont("Fonts/Arial.ttf");
	text->setCharacterSize(15.0);
	text->setColor(colors);

	osg::Geode *textGeode = new osg::Geode;
	textGeode->addDrawable(text);

	osg::MatrixTransform *mt = new osg::MatrixTransform;
	mt->setMatrix(osg::Matrix::translate(xPos, yPos, 0.0));

	mt->addChild(textGeode);

	return mt;
}
之后创建边框线:
osg::Group * createDisplayBorder()

为了获取显卡的扩展,需要我们在GraphicContext创建好之后获取,因此在Viewer视景器Realize的时候来获取是一个不错的时机。本课通过设置Realize的一个operation来获取扩展信息。Operation是一个自定义的操作,在osg中可以在某个过程完成之后定义一些操作。只需要重载Operation中的()操作符即可实现自定义操作:

在osg中有一个类用来获取扩展的信息:osg::GL2Extensions可以查看当前显卡支持的各种扩展以及支持的OpenGL版本,但是在它里面未找到显卡供应商和显卡型号的接口,我们可以用OpenGL的glGetString来获取。

	  virtual void operator () (osg::GraphicsContext* gc)
	  {
		  if (_isInitialized)
		  {
			  return;
		  }

		  OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);

		  unsigned int contextID = gc->getState()->getContextID();
		  osg::GL2Extensions* gl2ext = osg::GL2Extensions::Get(contextID,true);
		  if( gl2ext )
		  {	  
			  char *render = (char*)glGetString(GL_RENDERER);
			  char *vendor =  (char*)glGetString(GL_VENDOR);
			  char *version = (char*)glGetString(GL_VERSION);

                          ...
                   }
                  ...
           }

接着我们需要定义裁剪范围,在osg中osg::Scissor封装了OpenGL中glScissor的功能,它是一个StateAttribute,通过给节点设置StateAttribute进一步控制节点在视口

中的显示范围:

			  osg::Group *scissorGroup = new osg::Group;
			  g_scissorGroup = scissorGroup;
			  osg::Scissor *scissor = new osg::Scissor;
			  scissor->setScissor(1, TY(417), g_width-2 , 289);
			  g_scissorGroup->getOrCreateStateSet()->setAttributeAndModes(scissor);

通过键盘上下键操作的部分如下:

				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)
				{
					if((scroll<32*(maxtokens-9)))
					{
						scroll += 2;
						
						for (unsigned i = 0, j = 0; i < g_scissorGroup->getNumChildren(); i +=2)
						{
							osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(g_scissorGroup->getChild(i));
							if (!mt)
								return false;
							//扩展的序号:如1 2 3 等
							mt->setMatrix(osg::Matrix::translate(TX(0), TY(115+(j*32)-scroll), 0.0));	
							osg::MatrixTransform *mt2 = dynamic_cast<osg::MatrixTransform*>(g_scissorGroup->getChild(i+1));
							if (!mt2)
								return false;
							//扩展的内容 如GL_ARB_clear_buffer_object等
							mt2->setMatrix(osg::Matrix::translate(TX(50), TY(115+(j*32)-scroll), 0.0));	
							++j;
						}

					}
				}

编译运行程序:

用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十四课_第1张图片

附:本课源码(源码中可能存在错误和不足,仅供参考)

#include "../osgNeHe.h"

#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QVBoxLayout>

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgQt/GraphicsWindowQt>

#include <osg/MatrixTransform>

#include <osg/Geode>
#include <osgText/Text>

#include <osg/Scissor>

#include <osg/GraphicsThread>


#define TX(x) (x)
#define TY(y) (480.0-(y))

char *glExtensionString = NULL;

int			scroll;
int			maxtokens;
int g_height = 480;
int g_width = 640;
osg::Group *g_scissorGroup;


//////////////////////////////////////////////////////////////////////////
//在指定位置显示文本

osg::Group* createText(int xPos, int yPos, osg::Vec4 colors, const char *contents)
{
	osgText::Text *text = new osgText::Text;
	text->setText(contents);
	text->setFont("Fonts/Arial.ttf");
	text->setCharacterSize(15.0);
	text->setColor(colors);

	osg::Geode *textGeode = new osg::Geode;
	textGeode->addDrawable(text);

	osg::MatrixTransform *mt = new osg::MatrixTransform;
	mt->setMatrix(osg::Matrix::translate(xPos, yPos, 0.0));

	mt->addChild(textGeode);

	return mt;
}

//////////////////////////////////////////////////////////////////////////
osg::Group * createDisplayBorder()
{
	//
	osg::Group *borderGroup = new osg::Group;
	osg::Geode*	borderGeode1 = new osg::Geode;
	osg::Geometry *borderGeometry1 = new osg::Geometry;

	osg::Vec2Array *verticesArray1 = new osg::Vec2Array;
	verticesArray1->push_back(osg::Vec2(639,TY(417)));
	verticesArray1->push_back(osg::Vec2(  0,TY(417)));
	verticesArray1->push_back(osg::Vec2(  0,TY(480)));
	verticesArray1->push_back(osg::Vec2(639,TY(480)));
	verticesArray1->push_back(osg::Vec2(639,TY(128)));
	borderGeometry1->setVertexArray(verticesArray1);
	borderGeometry1->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, 5));
	osg::Vec3Array *colorsArray1 = new osg::Vec3Array;
	colorsArray1->push_back(osg::Vec3(1.0f,1.0f,1.0f));
	borderGeometry1->setColorArray(colorsArray1, osg::Array::BIND_OVERALL);
	borderGeode1->addDrawable(borderGeometry1);

	borderGroup->addChild(borderGeode1);
	

	osg::Geode*	borderGeode2 = new osg::Geode;
	osg::Geometry *borderGeometry2 = new osg::Geometry;

	osg::Vec2Array *verticesArray2 = new osg::Vec2Array;
	verticesArray2->push_back(osg::Vec2(  0,TY(128)));
	verticesArray2->push_back(osg::Vec2(639,TY(128)));
	verticesArray2->push_back(osg::Vec2(639,  TY(1)));
	verticesArray2->push_back(osg::Vec2(  0,  TY(1)));
	verticesArray2->push_back(osg::Vec2(  0,TY(417)));
	borderGeometry2->setVertexArray(verticesArray2);
	borderGeometry2->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, 5));
	osg::Vec3Array *colorsArray2 = new osg::Vec3Array;
	colorsArray2->push_back(osg::Vec3(1.0f,1.0f,1.0f));
	borderGeometry2->setColorArray(colorsArray2, osg::Array::BIND_OVERALL);
	borderGeode2->addDrawable(borderGeometry2);

	borderGroup->addChild(borderGeode2);
	return borderGroup;
}


//////////////////////////////////////////////////////////////////////////
//获取OpenGL扩展
class GetOpenGLExtensionsOperation: public osg::GraphicsOperation
{
public:

	GetOpenGLExtensionsOperation(const std::string& name, bool keep, osg::Group *root) : 
	  osg::GraphicsOperation("TestSupportOperation",false), _isInitialized(false), _root(root){ }

	  virtual void operator () (osg::GraphicsContext* gc)
	  {
		  if (_isInitialized)
		  {
			  return;
		  }

		  OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);

		  unsigned int contextID = gc->getState()->getContextID();
		  osg::GL2Extensions* gl2ext = osg::GL2Extensions::Get(contextID,true);
		  if( gl2ext )
		  {	  
			  char *render = (char*)glGetString(GL_RENDERER);
			  char *vendor =  (char*)glGetString(GL_VENDOR);
			  char *version = (char*)glGetString(GL_VERSION);

			  _root->addChild(createText(TX(200), TY(16), osg::Vec4(1.0f,0.7f,0.4f, 1.0f), render));
			  _root->addChild(createText(TX(200), TY(48), osg::Vec4(1.0f,0.7f,0.4f, 1.0f), vendor));
			  _root->addChild(createText(TX(200), TY(80), osg::Vec4(1.0f,0.7f,0.4f, 1.0f), version));

			  glExtensionString = (char *)malloc(strlen((char *)glGetString(GL_EXTENSIONS))+1);
			  strcpy (glExtensionString,(char *)glGetString(GL_EXTENSIONS));

			  osg::Group *scissorGroup = new osg::Group;
			  g_scissorGroup = scissorGroup;
			  osg::Scissor *scissor = new osg::Scissor;
			  scissor->setScissor(1, TY(417), g_width-2 , 289);
			  g_scissorGroup->getOrCreateStateSet()->setAttributeAndModes(scissor);
			  
			  _root->addChild(g_scissorGroup);

			  char *token;
			  int cnt = 0;
			  token=strtok(glExtensionString," ");								
			  while(token!=NULL)									
			  {
				  cnt++;	
				  if (cnt>maxtokens)	
				  {
					  maxtokens=cnt;
				  }
				

				  std::stringstream os;
				  std::string str;
				  os.precision(2);
				  os << std::fixed  << cnt;
				  str = os.str();

				  scissorGroup->addChild(createText(TX(0), TY(115+(cnt*32)-scroll), osg::Vec4(0.5f, 1.0f, 0.5f, 1.0f), str.c_str()));
				  scissorGroup->addChild(createText(TX(50), TY(115+(cnt*32)-scroll), osg::Vec4(1.0f, 1.0f, 0.5f, 1.0f), token));

				  token=strtok(NULL," ");
			  }

		  }
		  _isInitialized = true;
	  }

	  OpenThreads::Mutex  _mutex;
	  bool _isInitialized;
	  osg::Group *_root;
};

//////////////////////////////////////////////////////////////////////////

class SceneEventHandler : public osgGA::GUIEventHandler
{
public:
	SceneEventHandler(){}

	virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
		if (!viewer)
			return false;
		osg::Group *root = dynamic_cast<osg::Group*>(viewer->getSceneData());
		if (!root)
			return false;
		if (ea.getHandled()) 
			return false;

		switch(ea.getEventType())
		{
		case (osgGA::GUIEventAdapter::KEYDOWN):
			{
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)
				{
					if((scroll<32*(maxtokens-9)))
					{
						scroll += 2;
						
						for (unsigned i = 0, j = 0; i < g_scissorGroup->getNumChildren(); i +=2)
						{
							osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(g_scissorGroup->getChild(i));
							if (!mt)
								return false;
							//扩展的序号:如1 2 3 等
							mt->setMatrix(osg::Matrix::translate(TX(0), TY(115+(j*32)-scroll), 0.0));	
							osg::MatrixTransform *mt2 = dynamic_cast<osg::MatrixTransform*>(g_scissorGroup->getChild(i+1));
							if (!mt2)
								return false;
							//扩展的内容 如GL_ARB_clear_buffer_object等
							mt2->setMatrix(osg::Matrix::translate(TX(50), TY(115+(j*32)-scroll), 0.0));	
							++j;
						}

					}
				}
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)
				{
					if (scroll >= 0)
					{
						scroll -= 2;

						for (unsigned i = 0, j = 0; i < g_scissorGroup->getNumChildren(); i +=2)
						{
							osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(g_scissorGroup->getChild(i));
							if (!mt)
								return false;
							mt->setMatrix(osg::Matrix::translate(TX(0), TY(115+(j*32)-scroll), 0.0));	

							osg::MatrixTransform *mt2 = dynamic_cast<osg::MatrixTransform*>(g_scissorGroup->getChild(i+1));
							if (!mt2)
								return false;
							mt2->setMatrix(osg::Matrix::translate(TX(50), TY(115+(j*32)-scroll), 0.0));	
							++j;
						}
					}
				}
			}	
		case (osgGA::GUIEventAdapter::RESIZE):
			{
				g_height = ea.getWindowHeight();
				g_width = ea.getWindowWidth();
			}
		default: break;
		}
		return false;
	}
};
//////////////////////////////////////////////////////////////////////////

class ViewerWidget : public QWidget, public osgViewer::Viewer
{
public:
	ViewerWidget(osg::Node *scene = NULL)
	{
		QWidget* renderWidget = getRenderWidget( createGraphicsWindow(0,0,640,480), scene);

		QVBoxLayout* layout = new QVBoxLayout;
		layout->addWidget(renderWidget);
		layout->setContentsMargins(0, 0, 0, 1);
		setLayout( layout );

		connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
		_timer.start( 10 );
	}

	QWidget* getRenderWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene )
	{
		osg::Camera* camera = this->getCamera();
		camera->setGraphicsContext( gw );

		const osg::GraphicsContext::Traits* traits = gw->getTraits();

		camera->setClearColor( osg::Vec4(0.0, 0.0, 0.0, 1.0) );
		camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
		camera->setProjectionMatrixAsOrtho(0.0, 640.0, 0.0, 480.0, -1.0, 1.0);
		camera->setViewMatrixAsLookAt(osg::Vec3d(0, 0, 1), osg::Vec3d(0, 0, 0), osg::Vec3d(0, 1, 0));

		setRealizeOperation(new GetOpenGLExtensionsOperation("OpenGLExtension", false, scene->asGroup()));
		addEventHandler(new SceneEventHandler());
		this->setSceneData( scene );

		return gw->getGLWidget();
	}

	osgQt::GraphicsWindowQt* createGraphicsWindow( int x, int y, int w, int h, const std::string& name="", bool windowDecoration=false )
	{
		osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
		osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
		traits->windowName = name;
		traits->windowDecoration = windowDecoration;
		traits->x = x;
		traits->y = y;
		traits->width = w;
		traits->height = h;
		traits->doubleBuffer = true;
		traits->alpha = ds->getMinimumNumAlphaBits();
		traits->stencil = ds->getMinimumNumStencilBits();
		traits->sampleBuffers = ds->getMultiSamples();
		traits->samples = ds->getNumMultiSamples();

		return new osgQt::GraphicsWindowQt(traits.get());
	}

	virtual void paintEvent( QPaintEvent* event )
	{ 
		frame(); 
	}

protected:

	QTimer _timer;
};



osg::Node*	buildScene()
{
	osg::Group *root = new osg::Group;

	root->addChild(createText(TX(60), TY(16), osg::Vec4(1.0f,0.5f,0.5f, 1.0f), "Renderer"));
	root->addChild(createText(TX(80), TY(48), osg::Vec4(1.0f,0.5f,0.5f, 1.0f), "Vendor"));
	root->addChild(createText(TX(70), TY(80), osg::Vec4(1.0f,0.5f,0.5f, 1.0f), "Version"));
	root->addChild(createText(TX(192), TY(432), osg::Vec4(0.5f,0.5f,1.0f, 1.0f), "NeHe Productions"));
	
	root->addChild(createDisplayBorder());
	return root;
}



int main( int argc, char** argv )
{
	QApplication app(argc, argv);
	ViewerWidget* viewWidget = new ViewerWidget(buildScene());
	viewWidget->setGeometry( 100, 100, 640, 480 );
	viewWidget->show();
	return app.exec();
}

你可能感兴趣的:(C++,qt,OpenGL,nehe,OSG)