2016-11-15 16 views
1

OpenGL과 SDL을 사용하려고 시도 중입니다. SDL_ttf를 사용하여 텍스트를 텍스처로 렌더링하려고하지만 코드가 쓰레기를 렌더링 중입니다. 텍스처에 쓰레기를 렌더링하는 SDL_TTF

내 "질감 코드 렌더링"

GLuint textToTexture(std::string & text, TTF_Font* font, glm::vec4 textColour, glm::vec4 bgColour) 
{ 
    if (!TTF_WasInit()) 
    { 
     if (TTF_Init() == -1) 
      exit(6); 
    } 
    SDL_Color colour = { (Uint8)(textColour.r*255), (Uint8)(textColour.g*255), (Uint8)(textColour.b*255), (Uint8)(textColour.a*255) }; 
    SDL_Color bg = { (Uint8)(bgColour.r*255), (Uint8)(bgColour.g*255), (Uint8)(bgColour.b*255), (Uint8)(bgColour.a*255) }; 

    SDL_Surface *stringImage = NULL; 
    stringImage = TTF_RenderText_Blended(font, text.c_str(), colour); 

    if (stringImage == NULL) 
    { 
     exit(5); 
    } 

    GLuint trueH = powerofTwo(stringImage->h); 
    GLuint trueW = powerofTwo(stringImage->w); 
    unsigned char* pixels = NULL; 
    GLuint w = stringImage->w; 
    GLuint h = stringImage->h; 
    GLuint colours = stringImage->format->BytesPerPixel; 
    pixels = padTexture((unsigned char*)stringImage->pixels, w, h, pixels, trueW, trueH, colours); 
    GLuint format, internalFormat; 
    if (colours == 4) { 

     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGBA; 
     else 
      format = GL_BGRA; 
    } 
    else {  

     // no alpha 
     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGB; 
     else 
      format = GL_BGR; 
    } 
    internalFormat = (colours == 4) ? GL_RGBA : GL_RGB; 


    GLuint texId = 0; 
    //GLuint texture; 

    glGenTextures(1, &texId); 

    glBindTexture(GL_TEXTURE_2D, texId); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0,format, GL_UNSIGNED_BYTE, pixels); 

    // SDL surface was used to generate the texture but is no longer 
    // required. Release it to free memory 
    SDL_FreeSurface(stringImage); 
    free(pixels) 
    return texId; 
} 

패딩에 대한 정확한 크기를 계산하기위한 코드 :

int powerofTwo(int num) 
{ 
    if (num != 0) 
    { 
     num--; 
     num |= num >> 1; // Divide by 2^k for consecutive doublings of k up to 32, 
     num |= num >> 2; // and then or the results. 
     num |= num >> 4; 
     num |= num >> 8; 
     num |= num >> 16; 
     num++; 
    } 
    return num; 
} 

과 마지막 코드 것을의 질감 복사 바이트 ! [왜곡 질감] [1 : 정확한 치수 : 다음

unsigned char* padTexture(unsigned char * src, int srcW, int srcH, unsigned char * dest, int width, int height, int bpp) 
{ 
    dest = (unsigned char*)calloc(1, width*height*bpp); 
    for (int i = 0; i < srcH; i++) 
    { 
     memcpy(dest + (width*i*bpp),src + (srcW*i*bpp), srcW*bpp); 
    } 
    return dest; 
} 

이 코드의 결과는 ]] [1]

SDL_TTF가 코드베이스의 다른 곳에서 제대로 초기화되었고 글꼴도로드되고 있는지 확인하고 오류를 확인했습니다. 동일한 결과를 가진 세 가지 다른 ttf 글꼴로 테스트했습니다. I 다른 TTF_rendering 기능 (음영 솔리드 등)을 사용하는 경우에도

, 고체 쿼드 렌더링되고 textToTexture 함수의 "색상"변수도 추가 1.

로 끝낸다 :

MavenPro - 일반, 내가 인터넷을 발견 HelveticaNeueLTStd - 목

