forked from mremallin/christmas_tree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspiral.c
171 lines (139 loc) · 4.58 KB
/
spiral.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
* Christmas Tree - Brought to you by SDL2 and OpenGL
* Inspired by: https://github.com/anvaka/atree#
*
* Mike Mallin, 2019 - 2020
*/
#include "spiral.h"
#include <assert.h>
#include <math.h>
#include <string.h>
#include <GLES3/gl3.h>
#include "shader.h"
/* Internal context to encapsulate a given spiral */
typedef struct spiral_ctx_ {
int num_slices;
int num_rotations;
int cycle_time_ms;
float y_max;
float slope;
float starting_angle_offset;
GLuint vbo_id;
GLuint vao_id;
vec4 *verticies;
vec4 color;
} spiral_ctx;
/* This represents the bounding cone for the tree */
static float
get_r_for_point (spiral_ctx *ctx, float y)
{
/* ( y - b ) / m = r */
return (y - ctx->y_max) / ctx->slope;
}
static float
get_y_speed (spiral_ctx *ctx)
{
return (ctx->y_max / ctx->cycle_time_ms);
}
static void
spiral_update_point (spiral_ctx *ctx, vec4 point)
{
float r_clamp = get_r_for_point(ctx, point[1]);
/* Each one also gets rotated around the trunk.
* 3 rotations from start to finish should make a decent tree.
* The radius calculated above is the distance from the trunk
* the point must be. Need to turn the radius into an (x, z)
* coordinate to have it around the tree. Starting from
* y=0, want the spiral to also start from x=1 -> cos(3x) to
* know the x-component of the vertex.
*/
point[0] = r_clamp * cosf((ctx->num_rotations * 2.0f * point[1]) + ctx->starting_angle_offset);
point[2] = r_clamp * sinf((ctx->num_rotations * 2.0f * point[1]) + GLM_PI + ctx->starting_angle_offset);
}
static void
spiral_init_verticies (spiral_ctx *ctx)
{
size_t i;
for (i = 0; i < ctx->num_slices; i++) {
ctx->verticies[i][1] = (ctx->y_max/ctx->num_slices) * i;
ctx->verticies[i][3] = 1.0f;
spiral_update_point(ctx, ctx->verticies[i]);
}
}
static void
spiral_init_opengl (spiral_ctx *ctx)
{
glGenBuffers(1, &ctx->vbo_id);
glBindBuffer(GL_ARRAY_BUFFER, ctx->vbo_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(ctx->verticies[0]) * ctx->num_slices, ctx->verticies, GL_DYNAMIC_DRAW);
glGenVertexArrays(1, &ctx->vao_id);
glBindVertexArray(ctx->vao_id);
glBindBuffer(GL_ARRAY_BUFFER, ctx->vbo_id);
glVertexAttribPointer(get_vertex_attribute(),
4,
GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(get_vertex_attribute());
}
spiral
spiral_init(spiral_init_ctx *init)
{
spiral_ctx *ctx = malloc(sizeof(spiral_ctx));
assert(ctx);
ctx->num_slices = init->num_slices;
ctx->num_rotations = init->num_rotations;
ctx->cycle_time_ms = init->cycle_time_ms;
ctx->y_max = init->y_max;
ctx->slope = init->slope;
ctx->starting_angle_offset = init->starting_angle_offset;
memcpy(ctx->color, init->color, sizeof(ctx->color));
ctx->verticies = malloc(sizeof(vec4) * ctx->num_slices);
assert(ctx->verticies);
spiral_init_verticies(ctx);
spiral_init_opengl(ctx);
return (spiral)ctx;
}
/* To render the christmas tree:
* 1) Slice up the y-axis into discrete steps. Each one has a single point
* in it's plane (or n points eqidistant from each other)
* 2) Based on which slice this is, that determines how far away (r)
* from the y-axis the point is (r = (y-b)/m) to find the bounding cone
* of the spiral.
* Each slice also is at a different position on the circle from the
* ones surrounding it.
* 3) Each time step, update the points to move along the y-axis. Once
* a given point has surpassed a y-max, reset it to y=0 and continue.
*/
void
spiral_update (spiral _ctx, uint32_t delta_ms)
{
spiral_ctx *ctx = _ctx;
size_t i;
for (i = 0; i < ctx->num_slices; i++) {
ctx->verticies[i][1] += get_y_speed(ctx) * delta_ms;
if (ctx->verticies[i][1] > ctx->y_max) {
ctx->verticies[i][1] = 0.0f;
}
spiral_update_point(ctx, ctx->verticies[i]);
}
}
void
spiral_render (spiral _ctx)
{
spiral_ctx *ctx = _ctx;
glBindBuffer(GL_ARRAY_BUFFER, ctx->vbo_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(ctx->verticies[0]) * ctx->num_slices, ctx->verticies, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(get_vertex_attribute());
glUniform4fv(get_color_uniform_attribute(),
1, (GLfloat *)ctx->color);
glBindVertexArray(ctx->vao_id);
glDrawArrays(GL_POINTS, 0, ctx->num_slices);
glDisableVertexAttribArray(get_vertex_attribute());
}
void
spiral_free(spiral _ctx)
{
spiral_ctx *ctx = _ctx;
glDeleteVertexArrays(1, &ctx->vao_id);
glDeleteBuffers(1, &ctx->vbo_id);
free(ctx->verticies);
}