-
简介
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::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;
- }
- }
- }
编译运行程序:
附:本课源码(源码中可能存在错误和不足,仅供参考)
- #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();
- }