Subversion Repositories DIN Is Noise

Rev

Rev 329 | Rev 398 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* ball.cc
* DIN Is Noise is copyright (c) 2006-2017 Jagannathan Sampath
* For more information, please visit http://dinisnoise.org/
*/


#include "ball.h"
#include "mondrian.h"
#include "console.h"
#include "utils.h"
#include "vector2d.h"
#include <utility>
using namespace std;

extern mondrian mondrian0;
extern float PI_BY_180;

ball::ball (float _x, float _y, rect* _R) : x(_x), y(_y), R(_R) {init ();}

ball::ball (int _type) : trail (1, 10) { init (_type); }

void ball::init (int _type) {
  V = 0;
  vx = vy = 0;
  select = 0;
  frozen = 1;
  vol_mult = 1;
  mod = 0;
  r = g = b = 0.75f;
  attack_time = recent_attack_time;
  decay_time = recent_decay_time;
  pitch_mult = recent_pitch_mult;
  num_notes = 0;
  del = 0;
  auto_rotate = 0;
  dtheta = PI_BY_180;
  set_type (_type);
  ++ref;
}

void ball::set_velocity (float dx, float dy) {
  V = unit_vector (vx, vy, dx, dy);
  if (V == 0) V = unit_vector (vx, vy, 1.0f, 1.0f);
  calc_velocity_slope ();
}

void ball::rotate_velocity (int dir) {
  rotate_vector (vx, vy, dir * dtheta);
  calc_velocity_slope ();
}

void ball::calc_velocity_slope () {
  if (vx != 0) {
    vm = vy * 1.0f / vx;
    vm_1 = 1.0f / vm;
    vm_inf = 0;
  } else {
    vm = 0.0f;
    vm_1 = 0.0f;
    vm_inf = 1;
  }
}

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) {
  eh = 1;
  int walle [] = {e1, 0, e2};
  slit* S = 0;
  rect* RO = get_other_rect_of_slit (R, walle[cl+1], xry, &S);
  if (RO) { // ball in slit
    eh = 0; // edge hit didnt happen
    if (type == HEALER) mondrian0.remove_slit (S); // close slit
    R->erase (this);
    R = RO; // ball is now in other box
    R->balls.push_back (this);
  } else { // ball hit edge
    if (type == WRECKER) {
      if (mondrian0.slitting == mondrian::ANIMATE_SLIT) {
        mondrian0.fdr.restart ();
        mondrian0.add_remove_slit (x, y, &mondrian0.fdr); // make animated slit
      }
      else
        mondrian0.add_remove_slit (x, y); // make slit
    }
    v = -v; // flip component of velocity to rebound
    calc_velocity_slope ();
    float xy, t0, dt;
    xy = yrx;
    t0 = elb;
    dt = ewh;
    mondrian0.launch_note (this, xy, t0, dt, invl);
  }
}

void ball::update () {

  int edge_hit = 0;

  trail.add (x, y);

  if (!frozen) {

    float px = x, py = y;

    // move the ball by a constant speed we found when user made the ball
    x += (V * vx);
    y += (V * vy);

    box<float>& e = R->extents; // get the box the ball is bouncing in
    box<float>& eroot = mondrian0.root->extents; // get the root box
   
    // check if the ball is still inside this box after move
    if (inbox (e, x, y)) {
      // ball is still inside the box so theres nothing to do
    } else { // ball has hit a wall or ceiling of box
      check:
      int clx = clamp<float> (e.left, x, e.right);
      if (clx) { // hit wall
        if (vm_inf == 0) y = py + vm * (x - px); else y = py;
        float yb4 = y;
        if (clamp (e.bottom, y, e.top)) { // below floor or above ceiling
          y = yb4;
          goto check;
        }
        on_edge_hit (edge::LEFT, edge::RIGHT, clx, vx, y, x, eroot.left, eroot.width_1, R->vint, edge_hit);
      } else {
        int cly = clamp<float> (e.bottom, y, e.top);
        if (cly) { // hit floor or ceiling
          if (vm_inf == 0) x = px + vm_1 * (y - py); else x = px;
          on_edge_hit (edge::BOTTOM, edge::TOP, cly, vy, x, y, eroot.bottom, eroot.height_1, R->hint, edge_hit);
        }
      }
    }
  }
  if (auto_rotate && !edge_hit) rotate_velocity (auto_rotate); // auto_rotate = -1 is clockwise; auto_rotate = 1 is anti-clockwise
}


void ball::set_type (int T) {
  type = T;
  switch (type) {
    case ball::BOUNCER:
      color_using_modulation ();
      break;
    case ball::WRECKER:
      r = 1.0f; g = 0.25f; b = 0.25f;
      break;
    case ball::HEALER:
      r = 0.0f; g = 1.0f; b = 1.0f;
  }
}

void ball::color_using_modulation () {
  if (type != ball::BOUNCER) return;
  if (mod < 0) {
    r = g = b = 0.15f;
  } else if (mod > 0) {
    r = g = b = 1.0f;
  } else {
    r = g = b = 0.60f;
  }
}

void ball::print () {
  extern char BUFFER [];
  sprintf (BUFFER, "Ball's type = %s, attack = %0.3f sec, decay = %0.3f sec, modulation = %0.3f", types_str[type], attack_time, decay_time, pitch_mult);
  cons << BUFFER << eol;
}