227 lines
4.5 KiB
C
227 lines
4.5 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, veloicty and color pattern, using a next
|
|
// index for single linked list
|
|
struct Particle
|
|
{
|
|
int px, py, vx, vy;
|
|
char pat;
|
|
char next;
|
|
};
|
|
|
|
// Striped storage of particles, using an index for linkage
|
|
__striped Particle particles[256];
|
|
|
|
#pragma align(particles, 256)
|
|
|
|
// Index for used and free list heads
|
|
char pfirst, pfree;
|
|
|
|
static char * Hirows[25];
|
|
|
|
static const char setmask[4] = {0xc0, 0x30, 0x0c, 0x03};
|
|
static const char clrmask[4] = {0x3f, 0xcf, 0xf3, 0xfc};
|
|
|
|
// Set a pixel at the given coordinate
|
|
void pix_set(char px, char py, char pat)
|
|
{
|
|
__assume(px < 160);
|
|
__assume(py < 100);
|
|
|
|
// Calculate base position in hires
|
|
char * dp = Hirows[py >> 2] + 2 * (px & ~3);
|
|
|
|
// Set two pixels for a square pixel look
|
|
char ly = 2 * (py & 3);
|
|
dp[ly + 1] = dp[ly + 0] |= setmask[px & 3] & pat;
|
|
}
|
|
|
|
// Clear a pixel at the given coordinate
|
|
void pix_clr(char px, char py)
|
|
{
|
|
__assume(px < 160);
|
|
__assume(py < 100);
|
|
|
|
// Calculate base position in hires
|
|
char * dp = Hirows[py >> 2] + 2 * (px & ~3);
|
|
|
|
// Clear two pixels for a square pixel look
|
|
char ly = 2 * (py & 3);
|
|
dp[ly + 1] = dp[ly + 0] &= clrmask[px & 3];
|
|
}
|
|
|
|
// 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, using index 0 for list termination
|
|
pfirst = 0;
|
|
pfree = 1;
|
|
|
|
// Link all particles in free list
|
|
for(int i=1; i<255; i++)
|
|
particles[i].next = i + 1;
|
|
}
|
|
|
|
// Add a particle to the list
|
|
void particle_add(int px, int py, int vx, int vy, char pat)
|
|
{
|
|
// Check if we have a particle left
|
|
if (pfree)
|
|
{
|
|
// Use "auto" to generate a striped pointer
|
|
char i = pfree;
|
|
auto p = particles + pfree;
|
|
|
|
// Remove from free list
|
|
pfree = p->next;
|
|
p->next = pfirst;
|
|
|
|
// Add to used list
|
|
pfirst = i;
|
|
|
|
// Init particle data
|
|
p->px = px;
|
|
p->py = py;
|
|
p->vx = vx;
|
|
p->vy = vy;
|
|
p->pat = pat;
|
|
}
|
|
}
|
|
|
|
// Move particles in used list
|
|
void particle_move(void)
|
|
{
|
|
// Start with first particle, remember previous
|
|
// particle for list removal, using indices instead of pointers
|
|
char i = pfirst, pi = 0;
|
|
|
|
// Zero is still list termination
|
|
while (i)
|
|
{
|
|
// Use "auto" to generate a striped pointer
|
|
auto p = particles + i;
|
|
|
|
// Clear previous particle image, using 9.7 fixed point
|
|
pix_clr(p->px >> 7, p->py >> 7);
|
|
|
|
// 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 >= 160 * 128 || p->py < 0 || p->py >= 100 * 128)
|
|
{
|
|
// Particle is offscreen, so we remove it from the used list
|
|
|
|
// Remember next particle in used list
|
|
char pn = p->next;
|
|
|
|
// Remove from used list
|
|
if (pi)
|
|
particles[pi].next = pn;
|
|
else
|
|
pfirst = pn;
|
|
|
|
// Attach to free list
|
|
p->next = pfree;
|
|
pfree = i;
|
|
|
|
// Advance to next particle
|
|
i = pn;
|
|
}
|
|
else
|
|
{
|
|
// Set image at new position
|
|
pix_set(p->px >> 7, p->py >> 7, p->pat);
|
|
|
|
// Advance to next particle
|
|
pi = i;
|
|
i = 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 multicolor mode
|
|
vic_setmode(VICM_HIRES_MC, Screen, Hires);
|
|
|
|
// Clear screen
|
|
memset(Screen, 0x78, 1000);
|
|
memset(Color, 0x0e, 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)), 0x55);
|
|
}
|
|
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)), 0xaa);
|
|
}
|
|
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)), 0xff);
|
|
}
|
|
|
|
// Advance thirds counter
|
|
k++;
|
|
if (k == 75)
|
|
k = 0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|