Two simple classes are needed for the little demo:
fb-bitmap.bi:
Code: Select all
#include once "fbgfx.bi"
namespace gfx
'' The TGA file format header
type TGAHeader field = 1
as ubyte idlength
as ubyte colormaptype
as ubyte datatypecode
as short colormaporigin
as short colormaplength
as ubyte colormapdepth
as short x_origin
as short y_origin
as short width
as short height
as ubyte bitsperpixel
as ubyte imagedescriptor
end type
type Bitmap extends Object
public:
declare constructor( byval as integer, byval as integer )
declare constructor( byref rhs as fb.image ptr )
declare constructor( byref rhs as Bitmap )
declare destructor()
declare operator let( byref rhs as fb.image ptr )
declare operator let( byref rhs as Bitmap )
declare operator cast() as fb.image ptr
declare property width() as integer
declare property height() as integer
declare static function fromBMP( byref as const string ) as fb.image ptr
declare static function fromTGA( byref as const string ) as fb.image ptr
declare function clone() as fb.image ptr
declare sub dispose()
private:
declare constructor()
m_bitmap as fb.image ptr
end type
constructor Bitmap( byval w as integer, byval h as integer ) export
m_bitmap = imageCreate( w, h, rgba( 0, 0, 0, 0 ), 32 )
end constructor
constructor Bitmap( byref rhs as fb.image ptr ) export
dispose()
m_bitmap = rhs
end constructor
constructor Bitmap( byref rhs as Bitmap ) export
dispose()
m_bitmap = rhs.clone()
end constructor
operator Bitmap.let( byref rhs as fb.image ptr ) export
dispose()
m_bitmap = rhs
end operator
operator Bitmap.let( byref rhs as Bitmap ) export
dispose()
m_bitmap = rhs.clone()
end operator
operator Bitmap.cast() as fb.image ptr export
return( m_bitmap )
end operator
destructor Bitmap() export
dispose()
end destructor
sub Bitmap.dispose() export
if( m_bitmap <> 0 ) then
imageDestroy( m_bitmap )
m_bitmap = 0
'' For testing purposes. Remove this when/if you use the code
? "Bitmap destroyed"
end if
end sub
property Bitmap.width() as integer export
return( m_bitmap->width )
end property
property Bitmap.height() as integer export
return( m_bitmap->height )
end property
function Bitmap.fromBMP( byref fileName as const string ) as fb.image ptr
/'
Loads a BMP file
Be careful here, as passing whatever crap to the function will likely
result in an invalid buffer and/or crashes. There's not much on the
error handling side as this is a simple example
'/
dim as any ptr imgData = 0
dim as integer fileNum = freeFile()
dim as long w, h
' Open file
dim as integer result = open( fileName, for binary, access read, as fileNum )
if( result = 0 ) then
' Get width from file
get #fileNum, 19, w
' Get height from file
get #fileNum, 23, h
close( fileNum )
imgData = imageCreate( w, h, rgba( 0, 0, 0, 0 ), 32 )
dim as integer res = bload( fileName, imgData )
if( res <> 0 ) then
imageDestroy( imgData )
imgData = 0
end if
end if
return( imgData )
end function
function Bitmap.fromTGA( byref fileName as const string ) as fb.image ptr export
/'
Loads a TGA file
Currently this code only loads 32-bit uncompressed TGA files
Note that you must specify the origin of the TGA file as 'top-left' in apps like
GIMP, or else the bitmap is displayed upside down, as TGAs normally store the
bitmap like that (makes working with APIs like OpenGL more comfortable)
Yep, I'm too lazy to implement proper TGA loading XD
'/
'' Read header
dim as TGAHeader header
dim as ulong ptr imagePixels
dim as fb.image ptr imageData
'' We need to calculate this value, as FB aligns image buffers to 16 byte boundaries
dim as uinteger padding
'' Open file
dim as integer fileNum = freeFile()
dim as integer result = open( filename, for binary, access read, as fileNum )
if( result = 0 ) then
'' Retrieve header first
get #fileNum, , header
'' Create a fb image buffer
imageData = imageCreate( header.width, header.height )
'' Pointer to pixel data
imagePixels = cast( ulong ptr, imageData )
/'
Calculate size of padding, as FB aligns the width of the images to a multiple of 16 bytes
The size of the padding is calculated in pixels, not bytes, to allow for a pretty tight
drawing loop
'/
padding = imageData->pitch \ imageData->bpp - header.width
'' Skip header size ( in dwords / 4 bytes per pixel )
imagePixels += sizeOf( fb.image ) \ sizeOf( ulong )
'' This will hold the pixel read from file
dim as ulong pixelRead
'' Load pixel data into a fb.image buffer
for y as integer = 0 to header.height - 1
for x as integer = 0 to header.width - 1
get #1, , pixelRead
*imagePixels = pixelRead
imagePixels += 1
next
'' Remember to add the padding at the end of horizontal scanline
imagePixels += padding
next
close( fileNum )
end if
return( imageData )
end function
function Bitmap.clone() as fb.image ptr
dim as fb.image ptr myClone = imageCreate( m_bitmap->width, m_bitmap->height, rgba( 0, 0, 0, 0 ), 32 )
/'
Creates a copy of this bitmap instance
Here it just copies the pixel data to another buffer and returns it. Primarily used
to create another image from already loaded data
'/
dim as ulong ptr d = cast( ulong ptr, myClone ) + sizeOf( fb.image ) \ sizeOf( ulong )
dim as ulong ptr s = cast( ulong ptr, m_bitmap ) + sizeOf( fb.image ) \ sizeOf( ulong )
dim as uinteger pixels = ( m_bitmap->pitch \ sizeOf( ulong ) ) * m_bitmap->height
for i as uinteger = 0 to pixels - 1
*d = *s
d += 1
s += 1
next
return( myClone )
end function
end namespace
Code: Select all
#include once "fbgfx.bi"
#include once "fb-bitmap.bi"
/'
A simple implementation of a list of images. Only barebones functionality
is implemented, but you can easily extend it to include all sort of
neat things, if you desire
'/
namespace gfx
type BitmapList extends object
public:
declare constructor()
declare destructor()
declare sub add( byval as Bitmap ptr )
declare function item( byval as integer ) as Bitmap ptr
declare function count() as uinteger
private:
m_count as uinteger
m_bitmaps( any ) as Bitmap ptr
end type
constructor BitmapList()
end constructor
destructor BitmapList()
for i as integer = 0 to m_count - 1
delete( m_bitmaps( i ) )
next
end destructor
sub BitmapList.add( byval bm as Bitmap ptr )
m_count += 1
redim preserve m_bitmaps( 0 to m_count - 1 )
m_bitmaps( m_count - 1 ) = bm
end sub
function BitmapList.item( byval index as integer ) as Bitmap ptr
return( m_bitmaps( index ) )
end function
function BitmapList.count() as uinteger
return( m_count )
end function
end namespace
Code: Select all
#include once "fbgfx.bi"
#include once "fb-bitmap.bi"
#include once "fb-bitmap-list.bi"
/'
Simple code to demonstrate two helper classes, Bitmap and BitmapList
'/
screenRes( 800, 600, 32, , fb.gfx_alpha_primitives )
scope
'' Create a list of bitmaps
dim as gfx.BitmapList blist
'' Load some images (change them to anything you like, of course)
with blist
.add( new gfx.Bitmap( gfx.Bitmap.fromBMP( "mage002.bmp" ) ) )
.add( new gfx.Bitmap( gfx.Bitmap.fromTGA( "star.tga" ) ) )
'' ... add any image you wish
end with
'' Creates a bitmap from another one
dim as gfx.Bitmap bm = blist.item( 1 )->clone()
/'
And display them. Note that the bitmaps returned directly from the list
had to be dereferenced, as they're returned as raw fb.image pointers,
so you can simply use the put statement to blit them to the screen
If you don't do this, the code will simply crash
'/
put( 100, 100 ), *blist.item( 0 ), pset
put( 200, 100 ), *blist.item( 1 ), alpha
'' This one doesn't need dereferencing, courtesy of the cast() operator
put( 300, 100 ), bm, alpha
end scope
/'
The images don't have to be destroyed, since the Bitmap class takes care of
that. The BitmapList simply deletes each of it's elements at destruction, sparing
you from having to release each image manually
'/
sleep()
EDIT: Fixed a tiny leak.