Skip to content

Instantly share code, notes, and snippets.

@felixjones
Last active March 21, 2019 13:25
Show Gist options
  • Save felixjones/ce5b7776823ce8446fbbe7dc9bdb5a32 to your computer and use it in GitHub Desktop.
Save felixjones/ce5b7776823ce8446fbbe7dc9bdb5a32 to your computer and use it in GitHub Desktop.
C++ fire effect for Game Boy Advance
#include <gba.hpp>
#define EVER ;;
using namespace gba;
// Palette of fire "heat" values
static constexpr color::bgr555 fire_colors[] = {
color::rgb888( 0x070707 ), color::rgb888( 0x1F0707 ), color::rgb888( 0x2F0F07 ), color::rgb888( 0x470F07 ),
color::rgb888( 0x571707 ), color::rgb888( 0x671F07 ), color::rgb888( 0x771F07 ), color::rgb888( 0x8F2707 ),
color::rgb888( 0x9F2F07 ), color::rgb888( 0xAF3F07 ), color::rgb888( 0xBF4707 ), color::rgb888( 0xC74707 ),
color::rgb888( 0xDF4F07 ), color::rgb888( 0xDF5707 ), color::rgb888( 0xDF5707 ), color::rgb888( 0xD75F07 ),
color::rgb888( 0xD75F07 ), color::rgb888( 0xD7670F ), color::rgb888( 0xCF6F0F ), color::rgb888( 0xCF770F ),
color::rgb888( 0xCF7F0F ), color::rgb888( 0xCF8717 ), color::rgb888( 0xC78717 ), color::rgb888( 0xC78F17 ),
color::rgb888( 0xC7971F ), color::rgb888( 0xBF9F1F ), color::rgb888( 0xBF9F1F ), color::rgb888( 0xBFA727 ),
color::rgb888( 0xBFA727 ), color::rgb888( 0xBFAF2F ), color::rgb888( 0xB7AF2F ), color::rgb888( 0xB7B72F ),
color::rgb888( 0xB7B737 ), color::rgb888( 0xCFCF6F ), color::rgb888( 0xDFDF9F ), color::rgb888( 0xEFEFC7 ),
color::rgb888( 0xFFFFFF )
};
static constexpr auto fire_colors_num = sizeof( fire_colors ) / sizeof( fire_colors[0] );
static void IWRAM_ main_fire();
static void IWRAM_ spread_fire( uint8 xx, int8 wind );
int main( int argc, char * argv[] ) {
display::control = display::mode( 4 ).enable_layers( { 2 } );
// Upload 16bit palette colours
dma::channel[3].submit( dma::transfer( video::mode4.get_palette_address(), fire_colors, fire_colors_num ) );
// Clear VRAM
video::mode4.get_frontpage().fill( 0 );
// Begin the loop
main_fire();
return 0;
}
// Generates psuedo random 8-bit values
static rng<uint8> random_generator( 56, 199, 143 );
// Buffer line read/writes to avoid 16bit VRAM
static uint8 line_buffer_read[240];
static uint8 line_buffer_write[248];
void spread_fire( uint8 xx, int8 wind ) {
uint8 pixel = line_buffer_read[xx];
if ( pixel ) {
uint8 randIdx = ( random_generator.roll() * 3 ) >> 8; // modulo 3
uint8 dst = xx + 3 + randIdx + wind;
line_buffer_write[dst] = pixel - ( randIdx & 1 );
} else {
line_buffer_write[xx + 4] = 0;
}
}
// DMA control to copy 240 bytes of VRAM
static constexpr dma::control line_dma_copy = dma::control( 60 ).transfer_32bit( true );
void main_fire() {
// Front buffer rendering
auto& drawpage = video::mode4.get_frontpage();
// Seed value starts the burn
uint8 seed = 0;
for ( EVER ) {
auto keystate = io::keys.read_keys();
if ( keystate.button.A && seed > 0 ) {
seed--;
drawpage.fill( seed, 0, 159, 240, 1 );
} else if ( !keystate.button.A && seed < ( fire_colors_num - 1 ) ) {
seed++;
drawpage.fill( seed, 0, 159, 240, 1 );
}
int8 wind = keystate.pad.axis_x();
for ( uint8 yy = 1; yy < 160; yy++ ) {
// Read line
dma::channel[1].submit( line_dma_copy, line_buffer_read, &drawpage.get_line( yy ) );
if ( yy & 1 ) { // Odd lines
// Loop left to right
for ( uint8 xx = 0; xx < 240; xx++ ) {
spread_fire( xx, wind );
}
} else { // Even lines
// Loop right to left
uint8 xx = 240;
while ( xx-- ) {
spread_fire( xx, wind );
}
}
// Write above line
dma::channel[2].submit( line_dma_copy, &drawpage.get_line( yy - 1 ), line_buffer_write + 4 );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment