2012-05-15 87 views
2

我正在尝试在OpenGL中编写UI,并在调整控件大小时遇到​​问题。缓冲区被破坏?

Texture errors

正如我缩面板,文字的质感似乎萎缩或破坏,并最终按钮做同样的。这些按钮并不依赖于窗口的大小,所以问题不在于计算大小。我打印了文本纹理和按钮尺寸的大小,并在测试过程中保持一致。

所以每次我调整窗口大小时,这里是正在发生的事情:

onResize 
    Delete TexturedRectangle object 
     | Delete 9 sprites (including vertex data) used for the TexturedRectangle 
     | Delete the RenderTexture 
    New TexturedRectangle Object 
     | Create 9 sprites (new vertex data) for the textured rectangle 
     | Render the rectangle using the 9 sprites to a new RenderTexture the size of the window 

我通过代码去,并确保创建新的缓冲区前,我删除掉GPU的旧数据。我的缓冲区是否已损坏,或者我正在渲染RenderTextures的方式不正确?我检查了glGetError()并且在运行时没有错误。这个问题可以用OpenGL堆栈吗?我无法确定问题出在哪里,因为当我调整窗口大小时,按钮没有改变。

Sprite::Sprite() 
    : ISprite(), mVbo(0) { 
    mDiffuse = ResourceCache::getSingleton().getTexture("Texture_NOTFOUND"); 
    createVbo(); 
} 

Sprite::Sprite(ITexture *diffuse, FloatRect textureBounds) 
    : ISprite(), mVbo(0) { 
    mDiffuse = diffuse; 

    if(textureBounds.x == 0 && textureBounds.y == 0) { 
     mTextureBounds = diffuse->getBounds(); 
    } else { 
     mTextureBounds = textureBounds; 
    } 

    createVbo(); 
} 

Sprite::~Sprite() { 
    glDeleteBuffers(1, &mVbo); 
} 

void Sprite::draw(IRenderTarget *target, RenderState *state) const { 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

    glBindBuffer(GL_ARRAY_BUFFER, mVbo); 

    switch(state->getRenderMode()) { 
    default: 
    case RenderState::DIFFUSE: 
     mDiffuse->bindTexture(); 
     break; 
    case RenderState::NORMAL_MAP: 
     mNormalMap->bindTexture(); 
     break; 
    case RenderState::HEIGHT_MAP: 
     mHeightMap->bindTexture(); 
     break; 
    }; 

    glPushMatrix(); 
    glTranslatef(mPosition.x, mPosition.y, mPosition.z); 
    glColor4f(mColor.r, mColor.g, mColor.b, mColor.a); 

    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x)); 
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx)); 

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 

    glPopMatrix(); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
    glDisableClientState(GL_VERTEX_ARRAY); 
} 

void Sprite::createVbo() { 
    if(mVbo != 0) { 
     glDeleteBuffers(1, &mVbo); 
    } 

    // Generate the VBO 
    glGenBuffers(1, &mVbo); 
    Vector2f size = getSize(); 

    float texW = mDiffuse->getWidth(); 
    float texH = mDiffuse->getHeight(); 
    float srcW = size.x/texW; 
    float srcH = size.y/texH; 


    // Calculate the vertices 
    Vertex verts[] = {{0.f, 0.f, 0.f, mTextureBounds.x/texW, mTextureBounds.y/texH}, 
         {size.x, 0.f, 0.f, (mTextureBounds.x/texW) + srcW, mTextureBounds.y/texH}, 
         {0.f, size.y, 0.f, mTextureBounds.x/texW, (mTextureBounds.y/texH) + srcH}, 
         {size.x, size.y, 0.f, (mTextureBounds.x/texW) + srcW, (mTextureBounds.y/texH) + srcH}}; 

    int vertSize = sizeof(verts); 

    // Bind the VBO 
    glBindBuffer(GL_ARRAY_BUFFER, mVbo); 

    // Submit the vertex data to the GPU 
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 4, &verts[0].x, GL_STATIC_DRAW_ARB); 

    // Unbind the VBO 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
} 

重复雪碧

RepeatingSprite::RepeatingSprite(Texture *diffuseTexture, FloatRect spriteBounds, int xRepeat, int yRepeat) 
    : ISprite(), mXRepeat(xRepeat), mYRepeat(yRepeat) { 
    mVbo = 0; 
    mDiffuse = diffuseTexture; 
    mTextureBounds = spriteBounds; 
    createVbo(); 
} 

RepeatingSprite::~RepeatingSprite() { 
    glDeleteBuffers(1, &mVbo); 
} 



void RepeatingSprite::draw(IRenderTarget *target, RenderState *state) const { 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

    glBindBuffer(GL_ARRAY_BUFFER, mVbo); 

    switch(state->getRenderMode()) { 
    default: 
    case RenderState::DIFFUSE: 
     mDiffuse->bindTexture(); 
     break; 
    case RenderState::NORMAL_MAP: 
     mNormalMap->bindTexture(); 
     break; 
    case RenderState::HEIGHT_MAP: 
     mHeightMap->bindTexture(); 
     break; 
    }; 

    glPushMatrix(); 
    glTranslatef(mPosition.x, mPosition.y, mPosition.z); 
    glColor4f(mColor.r, mColor.g, mColor.b, mColor.a); 

    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x)); 
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx)); 

    glDrawArrays(GL_QUADS, 0, (mXRepeat * mYRepeat) * 4); 

    glPopMatrix(); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
    glDisableClientState(GL_VERTEX_ARRAY); 
} 

void RepeatingSprite::createVbo() { 
    int totalRepeats = mXRepeat * mYRepeat; 
    float textureWidth = mDiffuse->getWidth(); 
    float textureHeight = mDiffuse->getHeight(); 
    Vertex *vertices = new Vertex[totalRepeats*4]; 

    int counter = 0; 
    // For each sprite count, create a quad 
    for(float y = 0; y < mYRepeat; y++) { 
     for(float x = 0; x < mXRepeat; x++) { 

      Vertex v1 = {x * mTextureBounds.w, 
         y * mTextureBounds.h, 0.f, 
         mTextureBounds.x/textureWidth, 
         mTextureBounds.y/textureHeight}; 

      Vertex v2 = {x * mTextureBounds.w + mTextureBounds.w, 
         y * mTextureBounds.h, 0.f, 
         (mTextureBounds.x/textureWidth) + (mTextureBounds.w/textureWidth), 
         mTextureBounds.y/textureHeight}; 

      Vertex v3 = {x * mTextureBounds.w, 
         y * mTextureBounds.h + mTextureBounds.h, 0.f, 
         mTextureBounds.x/textureWidth, 
         (mTextureBounds.y/textureHeight) + (mTextureBounds.h/textureHeight)}; 

      Vertex v4 = {x * mTextureBounds.w + mTextureBounds.w, 
         y * mTextureBounds.h + mTextureBounds.h, 0.f, 
         (mTextureBounds.x/textureWidth) + (mTextureBounds.w/textureWidth), 
         (mTextureBounds.y/textureHeight) + (mTextureBounds.h/textureHeight)}; 


      vertices[counter] = v1; 
      counter++; 
      vertices[counter] = v2; 
      counter++; 
      vertices[counter] = v4; 
      counter++; 
      vertices[counter] = v3; 
      counter++; 
     } 
    } 

    glGenBuffers(1, &mVbo); 

    glBindBuffer(GL_ARRAY_BUFFER, mVbo); 

    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * (totalRepeats*4), &vertices[0].x, GL_STATIC_DRAW_ARB); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    delete[] vertices; 
} 

渲染纹理

RenderTexture::RenderTexture(float width, float height) { 
    mWidth = width; 
    mHeight = height; 

    // Create the color buffer 
    glGenTextures(1, &mId); 
    glBindTexture(GL_TEXTURE_2D, mId); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)mWidth, (int)mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 
    glBindTexture(GL_TEXTURE_2D, 0); 

    // Create the framebuffer 
    glGenFramebuffers(1, &mFbo); 
    glBindFramebuffer(GL_FRAMEBUFFER, mFbo); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mId, 0); 

    GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
    assert(err == GL_FRAMEBUFFER_COMPLETE); // Make sure texture is valid 

    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
} 

RenderTexture::~RenderTexture() { 
    glDeleteBuffers(1, &mFbo); 
    glDeleteTextures(1, &mId); 
    mFbo = 0; 
} 


void RenderTexture::preDraw() { 
    // store the glViewport and glEnable states 
    glPushAttrib(GL_VIEWPORT_BIT); 

    // Bind the frame buffer 
    //glBindTexture(GL_TEXTURE_2D, 0); 
    glBindFramebuffer(GL_FRAMEBUFFER, mFbo); 

    // Save the current matrix 
    glPushMatrix(); 
    glLoadIdentity(); 

    // Setup the projection matrix for the render target 
    glMatrixMode(GL_PROJECTION); 
    glPushMatrix(); 
    glLoadIdentity(); 
    glViewport(0, 0, (int)mWidth, (int)mHeight); 
    glOrtho(0, mWidth, 0.f, mHeight, 0.f, 100.f); 

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 
    glDrawBuffer(GL_COLOR_ATTACHMENT0); 
} 

void RenderTexture::postDraw() { 
    // Pop the render target's projection matrix off the stack 
    glPopMatrix(); 
    // Restore previouse projection matrix 
    glPopMatrix(); 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
    // Restore the previous viewport settings 
    glPopAttrib(); 
} 
+0

C 0 d即 – vines

回答

2

在OpenGL中,当您将转换某种为对象,看看其它物体的影响,一个好地方开始寻找是你的变换和栈操作逻辑。

所以在RenderTexture::preDraw()您有:

glPushMatrix(); 
// ... 
glMatrixMode(GL_PROJECTION); 
glPushMatrix(); 

RenderTexture::postDraw()

glPopMatrix(); 
// Restore previouse projection matrix 
glPopMatrix(); 

,而不在它们之间glMatrixMode()任何呼叫。

它不会像这样正常工作。每个矩阵模式都有自己的堆栈,所以第二个glPopMatrix()会弹出错误的堆栈。

你需要去类似:F I R式T

glPopMatrix(); 
glMatrixMode(GL_MODELVIEW); 
glPopMatrix();