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.

Reply via email to