다른 : 나는 이전에 언급 한 바와 같이

, 나는 세 TTF 폰트 테스트. "Select Scenario"문자열을 렌더링하려고했습니다.

미리 패딩 된 이미지 크기는 138x25 픽셀입니다.

채워진 이미지 크기는 256x32 픽셀입니다.

업데이트 1 : 다음과 같이

BPP 문제를 해결 한 후 새로운 질감은 다음과 같습니다

New garbled

이 이미지는 내가 프로그램을 실행할 때마다 변경됩니다.

업데이트 2 : 나는 TTF_RenderText_Shaded를 사용할 때 이미지를 패딩, 나는 내가 할 모든 검은 쿼드이며, TTF_RenderText_Blended를 사용하는 경우, 텍스처 자체에 픽셀 데이터를 설정하여 추가 발견 된 오류를 수정 한 후 내가 얻을 :

enter image description here

업데이트 3 :

내가 immedietly GL의 코드를 호출하기 전에 및 SDL_RenderText_Blended를 호출 한 후 SDL_SaveBMP를 사용, 결과는 (이 텍스트 색상 지정) 완전히 흰색 이미지였다.

TTF_RenderText_Solid을 사용하여 동일한 작업을 수행 할 때 저장된 이미지는 그대로 유지되지만 위의 이미지처럼 OpenGL에 의해 렌더링됩니다.

SDL_TTF를 초기화하면 오류없이 글꼴이로드되고 텍스트 렌더링이 오류를 반환하지 않으므로 다음에 수행 할 작업을 생각할 수 없습니다.

업데이트 4 : (현대 OpenGL은 그것에 대해 상관하지 않는 한) 내가 있기 때문에 하나의 함수로 모든 TTF 코드를 리팩토링과 패딩 코드를 제거한

. 그러나 모든 프로젝트 설정과 코드가 동일한 하드웨어에서 작동하는 것으로 알려진 테스트 프로젝트와 동일하지만이 문제는 계속 발생합니다.

GLuint textToTexture(const char * text, const char * font, glm::vec4 textColour, glm::vec4 bgColour, unsigned int & texID) 
{ 
    if (!TTF_WasInit()) { 
     if (TTF_Init() == -1) 
      exit(6); 
    } 
    SDL_Color colour = { (Uint8)(textColour.r * 255), (Uint8)(textColour.g * 255), (Uint8)(textColour.b * 255),(Uint8)(textColour.a * 255) }; 
    SDL_Color bg = { (Uint8)(bgColour.r * 255), (Uint8)(bgColour.g * 255), (Uint8)(bgColour.b * 255),255 }; 
    TTF_Font* fontObj = TTF_OpenFont(font, 24); 
    if (!fontObj) 
    { 
     SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 
      "Texture Error", 
      "Cannot load font to create texture.", 
      NULL); 
     return 0; 
    } 
    SDL_Surface *image = NULL; 
    image = TTF_RenderText_Blended(fontObj, text, colour); 
    if (image == NULL) 
    { 
     exit(5); 
     //exitFatalError("String surface not created."); 
     std::cout << "String surface not created." << std::endl; 

    } 
    unsigned char* pixels = NULL; 
    GLuint w = image->w; 
    GLuint h = image->h; 
    GLuint colours = image->format->BytesPerPixel; 
    GLuint externalFormat, internalFormat; 
    SDL_PixelFormat *format = image->format; 
    if (colours == 4) { 

     if (image->format->Rmask == 0x000000ff) 
      externalFormat = GL_RGBA; 
     else 
      externalFormat = GL_BGRA; 
    } 
    else { 

     // no alpha 
     if (image->format->Rmask == 0x000000ff) 
      externalFormat = GL_RGB; 
     else 
      externalFormat = GL_BGR; 
    } 
    internalFormat = (colours == 4) ? GL_RGBA : GL_RGB; 


    GLuint texId = 0; 
    //GLuint texture; 

    glGenTextures(1, &texID); 

    glBindTexture(GL_TEXTURE_2D, texID); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, image->pixels); 
    //glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0, externalFormat, GL_UNSIGNED_BYTE, pixels); 
    glGenerateMipmap(GL_TEXTURE_2D); 

    //// SDL surface was used to generate the texture but is no longer 
    //// required. Release it to free memory 
    SDL_FreeSurface(image); 
    TTF_CloseFont(fontObj); 
    return texID; 
} 

