2010-01-29 30 views
5

Tôi có một ứng dụng nghệ thuật opengl mà tôi đang làm việc. Sản phẩm cuối cùng sẽ không cần hiển thị văn bản. Nhưng trong quá trình phát triển, tôi muốn hiển thị các bit dữ liệu lẻ cho các mục đích chẩn đoán, như tốc độ khung hình, số đối tượng. Tôi muốn hiển thị văn bản không làm giảm đáng kể hiệu suất của mã.Cách tốt nhất để hiển thị văn bản chẩn đoán trong Windows OpenGL

Tôi nhận ra đây là một câu hỏi nhẹ nhàng chủ quan, nhưng tất cả cùng tôi sẽ đánh giá cao những suy nghĩ của bạn

Trả lời

1

Nếu bạn cần nó chỉ trong quá trình phát triển, bạn có thể muốn kiểm tra chức năng Win32 OutputDebugString(). Nó sẽ gửi văn bản đến một trình gỡ lỗi đính kèm và không yêu cầu thay đổi chương trình hiện tại của bạn. Bạn cũng có thể xây dựng chương trình của bạn như là một ứng dụng giao diện điều khiển và chỉ cần viết văn bản để stdout (printf, std :: cout). Điều này có thể không đẹp như một trình kết xuất văn bản OpenGL tùy chỉnh, nhưng nó đơn giản như nó được.

7

tôi đã viết một renderer văn bản OpenGL chỉ sử dụng nguyên thủy gl_line nếu phù hợp với nhu cầu của bạn:

#ifndef SIMPLETEXT_H 
#define SIMPLETEXT_H 

#include <GL/gl.h> 

namespace SimpleText { 

    // internal vertex 
    union vertex { 
     float data[3]; 
    }; 

    // use 15 verts to hold all possible letters 
    // 0 - 1 - 2 
    // 3 - 4 - 5 
    // 6 - 7 - 8 
    // 9 - 10- 11 
    // 12- 13- 14 
    vertex verts[15] = { 
     {0, 4, 0}, {1, 4, 0}, {2, 4, 0}, 
     {0, 3, 0}, {1, 3, 0}, {2, 3, 0}, 
     {0, 2, 0}, {1, 2, 0}, {2, 2, 0}, 
     {0, 1, 0}, {1, 1, 0}, {2, 1, 0}, 
     {0, 0, 0}, {1, 0, 0}, {2, 0, 0} 
    }; 

    // start/end char values 
    const int START = 33; 
    const int END = 90; 

    // size of the window (assumed square) 
    // increase this to decrease the size of text 
    const int WINDOW_EXTENT = 300; 

