0
votes

I'm working on a program that creates an SDL_Surface using http://www.fontspace.com/work-ins-studio/variane-script. I set the background of the surface to be transparent. Then I extract the pixels from the surface, and place them in part of an opengl texture.

It all works fine, except that the text ends up looking like this (the text should read "testing")

text

My question: Did I mess up the math somehow and do this myself, or is this just the behaviour of SDL_TTF? And, if it is just the behaviour of SDL_TTF, how do I work around it to get pixel data that I can use?

Here is the relevant code:

int main(int argc, char* args[]) {
//other sdl and opengl overhead stuff here...
TTF_Init();
//shader setup here...
TTF_Font *font;
font = TTF_OpenFont("VarianeScript.ttf", 50);
SDL_Surface* surface;
SDL_Color color = { 255, 0, 0 };
surface = TTF_RenderText_Solid(font, "testing", color);
SDL_SetSurfaceAlphaMod(surface, 255);
int surfaceWidth = surface->w;
int surfaceHeight = surface->h;
Uint8 red, green, blue, alpha;
float* textImage = new float[(surfaceWidth * surfaceHeight) * 4];
int countText = 0;
SDL_LockSurface(surface);
Uint8* p = (Uint8*)surface->pixels;
for (int y = 0; y < surfaceHeight; ++y) {
    for (int x = 0; x < (surfaceWidth); ++x) {
        Uint8 pixel = p[(y * surface->w) + x];
        SDL_GetRGBA(pixel, surface->format, &red, &green, &blue, &alpha);
        textImage[countText] = ((float)red / 255.0f);
        ++countText;
        textImage[countText] = ((float)green / 255.0f);
        ++countText;
        textImage[countText] = ((float)blue / 255.0f);
        ++countText;
        textImage[countText] = ((float)alpha / 255.0f);
        ++countText;
    }
}
SDL_UnlockSurface(surface);
SDL_FreeSurface(surface);
GLuint texture;
float* image;
int width = 1000, height = 1000;
int textX = width - (int)(width / 1.5);
int textY = height - (int)(height / 1.5);
setupTexture(texture, shader, width, height, image, textImage, textX, textY, surfaceWidth, surfaceHeight);
//etc...

also (the important part starts around where I declare the startpos variables)

void setupTexture(GLuint &texture, Shader &shader, int &width, int &height, float* &image, float* text, int textX, int textY, int textW, int textH) {
glGenTextures(1, &texture);
image = new float[(width * height) * 3];
for (int a = 0; a < (width * height) * 3; ) {
    if (a < ((width * height) * 3) / 2) {
        image[a] = 0.5f;
        ++a;
        image[a] = 1.0f;
        ++a;
        image[a] = 0.3f;
        ++a;
    }
    else {
        image[a] = 0.0f;
        ++a;
        image[a] = 0.5f;
        ++a;
        image[a] = 0.7f;
        ++a;
    }
}
int startpos1, startpos2;
for(int y = 0; y < textH; ++y) {
    for(int x = 0; x < textW; ++x) {
        startpos1 = (((y + textY) * width) * 3) + ((x + textX) * 3);
        startpos2 = ((y * textW) *4) + (x * 4);
        if (text[startpos2 + 3] != 0.0) {
            image[startpos1] = text[startpos2];
            image[startpos1 + 1] = text[startpos2 + 1];
            image[startpos1 + 2] = text[startpos2 + 2];
        }
    }
}
glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, image);
glUniform1i(glGetUniformLocation(shader.shaderProgram, "texSampler"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
1
Since your create a tightly packed RGB texture, you have to set glPixelStore(GL_UNPACK_ALIGNMENT, 1)Rabbid76
How would I go about implementing that into my code? I'm very new to opengl, sorryunciq420
textX and textY calculated from hardcoded constant 1000 and does not represent actual pitch of textImage. What's that constants supposed to mean? Shouldn't it be surfaceWidth and surfaceHeight instead?keltar
textX and textY represent the origin (top left corner) of the area where the pixels from text will overwrite those in imageunciq420
the problem as I see it isn't with my code per se. It's that sdl_ttf wraps text around to the front of the pixel array to conserve space (I assume) and I've no idea how to work with that. Or I could have screwed up the math. I'll try implementing your code and report backunciq420

1 Answers

1
votes

Your problem is in the way you extract pixel from surface:

Uint8 pixel = p[(y * surface->w) + x];

You assume that each pixel takes one byte (could be verified by inspecting surface->format->BytesPerPixel), and that each row is surface->w*1 bytes long - but it isn't. Instead, each row is surface->pitch bytes long, so your code should be

Uint8 pixel = p[y * surface->pitch + x];

(that still assumes it is 1 byte long, but that's beside the point).

It is quite weird that you use floats to represent pixel data, as it gives you nothing here aside from much slower loading.