Hi David,
Thanks for the viewport suggestion.
I have made a version below that sets the viewport.
Saving the logo+triangle shows that the blue triangle has been drawn on the
frame buffer.
It disappears (?!) when I try to copy contents from the framebuffer to
screen though.
#lang racket/gui
(require opengl opengl/util ffi/vector)
(define logo-texture #f)
(define (load-logo-texture)
(unless logo-texture
(set! logo-texture (load-texture "plt-logo-red-gradient.png" #:repeat
'both)))
logo-texture)
(define (clear r g b a)
(glClearColor r g b a)
(glClear (bitwise-ior GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT)))
(define (set-color r g b)
(glColor3f r g b))
(define (reset-color)
(set-color 1. 1. 1.))
(define (draw-triangle x1 y1 x2 y2 x3 y3)
(glBegin GL_TRIANGLES)
(glVertex3d x1 y1 0.)
(glVertex3d x2 y2 0.)
(glVertex3d x3 y3 0.)
(glEnd))
(define sanity #f)
(define snapshot? #f)
(define bs (make-bytes (* 4 (* 256 256)) 0))
(define (example)
; make framebuffer
(define fbo-ids (glGenFramebuffers 1))
(define fbo (u32vector-ref fbo-ids 0))
; swith to the new framebuffer
(glBindFramebuffer GL_FRAMEBUFFER fbo)
; load logo texture (it is cached, so only loaded once)
(load-logo-texture) (unless logo-texture (error))
; use texture as color attachment 0
(glFramebufferTexture2D GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0 GL_TEXTURE_2D
logo-texture 0)
(glBindTexture GL_TEXTURE_2D logo-texture)
(glDrawBuffer GL_COLOR_ATTACHMENT0)
; we will now draw on the texture
(glViewport 0 0 256 256) ; size of logo is 256x256
(set-color 0.0 0.0 1.0) ; blue color
(draw-triangle 0.0 0.0 200.0 200.0 200.0 -200.)
(glFinish)
; let's make a snapshot of what we have
(unless snapshot?
(set! snapshot? #t)
(glGetTexImage GL_TEXTURE_2D 0 GL_RGBA GL_UNSIGNED_BYTE bs)
(rgba->argb! bs))
; Note: (bytes->bitmap bs 256 256) in the repl
; shows the logo with a blue triangle on top (as expected)
;;; *** Now we want to transfer the logo+triangle to the screen
; switch to screen framebuffer
(glBindFramebuffer GL_DRAW_FRAMEBUFFER 0)
; draw something to the screen, so we can see that the switch works
; red screen background
(clear 1.0 0.0 0.0 0.0)
; green triangle
(set-color 0.0 1.0 0.0)
(draw-triangle 0.0 0.0 0.3 0.0 0.0 0.3)
; we do see the green triangle in the result
; reset color in order for the transparency blending to work
(reset-color)
; read from the texture in the framebuffer
(glBindFramebuffer GL_READ_FRAMEBUFFER fbo)
(glEnable GL_TEXTURE_2D)
(glEnable GL_BLEND)
(glBlendFunc GL_ONE GL_ONE_MINUS_SRC_ALPHA) ; This is the correct setting
for pre-multiplied alpha.
; This is a square containing 2x2 copies of the logo
(define texcoord-array (s16vector 0 2 2 2 2 0 0 0))
; This is a square in the middle of the screen
(define vertex-array (f64vector -0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5
0.5))
(let-values (((type cptr) (gl-vector->type/cpointer vertex-array)))
(glVertexPointer 2 type 0 cptr))
(let-values (((type cptr) (gl-vector->type/cpointer texcoord-array)))
(glTexCoordPointer 2 type 0 cptr))
(glEnableClientState GL_VERTEX_ARRAY)
(glEnableClientState GL_TEXTURE_COORD_ARRAY)
; Now draw the square on screen using the prepared texture
(glDrawArrays GL_QUADS 0 4)
; clean up
(glDisableClientState GL_TEXTURE_COORD_ARRAY)
(glDisableClientState GL_VERTEX_ARRAY)
(glDisable GL_TEXTURE_2D)
(void))
;;;
;;; MODEL
;;;
(define frames-per-second 60.)
(define milliseconds-per-frame (/ 1000. frames-per-second))
(define time 0.)
(define (on-tick)
(set! time (+ time 1.))
(send gl on-paint))
;;;
;;; GUI
;;;
(define (resize w h)
(glViewport 0 0 w h))
(define (example2)
(define v (* 2. pi (/ time 60)))
(define c (cos v))
(define s (sin v))
(glClearColor 0.0 0.0 0.0 0.0)
(glClear GL_COLOR_BUFFER_BIT)
(glBegin GL_TRIANGLES)
(glColor3f c 0. 0.)
(glVertex3d c 0 0)
(glColor3f 0. s 0.)
(glVertex3d 0. s 0.)
(glColor3f 0. 0. 1.)
(glVertex3d -1. -1. 0.)
(glEnd))
(define my-canvas%
(class* canvas% ()
(inherit with-gl-context swap-gl-buffers)
(define/override (on-paint) (with-gl-context (λ() (example)
(swap-gl-buffers))))
(define/override (on-size width height) (with-gl-context (λ() (resize
width height) (on-paint))))
(super-instantiate () (style '(gl)))))
(define win (new frame% [label "Racket Rosetta Code OpenGL example"]
[min-width 200] [min-height 200]))
(define gl (new my-canvas% [parent win]))
(new timer%
[interval (exact-floor milliseconds-per-frame)] ; in milliseconds
[notify-callback on-tick])
(send win show #t)
(define (bytes->bitmap bs width height)
(define bm (make-bitmap width height))
(send bm set-argb-pixels 0 0 width height bs)
bm)
(define (rgba->argb! pixels)
(for ((i (in-range (/ (bytes-length pixels) 4))))
(let* ((offset (* 4 i))
( red (bytes-ref pixels (+ 0 offset)))
(green (bytes-ref pixels (+ 1 offset)))
( blue (bytes-ref pixels (+ 2 offset)))
(alpha (bytes-ref pixels (+ 3 offset))))
(bytes-set! pixels (+ 0 offset) alpha)
(bytes-set! pixels (+ 1 offset) red)
(bytes-set! pixels (+ 2 offset) green)
(bytes-set! pixels (+ 3 offset) blue))))
2018-04-08 0:49 GMT+02:00 David Vanderson <[email protected]>:
> I'm also learning, but I think in this case the viewport is not sized
> correctly to draw to the texture. I think you need something like this:
>
> ; Draw a blue triangle ***this is the part that isn't working***
> (glDrawBuffer GL_COLOR_ATTACHMENT0) ; draw to color attachment 0
> (glDisable GL_TEXTURE_2D) ; do not use the texture when
> drawing the triangle
> (glViewport 0 0 tw th) ; set the viewport to the size of the texture
> (get tw and th from the size of the png file bitmap)
> (clear 0.0 0.0 1.0 1.0)
> (set-color 0.0 1.0 0.0)
> (glDisable GL_BLEND)
> (draw-triangle -1.0 0.0 1.0 0.0 1.0 1.0)
>
> ; switch to screen framebuffer
> (glBindFramebuffer GL_FRAMEBUFFER 0)
> (glViewport 0 0 W H) ; set the viewport to the size of the framebuffer
> (set W and H from resize handler)
>
> Does that help?
>
> Thanks,
> Dave
>
> On Fri, Apr 6, 2018 at 2:05 PM, Jens Axel Søgaard <[email protected]>
> wrote:
>
>> Hi All,
>>
>> I am looking into opengl and have so far learned to draw directly to the
>> screen.
>> However I'd like to do some offscreen rendering and have therefore tried
>> to use a framebuffer.
>> The program below does the following:
>>
>> 1. Makes a framebuffer
>> 2. Adds a texture (a plt logo)
>> 3. Draws a blue triangle on top of the logo
>> 4. Switches to the screen
>> 5. Draw a green triangle
>> 6. Copies the logo with the blue triangle to the screen.
>>
>> My problem is that the blue triangle is missing in the result.
>>
>> The result: https://imgur.com/NBJf2DG
>> See program below.
>>
>> Ideas welcome.
>>
>> /Jens Axel
>>
>>
>>
>> #lang racket/gui
>> (require opengl opengl/util ffi/vector)
>>
>> (define logo-texture #f)
>> (define (load-logo-texture)
>> (unless logo-texture
>> (set! logo-texture (load-texture "plt-logo-red-gradient.png" #:repeat
>> 'both)))
>> logo-texture)
>>
>> (define (clear r g b a)
>> (glClearColor r g b a)
>> (glClear (bitwise-ior GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT)))
>>
>> (define (set-color r g b)
>> (glColor3f r g b))
>>
>> (define (reset-color)
>> (set-color 1. 1. 1.))
>>
>> (define (draw-triangle x1 y1 x2 y2 x3 y3)
>> (glBegin GL_TRIANGLES)
>> (glVertex3d x1 y1 0.)
>> (glVertex3d x2 y2 0.)
>> (glVertex3d x3 y3 0.)
>> (glEnd))
>>
>> (define (example)
>> ; make framebuffer
>> (define fbo-ids (glGenFramebuffers 1)) ; this returns a vector of
>> names
>> (define fbo (u32vector-ref fbo-ids 0)) ; get the first framebuffer
>> ; swith to the new framebuffer
>> (glBindFramebuffer GL_FRAMEBUFFER fbo) ; initialize framebuffer object
>> ; load logo texture if needed
>> (load-logo-texture) (unless logo-texture (error))
>> (glFramebufferTexture2D GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0
>> GL_TEXTURE_2D logo-texture 0)
>> (define status (glCheckFramebufferStatus GL_FRAMEBUFFER_EXT))
>> (define status-complete? (= status GL_FRAMEBUFFER_COMPLETE_EXT))
>>
>> ; Draw a blue triangle ***this is the part that isn't working***
>> (glDrawBuffer GL_COLOR_ATTACHMENT0) ; draw to color attachment 0
>> (glDisable GL_TEXTURE_2D) ; do not use the texture when
>> drawing the triangle
>> (clear 0.0 0.0 1.0 1.0)
>> (set-color 0.0 1.0 0.0)
>> (glDisable GL_BLEND)
>> (draw-triangle -1.0 0.0 1.0 0.0 1.0 1.0)
>>
>> ; switch to screen framebuffer
>> (glBindFramebuffer GL_FRAMEBUFFER 0)
>> ; red background
>> (clear 1.0 0.0 0.0 0.0)
>> ; green triangle
>> (set-color 0.0 1.0 0.0) (draw-triangle 0.0 0.0 1.0 0.0 0.0 1.0)
>> ; Copy logo with blue triangle to screen
>> (reset-color)
>> (glEnable GL_TEXTURE_2D)
>> (glEnable GL_BLEND)
>> (glBlendFunc GL_ONE GL_ONE_MINUS_SRC_ALPHA) ; settings for
>> pre-multiplied alpha.
>> (define vertex-array (f64vector -0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5
>> 0.5))
>> (define texcoord-array (s16vector 0 2 2 2 2 0 0
>> 0))
>> (let-values (((type cptr) (gl-vector->type/cpointer vertex-array)))
>> (glVertexPointer 2 type 0 cptr))
>> (let-values (((type cptr) (gl-vector->type/cpointer texcoord-array)))
>> (glTexCoordPointer 2 type 0 cptr))
>> (glEnableClientState GL_VERTEX_ARRAY)
>> (glEnableClientState GL_TEXTURE_COORD_ARRAY)
>>
>> (glDrawArrays GL_QUADS 0 4)
>> (glDisableClientState GL_TEXTURE_COORD_ARRAY)
>> (glDisableClientState GL_VERTEX_ARRAY)
>> (glDisable GL_TEXTURE_2D)
>> (void))
>>
>> ;;;
>> ;;; MODEL
>> ;;;
>>
>> (define frames-per-second 60.)
>> (define milliseconds-per-frame (/ 1000. frames-per-second))
>> (define time 0.)
>>
>> (define (on-tick)
>> (set! time (+ time 1.))
>> (send gl on-paint))
>>
>> ;;;
>> ;;; GUI
>> ;;;
>>
>> (define (resize w h)
>> (glViewport 0 0 w h))
>>
>> (define (example2)
>> (define v (* 2. pi (/ time 60)))
>> (define c (cos v))
>> (define s (sin v))
>>
>> (glClearColor 0.0 0.0 0.0 0.0)
>> (glClear GL_COLOR_BUFFER_BIT)
>>
>> (glBegin GL_TRIANGLES)
>> (glColor3f c 0. 0.)
>> (glVertex3d c 0 0)
>> (glColor3f 0. s 0.)
>> (glVertex3d 0. s 0.)
>> (glColor3f 0. 0. 1.)
>> (glVertex3d -1. -1. 0.)
>> (glEnd))
>>
>> (define my-canvas%
>> (class* canvas% ()
>> (inherit with-gl-context swap-gl-buffers)
>> (define/override (on-paint) (with-gl-context (λ()
>> (example) (swap-gl-buffers))))
>> (define/override (on-size width height) (with-gl-context (λ() (resize
>> width height) (on-paint))))
>> (super-instantiate () (style '(gl)))))
>>
>> (define win (new frame% [label "Racket Rosetta Code OpenGL example"]
>> [min-width 200] [min-height 200]))
>> (define gl (new my-canvas% [parent win]))
>>
>> (new timer%
>> [interval (exact-floor milliseconds-per-frame)] ; in milliseconds
>> [notify-callback on-tick])
>>
>> (send win show #t)
>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Racket Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> For more options, visit https://groups.google.com/d/optout.
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.
>
--
--
Jens Axel Søgaard
--
You received this message because you are subscribed to the Google Groups
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.