1
\$\begingroup\$

I've recently been trying to blend multiple textures based on the height at different points in a heightmap. However i've been getting poor results. I decided to backtrack and just attempt to recreate one single texture from an SDL_Surface (i'm using SDL) and just send that into opengl. I'll put my code for creating the texture and reading the colour values. It is a 24bit TGA i'm loading, and i've confirmed that the rest of my code works because i was able to send the surfaces pixels directly to my createTextureFromData function and it drew fine.

struct RGBColour
{
    RGBColour() : r(0), g(0), b(0) {}
    RGBColour(unsigned char red, unsigned char green, unsigned char blue) : r(red), g(green), b(blue) {}

    unsigned char r;
    unsigned char g;
    unsigned char b;
};


    // main loading code
SDLSurfaceReader* reader = new SDLSurfaceReader(m_renderer);
reader->readSurface("images/grass.tga");

// new texture
unsigned char* newTexture = new unsigned char[reader->m_surface->w * reader->m_surface->h * 3 * reader->m_surface->w];

for (int y = 0; y < reader->m_surface->h; y++)
{
    for (int x = 0; x < reader->m_surface->w; x += 3)
    {
        int index = (y * reader->m_surface->w) + x;

        RGBColour colour = reader->getColourAt(x, y);

        newTexture[index] = colour.r;
        newTexture[index + 1] = colour.g;
        newTexture[index + 2] = colour.b;
    }
}

unsigned int id = m_renderer->createTextureFromData(newTexture, reader->m_surface->w, reader->m_surface->h, RGB);

    // functions for reading pixels
RGBColour SDLSurfaceReader::getColourAt(int x, int y)
{
    Uint32 pixel;
    Uint8 red, green, blue;
    RGBColour rgb;

    pixel = getPixel(m_surface, x, y);

    SDL_LockSurface(m_surface);

    SDL_GetRGB(pixel, m_surface->format, &red, &green, &blue);

    SDL_UnlockSurface(m_surface);

    rgb.r = red;
    rgb.b = blue;
    rgb.g = green;

    return rgb;
}

    // this function taken from SDL documentation
// http://www.libsdl.org/cgi/docwiki.cgi/Introduction_to_SDL_Video#getpixel
Uint32 SDLSurfaceReader::getPixel(SDL_Surface* surface, int x, int y)
{
    int bpp = m_surface->format->BytesPerPixel;

    Uint8 *p = (Uint8*)m_surface->pixels + y * m_surface->pitch + x * bpp;

    switch (bpp) 
    {
    case 1:
        return *p;
    case 2:
        return *(Uint16*)p;
    case 3:
        if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;
    case 4:
        return *(Uint32*)p;
    default:
        return 0;
    }
}

I've been stumped at this, and I need help badly! Thanks so much for any advice.

\$\endgroup\$
3
  • \$\begingroup\$ What precisely isn't working here? \$\endgroup\$ Commented Apr 20, 2012 at 14:26
  • \$\begingroup\$ The code compiles fine, but when i'm applying this texture, i'm getting weird results. This is a screenshot of what i'm getting i.imgur.com/N6NFi.png and this is what it should be i.imgur.com/V6x0p.jpg \$\endgroup\$
    – James
    Commented Apr 20, 2012 at 14:32
  • \$\begingroup\$ As you can see its drawing the whole texture in 3 spots and only in 1/3 of the terrain. I dont know where i'm going wrong in my loading. \$\endgroup\$
    – James
    Commented Apr 20, 2012 at 14:34

1 Answer 1

1
\$\begingroup\$

First, the size of your newTexture[] array looks suspicious; why is the extra factor of "reader->m_surface->w" on the end? "width * height * 3" should be sufficient. That shouldn't affect correctness, but it's a big waste of memory.

More importantly, the indexing on your inner for loop doesn't look quite right. You need to be consistent about which variables are counting pixels vs. which are counting bytes. The "x" and "y" variables should be counting pixels, since that's what the getColourAt() function expects. But your inner for loop is incrementing x by 3 each time, which means you're only reading the color of every third pixel. Replace "x += 3" with "x++" and you'll hit every pixel.

The "index" variable is being used as a byte index into the newTexture[] array. After applying the above fix, "x" and "y" are pixel indices, so the byte index of pixel [x,y] would be given by "(y * reader->m_surface->w + x) * 3".

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .