Source

inpulse / stars.c

Full commit
/** \file
 * Draw an infinite starfield
 */
#include "app.h"
#include "sin_table.h"

#define MAX_STARS 128


struct star
{
	int16_t x; // scaled by 128
	int16_t y;
	int8_t dx;
	int8_t dy;
	uint8_t brightness;
	uint16_t age;
} __attribute__((packed));


struct stars_app
{
	uint32_t last_update;
	int8_t rotate_sin;
	int8_t rotate_cos;
	struct star stars[MAX_STARS];
} __attribute__((packed));

#define APP ((struct stars_app *) app_common_data)

// Ensure that the size of the struct is smaller than common block
enum { test_size = 1 / (sizeof(*APP) <= APP_COMMON_SIZE) };


static void
star_create(
	struct star * const star
)
{
	uint8_t theta = rand() & 0xFF;
	int32_t vel = (rand() & 0x7F) + 1;
	star->dx = (sin_lookup(theta) * vel) / 1024;
	star->dy = (cos_lookup(theta) * vel) / 1024;

	star->x = 0;
	star->y = 0;
	star->age = 0;

	// Brighter stars are faster
	star->brightness = vel * 2;
}


static void
stars_twist(void)
{
	// Pick a slow rotate speed
	uint8_t rotate = (rand() & 0x3) - 2;
	APP->rotate_sin = sin_lookup(rotate);
	APP->rotate_cos = cos_lookup(rotate);
}


static void
stars_init(void)
{
	pulse_blank_canvas();

	for (int i=0 ; i < MAX_STARS ; i++)
		star_create(&APP->stars[i]);

	stars_twist();
}


static void
star_draw_point(
	const struct star * const star,
	color24_t color
)
{
	int16_t x = star->x / 128 + SCREEN_WIDTH / 2;
	int16_t y = star->y / 128 + SCREEN_HEIGHT / 2;

	pulse_set_draw_window(x, y, x, y);
	pulse_draw_point24(color);
}
	


static void
star_draw(
	struct star * const star
)
{
	// Turn off its current location
	star_draw_point(star, COLOR_BLACK24);

	// Rotate the dx and allow it to speed up a bit
	int32_t dx = (APP->rotate_cos * star->dx - APP->rotate_sin * star->dy) / 120;
	int32_t dy = (APP->rotate_cos * star->dy + APP->rotate_sin * star->dx) / 120;

	// Rotate the position, also allowing for some speed up
	int32_t x = (APP->rotate_cos * star->x - APP->rotate_sin * star->y) / 120 + dx;
	int32_t y = (APP->rotate_cos * star->y + APP->rotate_sin * star->x) / 120 + dy;

	if (x <= -SCREEN_WIDTH * 64 || x >= SCREEN_WIDTH * 64
	||  y <= -SCREEN_HEIGHT * 64 || y >= SCREEN_HEIGHT * 64
	||  star->age++ > 4000)
	{
		star_create(star);
		return;
	}
		

	star->x = x;
	star->y = y;
	star->dx = dx;
	star->dy = dy;

	color24_t color = {
		.red	= star->brightness,
		.blue	= star->brightness,
		.green	= star->brightness,
	};

	// Earlier stars are darker
	if (star->age < 1000)
		color.red = color.blue = color.green = star->brightness / 4;
	else
	if (star->age < 2000)
		color.red = color.blue = color.green = star->brightness / 2;

	star_draw_point(star, color);
}




static void
stars_loop(
	const struct pulse_time_tm * const now
)
{
	uint32_t now_ms = pulse_get_millis();
	if (now_ms - APP->last_update < 30)
		return;
	APP->last_update = now_ms;

	for (int i=0 ; i < MAX_STARS ; i++)
		star_draw(&APP->stars[i]);
}


const app_t stars_app = {
	.init		= stars_init,
	.loop		= stars_loop,
	.button_down	= stars_twist,
};