2012-05-15 85 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();