forked from maximecb/uvm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplasma.c
138 lines (112 loc) · 3.42 KB
/
plasma.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Demoscene-style plasma effect
// Based on a tutorial by Lode Vandevenne
// https://lodev.org/cgtutor/plasma.html
#include <uvm/syscalls.h>
#include <uvm/utils.h>
#include <uvm/graphics.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#define FRAME_WIDTH 512
#define FRAME_HEIGHT 512
u64 prog_start_time;
// RGBA pixels
u32 frame_buffer[FRAME_HEIGHT][FRAME_WIDTH];
// Palette of RGB colors
u32 palette[256];
// Greyscale plasma values
int plasma[FRAME_HEIGHT][FRAME_WIDTH];
// Convert a color from HSV format to RGB format
u32 hsv_to_rgb(float h, float s, float v)
{
if (s < 0.01f)
{
// simple gray conversion
int c = (int)(v * 255.0f);
return rgb32(c, c, c);
}
// convert hue from [0, 360( to range [0,6)
h = h / 60.0f;
if (h >= 6.0f)
h = h - 6.0f;
// break "h" down into integer and fractional parts.
int i = (int)h;
float f = h - (float)i;
// Compute the permuted RGB values
int vi = (int)(f * 255.0f);
int p = (int)((v * (1.0f - s)) * 255.0f);
int q = (int)((v * (1.0f - (s * f))) * 255.0f);
int t = (int)((v * (1.0f - (s * (1.0f - f)))) * 255.0f);
// map v, p, q, and t into red, green, and blue values
if (i == 0)
return rgb32(vi, t, p);
if (i == 1)
return rgb32(q, vi, p);
if (i == 2)
return rgb32(p, vi, t);
if (i == 3)
return rgb32(p, q, vi);
if (i == 4)
return rgb32(t, p, vi);
return rgb32(vi, p, q);
}
void anim_callback()
{
u64 frame_start_time = time_current_ms();
int time_ms_i = (int)(frame_start_time - prog_start_time);
int palette_offs = time_ms_i / 20;
// Clear the frame buffer, set all pixels to black
memset32(frame_buffer, 0, sizeof(frame_buffer) / 4);
// Draw the plasma with a shifted palette
for (int y = 0; y < FRAME_HEIGHT; ++y)
{
for (int x = 0; x < FRAME_WIDTH; ++x)
{
frame_buffer[y][x] = palette[(plasma[y][x] + palette_offs) % 256];
}
}
window_draw_frame(0, frame_buffer);
// Schedule a fixed rate update for the next frame (40fps)
fixed_rate_update(frame_start_time, 1000 / 40, anim_callback);
}
void keydown(u64 window_id, u16 keycode)
{
if (keycode == KEY_ESCAPE)
{
exit(0);
}
}
void main()
{
prog_start_time = time_current_ms();
// Generate the palette
for (int i = 0; i < 256; ++i)
{
// Vary the hue through the palette
palette[i] = hsv_to_rgb(360.0f / 256.0f * (float)i, 1.0f, 1.0f);
}
// Generate the greyscale plasma values
for (int y = 0; y < FRAME_HEIGHT; ++y)
{
for (int x = 0; x < FRAME_WIDTH; ++x)
{
float dx1 = (float)x - 128;
float dy1 = (float)y - 128;
float d1 = sqrtf(dx1*dx1 + dy1*dy1) / 7.0f;
float dx2 = (float)x - 300;
float dy2 = (float)y - 306;
float d2 = sqrtf(dx2*dx2 + dy2*dy2) / 5.0f;
// Sum of multiple sine functions, divided by number of sines
plasma[y][x] = (int)(
128.0f + (128.0f * sinf((float)x / 12.0f))
+ 128.0f + (128.0f * sinf((float)y / 35.0f))
+ 128.0f + (128.0f * sinf(d1))
+ 128.0f + (128.0f * sinf(d2))
) / 4;
}
}
window_create(FRAME_WIDTH, FRAME_HEIGHT, "Demoscene Plasma Effect", 0);
window_on_keydown(0, keydown);
time_delay_cb(0, anim_callback);
enable_event_loop();
}