1

I'm using LWJGL with Clojure and am having difficulty lighting a scene. I am drawing GLU.Sphere objects which are visible when lighting is off but entirely black when lighting is enabled.

What am I doing wrong?

(ns gltest.core
  (:import [org.lwjgl.opengl Display DisplayMode GL11]
           [org.lwjgl.util.glu GLU Sphere]
           [org.lwjgl Sys]
           [org.lwjgl.input Keyboard]
           [java.nio ByteBuffer ByteOrder])
  (:gen-class))

(declare get-time)

(def temp-buf (ByteBuffer/allocateDirect 16))

(def s (Sphere.))

(def display-state (atom {:mode nil
                          :max-fps 60}))
(def render-state (atom {:last-frame nil
                         :last-fps (float 0)
                         :fps (float 0)}))
(def world-state (atom {:x 400
                        :y 300
                        :rotation 0}))

(defn get-time []
  (/ (* (Sys/getTime) 1000)
        (Sys/getTimerResolution)))

(defn update-fps []
  (let [time (get-time)]
    (when (> (- time (@render-state :last-fps))
             1000)
      (Display/setTitle (format "FPS: %s" (@render-state :fps)))
      (swap! render-state
             assoc :fps (float 0) :last-fps time)))
  (swap! render-state assoc :fps (float (+ (@render-state :fps)
                                           1))))

(defn update [delta]
  (swap! world-state assoc :rotation (+ (:rotation @world-state)
                                        (* (float 0.15) delta)))

  (update-fps))

(defn init-gl []
  (GL11/glClearColor 0.1 0.1 0.1 0.0) ; background
  (GL11/glClearDepth 1)
  (GL11/glDepthFunc GL11/GL_LEQUAL)
  (GL11/glHint GL11/GL_PERSPECTIVE_CORRECTION_HINT GL11/GL_NICEST)
  (GL11/glShadeModel GL11/GL_SMOOTH)
  (GL11/glEnable GL11/GL_DEPTH_TEST)

  ;; fovy, aspect ratio, zNear, zFar
  (let [width (.getWidth (:mode @display-state))
        height (.getHeight (:mode @display-state))
        aspect-ratio (float (/ width height))]
    ;; select projection matrix (controls perspective)
    (GL11/glMatrixMode GL11/GL_PROJECTION)
    (GL11/glLoadIdentity)
    (GLU/gluPerspective 45 aspect-ratio 0.1 100)

    (GL11/glMatrixMode GL11/GL_MODELVIEW)
    (GL11/glLoadIdentity)
    (GL11/glViewport 0 0 width height))

  (GL11/glMaterial GL11/GL_FRONT GL11/GL_SPECULAR (-> temp-buf
                                                      .clear
                                                      .asFloatBuffer
                                                      (.put (float-array [1 1 1 1]))
                                                      .flip))
  (GL11/glMaterial GL11/GL_FRONT GL11/GL_AMBIENT (-> temp-buf
                                                     .clear
                                                     .asFloatBuffer
                                                     (.put (float-array [1 1 1 1]))
                                                     .flip))
  (GL11/glMaterial GL11/GL_FRONT GL11/GL_DIFFUSE (-> temp-buf
                                                     .clear
                                                     .asFloatBuffer
                                                     (.put (float-array [1 1 1 1]))
                                                     .flip))

  (GL11/glMaterialf GL11/GL_FRONT_AND_BACK GL11/GL_SHININESS 10)

  ;; setup light
  (let [ambient-light (float-array [0.5 0.5 0.5 0])
        diffuse-light (float-array [0 1.0 0 0])]
    (GL11/glLight GL11/GL_LIGHT0 GL11/GL_AMBIENT (-> temp-buf
                                                     .clear
                                                     .asFloatBuffer
                                                     (.put ambient-light)
                                                     .flip))
    (GL11/glLight GL11/GL_LIGHT0 GL11/GL_DIFFUSE (-> temp-buf .clear
                                                     .asFloatBuffer
                                                     (.put diffuse-light)
                                                     .flip))
    (GL11/glLight GL11/GL_LIGHT0 GL11/GL_POSITION (-> temp-buf
                                                      .clear
                                                      .asFloatBuffer
                                                      (.put (float-array [0 -1 0 0]))
                                                      .flip)))

  (GL11/glEnable GL11/GL_LIGHTING)
  (GL11/glEnable GL11/GL_LIGHT0)

  (swap! render-state assoc :last-frame (get-time)))

