Hey guys,
I'm trying to load pixel data from a TileStudio map into a Bitmap. Basically my code locks a square on the tileset bitmap and then freads it into the locked area.
bytesPerTile = 4 * m_iTileHeight * m_iTileWidth; // now load the tiles for ( byCount = 0; byCount < m_iTileCount; byCount++ ) { // calculate the location on the grid of the current tile x = ( byCount % m_byTilesPerRow ) * m_iTileWidth; y = ( byCount / m_byTilesPerRow ) * m_iTileHeight; // now load the tile into the bitmap tileRegion = al_lock_bitmap_region( m_pTileBitmap, x, y, m_iTileWidth, m_iTileHeight, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY ); al_fread( pFile, tileRegion->data, bytesPerTile ); al_unlock_bitmap( m_pTileBitmap ); }
However its showing up blue and distorted. Any reason why?
The pixel format has to be exactly the same between the file on disk and the ALLEGRO_BITMAP in (video)memory. Bitmaps usually have a header (data that is not pixels). ALLEGRO_BITMAPs can have 'padding' between lines IIRC[1]. I.e. you need skip some bytes when writing to it. There was an example, but I can't remember where...
If it's only for loading purposes al_put_pixel can also be used on locked bitmaps, and it takes care of the 'stride' issue.
BTW I think a nested loop would look cleaner.
Quick guess
Blue: You're only writing to the blue channel. Like loading single bytes from an 8 bit image and putting them into a 24 bit bitmap.
Distorted: A square (or any rectangular) area of a bitmap is not consecutive memory.
ok, sounds good. I did use al_put_pixel at first, but I found it took up to a minute to load a 45-tile set with tile size 32x32. So I wanted something that ran faster.
I'll have a shot at using stride. Hopefully it'll work better.
-- EDIT --
Must say, not really digging the pitch approach. Just how much padding do the bitmaps have, anyway? Here's my new approach:
// now load the tile into the bitmap tileRegion = al_lock_bitmap_region( m_pTileBitmap, x, y, m_iTileWidth, m_iTileHeight, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY ); for( j=0; j < m_iTileHeight; j++ ) { p = (size_t*)tileRegion->data + j * tileRegion->pitch; al_fread( pFile, p, m_iTileWidth*4 ); } al_unlock_bitmap( m_pTileBitmap );
Must say, not really digging the pitch approach.
Do you have a choice?
Just how much padding do the bitmaps have, anyway?
In any case the ones in memory will have more than the ones on disk >_> Unless, maybe if you use a non-video memory bitmap.
The pitch is in bytes, so I think you are advancing 4 or 8 times too far (depending if you are 32-bit or 64-bit). Try:
p = (char*)tileRegion->data + j * tileRegion->pitch;
Do you have a choice?
What I meant to say is, I've tried the pitch approach, and it segfaulted.
I'll have a shot using what Leverton suggested.
-EDIT-
Ok, that worked. However, the colour's all confused. The greens are greens, but the browns are blues, and the blues are yellow. I'm still iffie on how colour conversion works.
Try other pixel formats[1]? There are differences in which order each color component is stored. (Apparently it is 32-bit and there is no header, when your image isn't distorted.)
You don't have any colour conversions; You're loading raw data.
I got it working. Just the endian-ness issue. Anyway, now comes to the drawing part.
What I've got now is a proper, non-colour-confused rendering of the map. However, when it renders tiles that have a portion transparent (like part of a pillar or something), it draws semi-transparent mask colour (as in [255,0,255]) where it should be drawing nothing. This didn't happen before when I just used put_pixel, and al_convert_mask_to_alpha doesn't seem to do anything. The bitmap format is ARGB 32bit.
-EDIT-
Got it working. But it's a bit of an ugly hack with TileStudio. I had to fix the export so that instead of outputting the proper alpha channel from the tile, TileStudio just outputs 255. This will make it hard if/when i want to do transparency in tiles rather than just masks.
Loading the alpha should work perfectly. Maybe the blender was set wrong?