计算机图形学 实验5 《显示列表》

计算机图形学 实验5 《显示列表》

一、实验目的

学习加快图形显示的显示列表技术。

二、实验内容

1、用显示列表输出文字;
2、用显示列表显示图形。

三、实验方法

OpenGL并没有直接提供显示文字的功能,并且,OpenGL也没有自带专门的字库。因此,要显示文字,就必须依赖操作系统所提供的功能。各种流行的图形操作系统,例如 Windows系统和 Linux系统,都提供了一些功能,以便能够在 OpenGL程序中方便的显示文字。

最常见的方法就是,我们给出一个字符,给出一个显示列表编号,然后操作系统由把绘制这个字符的 OpenGL命令装到指定的显示列表中。当需要绘制字符的时候,我们只需要调用这个显示列表即可。假如我们要显示的文字全部是 ASCII字符,则总共只有 0到 127这 128种可能,因此可以预先把所有的字符分别装到对应的显示列表中,然后在需要时调用这些显示列表即可。

四、实验步骤

1、准备好绘制文字/图形的显示列表,(如果输出文字)申请MAX_CHAR个连续的显示列表编号,并把每个字符的绘制命令都装到对应的显示列表中;(如果输出图形)将绘制图形的各个函数装入显示列表;
2、绘制时执行显示列表,使用callList函数。

五、实验结果与实验结论

实验输出图(部分是解释):
1、使用显示列表显示文字:


关键代码:

#define MAX_CHAR       128

void drawString(const char* str) {
    static int isFirstCall = 1;
    static GLuint lists;
    if (isFirstCall) { // 如果是第一次调用,执行初始化
        // 为每一个ASCII字符产生一个显示列表
        isFirstCall = 0;
        // 申请MAX_CHAR个连续的显示列表编号
        lists = glGenLists(MAX_CHAR);
        // 把每个字符的绘制命令都装到对应的显示列表中
        wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
    }

    // 调用每个字符对应的显示列表,绘制每个字符
    for (; *str != '\0'; ++str)
        glCallList(lists + *str);

}

void selectFont(int size, int charset, const char* face) {
    HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,
        charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
        DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);

    HFONT hOldFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);
    DeleteObject(hOldFont);
}

void display(void) {
    selectFont(48, ANSI_CHARSET, "Comic Sans MS");
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0f, 1.0f, 1.0f);
    glRasterPos2f(0.0f, 0.0f);
    drawString("Hello FALL GUYS!");
    glutSwapBuffers();	
}

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0); /* select clearing olor  */
    //  glMatrixMode(GL_PROJECTION); /* initialize viewing values  */
    //  glLoadIdentity();
    //  glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //注意该视景体的范围和几何中心
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(500, 500); //改为glutInitWindowSize (250, 250); 可以看出这个变换仅仅是物体按比例大小的变换
    glutInitWindowPosition(100, 100);
    glutCreateWindow("First");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

2、使用显示列表显示图形


关键源码:
GLuint listName;

static void init(void)
{
    listName = glGenLists(1);
    glNewList(listName, GL_COMPILE);
    glColor3f(1.0, 0.0, 0.0);  /*  current color red  */
    glBegin(GL_TRIANGLES);
    glVertex2f(0.0, 0.0);
    glVertex2f(1.0, 0.0);
    glVertex2f(0.0, 1.0);
    glEnd();
    glTranslatef(1.5, 0.0, 0.0); /*  move position  */
    glEndList();
    glShadeModel(GL_FLAT);
}

static void drawLine(void)
{
    glBegin(GL_LINES);
    glVertex2f(0.0, 0.5);
    glVertex2f(15.0, 0.5);
    glEnd();
}

void display(void)
{
    if (1) {
        GLuint i;

        glClear(GL_COLOR_BUFFER_BIT);
        glColor3f(0.0, 1.0, 0.0);  /*  current color green  */
        for (i = 0; i < 10; i++)    /*  draw 10 triangles    */
            glCallList(listName);
        drawLine();  /*  is this line green?  NO!  */
                      /*  where is the line drawn?  */
        glFlush();
    }
}

void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        gluOrtho2D(0.0, 2.0, -0.5 * (GLfloat)h / (GLfloat)w,
            1.5 * (GLfloat)h / (GLfloat)w);
    else
        gluOrtho2D(0.0, 2.0 * (GLfloat)w / (GLfloat)h, -0.5, 1.5);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case 27:
        exit(0);
        break;
    }
}

/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(650, 50);
    glutCreateWindow(argv[0]);
    init();
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}

六、实验小结

本次实验主要是了解了显示列表的装载、callList函数的使用等。使用显示列表一般有四个步骤:分配一个未使用的显示列表编号,把OpenGL函数装入显示列表来创建显示列表,调用显示列表,销毁显示列表。显示列表一旦产生就一直存在(除非调用glDeleteLists函数进行销毁),所以我们只需要在第一次调用的时候初始化,以后就可以很方便的调用这些显示列表来绘制字符了。Windows系统中,可以使用wglUseFontBitmaps函数来批量的产生显示字符用的显示列表。

在图形图像中显示列表表示一组存储在一起的OpenGL函数,可以创建后再多次调用,以提高绘图效率,节省计算机的处理资源。调用一个显示列表时,它所存储的函数就会按照顺序执行。使用显示列表,可以一次定义几何图形(或状态更改),并在以后多次执行它们。
显示列表的局限性在于是存储OpenGL函数调用的一种高速的缓存,而非动态的数据仓库,因此显示列表不能够进行动态的修改。例如,创建物体的变形动画或者删除某些定点的图元时,都需要销毁和重新建立相应的显示列表,反而因此降低了动态模型绘制的性能。并且由于调用显示列表时程序本身也有一些开销,尤其是当一个显示列表太小会导致系统开销超过列表的优越性,所以并不是只要调用显示列表就能优化程序性能。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值