Hi David.
Heureka! I think I figured it out. When load-texture defined in
opengl/utils loads an image
it automatically generates an mimap, which are smaller versions of the same
image.
When I draw I am drawing on the full size image - so all I need to do is to
generate
a new mimap.
(glGenerateMipmap GL_TEXTURE_2D)
This explains why you are seeing different results depending on the size of
the window.
Thanks for the hint.
Jens Axel
2018-04-08 20:23 GMT+02:00 David Vanderson <[email protected]>:
> Something weird is going on. If I make the viewport bigger when drawing
> to the screen then I see the blue triangle:
>
> ; switch to screen framebuffer
> (glBindFramebuffer GL_DRAW_FRAMEBUFFER 0)
> (glViewport 0 0 1000 1000) ; somehow this makes a difference?
>
> If I make the viewport exactly match the window size, then as I make the
> window bigger the blue triangle slowly fades in once it gets near to
> fullscreen. Do you see this as well?
>
> On Sun, Apr 8, 2018 at 9:45 AM, Jens Axel Søgaard <[email protected]>
> wrote:
>
>> 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.
>
--
--
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.