// // main.cpp // tests/render-utils/src // // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "TextRenderer.h" #include "MatrixStack.h" #include "OffscreenUi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class RateCounter { std::vector times; QElapsedTimer timer; public: RateCounter() { timer.start(); } void reset() { times.clear(); } unsigned int count() const { return times.size() - 1; } float elapsed() const { if (times.size() < 1) { return 0.0f; } float elapsed = *times.rbegin() - *times.begin(); return elapsed; } void increment() { times.push_back(timer.elapsed() / 1000.0f); } float rate() const { if (elapsed() == 0.0f) { return NAN; } return (float) count() / elapsed(); } }; // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT QOpenGLContext * _context{ nullptr }; QSize _size; TextRenderer* _textRenderer[4]; RateCounter fps; OffscreenUi _offscreenUi; int testQmlTexture{ 0 }; //ProgramPtr _planeProgam; //ShapeWrapperPtr _planeShape; protected: void renderText(); void renderQml(); private: void resizeWindow(const QSize & size) { _size = size; _offscreenUi.resize(_size); } public: QTestWindow() { setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; // Qt Quick may need a depth and stencil buffer. Always make sure these are available. format.setDepthBufferSize(16); format.setStencilBufferSize(8); format.setVersion(4, 5); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); format.setOption(QSurfaceFormat::DebugContext); setFormat(format); _context = new QOpenGLContext; _context->setFormat(format); _context->create(); show(); makeCurrent(); { QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx logger->enableMessages(); connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { qDebug() << debugMessage; }); // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); } qDebug() << (const char*)glGetString(GL_VERSION); #ifdef WIN32 glewExperimental = true; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ const GLubyte * errStr = glewGetErrorString(err); qDebug("Error: %s\n", errStr); } qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); if (wglewGetExtension("WGL_EXT_swap_control")) { int swapInterval = wglGetSwapIntervalEXT(); qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); } glGetError(); #endif _textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); _textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, TextRenderer::SHADOW_EFFECT); _textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, false, TextRenderer::OUTLINE_EFFECT); _textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0.2f, 0.2f, 0.2f, 1); glDisable(GL_DEPTH_TEST); _offscreenUi.create(_context); // FIXME, need to switch to a QWindow for mouse and keyboard input to work _offscreenUi.setProxyWindow(this); // "#0e7077" setFramePosition(QPoint(-1000, 0)); resize(QSize(800, 600)); static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/Root.qml"); _offscreenUi.loadQml(QUrl::fromLocalFile(f)); connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) { _offscreenUi.lockTexture(textureId); assert(!glGetError()); GLuint oldTexture = testQmlTexture; testQmlTexture = textureId; if (oldTexture) { _offscreenUi.releaseTexture(oldTexture); } }); installEventFilter(&_offscreenUi); _offscreenUi.resume(); } virtual ~QTestWindow() { } void draw(); void makeCurrent() { _context->makeCurrent(this); } protected: void resizeEvent(QResizeEvent * ev) override { resizeWindow(ev->size()); } void keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Slash: qDebug() << "Foo"; _offscreenUi.load(QString("Login.qml")); break; } QWindow::keyPressEvent(event); } }; #ifndef SERIF_FONT_FAMILY #define SERIF_FONT_FAMILY "Times New Roman" #endif static const wchar_t * EXAMPLE_TEXT = L"Hello"; //static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y"; static const glm::uvec2 QUAD_OFFSET(10, 10); static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { 1.0, 0.5, 0.5 }, { 0.5, 0.5, 1.0 } }; void QTestWindow::renderText() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, _size.width(), _size.height(), 0, 1, -1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const glm::uvec2 size = glm::uvec2(_size.width() / 2, _size.height() / 2); const glm::uvec2 offsets[4] = { { QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, }; QString str = QString::fromWCharArray(EXAMPLE_TEXT); for (int i = 0; i < 4; ++i) { glm::vec2 bounds = _textRenderer[i]->computeExtent(str); glPushMatrix(); { glTranslatef(offsets[i].x, offsets[i].y, 0); glColor3f(0, 0, 0); glBegin(GL_QUADS); { glVertex2f(0, 0); glVertex2f(0, bounds.y); glVertex2f(bounds.x, bounds.y); glVertex2f(bounds.x, 0); } glEnd(); } glPopMatrix(); const int testCount = 100; for (int j = 0; j < testCount; ++j) { // Draw backgrounds around where the text will appear // Draw the text itself _textRenderer[i]->draw(offsets[i].x, offsets[i].y, str.toLocal8Bit().constData(), glm::vec4(COLORS[i], 1.0f)); } } } void QTestWindow::renderQml() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (testQmlTexture > 0) { glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, testQmlTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } glBegin(GL_QUADS); { glTexCoord2f(0, 0); glVertex2f(-1, -1); glTexCoord2f(0, 1); glVertex2f(-1, 1); glTexCoord2f(1, 1); glVertex2f(1, 1); glTexCoord2f(1, 0); glVertex2f(1, -1); } glEnd(); } void QTestWindow::draw() { makeCurrent(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width(), _size.height()); renderText(); //renderQml(); _context->swapBuffers(this); glFinish(); fps.increment(); if (fps.elapsed() >= 2.0f) { //qDebug() << "FPS: " << fps.rate(); fps.reset(); } } int main(int argc, char** argv) { QApplication app(argc, argv); //QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true"); QTestWindow window; QTimer timer; timer.setInterval(1); app.connect(&timer, &QTimer::timeout, &app, [&] { window.draw(); }); timer.start(); app.exec(); return 0; } #include "main.moc"