Subversion Repositories DIN Is Noise

Rev

Rev 2097 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
244 jag 1
/*
2
* ball.cc
2302 jag 3
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
1713 jag 4
* DIN Is Noise is released under GNU Public License 2.0
1822 jag 5
* DIN Is Noise is released under GNU Public License 2.0
1479 jag 6
* For more information, please visit https://dinisnoise.org/
244 jag 7
*/
8
 
81 - 9
#include "mondrian.h"
10
#include "console.h"
11
#include "utils.h"
12
#include "vector2d.h"
13
#include <utility>
395 jag 14
 
127 jag 15
using namespace std;
81 - 16
 
17
extern mondrian mondrian0;
1797 jag 18
extern const float PI_BY_180;
1822 jag 19
extern const float TWO_PI;
1756 jag 20
extern int TRAILSIZE;
81 - 21
 
1756 jag 22
ball::ball (int _type) : trail (TRAILSIZE) {
478 jag 23
  init (_type);
24
}
81 - 25
 
26
void ball::init (int _type) {
1419 jag 27
  trig_what = NOTE;
478 jag 28
  x = y = 0;
29
  R = 0;
81 - 30
  V = 0;
31
  vx = vy = 0;
478 jag 32
  vm = vm_1 = vm_inf = 0;
81 - 33
  select = 0;
34
  frozen = 1;
35
  vol_mult = 1;
36
  mod = 0;
37
  attack_time = recent_attack_time;
38
  decay_time = recent_decay_time;
2001 jag 39
  pitch_mult = 1.0; // recent_pitch_mult;
81 - 40
  num_notes = 0;
41
  del = 0;
42
  auto_rotate = 0;
43
  dtheta = PI_BY_180;
44
  set_type (_type);
45
  ++ref;
46
}
47
 
445 jag 48
void ball::clone_this (ball* C) {
437 jag 49
 
50
  rnd<float> rd (0, TWO_PI);
51
  float rad = rd ();
445 jag 52
  C->x = x + op_clone.offset * cos (rad);
53
  C->y = y + op_clone.offset * sin (rad);
437 jag 54
 
445 jag 55
  C->R = R;
56
  C->R->balls.push_back (C);
437 jag 57
 
445 jag 58
  C->V = V;
59
  C->vx = vx;
60
  C->vy = vy;
61
  C->vol_mult = vol_mult;
62
  C->mod = mod;
63
  C->attack_time = attack_time;
64
  C->decay_time = decay_time;
65
  C->pitch_mult = pitch_mult;
66
  C->auto_rotate = auto_rotate;
67
  C->dtheta = dtheta;
68
  C->set_type (type);
69
  C->op_turn = op_turn;
70
  C->op_speed = op_speed;
71
  C->op_teleport = op_teleport;
72
  C->op_clone = op_clone;
73
  C->op_clone.n = op_clone.max;
441 jag 74
  if (op_clone.alarm.active) {
459 jag 75
    if (op_clone.clone_can_clone)
445 jag 76
      C->op_clone.alarm.start ();
459 jag 77
    else
445 jag 78
      C->op_clone.alarm.stop ();
441 jag 79
  }
490 jag 80
  C->op_transform = op_transform;
445 jag 81
  C->frozen = frozen;
474 jag 82
  C->trail = trail;
1419 jag 83
  C->trig_what = trig_what;
437 jag 84
}
85
 
81 - 86
void ball::set_velocity (float dx, float dy) {
87
  V = unit_vector (vx, vy, dx, dy);
301 jag 88
  if (V == 0) V = unit_vector (vx, vy, 1.0f, 1.0f);
1302 jag 89
  op_speed.max = max (op_speed.max, V);
81 - 90
  calc_velocity_slope ();
91
}
92
 
93
void ball::rotate_velocity (int dir) {
94
  rotate_vector (vx, vy, dir * dtheta);
95
  calc_velocity_slope ();
96
}
97
 
98
void ball::calc_velocity_slope () {
99
  if (vx != 0) {
100
    vm = vy * 1.0f / vx;
101
    vm_1 = 1.0f / vm;
102
    vm_inf = 0;
103
  } else {
104
    vm = 0.0f;
105
    vm_1 = 0.0f;
106
    vm_inf = 1;
107
  }
108
}
109
 
127 jag 110
void ball::on_edge_hit (int e1, int e2, int cl, float& v, float xry, float yrx, float elb, float ewh, pair<float, float>& invl, int& eh) {
111
  eh = 1;
112
  int walle [] = {e1, 0, e2};
113
  slit* S = 0;
114
  rect* RO = get_other_rect_of_slit (R, walle[cl+1], xry, &S);
115
  if (RO) { // ball in slit
116
    eh = 0; // edge hit didnt happen
117
    if (type == HEALER) mondrian0.remove_slit (S); // close slit
118
    R->erase (this);
119
    R = RO; // ball is now in other box
120
    R->balls.push_back (this);
121
  } else { // ball hit edge
122
    if (type == WRECKER) {
123
      if (mondrian0.slitting == mondrian::ANIMATE_SLIT) {
124
        mondrian0.fdr.restart ();
125
        mondrian0.add_remove_slit (x, y, &mondrian0.fdr); // make animated slit
126
      }
127
      else
128
        mondrian0.add_remove_slit (x, y); // make slit
129
    }
130
    v = -v; // flip component of velocity to rebound
1310 jag 131
    if (op_turn.alarm.active) op_turn.start (this);
127 jag 132
    calc_velocity_slope ();
133
    float xy, t0, dt;
134
    xy = yrx;
135
    t0 = elb;
136
    dt = ewh;
137
    mondrian0.launch_note (this, xy, t0, dt, invl);
138
  }
139
}
140
 
81 - 141
void ball::update () {
142
 
143
  int edge_hit = 0;
144
 
243 jag 145
  trail.add (x, y);
146
 
81 - 147
  if (!frozen) {
148
 
313 jag 149
    float px = x, py = y;
81 - 150
 
151
    // move the ball by a constant speed we found when user made the ball
152
    x += (V * vx);
153
    y += (V * vy);
313 jag 154
 
81 - 155
    box<float>& e = R->extents; // get the box the ball is bouncing in
156
    box<float>& eroot = mondrian0.root->extents; // get the root box
127 jag 157
 
81 - 158
    // check if the ball is still inside this box after move
159
    if (inbox (e, x, y)) {
160
      // ball is still inside the box so theres nothing to do
161
    } else { // ball has hit a wall or ceiling of box
313 jag 162
      check:
81 - 163
      int clx = clamp<float> (e.left, x, e.right);
164
      if (clx) { // hit wall
165
        if (vm_inf == 0) y = py + vm * (x - px); else y = py;
313 jag 166
        float yb4 = y;
167
        if (clamp (e.bottom, y, e.top)) { // below floor or above ceiling
168
          y = yb4;
169
          goto check;
301 jag 170
        }
127 jag 171
        on_edge_hit (edge::LEFT, edge::RIGHT, clx, vx, y, x, eroot.left, eroot.width_1, R->vint, edge_hit);
81 - 172
      } else {
173
        int cly = clamp<float> (e.bottom, y, e.top);
127 jag 174
        if (cly) { // hit floor or ceiling
81 - 175
          if (vm_inf == 0) x = px + vm_1 * (y - py); else x = px;
127 jag 176
          on_edge_hit (edge::BOTTOM, edge::TOP, cly, vy, x, y, eroot.bottom, eroot.height_1, R->hint, edge_hit);
81 - 177
        }
178
      }
179
    }
180
  }
181
  if (auto_rotate && !edge_hit) rotate_velocity (auto_rotate); // auto_rotate = -1 is clockwise; auto_rotate = 1 is anti-clockwise
182
}
183
 
184
 
185
void ball::set_type (int T) {
186
  type = T;
187
  switch (type) {
188
    case ball::BOUNCER:
189
      color_using_modulation ();
190
      break;
191
    case ball::WRECKER:
192
      r = 1.0f; g = 0.25f; b = 0.25f;
193
      break;
194
    case ball::HEALER:
195
      r = 0.0f; g = 1.0f; b = 1.0f;
196
  }
197
}
198
 
199
void ball::color_using_modulation () {
200
  if (type != ball::BOUNCER) return;
1546 jag 201
  if (mod < 1) {
131 jag 202
    r = g = b = 0.15f;
1546 jag 203
  } else if (mod > 1) {
81 - 204
    r = g = b = 1.0f;
205
  } else {
131 jag 206
    r = g = b = 0.60f;
81 - 207
  }
208
}
335 jag 209
 
210
void ball::print () {
211
  extern char BUFFER [];
1994 jag 212
  sprintf (BUFFER, "type = %s > %s, attack = %0.3f s, decay = %0.3f s, modulation = %0.3f", types_str [type], trigstr [trig_what], attack_time, decay_time, pitch_mult);
335 jag 213
  cons << BUFFER << eol;
214
}
395 jag 215
 
216
void ball::eval_ops () {
490 jag 217
  ball_op* ops [ball_op::NUM_OPS] = {&op_turn, &op_speed, &op_teleport, &op_clone, &op_transform};
489 jag 218
  for (int i = 0; i < ball_op::NUM_OPS; ++i) ops[i]->eval (this);
395 jag 219
}