난 후, BMP에 이미지를 저장을 다시로드와 텍스처를 생성하는 해결 방법을 가지고,하지만 난 TTF_RenderText_Shaded 만을 사용하는 경우. TTF_RenderText_Blended을 사용하면 텍스트 색상에 해당하는 단일 색상 이미지를 얻습니다.

+0

'SRC + (srcW * I)'- 당신이 (동일 DST 간다) 너무 BPP를 곱해야합니다. 또한 픽셀 버퍼를 결코 확보 할 수 없지만 현재 문제와 관련이 없습니다. – keltar

+0

그래, 그 오류 (멋지게 발견 btw),하지만 그것은 결과 질감에 아무런 개선, 그래서 거기에 다른 문제가 있습니까? –

+0

기술적으로 행을 정렬해야하지만 bpp = 4는 이미 있습니다. 귀하가 변경 한 내용과 결과를 귀하가 받고있는 상태로 업데이트하십시오. 원래 표면의 너비와 높이, 사용 된 글꼴 및 렌더링되는 텍스트의 실제 값을 아는 것도 도움이 될 수 있습니다. – keltar

답변

2
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueH, trueW, 0,format, GL_UNSIGNED_BYTE, pixels); 

trueHtrueW 순서는

memcpy(src + (srcW*i*bpp), dest + (width*i*bpp), srcW*bpp); 

소스 및 대상 순서 반전 반전됩니다. 크기 width*height*bpp

dest = (unsigned char*)calloc(0, width*height*bpp); 

요소 0 0 바이트 인 할당. 1 대신 0

해야하는 것은 여기에 완벽한 예입니다

#include <SDL2/SDL.h> 
#include <GL/gl.h> 
#include <SDL2/SDL_ttf.h> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

static unsigned char* padTexture(unsigned char * src, int srcW, int srcH, unsigned char * dest, int width, int height, int bpp, const SDL_Palette *palette) 
{ 
    int dst_bpp = (bpp == 1) ? 4 : bpp; 
    dest = (unsigned char*)calloc(1, width*height*dst_bpp); 
    if(bpp != 1) { 
     for (int i = 0; i < srcH; i++) 
     { 
      memcpy(dest + (width*i*bpp), src + (srcW*i*bpp), srcW*bpp); 
     } 
    } else { 
     /* indexed - read colours from palette */ 
     for(int i = 0; i < srcH; i++) { 
      for(int j = 0; j < srcW; j++) { 
       memcpy(dest + (width*i+j)*dst_bpp, 
         &palette->colors[src[srcW*i+j]], sizeof(SDL_Color)); 
      } 
     } 
    } 
    return dest; 
} 

static int powerofTwo(int num) { 
    if (num != 0) 
    { 
     num--; 
     num |= num >> 1; // Divide by 2^k for consecutive doublings of k up to 32, 
     num |= num >> 2; // and then or the results. 
     num |= num >> 4; 
     num |= num >> 8; 
     num |= num >> 16; 
     num++; 
    } 
    return num; 
} 

