Rotate Robj

using GLVisualize, GLAbstraction
using FileIO, GeometryTypes, Reactive

window = glscreen()
timesignal = loop(linspace(0f0,1f0,360))
# loadasset is defined in GLVisualize like this:
# loadasset(path_segments...) = FileIO.load(assetpath(path_segments...))
# where assetpath just looks up the file in the asset folder
# You can load these (file types)[https://github.com/JuliaIO/FileIO.jl/blob/master/docs/registry.md]
mesh            = loadasset("cat.obj")

# GLAbstraction.const_lift is an alias for Reactive.map, which also works for non
# signal arguments.
# Reactive.map takes a function and signals like the one created via `loop` (or just Signal(x))
# as an argument, applies the function to the signals whenever they update and
# returns a new signal.
rotation_angle  = const_lift(*, timesignal, 2f0*pi)
# the cat needs some rotation on the x axis to stand straight
# so we start off with a rotation of 90 degrees
start_rotation  = Signal(rotationmatrix_x(deg2rad(90f0)))
rotation        = map(rotationmatrix_y, rotation_angle)
final_rotation  = map(*, start_rotation, rotation)

# now we visualize the mesh and pass the rotation via the model keyword argument,
# which is short for the modelmatrix, which allows you to transform the visualization
# with any arbitrary transformation matrix
# You can create the most common transformation matrix with `translationmatrix(::Vec3f0)`,
# `rotationmatrix_x`/`y`/`z` (rotation around axis x,y,z), and `scalematrix(::Vec3f0)`

# the visualize function always only takes one argument, plus an optional style
# argument and then visualization dependant many keywords to customize the visualization.
# for all parameters Signals can be used and thus the visualization becomes animated

robj = visualize(mesh, model=final_rotation)


view(robj, window)

renderloop(window)

Simulation

#this is an example by https://github.com/musmo

using GLVisualize, GeometryTypes, Reactive, GLAbstraction, Colors, GLWindow, ModernGL


"""
Simulation function
"""
function solve_particles(pos_vel_s)
    dt = 1.0f0

    positions, velocity, s = pos_vel_s
    for i in eachindex(positions)
        velx = 0.0f0
        vely = 0.0f0
        posi = positions[i]
        for j in eachindex(positions)
            posj = positions[j]
            dx = posj[1] - posi[1]
            dy = posj[2] - posi[2]
            distsq = dx*dx + dy*dy + 1f0
            velx = velx - s[j]*dy/distsq
            vely = vely + s[j]*dx/distsq
        end
        positions[i] = Point2f0(posi[1] + dt*velx, posi[2] + dt*vely)
    end
    positions, velocity, s
end
"""
Clears the image of the window to `color`
"""
function clear_frame!(window, color=RGB(0.2,0.2,0.2))
    glClearColor(red(color), green(color), blue(color), 1)
    GLWindow.clear_all!(window)
end

"""
Resets the state of a window
"""
function reset!(window, color=RGB(0.2,0.2,0.2))
    clear_frame!(window, color)
    empty!(window.renderlist) # removes all viewables that where added with `view`
end

"""
This code should be executed only one time per julia session!!
If you accidantly close the window, you can call this again.
"""
function init(res=(800,600))
    # giving the window a transparent background color makes it transparent to
    # the previous frame. It's arguable, if that's really how things should be,
    # but that's how it currently works ;)
    window = glscreen("vortex", resolution=res, background=RGBA(0,0,0,0))
    timesignal = Signal(0.0)
    speed = Signal(1/30)

    # this is equivalent to @async renderloop(window).
    # but now you can do other stuff before an image is rendered
    # the @async is used to make this non blocking for working in the REPL/Atom
    @async while isopen(window)
        push!(timesignal, value(timesignal)+0.01)
        render_frame(window)
        sleep(value(speed))
    end

    # this registers a callback whenever a keybutton is clicked.
    # We use Reactive signals, so every registered callback
    # returns a new signal with the returnvalue of that callback. Since we don't
    # use that signal, Reactive will try to garbage collect it, which is why we need
    # to call preserve on it.
    preserve(map(window.inputs[:keyboard_buttons]) do kam
            key, action, mods = kam
            if key == GLFW.KEY_S
                println("saving screenshot")
                screenshot(window, path="screenshot.jpg")
            end
            # make sure that this function doesn't return different types
            # for the if branch.
            # Reactive would try to convert them otherwise.
            nothing
        end
    )

    window, timesignal, speed
end


function main(window, timesignal)
    # get the resolution of the window
    res = widths(window)
    num = 1000

    # use Float32 whenever possible to avoid conversions (GLVisualize can
    # convert to appropriate type most of the time, though)
    x = Float32[(res[1]/2.0) + (res[2]/3.5) * sin(i*2*pi/num) for i=0:num-1]
    y = Float32[(res[2]/2.0) + (res[2]/3.5) * cos(i*2*pi/num) for i=0:num-1]
    s = (-1 + 2*rand(Float32,num))

    # GeometryTypes.Point2f0 -> Point{2, Float32}
    start_position = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)]


    # Everything in GLVisualize gets animated with Reactive signals. So drawing a frame
    # and animating some graphic is decoupled.
    # for more infos, checkout Reactives documentation:
    # https://github.com/JuliaLang/Reactive.jl/blob/master/doc/index.md
    # In this case we use foldp to simulate the particles for every time step.
    # signature: foldp(function, startvalue, signals...), function will be called
    # with f(startvalue, signals...) every time timesignal updates.

    position_velocity = foldp(
        (v0, t) -> solve_particles(v0),
        (start_position, zeros(Float32,num), s),
        timesignal
    )
    # extract the position
    position = map(first, position_velocity)

    # create a color signal that changes over time
    # the color will update whenever timesignal updates
    color = map(timesignal) do t
        RGBA(1,1,(sin(t)+1.)/2., 0.05)
    end

    circle = Circle(Point2f0(0), 0.7f0)

    # boundingbox is still a very expensive operation, so if you don't need it
    # you can simply set it to nothing.
    # The signature for all kind of particles is:
    # visualize((primitive, positions), keyword_arguments...)
    viewable = visualize(
        (circle, position),
        boundingbox=nothing,
        color=color
    )
    # reset is basically the antagonist of view
    reset!(window) # when you reset the window here, you can call main multiple times

    # view adds an (animated) viewable to the list of things that you want to see
    # in `window`
    view(viewable, window, camera=:fixed_pixel)
end


#=
workflow in Julia REPL or you can also just evaluate parts in Atom:
include("simulation.jl")
window, t, speed = init()
main(window, t)
#redefine main/solve_particles
include("simulation.jl") # if you have the changes in the file
main() # call again! If you only changed solve_particles, you don't even have to call main again
push!(speed, 1/20) # this is fully interactive so you can, e.g. change the speed
=#

window, timesignal, speed = init()

main(window, timesignal)