[racket] OpenGL sgl GL_TEXTURE_3D glTexImage3D

142 views
Skip to first unread message

mosi

unread,
Nov 27, 2010, 2:08:21 PM11/27/10
to us...@racket-lang.org
Hi,

this is a question about how to run a code in DrRacket which displays a 3D (volumetric) texture in an OpenGL window.
Displaying a 2D Texture works beautifully.
Displaying a 3D Texture returns an Error:

Racket\collects\sgl\gl.rkt:21:23: glTexImage3D: unavailable on this system
(I`m working on the windows version of DrRacket)

Does anybody know about the implementation of sgl/gl.rkt in detail ?
The problem is, i think, in the following:
The following C++ GLUT code works fine on my machine and needs an external DLL glut32.dll and a dynamic load of the function "glTexImage3D" on the run.
However,  Racket\collects\sgl\gl.rkt only creates FFI functions for C:\Windows\system32\glu32.dll
where the OpenGL extensions are not available in glu32.dll .

Is there a book,  or an example code which could help showing that Racket can do magic with OpenGL in a REPL on volumetric textures ?
Backup plan: is there a good book on MZScheme, FFI, dynamic loading of DLL functions ?
(The mzscheme examples in DrRacket don`t seem to work out of the box on Windows)

I have experience with SBCL and C++, Racket is fairly new to me.

--------------------
Here is what I tried so far:

I used and modified the following code by Brendan Burns with modifications by Scott Owens:

C:\Program Files\Racket\collects\sgl\examples\alpha.rkt 
C:\Program Files\Racket\collects\sgl\examples\gl-frame.rkt

which displays 2D textures on a cube.

The following C++ GLUT code works fine on my machine, needs an external DLL glut32.dll.
However,  Racket\collects\sgl\gl.rkt only creates FFI functions for C:\Windows\system32\glu32.dll
where the OpenGL Extensions are not available.
...
#include <GL/glext.h>
...
    // VERY IMPORTANT:
    // this line loads the address of the glTexImage3D function into the function pointer of the same name.
    // glTexImage3D is not implemented in the standard GL libraries and must be loaded dynamically at run time,
    // the environment the program is being run in MAY OR MAY NOT support it, if not we'll get back a NULL pointer.
    // this is necessary to use any OpenGL function declared in the glext.h header file
    // the Pointer to FunctioN ... PROC types are declared in the same header file with a type appropriate to the function name
    glTexImage3D = (glTexImage3D) wglGetProcAddress("glTexImage3D");
    if (glTexImage3D == NULL) {
        printf("Error in line %d: Couldn't load glTexImage3D function. Aborting.\n", __LINE__);
        return -1;
    }
...

The code displays a nice 3D texture on a pyramid.

Now trying to do the same in DrRacket:
;;----------- Code Excerpt for GL_TEXTURE_3D -------------
(glEnable GL_3D)
(glEnable GL_TEXTURE_3D)
...

;; --- Create a 3D texture for OpenGL ---

  (define (get-tex3d fname)
    (let* ((xx 4)
           (yy 6)
           (zz 12)                    
           (pixels (* xx yy zz))
           (vec (make-gl-ubyte-vector (* pixels 3)))
           (data (make-bytes (* pixels 4)))
           (i 0)
           (cr (round (* (/ 255 pixels) 1))) ; color range increment from pixel to pixel
           )

      (letrec
          ([loop
            (lambda ()
              (if (< i pixels)
                  (begin
                    (gl-vector-set! vec (* i  3) (- 255 (round (* cr i))))
                    (gl-vector-set! vec (+ (* i 3) 1) (round (* cr i)))
                    (gl-vector-set! vec (+ (* i 3) 2) (- 124 (round (* (/ cr 2) i))))
                    (set! i (+ i 1))
                    (loop))))])
        (loop))
      (list xx yy zz vec)))

;; ---------- Try to Load a 3D openGL texture into OpenGL ----------
  (define gl-load-texture3d
    (lambda (image-vector width height depth min-filter mag-filter ix)
      (glBindTexture GL_TEXTURE_3D (gl-vector-ref *textures* ix))
      (glTexParameteri GL_TEXTURE_3D GL_TEXTURE_MIN_FILTER min-filter)
      (glTexParameteri GL_TEXTURE_3D GL_TEXTURE_MAG_FILTER mag-filter)
      (let* ((new-img-vec (make-gl-ubyte-vector
                           (* width height depth 3)))
      ;       (new-img-vec image-vector)
             )       
        (if (or (= min-filter GL_LINEAR_MIPMAP_NEAREST)
                (= mag-filter GL_LINEAR_MIPMAP_NEAREST))
            (gluBuild3DMipmaps GL_TEXTURE_3D 3 width height depth GL_RGB GL_UNSIGNED_BYTE new-img-vec)           ;; this is not supported in my Racket ! ? !
            (glTexImage3D GL_TEXTURE_3D 0 3 width height depth 0 GL_RGB GL_UNSIGNED_BYTE new-img-vec)             ;; this is not supported in my Racket ! ? !
            )))
    )

