oscar64/samples/particles/fireworks_hires.c

216 lines
4.2 KiB
C

#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
static char * const Screen = (char *)0xc800;
static char * const Color = (char *)0xd800;
static char * const Hires = (char *)0xe000;
// Single particle, with position and veloicty, using a next
// pointer for single linked list
struct Particle
{
int px, py, vx, vy;
Particle * next;
};
// Storage for up to 256 particles
Particle particles[256];
// Heads of used and free list
Particle * pfirst, * pfree;
// Lookup table for hires row buffer
static char * Hirows[25];
// Pixel masks
static const char setmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
static const char clrmask[8] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};
// Set a pixel at the given coordinate
void pix_set(unsigned px, unsigned py)
{
// Give the compiler a hand
__assume(px < 320);
__assume(py < 200);
// Calculate base position in hires
char * dp = Hirows[py >> 3] + (px & ~7);
// Set the pixel
dp[py & 7] |= setmask[px & 7];
}
// Clear a pixel at the given coordinate
void pix_clr(unsigned px, unsigned py)
{
__assume(px < 320);
__assume(py < 200);
// Calculate base position in hires
char * dp = Hirows[py >> 3] + (px & ~7);
// Clear the pixel
dp[py & 7] &= clrmask[px & 7];
}
// Init free list of particles
void particle_init(void)
{
// Init address table for hires
for(int i=0; i<25; i++)
Hirows[i] = Hires + 320 * i;
// Init list heads
pfirst = nullptr;
pfree = particles;
// Link all particles in free list
for(int i=0; i<255; i++)
particles[i].next = particles + i + 1;
}
// Add a particle to the list
void particle_add(int px, int py, int vx, int vy)
{
// Check if we have a particle left
if (pfree)
{
// Remove from free list
Particle * p = pfree;
pfree = pfree->next;
// Add to used list
p->next = pfirst;
pfirst = p;
// Init particle data
p->px = px;
p->py = py;
p->vx = vx;
p->vy = vy;
}
}
// Move particles in used list
void particle_move(void)
{
// Start with first particle, remember previous
// particle for list removal
Particle * p = pfirst, * pp = nullptr;
// Loop over all particles in used list
while (p)
{
// Clear previous particle image, using 10.6 fixed point
pix_clr(p->px >> 6, p->py >> 6);
// Advance position by velocity
p->px += p->vx;
p->py += p->vy;
// Apply gravity
p->vy += 8;
// Check if particle is still on screen
if (p->px < 0 || p->px >= 320 * 64 || p->py < 0 || p->py >= 200 * 64)
{
// Particle is offscreen, so we remove it from the used list
// Remember next particle in used list
Particle * pn = p->next;
// Remove from used list
if (pp)
pp->next = pn;
else
pfirst = pn;
// Attach to free list
p->next = pfree;
pfree = p;
// Advance to next particle
p = pn;
}
else
{
// Set image at new position
pix_set(p->px >> 6, p->py >> 6);
// Advance to next particle
pp = p;
p = p->next;
}
}
}
// Normalized random function
int rnorm(void)
{
int l0 = (rand() & 0xfff) - 0x800;
int l1 = (rand() & 0xfff) - 0x800;
int l2 = (rand() & 0xfff) - 0x800;
int l3 = (rand() & 0xfff) - 0x800;
return l0 + l1 + l2 + l3;
}
int main(void)
{
// Turn off BASIC ROM
mmap_set(MMAP_NO_BASIC);
// Install IRQ trampoline
mmap_trampoline();
// Turn off kernal ROM
mmap_set(MMAP_NO_ROM);
// Switch to hires mode
vic_setmode(VICM_HIRES, Screen, Hires);
// Clear screen
memset(Screen, 0x10, 1000);
memset(Hires, 0x00, 8000);
// Black background
vic.color_border = 0x00;
vic.color_back = 0x00;
// Init particle system
particle_init();
char k = 0;
for(int i=0; i<10000; i++)
{
// Advance particles
particle_move();
if (k < 25)
{
// Add a particle from the left for the first third
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)));
}
else if (k < 50)
{
// Add a particle from the right for the second third
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)));
}
else if (k < 75)
{
// Add a particle from the middle for the final third
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)));
}
// Advance thirds counter
k++;
if (k == 75)
k = 0;
}
return 0;
}