    // use index arrays to create letters 
    unsigned int letters[END - START + 1][15] = { 
     {4, 1, 7, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // ! 
     {4, 1, 4, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // " 
     {8, 0, 12, 2, 14, 3, 5, 9, 11, 0, 0, 0, 0, 0, 0},  // # 
     {8, 2, 3, 3, 11, 11, 12, 1, 13, 0, 0, 0, 0, 0, 0}, // $ 
     {14, 2, 12, 0, 3, 3, 1, 1, 0, 11, 13, 13, 14, 14, 11}, // % 
     {14, 14, 3, 3, 1, 1, 7, 7, 9, 9, 12, 12, 13, 13, 11}, // & 
     {2, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // ' 
     {6, 1, 3, 3, 9, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0},  // (
     {6, 1, 5, 5, 11, 11, 13, 0, 0, 0, 0, 0, 0, 0, 0},  //) 
     {6, 0, 8, 6, 2, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0},  // * 
     {4, 6, 8, 4, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // + 
     {2, 10, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // , 
     {2, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // - 
     {8, 12, 13, 13, 10, 10, 9, 9, 12, 0, 0, 0, 0, 0, 0}, // . 
     {2, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  ///
     {10, 0, 2, 2, 14, 14, 12, 12, 0, 0, 14, 0, 0, 0, 0}, // 0 
     {6, 3, 1, 1, 13, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0},  // 1 
     {10, 3, 1, 1, 5, 5, 8, 8, 12, 12, 14, 0, 0, 0, 0}, // 2 
     {12, 0, 1, 1, 5, 5, 11, 11, 13, 13, 12, 8, 7, 0, 0}, // 3 
     {6, 14, 2, 2, 6, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0},  // 4 
     {12, 2, 0, 0, 6, 6, 7, 7, 11, 11, 13, 13, 12, 0, 0}, // 5 
     {14, 2, 1, 1, 3, 3, 12, 12, 13, 13, 11, 11, 7, 7, 6}, // 6 
     {4, 0, 2, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // 7 
     {12, 1, 3, 3, 11, 11, 13, 13, 9, 9, 5, 5, 1, 0, 0}, // 8 
     {10, 2, 1, 1, 3, 3, 7, 7, 8, 2, 14, 0, 0, 0, 0},  // 9 
     {4, 1, 4, 10, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // : 
     {4, 1, 4, 10, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // ; 
     {4, 5, 6, 6, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // < 
     {4, 5, 3, 9, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // = 
     {4, 3, 8, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // > 
     {8, 3, 1, 1, 5, 5, 7, 7, 10, 0, 0, 0, 0, 0, 0},  // ? 
     {14, 4, 7, 7, 8, 8, 5, 5, 1, 1, 3, 3, 9, 9, 14},  // @ 
     {10, 1, 6, 1, 8, 6, 12, 8, 14, 6, 8, 0, 0, 0, 0},  // A 
     {14, 0, 12, 0, 5, 5, 7, 7, 6, 7, 11, 11, 13, 13, 12}, // B 
     {10, 2, 1, 1, 3, 3, 9, 9, 13, 13, 14, 0, 0, 0, 0}, // C 
     {12, 0, 1, 1, 5, 5, 11, 11, 13, 13, 12, 12, 0, 0, 0}, // D 
     {8, 0, 12, 0, 2, 6, 7, 12, 14, 0, 0, 0, 0, 0, 0},  // E 
     {6, 0, 12, 0, 2, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0},  // F 
     {14, 2, 1, 1, 3, 3, 9, 9, 13, 13, 11, 11, 8, 8, 7}, // G 
     {6, 0, 12, 6, 8, 2, 14, 0, 0, 0, 0, 0, 0, 0, 0},  // H 
     {6, 0, 2, 1, 13, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0},  // I 
     {8, 1, 2, 2, 11, 11, 13, 13, 9, 0, 0, 0, 0, 0, 0}, // J 
     {6, 0, 12, 6, 2, 6, 14, 0, 0, 0, 0, 0, 0, 0, 0},  // K 
     {4, 0, 12, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // L 
     {8, 0, 12, 0, 7, 7, 2, 2, 14, 0, 0, 0, 0, 0, 0},  // M 
     {6, 0, 12, 0, 14, 14, 2, 0, 0, 0, 0, 0, 0, 0, 0},  // N 
     {12, 1, 5, 5, 11, 11, 13, 13, 9, 9, 3, 3, 1, 0, 0}, // O 
     {10, 0, 12, 0, 1, 1, 5, 5, 7, 7, 6, 0, 0, 0, 0},  // P 
     {12, 0, 12, 12, 13, 13, 11, 11, 2, 2, 0, 10, 14, 0, 0}, // Q 
     {12, 0, 12, 0, 1, 1, 5, 5, 7, 7, 6, 7, 14, 0, 0},  // R 
     {14, 2, 1, 1, 3, 3, 6, 6, 8, 8, 11, 11, 13, 13, 12}, // S 
     {4, 0, 2, 1, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // T 
     {8, 0, 9, 9, 13, 13, 11, 11, 2, 0, 0, 0, 0, 0, 0}, // U 
     {4, 0, 13, 13, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // V 
     {8, 0, 12, 12, 1, 1, 14, 14, 2, 0, 0, 0, 0, 0, 0}, // W 
     {4, 0, 14, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  // X 
     {6, 0, 7, 7, 2, 7, 13, 0, 0, 0, 0, 0, 0, 0, 0},  // Y 
     {6, 0, 2, 2, 12, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0}  // Z 
    }; 

} 

// Draws a string of length <len> at an <x>/<y> position on the screen, optionally with a <shadow> 
// The screen is set up to be 0,0 at the lower left and 150,150 at the upper right for positioning 
// by default. 
static void DrawText(const char * string, int len, float x, float y, bool shadow = false) { 
    if (len <= 0) return; 

    glPushMatrix(); 
    glLoadIdentity(); 

    glMatrixMode(GL_PROJECTION); 
    glPushMatrix(); 

    glLoadIdentity(); 
    glOrtho(0, SimpleText::WINDOW_EXTENT, 0, SimpleText::WINDOW_EXTENT, -10, 10); 

    glMatrixMode(GL_MODELVIEW); 

    glBindTexture(GL_TEXTURE_2D, 0); 

    glVertexPointer(3, GL_FLOAT, 0, SimpleText::verts); 
    glEnableClientState(GL_VERTEX_ARRAY); 

    char temp = 0; 

    // draw first copy if we need a shadow 
    if (shadow) { 
     glTranslatef(x + 0.3, y - 0.5, 0); 
     glColor4f(0.0f, 0.0f, 0.0f, 1.0f); 

     for (int i = 0; i < len; i++) { 
     temp = string[i]; 
     temp = (temp < 97) ? temp : temp - 32; 
     if (temp >= SimpleText::START && temp <= SimpleText::END) { 

      glDrawElements(
       GL_LINES, 
       SimpleText::letters[temp - SimpleText::START][0], 
       GL_UNSIGNED_INT, 
       &(SimpleText::letters[temp - SimpleText::START][1]) 
      ); 
     } 

     glTranslatef(2.7f, 0, 0); 
     } 
    } 

    glLoadIdentity(); 
    glTranslatef(x, y, 0); 
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 

    // draw regular text 
    for (int i = 0; i < len; i++) { 
     temp = string[i]; 
     temp = (temp < 97) ? temp : temp - 32; 
     if (temp >= SimpleText::START && temp <= SimpleText::END) { 

     glDrawElements(
      GL_LINES, 
      SimpleText::letters[temp - SimpleText::START][0], 
      GL_UNSIGNED_INT, 
      &(SimpleText::letters[temp - SimpleText::START][1]) 
     ); 
     } 

     glTranslatef(2.7f, 0, 0); 
    } 

    glDisableClientState(GL_VERTEX_ARRAY); 


    glMatrixMode(GL_PROJECTION); 
    glPopMatrix(); 

    glMatrixMode(GL_MODELVIEW); 
    glPopMatrix(); 
} 

#endif 
+0

Tôi nên lưu ý rằng điều này đã được thử nghiệm làm việc trên Linux và Windows và có lẽ nên làm việc trên bất cứ thứ gì hợp lý. Tôi chưa thử nghiệm hiệu suất nhưng nó phải hợp lý trong hầu hết các môi trường. –

+0

Người đăng tải đã đề cập đến hiệu suất đó là một vấn đề. Nó sẽ không được dễ dàng hơn để chỉ cần sprintf văn bản cần thiết vào một bộ đệm char [] và sau đó sử dụng chức năng hiển thị văn bản tích hợp của OpenGL (GLRasterPos, glutBitmapCharacter)? Bằng cách này là nguyên thủy hơn nhiều, và có lẽ ít hiệu quả hơn. – AndyG

+1

Điều này được thiết kế cho các hệ thống muốn văn bản gỡ lỗi nhanh mà không phải lo lắng về thư viện bên ngoài hoặc mã hệ điều hành đa nền tảng. Có chắc chắn là cách tốt hơn để hiển thị văn bản nhưng khi bạn chỉ cần để có được một cái gì đó trên màn hình để xem những gì đang xảy ra nó hiện công việc tốt. Điều đó nói rằng OpenGL không có 'dựng sẵn' văn ​​bản dựng hình. GLUT có giao diện hiển thị văn bản và hệ điều hành cung cấp các cơ sở trong một số trường hợp (glXUseXFont hoặc wglFontBitmaps) nhưng điều này có lợi thế của các cuộc gọi C++ và OpenGL thuần túy. –

1

Do bạn đang thực hiện điều này trên Windows, cách dễ dàng để xử lý mọi thứ là sử dụng wglUseFontBitmaps để tải một tập hợp các ký tự vào danh sách hiển thị, sau đó glRasterPos2i để chọn vị trí vẽ văn bản và glCallLists để vẽ một chuỗi. Nếu bạn muốn một cái gì đó huyền ảo hơn so với chẩn đoán, bạn có thể sử dụng wglUseFontOutlines để có được một chút fancier, chẳng hạn như tạo văn bản 2.5D (ép đùn).

0

Lấy 8x8 CP437 glyph và dán chúng (theo thứ tự ASCII) trong kết cấu 128x128. Kể từ khi chúng được đóng gói chặt chẽ, hãy chắc chắn để biến lọc bilinear hoặc người nào khác bạn sẽ nhận được chảy máu vào glyphs liền kề.

Các vấn đề liên quan