(defn render []
  ;; Clear The Screen And The Depth Buffer
  (GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT))

  ;; setup camera
  (GL11/glLoadIdentity)
  (GL11/glTranslatef (float 0) (float 0) (float -3))
  (GL11/glRotatef 30 1 0 0)

  (GL11/glPushMatrix)
  (GL11/glTranslatef 0 1 0)
  (.draw s 0.1 50 50)
  (GL11/glPopMatrix))

(defn -main []
  (let [display-mode (first (filter #(and
                                      (== (.getWidth %) 800)
                                      (== (.getHeight %) 600)
                                      (== (.getBitsPerPixel %) 32))
                                    (Display/getAvailableDisplayModes)))]
    (swap! display-state assoc :mode display-mode)

    (Display/setDisplayMode display-mode)
    (Display/setTitle "Test")
    (Display/create))

  (init-gl)

  (while (not (Display/isCloseRequested))
    (let [time (get-time)
          last-frame (@render-state :last-frame)]
      (swap! render-state assoc :last-frame time)
      (update (int (- time last-frame))))
    (render)
    (Display/update)
    (Display/sync (@display-state :max-fps)))

  (Display/destroy)
  (System/exit 0))
mattrepl
  • 602
  • 1
  • 6
  • 18
  • 1
    is this an explanation to resolve a problem you have faced? – Luiggi Mendoza May 25 '12 at 04:01
  • 1
    Your 'report' does not constitute a question. Even if it were one, there is not enough information for others to be able to help you with it. Voting to close. – Andrew Thompson May 25 '12 at 04:04
  • Should probably read this blog post: http://blog.stackoverflow.com/2012/05/encyclopedia-stack-exchange/ – Kirk Woll May 25 '12 at 04:06
  • 1
    [This is exactly the sort of thing I was concerned about.](http://meta.stackexchange.com/questions/133353/is-there-a-way-for-us-to-monitor-new-questions-that-leverage-answer-your-own-qu) @mattrepl could have admitedly put more work in making the "question" part of his answer more appropriate, but there's nothing wrong with what he's doing. – Kirk Woll May 25 '12 at 04:07
  • @KirkWoll I was looking for those links. Yeah, its not wrong to answer your own question, but when I read this post I can't understand how this problem arises. – Luiggi Mendoza May 25 '12 at 04:11
  • This sort of scenario seems inevitable. mattrepl clearly had this exact problem and used the answer he posted below to solve it. It's not unreasonable to think that this answer will in fact be helpful to future googlers, despite the fact that it's a totally ridiculous question to expect another person to successfully answer. – Kirk Woll May 25 '12 at 04:13
  • I cannot remove the 'close vote', but your edit enabled me to remove the down-vote. :) – Andrew Thompson May 25 '12 at 04:13
  • For those interested, [here's an ongoing meta on this very topic](http://meta.stackexchange.com/questions/133549/can-self-answered-qas-be-broad-or-even-duplicates). – Kirk Woll May 25 '12 at 04:17
  • The phrasing of this "question" could be better. I wanted to capture what took me hours to debug after browsing docs and code. I stumbled upon the source of my problem (ByteBuffer endianness) after looking at the umpteenth source code example. – mattrepl May 25 '12 at 04:28
  • @mattrepl: This question is not a question. It doesn't provide *nearly* enough information for anyone who isn't *you* to answer it. It won't help anyone in the future, because the answer doesn't really match the question itself. There are any number of reasons for lighting to fail; that it just so happened to be an endian issue means nothing for people other than you. – Nicol Bolas May 25 '12 at 04:36
  • @NicolBolas Hmm, my hope was that someone using a search engine would stumble upon this. Would it be better for me to provide my specific problem and focus on the endianness issue? Or, remove this post? – mattrepl May 25 '12 at 04:39
  • @mattrepl: The best solution would be to put sufficient detail in the question that someone who isn't you could actually answer it. – Nicol Bolas May 25 '12 at 04:41

1 Answers1

3

In this case, setting the order of the ByteBuffer used in the glLight and glMaterial calls fixed the problem.

// Java
ByteBuffer buf = ByteBuffer.allocateDirect(16);
buf.order(ByteOrder.nativeOrder);

;; Clojure
(def buf (doto (ByteBuffer/allocateDirect 16)
           (.order (ByteOrder/nativeOrder)))
mattrepl
  • 602
  • 1
  • 6
  • 18
  • 1
    I'm confused, either my SO is screwing up, or it looks like you answered your own question in 1 second? – RoneRackal May 25 '12 at 04:03
  • 1
    @RoneRackal I did this as a self-answer since it was difficult to find the solution to the lighting problem and there are several errors that could occur. The error I experienced, setting the order of the ByteBuffer, was not mentioned in any documentation that I found after spending several hours searching. – mattrepl May 25 '12 at 04:31