;;...
;; Perform the 3D Texture Load
(unless (gl-load-texture3d (list-ref res 3) (list-ref res 0) (list-ref res 1) (list-ref res 2) GL_NEAREST GL_NEAREST 0)
        (error "Couldn't load texture"))


Thank you for your comments.

mosi


Noel Welsh

unread,
Nov 27, 2010, 5:10:32 PM11/27/10
to mosi, us...@racket-lang.org
I didn't write SGL but the code is quite easy to understand. At the
top a bunch of shared libraries are loaded (gl-lib and glu-lib). You'd
want to add glut-lib there.

;; Windows only for now
(define glut-lib (ffi-lib "glut32"))

Then glTexImage3D is defined with the following code:

(define-foreign glTexImage3D _gl-enum _gl-int _gl-int _gl-sizei _gl-sizei
_gl-sizei _gl-int _gl-enum _gl-enum _gl-voidv ->)

define-foreign is a simple macro defined at the top of the file. You
need to define a new version that uses glut-lib

(define-syntax define-foreign-glut
(syntax-rules ()
[(_ args ...) (define-foreign-lib glut-lib args ...)]))

Then change the definition of glTexImage3D to use define-foreign-glut
instead of define-foreign.

The above is totally untested but should work.

HTH,
N.
On Sat, Nov 27, 2010 at 7:08 PM, mosi <amosa...@gmail.com> wrote:
...


> Does anybody know about the implementation of sgl/gl.rkt in detail ?
> The problem is, i think, in the following:
> The following C++ GLUT code works fine on my machine and needs an external
> DLL glut32.dll and a dynamic load of the function "glTexImage3D" on the run.
> However,  Racket\collects\sgl\gl.rkt only creates FFI functions for
> C:\Windows\system32\glu32.dll
> where the OpenGL extensions are not available in glu32.dll .

...
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users

Ben Goetter

unread,
Nov 29, 2010, 7:14:00 PM11/29/10
to mosi, us...@racket-lang.org
Andrej,

glTexImage3D is not a GLUT entry point, but rather is a standard GL 1.2
entry point. However, Windows uses GL 1.1, and only defines the 1.1
entry points in its system DLLs opengl32.dll and glu32.dll. Hence you
must use wglGetProcAddress to access glTexImage3D as a non-standard (on
1.1) entry point.

(The following example uses DrScheme 4.2 FFI syntax, for which I
apologize-- I have not tracked the changes in Racket 5.0 and beyond, nor
even had a chance to use it. I believe that the Racket FFI is pretty
similar to its ancestor. If not, then I apologize again for the on-list
noise, and hope that somebody else will chime in and correct me.)

First, we dynamically load wglGetProcAddress from the Windows
implementation of OpenGL:

(define wglGetProcAddress
(get-ffi-obj 'wglGetProcAddress (ffi-lib "opengl32") (_fun #:abi
'stdcall _string -> _fpointer)) )

Add a little sauce to convert the code address returned by that Windows
syscall into a Scheme procedure:

(define (gl-load-extension name ftype)
(let ((f (wglGetProcAddress name)))
(if f (ptr-ref f ftype) (lambda x (DIE-HORRIBLY)))))

(For (lambda x (DIE-HORRIBLY)), substitute the abend or log output of
your choice signaling the lack of the extension. (lambda x #f) works, too.)

Now we use this to access the implementation of glTexImage3D in your
video card's driver, assuming that the entry point exists therein:

(define glTexImage3D
(gl-load-extension "glTexImage3D"
(_fun #:abi 'stdcall _gl-enum _gl-int _gl-int _gl-sizei _gl-sizei
_gl-sizei _gl-int _gl-enum _gl-enum _gl-voidv ->) ))

And voila, there's your glTexImage3D procedure. (Or so I hope. To echo
Noel's caveat, the above is totally untested but Should Work.)

For further reading, please see the "FFI" chapter in the Racket
documentation. You will find it quite enlightening. The FFI is a
marvelous thing.

Good luck.
Ben


On 11/27/2010 11:08 AM, mosi wrote:
> Backup plan: is there a good book on MZScheme, FFI, dynamic loading of
> DLL functions ?

> [...]


> (glTexImage3D GL_TEXTURE_3D 0 3 width height depth 0
> GL_RGB GL_UNSIGNED_BYTE new-img-vec) ;; this is not
> supported in my Racket ! ? !

_________________________________________________

Reply all
Reply to author
Forward
0 new messages