-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsim_blank.c
More file actions
155 lines (133 loc) · 7.38 KB
/
Copy pathsim_blank.c
File metadata and controls
155 lines (133 loc) · 7.38 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// The blank simulation -> SIM_BLANK. Reference sim: the least a SimDef can implement and still
// draw something. One density channel, goo's density repulsion on it, white particles, no trail,
// no per-particle identity, no flags of its own.
//
// NOT compiled by default -- see GOO_SIM_BLANK in nob.c. It exists to be read and copied when
// starting a new sim, and to be the control when a change to core makes one of the real sims look
// different: if blank moves too, the change was core's.
//
// Half the vtable is NULL here, and that is the point. Compare sim_goo.c (trail buffers, its own
// flags, a bool fixup) and sim_pollock.c (stored family membership, a snapshot, a per-pair
// transition hook) to see what each of those slots is actually for.
#include "sim_def.h"
#include <gl.h>
#include "blank/screen.h"
#include "blank/velocity.h"
Shader blankScreenShader = {.name = "blankScreenShader"};
Shader blankVelocityShader = {.name = "blankVelocityShader"};
// One channel. Core owns the buffer, the splat and the exposure follower; the sim only says how
// many channels it wants.
static Density blank_density = {0};
static void blank_shaders(void) {
shader_create(&blankVelocityShader);
shader_compile(&blankVelocityShader, GL_VERTEX_SHADER, blank_velocity_VertexShaderSource);
shader_compile(&blankVelocityShader, GL_FRAGMENT_SHADER, blank_velocity_FragmentShaderSource);
shader_link(&blankVelocityShader);
shader_create(&blankScreenShader);
shader_compile(&blankScreenShader, GL_VERTEX_SHADER, blank_screen_VertexShaderSource);
shader_compile(&blankScreenShader, GL_FRAGMENT_SHADER, blank_screen_FragmentShaderSource);
shader_link(&blankScreenShader);
}
// No assigned state to restore, so the blob is ignored -- the density field regenerates from
// particle positions within a frame or two, which is also why snapshot is NULL below.
static void blank_buffers(const void *blob, size_t blob_size) {
(void)blob;
(void)blob_size;
density_create(&blank_density, "Blank density buffer", 1);
}
static void blank_static_uniforms(void) {
shader_set_uniform_int(&blankVelocityShader, "position_buffer", positionBuffer.current);
shader_set_uniform_int(&blankVelocityShader, "velocity_buffer", velocityBuffer.current);
shader_set_uniform_int(&blankVelocityShader, "density_buffer", blank_density.buffer.current);
shader_set_uniform_int(&blankVelocityShader, "repel_buffer", repelBuffer.current);
shader_set_uniform_float(&blankVelocityShader, "drag_coefficient", (float)dragCoefficient);
shader_set_uniform_float(&blankVelocityShader, "dither_coefficient", (float)ditherCoefficient);
shader_set_uniform_float(&blankVelocityShader, "dither_density_gain", (float)ditherDensityGain);
shader_set_uniform_float(&blankVelocityShader, "dither_ortho", (float)ditherOrtho);
shader_set_uniform_float(&blankVelocityShader, "density_force", (float)densityForce);
shader_set_uniform_float(&blankVelocityShader, "reach", (float)reach);
shader_set_uniform_float(&blankVelocityShader, "repel_coefficient", (float)repel);
shader_set_uniform_float(&blankVelocityShader, "anti_stick", (float)antiStick);
shader_set_uniform_int(&blankScreenShader, "density_buffer", blank_density.buffer.current);
shader_set_uniform_float(&blankScreenShader, "cull_amount", (float)cullAmount);
shader_set_uniform_float(&blankScreenShader, "render_gamma", (float)renderGamma);
shader_set_uniform_float(&blankScreenShader, "alpha_speed", (float)alphaSpeed);
}
static void blank_integrate(int epoch_counter, const float mouse_position[2], const float mouse_velocity[2]) {
(void)mouse_position;
(void)mouse_velocity; // the mouse arrives through the shared repel field, not directly
shader_use(&blankVelocityShader);
shader_set_uniform_vec(&blankVelocityShader, "buffer_shape", 2, (float[]){(float)repel_width, (float)repel_height});
shader_set_uniform_int(&blankVelocityShader, "position_buffer", positionBuffer.current);
shader_set_uniform_int(&blankVelocityShader, "velocity_buffer", velocityBuffer.current);
shader_set_uniform_int(&blankVelocityShader, "epoch_counter", epoch_counter);
buffer_bind(&velocityBuffer, other);
buffer_update(&velocityBuffer);
buffer_flip(&velocityBuffer);
LAP(sim_pass_base + 0); // vel
shader_use(&positionShader); // core's, shared by every sim
shader_set_uniform_int(&positionShader, "position_buffer", positionBuffer.current);
shader_set_uniform_int(&positionShader, "velocity_buffer", velocityBuffer.current);
buffer_bind(&positionBuffer, other);
buffer_update(&positionBuffer);
buffer_flip(&positionBuffer);
LAP(sim_pass_base + 1); // pos
}
static void blank_fields(int epoch_counter) {
if (dens_every <= 1 || epoch_counter % dens_every == 0)
density_splat(&blank_density);
LAP(sim_pass_base + 2); // dens
}
static void blank_draw(float weight) {
// The point pass shares its vertex stage with pollock, which reads attribute 2 as the density
// channel. One channel here, so pin the constant at 0 -- and per draw, not at setup: in a
// transition pollock's splat enables the array on the same slot.
glDisableVertexAttribArray(2);
glVertexAttrib1f(2, 0.0f);
shader_use(&blankScreenShader);
shader_set_uniform_float(&blankScreenShader, "draw_weight", weight);
shader_set_uniform_float(&blankScreenShader, "render_headroom",
renderHeadroom > 0.0 ? (float)renderHeadroom : blank_density.headroom.ema);
glDrawElements(GL_POINTS, P, GL_UNSIGNED_INT, 0);
}
static void blank_resize(void) {
density_resize(&blank_density);
}
static void blank_update_shapes(const float sim_shape[2], const float render_shape[2]) {
shader_set_uniform_vec(&blankScreenShader, "window_shape", 2, (float *)sim_shape);
shader_set_uniform_vec(&blankVelocityShader, "window_shape", 2, (float *)sim_shape);
shader_set_uniform_vec(&blankScreenShader, "render_shape", 2, (float *)render_shape);
}
static void blank_dump(const char *prefix) {
char path[1024];
snprintf(path, sizeof path, "%s_density.ppm", prefix);
dump_ppm_scalar(path, blank_density.width, blank_density.height,
pool_framebuffers.items[blank_density.buffer.current]);
}
// Placeholder so blank keeps a --blank.* block: the option table, its --help section and the merge
// into core's table all key off a non-empty opts array. Reads and writes nothing.
static dropt_bool blank_dummy = 0;
static dropt_option blank_opts[] = {
{'\0', "blank.dummy", "Placeholder, does nothing -- blank has no tunables of its own.", NULL,
dropt_handle_bool, &blank_dummy},
};
static const char *const blank_pass_names[] = {"vel", "pos", "dens"};
const SimDef SIM_BLANK = {
.name = "blank",
.shaders = blank_shaders,
.buffers = blank_buffers,
.static_uniforms = blank_static_uniforms,
.integrate = blank_integrate,
.fields = blank_fields,
.draw = blank_draw,
.resize = blank_resize,
.update_shapes = blank_update_shapes,
.dump = blank_dump,
.density = &blank_density,
.opts = blank_opts,
.n_opts = sizeof blank_opts / sizeof blank_opts[0],
.pass_names = blank_pass_names,
.n_passes = sizeof blank_pass_names / sizeof blank_pass_names[0],
// teardown_cpu, apply_opts, key, enter_from, snapshot: nothing to do. No heap scratch, no bool
// flags, no keys, no per-pair setup, and no assigned state worth carrying across a context loss.
};