module sound3d;

import dsfml.system.all;
import dsfml.window.all;
import dsfml.graphics.all;
import dsfml.audio.all;

void main()
{
    //We create our window with a limit of 100 and a white backcolor.
    RenderWindow app = new RenderWindow (VideoMode(800, 600, 32), "Sound Spatialization Sample");
    app.useVerticalSync(true);
    
    Font f = new Font("Data/cheeseburger.ttf", 34);
    
    //Some instructions
    String s = new String("Click anywhere on screen to change listener position.\nPress + or - to modify the speed of the car."c, f);
    s.setPosition(20, 30);
    s.setColor(Color.BLACK);
    
    //We prepare our images and the sound
    char[][2] images = ["Data/bluerallyecarleft.bmp", "Data/bluerallyecarright.bmp"];
    Car c = new Car(images, "Data/car_idle.wav");
    
    int carSpeed = 100;
    
    //Set default position for the car and the listener
    c.setPosition(Vector2f(0, 300));
    SoundListener.setPosition(Vector2f(400, 300));
    
    c.startPlaying();
    
    //Start the main loop
    while (app.isOpened())
    {
        app.clear(Color.WHITE);
        Event evt;
        //The event loop
        while (app.getEvent(evt))
        {
            // if the window is closed, we can leave the game loop
            if (evt.Type == Event.EventType.CLOSED) 
                app.close();
            // we handle the click event to change listener position
            else if (evt.Type == Event.EventType.MOUSEBUTTONPRESSED && evt.MouseButton.Button == MouseButtons.LEFT)
            {
                Input i = app.getInput();
                SoundListener.setPosition(Vector2f(i.getMouseX(), i.getMouseY()));
            }
            // and eventual keys press
            else if (evt.Type == Event.EventType.KEYPRESSED)
            {
                //Change the car speed
                if (evt.Key.Code == KeyCode.ADD)
                {
                    carSpeed += 25;
                }
                else if (evt.Key.Code == KeyCode.SUBTRACT)
                {
                    carSpeed -= 25;
                }
            }
        }
        
        //We move constantly our car.
        c.move(Vector2f(app.getFrameTime() * carSpeed, 0));
    
        //Draw all the sprite and string on render window
        app.draw(s);
        app.draw(c.getSprite());
        app.draw(SoundListener.getSprite());
        
        //And finally display the window
        app.display();
    } 
    
    
}

// Encapsulate the listener position and the visor sprite.
// There is only one listener so all the methods are statics.
class SoundListener
{
    static Sprite s_crosshair;
    static Vector2f s_p;
    
    static this()
    {
        Image crosshairImg = new Image("Data/crosshair.tga");                
        crosshairImg.createMaskFromColor(Color.WHITE);
        
        s_crosshair = new Sprite(crosshairImg);
        s_crosshair.setCenter(Vector2f(s_crosshair.getSize().x / 2, s_crosshair.getSize().y / 2));
        
        //Listener.setTarget(1.f, 0.f, 0.f);
    }
    
    // Adjust position of the listener
    static void setPosition(Vector2f p)
    {
        Listener.setPosition(p.x, p.y, 5.f);
        s_crosshair.setPosition(p);
    }
    
    static Sprite getSprite()
    {
        return s_crosshair;
    }  
}


// Class encapsulating all data for our car
class Car
{
    Vector2f m_actual;
    Sprite m_sprite;
    Sound m_sound;
    bool reverse;
    Image[2] imgs;
    
    //Constructor with with a fixed size string array of image path, and a string for the sound path 
    this (char[][2] images, char[] soundFilename)
    {
        //load images and create filter
        imgs[0] = new Image(images[0]); imgs[1] = new Image(images[1]);
            
        foreach(img; imgs)
            img.createMaskFromColor(Color(97, 68, 43));
        
        m_sprite = new Sprite(imgs[0]);
        m_sprite.setCenter(Vector2f(m_sprite.getSize().x / 2, m_sprite.getSize().y / 2));
        
        SoundBuffer buff = new SoundBuffer(soundFilename);
        
        //load our sound with loop enabled
        m_sound = new Sound(buff, true);
        m_sound.setAttenuation(.05f);
    }
    
    // Begin the sound play
    void startPlaying()
    {
        m_sound.play();   
    }
    
    // Set the position of the car on the window
    // Used to setup the begin car window and sound location 
    void setPosition(Vector2f p)
    {
        m_sprite.setPosition(p);
        m_sound.setPosition(p.x, 0, p.y);
    }
    
    //Move the car (visual and sound position)
    //If the car leave the screen, we change the sprite image and reverse moving
    void move(Vector2f vec)
    {
        // if the car is beyond the right screen limit
        if (!reverse && m_sprite.getPosition().x > 850)
        {
            m_sprite.setImage(imgs[1]);
            reverse = true;
        }
        // same as above but for left limit
        else if (reverse && vec.x + m_sprite.getPosition().x < -50)
        {
            m_sprite.setImage(imgs[0]);
            reverse = false;
        }
        
        if (reverse)
            vec = -vec;
            
        m_sprite.move(vec);
        Vector2f pos = m_sprite.getPosition();
        m_sound.setPosition(pos.x , pos.y, 0);
    }

    Sprite getSprite()
    {
        return m_sprite;
    }
}