int main() { initGL(); GLuint texHandle = genTexture(); renderHandle = genRenderProg(texHandle); computeHandle = genComputeProg(texHandle); for (int i = 0; i < 1024; ++i) { updateTex(i); draw(); } return 0; }
bool TCOD_opengl_render( int oldFade, bool *ascii_updated, char_t *console_buffer, char_t *prev_console_buffer) { int x,y,i; int fade = (int)TCOD_console_get_fade(); bool track_changes=(oldFade == fade && prev_console_buffer); char_t *c=console_buffer; char_t *oc=prev_console_buffer; int ascii; /* update opengl data */ /* TODO use function pointers so that libtcod's putchar directly updates opengl data */ for (y=0;y<conheight;y++) { for (x=0; x<conwidth; x++) { bool changed=true; if ( c->cf == -1 ) c->cf = TCOD_ctx.ascii_to_tcod[c->c]; if ( track_changes ) { changed=false; if ( c->dirt || ascii_updated[ c->c ] || c->back.r != oc->back.r || c->back.g != oc->back.g || c->back.b != oc->back.b || c->fore.r != oc->fore.r || c->fore.g != oc->fore.g || c->fore.b != oc->fore.b || c->c != oc->c || c->cf != oc->cf) { changed=true; } } c->dirt=0; if ( changed ) { TCOD_opengl_putchar_ex(x,y,c->cf,c->fore,c->back); } c++;oc++; } } /* check if any of the textures have changed since they were last uploaded */ for( i = 0; i< ConsoleDataEnumSize; i++) { if(dirty[i]) { updateTex((ConsoleDataEnum)i); dirty[i] = false; } } if ( TCOD_ctx.renderer == TCOD_RENDERER_OPENGL ) { /* fixed pipeline for video cards without pixel shader support */ /* draw the background as a single quad */ float texw=(float)conwidth/POTconwidth; float texh=(float)conheight/POTconheight; float fonw=(float)fontwidth/(TCOD_ctx.fontNbCharHoriz*POTfontwidth); float fonh=(float)fontheight/(TCOD_ctx.fontNbCharVertic*POTfontheight); char_t *c; DBGCHECKGL(glBindTexture(GL_TEXTURE_2D, Tex[BackCol])); DBGCHECKGL(glBegin(GL_QUADS); glColor3f(1.0,1.0,1.0); glTexCoord2f( 0.0, 0.0 ); glVertex2i( 0, 0); glTexCoord2f( 0.0, texh); glVertex2i( 0, conheight ); glTexCoord2f( texw, texh ); glVertex2i( conwidth, conheight); glTexCoord2f( texw, 0.0 ); glVertex2i( conwidth, 0 ); glEnd()); /* draw the characters (one quad per cell) */ DBGCHECKGL(glBindTexture(GL_TEXTURE_2D, font_tex)); c=console_buffer; for (y=0;y<conheight;y++) { for (x=0; x<conwidth; x++) { if ( c->c != ' ' ) { TCOD_color_t f=c->fore; TCOD_color_t b=c->back; /* only draw character if foreground color != background color */ if ( f.r != b.r || f.g != b.g || f.b != b.b ) { int srcx,srcy,destx,desty; destx=x;/* *TCOD_font_width; */ desty=y;/* *TCOD_font_height; */ if ( TCOD_ctx.fullscreen ) { destx+=TCOD_ctx.fullscreen_offsetx/TCOD_ctx.font_width; desty+=TCOD_ctx.fullscreen_offsety/TCOD_ctx.font_height; } /* draw foreground */ ascii=c->cf; srcx = (ascii%TCOD_ctx.fontNbCharHoriz); srcy = (ascii/TCOD_ctx.fontNbCharHoriz); glBegin( GL_QUADS ); glColor3f((GLfloat)(f.r/255.0), (GLfloat)(f.g/255.0), (GLfloat)(f.b/255.0)); glTexCoord2f( srcx*fonw, srcy*fonh ); glVertex2i( destx, desty); glTexCoord2f( srcx*fonw, (srcy+1)*fonh ); glVertex2i( destx, desty+1 ); glTexCoord2f( (srcx+1)*fonw, (srcy+1)*fonh ); glVertex2i( destx+1, desty+1 ); glTexCoord2f( (srcx+1)*fonw, srcy*fonh ); glVertex2i( destx+1, desty ); glEnd(); } } c++; } } DBGCHECKGL(glBindTexture(GL_TEXTURE_2D, 0)); } else {
//大部分迷宫建设,以及旋转处理等工作都是在Update()函数中完成的。 //我们需要设置一个变量dir, 用它来表示记录随机的向上,向右,向下或向左值。 void MyGLWidget::timerEvent(QTimerEvent *event) { //xrot,yrot和zrot通过和一些小浮点数相乘而随着时间的消逝而增加。这样我们可以让物体绕x轴,y轴和z轴旋转。每个变量都增加不同的值使旋转好看一点 m_xrot+=(float)(15)*0.02f; m_yrot+=(float)(15)*0.03f; m_zrot+=(float)(15)*0.015f; //下面的代码用来检测我们是否画完了迷宫。我们开始设置done值为true, 然后循环检查每一个房间去看是否需要增加一面墙,如果有一间房还有被访问到,我们设置done为false. //如果tex_data[(x + (width*y))*3]的值为0, 我们就明白这个房间还没被访问到,而且没有在里面没有画一个象素。 //如果这儿有一个象素,那么它的值为255。我们只需要检查它的颜色红色分量值。因为我们知道这个值只能为0(空)或者255(更新过) bool done = true;// 循环所有的纹理素,如果为0则表示没有绘制完所有的迷宫,返回 for (int x=0; x<mazeWidth; x+=2) { for (int y=0; y<mazeHeight; y+=2) { if (m_tex_data[((x+(mazeWidth*y))*3)]==0) done=FALSE; } } //检查完所有的房间之后,如果done为true.那么迷宫就算建完了,SetWindowsText就会改变窗口的标题。我们改变标题为"迷宫建造完成!"。 //然后我们停顿5000毫秒使看这个例子的人有时间来看标题栏上的字(如果在全屏状态,他们会看到动画停顿了)。 if (done) //如果完成停止五秒后重置 { setWindowTitle("Maze Complete!"); Sleep(5000); setWindowTitle("Building Maze!"); reset(); } else { setWindowTitle("Building Maze!"); } //下面的代码也许让人看着糊涂,但其实并不难懂。我们检查当前房间的右边房间是否被访问过或者是否当前位置的右边是迷宫的右边界(当前房间右边的房间就不存在), //同样检查左边的房间是否访问过或者是否达到左边界。其它方向也作如此检查。 //如果房间颜色的红色分量的值为255,就表示这个房间已经被访问过了(因为它已经被函数UpdateTex更新过)。如果mx(当前x坐标)小于2, 就表示我们已经到了迷宫最左边不能再左了。 //如果往四个方向都不能移动了或以已经到了边界,就给mx和my一个随机值,然后检查这个值对应点是否被访问,如果没有,我们就重新寻找一个新的随机变量, //直到该变量对应的单元早已经被访问。因为需要从旧的路径中分叉出新的路径,所以我们必须保持搜素知道发觉有一老的路径可以从那里开始新的路径。 //为了使代码尽量简短,我没有打算去检查mx-2是否小于0。如果你想有100%的错误检测,你可以修改这段代码阻止访问不属于当前贴图的内存。 //检测是否走过这里 if (((m_tex_data[(((m_mx+2)+(mazeWidth*m_my))*3)]==255) || m_mx>(mazeWidth-4)) && ((m_tex_data[(((m_mx-2)+(mazeWidth*m_my))*3)]==255) || m_mx<2) && ((m_tex_data[((m_mx+(mazeWidth*(m_my+2)))*3)]==255) || m_my>(mazeHeight-4)) && ((m_tex_data[((m_mx+(mazeWidth*(m_my-2)))*3)]==255) || m_my<2)) { do { m_mx=int(rand()%(mazeWidth/2))*2; m_my=int(rand()%(mazeHeight/2))*2; } while (m_tex_data[((m_mx+(mazeWidth*m_my))*3)]==0); } //下面这行代码赋给dir变量0-3之间的随机值,这个值告诉我们该往右,往上,往左还是往下画迷宫。 //在得到随机的方向之后,我们检查dir的值是否为0(往右移),如果是并且我们不在迷宫的右边界, //然后检查当前房间的右边房间,如果没被访问,我们就调用UpdateTex(mx+1,my)在两个房间之间建立一堵墙,然后mx增加2移到新的房间. int dir=int(rand()%4);// 随机一个走向 if ((dir==0) && (m_mx<=(mazeWidth-4))) // 向右走,更新数据 { if (m_tex_data[(((m_mx+2)+(mazeWidth*m_my))*3)]==0) { updateTex(m_mx+1,m_my); m_mx+=2; } } //如果dir的值为1(往下),并且我们不在迷宫底部,我们检查当前房间的下面房间是否被访问过。 //如果没被访问过,我们就在两个房间(当前房间和当前房间下面的房间)建立一堵墙。然后my增加2移到新的房间. if ((dir==1) && (m_my<=(mazeHeight-4))) // 向下走,更新数据 { if (m_tex_data[((m_mx+(mazeWidth*(m_my+2)))*3)]==0) { updateTex(m_mx,m_my+1); m_my+=2; } } //如果dir的值为2(向左)并且我们不在左边界,我们就检查左边的房间是否被访问,如果没被访问,我们也在两个房间(当前房间和左边的房间)之间建立一堵墙,然后mx减2移到新的房间. if ((dir==2) && (m_mx>=2)) // 向左走,更新数据 { if (m_tex_data[(((m_mx-2)+(mazeWidth*m_my))*3)]==0) { updateTex(m_mx-1,m_my); m_mx-=2; } } //如果dir的值为3并且不在迷宫的最顶部,我们检?榈鼻胺考涞纳厦媸欠癖环梦剩绻挥校蛟诹礁龇考?(当前房间和当前房间上面个房间)之间建立一堵墙,然后my增加2移到新的房间。 if ((dir==3) && (m_my>=2)) // 向上走,更新数据 { if (m_tex_data[((m_mx+(mazeWidth*(m_my-2)))*3)]==0) { updateTex(m_mx,m_my-1); m_my-=2; } } //移到新的房间后,我们必须标志当前房间为正在访问状态。我们通过调用以当前位置mx, my为参数的UpdateTex()函数来达到这个目的。 updateTex(m_mx,m_my); // 更新纹理 updateGL(); QGLWidget::timerEvent(event); }