static GLuint textToTexture(const char *text, TTF_Font* font) { 
    if (!TTF_WasInit()) { 
     if (TTF_Init() == -1) 
      exit(6); 
    } 
    SDL_Color colour = { 255, 255, 255, 255 }; 
    SDL_Color bg = { 0, 0, 0, 255 }; 

    SDL_Surface *stringImage = NULL; 
// stringImage = TTF_RenderText_Blended(font, text, colour); 
    stringImage = TTF_RenderText_Shaded(font, text, colour, bg); 

    if (stringImage == NULL) { 
     exit(5); 
    } 

    GLuint trueH = powerofTwo(stringImage->h); 
    GLuint trueW = powerofTwo(stringImage->w); 
    unsigned char* pixels = NULL; 
    GLuint w = stringImage->w; 
    GLuint h = stringImage->h; 
    GLuint colours = stringImage->format->BytesPerPixel; 
    pixels = padTexture((unsigned char*)stringImage->pixels, w, h, pixels, trueW, trueH, 
      colours, stringImage->format->palette); 
    GLuint format, internalFormat; 

    /* If indexed, want resulting image to be 32bit */ 
    if(colours == 1) { 
     colours = 4; 
    } 

    if (colours == 4) { 

     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGBA; 
     else 
      format = GL_BGRA; 
    } 
    else {  

     // no alpha 
     if (stringImage->format->Rmask == 0x000000ff) 
      format = GL_RGB; 
     else 
      format = GL_BGR; 
    } 
    internalFormat = (colours == 4) ? GL_RGBA : GL_RGB; 


    GLuint texId = 0; 
    //GLuint texture; 

    glGenTextures(1, &texId); 

    glBindTexture(GL_TEXTURE_2D, texId); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0,format, GL_UNSIGNED_BYTE, pixels); 

    // SDL surface was used to generate the texture but is no longer 
    // required. Release it to free memory 
    SDL_FreeSurface(stringImage); 
    free(pixels); 
    return texId; 
} 

int main(int argc, char* argv[]) 
{ 
    SDL_Init(SDL_INIT_VIDEO); 
    TTF_Init(); 

    SDL_Window *window = SDL_CreateWindow("SDL2 Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 600, 400, SDL_WINDOW_OPENGL); 
    SDL_GLContext gl_ctx = SDL_GL_CreateContext(window); 

    TTF_Font *font = TTF_OpenFont(".fonts/tahoma.ttf", 16); 
    if(font) { 
     printf("font loaded\n"); 
     textToTexture("Select Scenario", font); 
     TTF_CloseFont(font); 
    } 

    int quit = 0; 
    while(!quit) { 
     SDL_Event ev; 
     while(SDL_PollEvent(&ev)) { 
      if(ev.type == SDL_QUIT || ev.type == SDL_KEYUP) { 
       quit = 1; 
      } 
     } 

     glClearColor(0.1f, 0.1f, 0.1f, 1.0f); 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

     glLoadIdentity(); 
     glEnable(GL_BLEND); 
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
     glEnable(GL_TEXTURE_2D); 
     glColor3f(1.0f, 1.0f, 1.0f); 
     glBegin(GL_QUADS); 
      glTexCoord2f(0, 1); 
      glVertex2f(-0.5, -0.5); 
      glTexCoord2f(0, 0); 
      glVertex2f(-0.5, 0.5); 
      glTexCoord2f(1, 0); 
      glVertex2f(0.5, 0.5); 
      glTexCoord2f(1, 1); 
      glVertex2f(0.5, -0.5); 
     glEnd(); 

     glFlush(); 
     SDL_GL_SwapWindow(window); 
    } 

    SDL_GL_DeleteContext(gl_ctx); 
    SDL_DestroyWindow(window); 

    TTF_Quit(); 
    SDL_Quit(); 

    return 0; 
} 
+0

멋지게 발견되었습니다. 오류는 수정했지만 개선되지 않았으므로 새 코드로 질문을 업데이트했습니다. –

+1

나를 위해 잘 작동합니다. 그런 다음 완전한 예를 만드십시오. – keltar

+0

GPU 램에 저장된 데이터를 검사했는데 이미지도 거기에서 왜곡되어 있으므로 문제는 SDL_TTF 자체이거나 GPU에 데이터를 복사하는 것입니다. 사용중인 SDL_TTF 버전은 무엇입니까? –