Pregunta

First of all, I'm programming in the kernel context so no existing libraries exist. In fact this code is going to go into a library of my own.

Two questions, one more important than the other:

  1. As the title suggests, how can I efficiently render a 24-bpp image onto a 32-bpp device, assuming that I have the address of the frame buffer?

Currently I have this code:

void BitmapImage::Render24(uint16_t x, uint16_t y, void (*r)(uint16_t, uint16_t, uint32_t))
{
    uint32_t imght = Math::AbsoluteValue(this->DIB->GetBitmapHeight());
    uint64_t ptr = (uint64_t)this->ActualBMP + this->Header->BitmapArrayOffset;

    uint64_t rowsize = ((this->DIB->GetBitsPerPixel() * this->DIB->GetBitmapWidth() + 31) / 32) * 4;

    uint64_t oposx = x;
    uint64_t posx = oposx;
    uint64_t posy = y + (this->DIB->Type == InfoHeaderV1 && this->DIB->GetBitmapHeight() < 0 ? 0 : this->DIB->GetBitmapHeight());


    for(uint32_t d = 0; d < imght; d++)
    {
        for(uint32_t w = 0; w < rowsize / (this->DIB->GetBitsPerPixel() / 8); w++)
        {
            r(posx, posy, (*((uint32_t*)ptr) & 0xFFFFFF));
            ptr += this->DIB->GetBitsPerPixel() / 8;
            posx++;
        }
        posx = oposx;
        posy--;
    }
}

r is a function pointer to a PutPixel-esque thing that accepts x, y, and colour parameters. Obviously this code is terribly slow, since plotting pixels one at a time is never a good idea.

For my 32-bpp rendering code (which I also have a question about, more on that later) I can easily Memory::Copy() the bitmap array (I'm loading bmp files here) to the frame buffer. However, how do I do this with 24bpp images? On a 24bpp display this would be fine but I'm working with a 32bpp one.

One solution I can think of right now is to create another bitmap array which essentially contains values of 0x00(colour) and the use that to draw to the screen -- I don't think this is very good though, so I'm looking for a better alternative.

Next question: 2. Given, for obvious reasons, one cannot simply Memory::Copy() the entire array at once onto the frame buffer, the next best thing would be to copy them row by row.

Is there a better way?

¿Fue útil?

Solución

Basically something like this:

for (uint32_t l = 0; l < h; ++l) // l line index in pixels
{
    // srcPitch is distance between lines in bytes
    char*     srcLine = (char*)srcBuffer + l * srcPitch; 
    unsigned* trgLine = ((unsigned*)trgBuffer) + l * trgPitch;

    for (uint32_t c = 0; c < w; ++c) // c is column index in pixels
    {
        // build target pixel. arrange indexes to fit your render target (0, 1, 2)
        ++(*trgLine) = (srcLine[0] << 16) | (srcLine[1] << 8)
           | srcLine[2] | (0xff << 24);
        srcLine += 3;
    }
}

A few notes: - better to write to a different buffer than the render buffer so the image is displayed at once. - using functions for pixel placement like you did is very (very very) slow.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top