Spiral kink mode for particles.
This is BAD code, but the particle kinking does not make it easy to write a non-local modifier that requires neighboring positions, curvature, etc. The feature is needed for Gooseberry.
This commit is contained in:
@@ -1230,14 +1230,22 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
|
||||
split = layout.split()
|
||||
split.active = part.kink != 'NO'
|
||||
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
sub.prop(part, "kink_amplitude")
|
||||
sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
|
||||
col.prop(part, "kink_flat", slider=True)
|
||||
col = split.column(align=True)
|
||||
col.prop(part, "kink_frequency")
|
||||
col.prop(part, "kink_shape", slider=True)
|
||||
if part.kink in {'SPIRAL'}:
|
||||
col = split.column()
|
||||
col.prop(part, "kink_amplitude", text="Radius")
|
||||
col.prop(part, "kink_flat", text="Start", slider=True)
|
||||
col = split.column(align=True)
|
||||
col.prop(part, "kink_frequency", text="Frequency")
|
||||
col.prop(part, "kink_shape", text="Shape", slider=True)
|
||||
else:
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
sub.prop(part, "kink_amplitude")
|
||||
sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
|
||||
col.prop(part, "kink_flat", slider=True)
|
||||
col = split.column(align=True)
|
||||
col.prop(part, "kink_frequency")
|
||||
col.prop(part, "kink_shape", slider=True)
|
||||
|
||||
|
||||
class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
|
||||
|
||||
@@ -105,7 +105,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
|
||||
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
|
||||
extern void do_child_modifiers(ParticleSimulationData *sim,
|
||||
ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3],
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t, float spiral_start[3], float *time_prev, float *co_prev);
|
||||
|
||||
/* few helpers for countall etc. */
|
||||
int count_particles(ParticleSystem *psys)
|
||||
@@ -1671,7 +1671,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
|
||||
/************************************************/
|
||||
|
||||
extern void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat,
|
||||
short type, short axis, float obmat[4][4], int smooth_start);
|
||||
short type, short axis, float obmat[4][4], int smooth_start, float spiral_start[3], float *time_prev, float *co_prev);
|
||||
extern float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
|
||||
bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
|
||||
|
||||
@@ -1729,90 +1729,91 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
|
||||
float vec_to_point[3];
|
||||
|
||||
if (effectors) for (eff = effectors->first; eff; eff = eff->next) {
|
||||
pd = eff->pd;
|
||||
|
||||
if (pd->forcefield != PFIELD_GUIDE)
|
||||
continue;
|
||||
|
||||
data = eff->guide_data + index;
|
||||
|
||||
if (data->strength <= 0.0f)
|
||||
continue;
|
||||
|
||||
guidetime = time / (1.0f - pd->free_end);
|
||||
|
||||
if (guidetime > 1.0f)
|
||||
continue;
|
||||
|
||||
cu = (Curve *)eff->ob->data;
|
||||
|
||||
if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
|
||||
if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
mul_m4_v3(eff->ob->obmat, guidevec);
|
||||
mul_mat3_m4_v3(eff->ob->obmat, guidedir);
|
||||
|
||||
normalize_v3(guidedir);
|
||||
|
||||
copy_v3_v3(vec_to_point, data->vec_to_point);
|
||||
|
||||
if (guidetime != 0.0f) {
|
||||
/* curve direction */
|
||||
cross_v3_v3v3(temp, eff->guide_dir, guidedir);
|
||||
angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir));
|
||||
angle = saacos(angle);
|
||||
axis_angle_to_quat(rot2, temp, angle);
|
||||
mul_qt_v3(rot2, vec_to_point);
|
||||
|
||||
/* curve tilt */
|
||||
axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
|
||||
mul_qt_v3(rot2, vec_to_point);
|
||||
}
|
||||
|
||||
/* curve taper */
|
||||
if (cu->taperobj)
|
||||
mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
|
||||
|
||||
else { /* curve size*/
|
||||
if (cu->flag & CU_PATH_RADIUS) {
|
||||
mul_v3_fl(vec_to_point, radius);
|
||||
}
|
||||
}
|
||||
|
||||
if (part->clumpcurve)
|
||||
curvemapping_changed_all(part->clumpcurve);
|
||||
if (part->roughcurve)
|
||||
curvemapping_changed_all(part->roughcurve);
|
||||
|
||||
{
|
||||
ParticleKey key, par;
|
||||
float orco_offset[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
par.co[0] = par.co[1] = par.co[2] = 0.0f;
|
||||
copy_v3_v3(key.co, vec_to_point);
|
||||
do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
|
||||
do_clump(&key, &par, guidetime, orco_offset, pd->clump_fac, pd->clump_pow, 1.0f,
|
||||
part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve);
|
||||
copy_v3_v3(vec_to_point, key.co);
|
||||
}
|
||||
|
||||
add_v3_v3(vec_to_point, guidevec);
|
||||
|
||||
//sub_v3_v3v3(pa_loc, pa_loc, pa_zero);
|
||||
madd_v3_v3fl(effect, vec_to_point, data->strength);
|
||||
madd_v3_v3fl(veffect, guidedir, data->strength);
|
||||
totstrength += data->strength;
|
||||
|
||||
if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT)
|
||||
totstrength *= weight;
|
||||
pd = eff->pd;
|
||||
|
||||
if (pd->forcefield != PFIELD_GUIDE)
|
||||
continue;
|
||||
|
||||
data = eff->guide_data + index;
|
||||
|
||||
if (data->strength <= 0.0f)
|
||||
continue;
|
||||
|
||||
guidetime = time / (1.0f - pd->free_end);
|
||||
|
||||
if (guidetime > 1.0f)
|
||||
continue;
|
||||
|
||||
cu = (Curve *)eff->ob->data;
|
||||
|
||||
if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
|
||||
if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
else {
|
||||
if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
mul_m4_v3(eff->ob->obmat, guidevec);
|
||||
mul_mat3_m4_v3(eff->ob->obmat, guidedir);
|
||||
|
||||
normalize_v3(guidedir);
|
||||
|
||||
copy_v3_v3(vec_to_point, data->vec_to_point);
|
||||
|
||||
if (guidetime != 0.0f) {
|
||||
/* curve direction */
|
||||
cross_v3_v3v3(temp, eff->guide_dir, guidedir);
|
||||
angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir));
|
||||
angle = saacos(angle);
|
||||
axis_angle_to_quat(rot2, temp, angle);
|
||||
mul_qt_v3(rot2, vec_to_point);
|
||||
|
||||
/* curve tilt */
|
||||
axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
|
||||
mul_qt_v3(rot2, vec_to_point);
|
||||
}
|
||||
|
||||
/* curve taper */
|
||||
if (cu->taperobj)
|
||||
mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
|
||||
|
||||
else { /* curve size*/
|
||||
if (cu->flag & CU_PATH_RADIUS) {
|
||||
mul_v3_fl(vec_to_point, radius);
|
||||
}
|
||||
}
|
||||
|
||||
if (part->clumpcurve)
|
||||
curvemapping_changed_all(part->clumpcurve);
|
||||
if (part->roughcurve)
|
||||
curvemapping_changed_all(part->roughcurve);
|
||||
|
||||
{
|
||||
ParticleKey key, par;
|
||||
float orco_offset[3] = {0.0f, 0.0f, 0.0f};
|
||||
float spiral_start[3], time_prev = 0.0f, co_prev[3] = {0,0,0};
|
||||
|
||||
par.co[0] = par.co[1] = par.co[2] = 0.0f;
|
||||
copy_v3_v3(key.co, vec_to_point);
|
||||
do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0, spiral_start, &time_prev, co_prev);
|
||||
do_clump(&key, &par, guidetime, orco_offset, pd->clump_fac, pd->clump_pow, 1.0f,
|
||||
part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve);
|
||||
copy_v3_v3(vec_to_point, key.co);
|
||||
}
|
||||
|
||||
add_v3_v3(vec_to_point, guidevec);
|
||||
|
||||
//sub_v3_v3v3(pa_loc, pa_loc, pa_zero);
|
||||
madd_v3_v3fl(effect, vec_to_point, data->strength);
|
||||
madd_v3_v3fl(veffect, guidedir, data->strength);
|
||||
totstrength += data->strength;
|
||||
|
||||
if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT)
|
||||
totstrength *= weight;
|
||||
}
|
||||
|
||||
if (totstrength != 0.0f) {
|
||||
if (totstrength > 1.0f)
|
||||
mul_v3_fl(effect, 1.0f / totstrength);
|
||||
@@ -3816,7 +3817,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
|
||||
copy_particle_key(&tstate, state, 1);
|
||||
|
||||
/* apply different deformations to the child path */
|
||||
do_child_modifiers(sim, &ptex, par, par->rot, par_orco, cpa, orco, hairmat, state, t);
|
||||
{
|
||||
float spiral_start[3], time_prev = 0.0f, co_prev[3] = {0,0,0};
|
||||
do_child_modifiers(sim, &ptex, par, par->rot, par_orco, cpa, orco, hairmat, state, t, spiral_start, &time_prev, co_prev);
|
||||
}
|
||||
|
||||
/* try to estimate correct velocity */
|
||||
if (vel) {
|
||||
@@ -3912,6 +3916,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
|
||||
ParticleKey *key1;
|
||||
float t = (cfra - pa->time) / pa->lifetime;
|
||||
float par_orco[3] = {0.0f, 0.0f, 0.0f};
|
||||
float spiral_start[3], time_prev = 0.0f, co_prev[3] = {0,0,0};
|
||||
|
||||
key1 = &pa->state;
|
||||
offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad);
|
||||
@@ -3919,7 +3924,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
|
||||
CLAMP(t, 0.0f, 1.0f);
|
||||
|
||||
unit_m4(mat);
|
||||
do_child_modifiers(sim, NULL, key1, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
|
||||
do_child_modifiers(sim, NULL, key1, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t, spiral_start, &time_prev, co_prev);
|
||||
|
||||
if (psys->lattice_deform_data)
|
||||
calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
struct Material;
|
||||
|
||||
void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat,
|
||||
short type, short axis, float obmat[4][4], int smooth_start);
|
||||
short type, short axis, float obmat[4][4], int smooth_start, float spiral_start[3], float *time_prev, float *co_prev);
|
||||
float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
|
||||
bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
|
||||
void do_child_modifiers(ParticleSimulationData *sim,
|
||||
ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3],
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t, float spiral_start[3], float *time_prev, float *co_prev);
|
||||
|
||||
static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
|
||||
{
|
||||
@@ -163,11 +163,15 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
|
||||
|
||||
{
|
||||
ParticlePathIterator iter;
|
||||
float spiral_start[3];
|
||||
float time_prev = 0.0f;
|
||||
float co_prev[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
for (k = 0, key = keys; k < totkeys; k++, key++) {
|
||||
psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
|
||||
|
||||
/* apply different deformations to the child path */
|
||||
do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
|
||||
do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time, spiral_start, &time_prev, co_prev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -203,7 +207,9 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start)
|
||||
void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape,
|
||||
float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start,
|
||||
float spiral_start[3], float *time_prev, float *co_prev)
|
||||
{
|
||||
float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f};
|
||||
float t, dt = 1.f, result[3];
|
||||
@@ -213,7 +219,7 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f
|
||||
|
||||
CLAMP(time, 0.f, 1.f);
|
||||
|
||||
if (shape != 0.0f && type != PART_KINK_BRAID) {
|
||||
if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID, PART_KINK_SPIRAL)) {
|
||||
if (shape < 0.0f)
|
||||
time = (float)pow(time, 1.f + shape);
|
||||
else
|
||||
@@ -222,14 +228,14 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f
|
||||
|
||||
t = time * freq * (float)M_PI;
|
||||
|
||||
if (smooth_start) {
|
||||
if (smooth_start && !ELEM(type, PART_KINK_SPIRAL)) {
|
||||
dt = fabsf(t);
|
||||
/* smooth the beginning of kink */
|
||||
CLAMP(dt, 0.f, (float)M_PI);
|
||||
dt = sinf(dt / 2.f);
|
||||
}
|
||||
|
||||
if (type != PART_KINK_RADIAL) {
|
||||
if (!ELEM(type, PART_KINK_RADIAL, PART_KINK_SPIRAL)) {
|
||||
float temp[3];
|
||||
|
||||
kink[axis] = 1.f;
|
||||
@@ -353,6 +359,65 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PART_KINK_SPIRAL:
|
||||
{
|
||||
if (time <= flat) {
|
||||
/* nothing to do for the flat section */
|
||||
}
|
||||
else {
|
||||
#if 0
|
||||
/* Creates a logarithmic spiral:
|
||||
* r(theta) = a * exp(b * theta)
|
||||
*
|
||||
* For now chose the golden spiral for the "density" parameter b:
|
||||
* http://en.wikipedia.org/wiki/Golden_spiral
|
||||
* This could be configurable, but the golden spiral is quite pleasant and natural
|
||||
*/
|
||||
const float b = (1.0f + sqrtf(5.0f)) / (2.0f * M_PI);
|
||||
const float arc_factor = sqrtf(1.0f + b*b) / b;
|
||||
|
||||
/* Relation to amplitude (spiral radius):
|
||||
* a*exp(b*theta0) = sqrt(2) * R
|
||||
*
|
||||
* Arc length of the logarithmic spiral:
|
||||
* s(theta) = a*exp(b*theta) * (1 + b^2)/b
|
||||
*/
|
||||
|
||||
const float a = arc_length / (sqrtf(2.0f) * amplitude * arc_factor);
|
||||
const float theta0 = logf(sqrtf(2.0f) * amplitude / a) / b;
|
||||
|
||||
float arc = max_length - time;
|
||||
float theta = logf(arc / (a * arc_factor)) / b;
|
||||
#else
|
||||
// float theta = (time - flat) / amplitude;
|
||||
#endif
|
||||
|
||||
float dir[3], up[3], rot[3][3];
|
||||
float vec[3];
|
||||
|
||||
float theta = freq * (time - flat) / (1.0f - flat);
|
||||
// float arc = theta * amplitude;
|
||||
float radius = amplitude * expf(shape * theta);
|
||||
|
||||
normalize_v3_v3(dir, par->vel);
|
||||
cross_v3_v3v3(up, dir, kink);
|
||||
axis_angle_normalized_to_mat3(rot, kink, theta);
|
||||
|
||||
if (*time_prev <= flat) {
|
||||
interp_v3_v3v3(spiral_start, co_prev, state->co, (flat - *time_prev) / (time - *time_prev));
|
||||
}
|
||||
|
||||
mul_v3_v3fl(vec, up, radius);
|
||||
mul_v3_m3v3(result, rot, vec);
|
||||
|
||||
madd_v3_v3fl(result, up, -radius);
|
||||
add_v3_v3(result, spiral_start);
|
||||
}
|
||||
|
||||
*time_prev = time;
|
||||
copy_v3_v3(co_prev, state->co);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* blend the start of the kink */
|
||||
@@ -475,7 +540,7 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa
|
||||
}
|
||||
|
||||
void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3],
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t)
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t, float spiral_start[3], float *time_prev, float *co_prev)
|
||||
{
|
||||
ParticleSettings *part = sim->psys->part;
|
||||
int i = cpa - sim->psys->child;
|
||||
@@ -506,11 +571,17 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part
|
||||
part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve);
|
||||
|
||||
if (kink_freq != 0.f) {
|
||||
float kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump);
|
||||
float kink_amp;
|
||||
/* seriously ... */
|
||||
if (ELEM(part->kink, PART_KINK_SPIRAL))
|
||||
kink_amp = part->kink_amp;
|
||||
else
|
||||
kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump);
|
||||
|
||||
do_kink(state, par, par_rot, t, kink_freq, part->kink_shape,
|
||||
kink_amp, part->kink_flat, part->kink, part->kink_axis,
|
||||
sim->ob->obmat, sim->psys->part->childtype == PART_CHILD_FACES);
|
||||
sim->ob->obmat, sim->psys->part->childtype == PART_CHILD_FACES,
|
||||
spiral_start, time_prev, co_prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -417,11 +417,14 @@ typedef enum eParticleDrawFlag {
|
||||
#define PART_PHYS_FLUID 4
|
||||
|
||||
/* part->kink */
|
||||
#define PART_KINK_NO 0
|
||||
#define PART_KINK_CURL 1
|
||||
#define PART_KINK_RADIAL 2
|
||||
#define PART_KINK_WAVE 3
|
||||
#define PART_KINK_BRAID 4
|
||||
typedef enum eParticleKink {
|
||||
PART_KINK_NO = 0,
|
||||
PART_KINK_CURL = 1,
|
||||
PART_KINK_RADIAL = 2,
|
||||
PART_KINK_WAVE = 3,
|
||||
PART_KINK_BRAID = 4,
|
||||
PART_KINK_SPIRAL = 5,
|
||||
} eParticleKink;
|
||||
|
||||
/* part->kink_flag */
|
||||
typedef enum eParticleChildFlag {
|
||||
|
||||
@@ -2001,6 +2001,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
{PART_KINK_RADIAL, "RADIAL", 0, "Radial", ""},
|
||||
{PART_KINK_WAVE, "WAVE", 0, "Wave", ""},
|
||||
{PART_KINK_BRAID, "BRAID", 0, "Braid", ""},
|
||||
{PART_KINK_SPIRAL, "SPIRAL", 0, "Spiral", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user