How to make a programmable pipeline OpenGL context in Racket - opengl

In Racket, I'd like to get an OpenGL context from the GUI, clear it to black, and display it to the screen. I'm using the opengl library to let me use the variable function pipeline. I presently have the following code:
#lang racket/gui
(require opengl)
(define video-canvas%
(class canvas%
(init-field width height)
(super-new [style '(gl no-autoclear)]
[min-width width]
[min-height height]
[stretchable-width #f]
[stretchable-height #f])
(send this with-gl-context
(λ ()
(glViewport 0 0 width height)
(glClearColor 0.0 0.0 0.0 0.0)))
(define/public (draw-frame)
(send this with-gl-context
(λ () (glClear GL_COLOR_BUFFER_BIT)))
(send this swap-gl-buffers))))
(define f (new frame% [label "test video"]))
(define vc (new video-canvas% [parent f]
[width 640] [height 480]))
(send f show #t)
(send vc draw-frame)
This would appear to create a frame, place a OpenGL viewport on top of it, and then render it after clearing it to black. However, on my machine, it actually produces:
This is the default background, not the solid black window I was expecting. I'm running this program on Windows 10 on a computer using Intel HD 520 graphics.

Related

Why are both expressions in this clojure if evaluated?

If I create a new project with
lein new quil foo
then reduce the src/foo/core.clj to
(ns foo.core
(:require [quil.core :as q]
[quil.middleware :as m]))
(defn draw [state]
(if (< (rand) 0.5)
(q/line 0 0 500 500)
(q/line 0 500 500 0)))
(q/defsketch foo
:title "Try this at home"
:size [500 500]
:draw draw
:features [:keep-on-top]
:middleware [m/fun-mode])
and evaluate the program in lein repl with (use 'foo.core), both lines are drawn (i.e. I get a big X). (if (< (rand) 0.5) true false) works as expected, so what am I missing?
Presumably draw is called many times - it wouldn't be a very interactive framework if it only drew the screen once! Some of those times, you randomly choose to draw one line, and sometimes the other; and you never erase either. As a result, both of them are visible on the screen.

Loading assets in libgdx (clojure)

I'm trying to make a game using clojure and libgdx. The information at Using Libgdx with Clojure was immensely helpful but now I'm stuck on the simple step of displaying a sprite. In my screen I have this
(def main-screen
(let [stage (atom nil)]
(proxy [Screen] []
(show []
(reset! stage (Stage.))
(let [style (Label$LabelStyle. (BitmapFont.) (Color. 0 1 1 1))
label (Label. "Hello world!" style)]
(.addActor #stage label)))
(render [delta]
(.glClearColor (Gdx/gl) 0 1 0 1)
(.glClear (Gdx/gl) GL20/GL_COLOR_BUFFER_BIT)
(doto (SpriteBatch.)
(. begin)
(. draw (ship-texture) 10 10)
(. end))
(doto #stage
(.act delta)
(.draw)))
(dispose[])
(hide [])
(pause [])
(resize [w h])
(resume []))))
and that references a simple function above
(defn ship-texture [] (Texture. (.internal Gdx/files "AShip.PNG")))
But no matter where I put the file libgdx can't seem to find it. I've placed it in resources, src, assets and the base directory. I feel like I must be misssing something tremendously simple.

Stopping a threaded sound loop in Clojure

I have a threaded looping sound clip:
(def f
(future
(let [sound-file (java.io.File. "/path/to/file.wav")
sound-in (javax.sound.sampled.AudioSystem/getAudioInputStream sound-file)
format (.getFormat sound-in)
info (javax.sound.sampled.DataLine$Info. javax.sound.sampled.Clip format)
clip (javax.sound.sampled.AudioSystem/getLine info)]
(.open clip sound-in)
(.loop clip javax.sound.sampled.Clip/LOOP_CONTINUOUSLY))))
The problem is that when I try to kill the thread:
(future-cancel f)
it doesn't stop the clip, which plays forever. I found that the only way to stop it was to call (.stop clip) explicitly. My question: what would be the best/idiomatic way of doing this? I'm pretty new to Clojure, so I only experimented with future so far, but maybe an agent would be better suited in this context?
Update: given that the .loop function is non-blocking (as was discussed below), I simplified my design by getting rid of the initial future:
(defn play-loop [wav-fn]
(let [sound-file (java.io.File. wav-fn)
sound-in (javax.sound.sampled.AudioSystem/getAudioInputStream sound-file)
format (.getFormat sound-in)
info (javax.sound.sampled.DataLine$Info. javax.sound.sampled.Clip format)
clip (javax.sound.sampled.AudioSystem/getLine info)]
(.open clip sound-in)
(.loop clip javax.sound.sampled.Clip/LOOP_CONTINUOUSLY)
clip))
along with a controlling atom:
(def ^:dynamic *clip* (atom nil))
with which I start the loop:
(when (nil? #*clip*)
(reset! *clip* (play-loop "/path/to/file.wav")))
and stop it:
(when #*clip*
(future (.stop #*clip*) ; to avoid a slight delay caused by .stop
(reset! *clip* nil)))
You can try something like this:
(def f
(future
(let [sound-file (java.io.File. "/path/to/file.wav")
sound-in (javax.sound.sampled.AudioSystem/getAudioInputStream sound-file)
format (.getFormat sound-in)
info (javax.sound.sampled.DataLine$Info. javax.sound.sampled.Clip format)
clip (javax.sound.sampled.AudioSystem/getLine info)
stop (fn [] (.stop clip))]
(.open clip sound-in)
(.loop clip javax.sound.sampled.Clip/LOOP_CONTINUOUSLY)
stop)))
(def stop-loop #f)
(stop-loop)

How to display an incanter graph in Jpanel

Does anyone know how to display an incanter chart to jpanel without reverting to jfreechart?
An Incanter chart is a JFreeChart under the hood so it's impossible to avoid the JFreeChart library altogether.
However, if you just want to include an incanter chart inside a Panel that you can use in a normal Swing application then there is a ready-made class called org.jfree.chart.ChartPanel which can do this for you.
Example code:
(ns my.chart
(:import [org.jfree.chart ChartPanel])
(:import [java.awt Component Dimension])
(:import [javax.swing JFrame])
(:use [incanter core stats charts]))
(defn show-component [^Component c]
"Utility Function to display any Java component in a frame"
(let [^JFrame frame (JFrame. "Test Window")]
(doto frame
(.add c)
(.setSize (Dimension. 640 480))
(.setVisible true))))
(show-component (ChartPanel. (function-plot sin -10 10)))

Clojure Agent question - using send-off

I have a couple of questions about the following code:
(import
'(java.awt Color Graphics Dimension)
'(java.awt.image BufferedImage)
'(javax.swing JPanel JFrame))
(def width 900)
(def height 600)
(defn render
[g]
(let [img (new BufferedImage width height
(. BufferedImage TYPE_INT_ARGB))
bg (. img (getGraphics))]
(doto bg
(.setColor (. Color white))
(.fillRect 0 0 (. img (getWidth)) (. img (getHeight)))
(.setColor (. Color red))
(.drawOval 200 200 (rand-int 100) (rand-int 50)))
(. g (drawImage img 0 0 nil))
(. bg (dispose))
))
(def panel (doto (proxy [JPanel] []
(paint [g] (render g)))
(.setPreferredSize (new Dimension
width
height))))
(def frame (doto (new JFrame) (.add panel) .pack .show))
(def animator (agent nil))
(defn animation
[x]
(send-off *agent* #'animation)
(. panel (repaint))
(. Thread (sleep 100)))
(send-off animator animation)
In the animation function - why is #' used before animation in send-off?
Why does send-off at the start of animation function work? Shouldn't it just go the start of animation function again and never execute the repaint and sleep methods?
Is there any disadvantage, as compared to the original, in writing the animation function as:
(defn animation
[x]
(. panel (repaint))
(. Thread (sleep 100))
(send-off *agent* animation))
In the animation function - why is #' used before animation in send-off?
To demonstrate Clojure's dynamic nature.
The form #'animation is a Var, one of Clojure's mutable reference types. The defn macro creates a Var. For convenience, invoking a Var which refers to a function is the same as invoking the function itself. But a Var, unlike a function, can change! We could redefine #'animation at the Clojure REPL and immediately see the effects.
Using (send-off *agent* #'animation) forces Clojure to look up of the current value of the #'animation Var every time. If the code had used (send-off *agent* animation) instead, then Clojure would look up the value only once, and it would not be possible to change the animation function without stopping the loop.
1. This is a little unclear to me as well but seems to be a design decision by Rich. If you notice:
user=> (defn x [y] (+ y 2))
#'user/x
user=> ((var x) 3)
5
If a var is in the function/macro location, it will eventually resolve to the function or macro.
2. One important thing to understand here is the agent model. Agents can be thought of as a worker that operates on a single mutable cell. There is a queue of work (a queue of functions) for that agent to do. send-off and send add work to that queue. Since send-off is only adding work to the queue, it immediately returns. Since the agent only executes the functions serially, the first animation call must finish before executing the next one. Therefore, you achieve basically the same thing regardless of putting send-off first or last.
3. There should be no noticeable difference between the two.