eths's picture

Newbie qeustion and a potential bug

Hello,

As a newbie to the world of OpenGL, I have started to teach myself a bit about OpenGL using OpenTK on a Windows XP Professional system with a NVidia GeForce 6600 graphic card. I am including one of my experiments as a bit VB.Net code written with VisualStudio 2005 (Microsoft .Net 2.0).

1) Potentialbug: When I move windows from other applications around, the GlControls appear to loose or shift their internal GL coordinate systems. I've attached screen shots of this.

2) They also do not redraw correctly if they have been hidden by another widow, but this may well be a GL problem, meaning I would need to do my own redraw.

3) There must be a kinder, gentler way of scrolling a "waterfall" display, than using GL.CopyPixels especially if (some) redraws (see above) must be be done by myself. Is there an easy way of drawing to my own buffers and then moving them screen buffers? I haven't been able to figure out how to do this (yet).

4) GL.CopyPixels can be very slow at times, which I why I ended up doing the copy in chunks. Is this a good or a poor method for doing these kinds of stuff in GL.

Thank you!

Option Strict On
Option Explicit On
 
Imports OpenTK
Imports OpenTK.Graphics
Imports OpenTK.Math
 
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.IO
Imports System.Drawing
 
Public Class Form1
    Private hasLoaded As Boolean = False
    Public Shared Event Idle As EventHandler
    Private handler As New EventHandler(AddressOf Application_Idle)
 
    Private spectrum(1999) As Integer
    Private noise As Integer = 12
 
    Private zufall As New Random
    Private sw As Stopwatch = New Stopwatch()
 
    Private accumulator As Double = 0
    Private idleCounter As Integer = 0
 
    'Private serif As TextureFont = New TextureFont(New Font(FontFamily.GenericSerif, 24.0F))
    Private sans As TextureFont = New TextureFont(New Font(FontFamily.GenericSansSerif, 8.0F))
    Private txt_handle As TextHandle
    Private txt As ITextPrinter = New TextPrinter()
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        hasLoaded = True
 
        Me.GlControl1.MakeCurrent()
        GL.ClearColor(Color.FromArgb(10, 10, 10))
 
        Me.GlControl2.MakeCurrent()
        GL.ClearColor(Color.FromArgb(100, 100, 100))
 
        SetupViewport()
 
        Me.GlControl2.MakeCurrent()
        GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)
        GlControl2.SwapBuffers()
        GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)
        GlControl2.SwapBuffers()
 
        sw.Start()
 
        AddHandler Application.Idle, handler
    End Sub
    Private Sub Application_Idle(ByVal sender As Object, ByVal e As System.EventArgs)
 
 
        Dim ms As Double = ComputeTimeSlice()
        Accumulate(ms)
 
        Animate(ms)
    End Sub
    Private Sub Accumulate(ByVal milliseconds As Double)
        idleCounter += 1
        accumulator += milliseconds
        If (accumulator > 1000) Then
            Label1.Text = idleCounter.ToString()
            accumulator -= 1000
            idleCounter = 0
        End If
    End Sub
    Private Function ComputeTimeSlice() As Double
        sw.Stop()
        Dim timeslice As Double = sw.Elapsed.TotalMilliseconds
        sw.Reset()
        sw.Start()
        Return timeslice
    End Function
 
    Private Sub Animate(ByVal ms As Double)
 
        spectrum(500) = 270
        spectrum(250) = 30
 
        For i As Integer = 600 To 880 Step 20
            spectrum(i) = i - 590
        Next
 
        For j As Integer = 0 To spectrum.Length - 1
            If j = 0 Then
                spectrum(j) = (spectrum(j) * 2 + spectrum(j + 1)) \ 3 + zufall.Next(-noise, noise)
            ElseIf j = spectrum.Length - 1 Then
                spectrum(j) = (spectrum(j) * 2 + spectrum(j - 1)) \ 3 + zufall.Next(-noise, noise)
            Else
                spectrum(j) = (spectrum(j) * 4 + spectrum(j + 1) + spectrum(j - 1)) \ 6 + zufall.Next(-noise, noise)
            End If
            Select Case spectrum(j)
                Case Is < 0
                    spectrum(j) = 0
                Case Is >= Me.GlControl1.Height
                    spectrum(j) = Me.GlControl1.Height - 1
            End Select
        Next
 
        GlControl1.Invalidate()
    End Sub
    Private Sub SetupViewport()
        Dim w As Integer = GlControl1.Width
        Dim h As Integer = GlControl1.Height
 
        Me.GlControl1.MakeCurrent()
        GL.MatrixMode(MatrixMode.Projection)
        GL.LoadIdentity()
        GL.Ortho(0, w, 0, h, -1, 1) ' Bottom-left corner pixel has coordinate (0, 0)
        GL.Viewport(0, 0, w, h) ' Use all of the glControl painting area
 
        w = GlControl2.Width
        h = GlControl2.Height
 
        Me.GlControl2.MakeCurrent()
        GL.MatrixMode(MatrixMode.Projection)
        GL.LoadIdentity()
        GL.Ortho(0, w, 0, h, -1, 1) ' Bottom-left corner pixel has coordinate (0, 0)
        GL.Viewport(0, 0, w, h) ' Use all of the glControl painting area
    End Sub
    Private Sub GlControl1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles GlControl1.Paint
        If hasLoaded Then
            Me.GlControl1.MakeCurrent()
            GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)
 
            GL.MatrixMode(MatrixMode.Modelview)
            GL.LoadIdentity()
 
            GL.Color3(Color.DarkGray)
            GL.Begin(BeginMode.Lines)
            For j As Integer = 20 To GlControl1.Height - 1 Step 20
                GL.Vertex2(25, j)
                GL.Vertex2(GlControl1.Width, j)
            Next
            GL.End()
 
            For j As Integer = 11 To GlControl1.Height - 11 Step 20
                txt.Prepare((-154 + (j - GlControl1.Height) \ -2).ToString, sans, txt_handle)
                txt.Begin()
                GL.Translate(0.0F, j + 2, 0.0F)
                txt.Draw(txt_handle)
                txt.End()
            Next
 
            GL.Color3(Color.YellowGreen)
            GL.Begin(BeginMode.LineStrip)
            For j As Integer = 0 To spectrum.Length - 1
                GL.Vertex2(j, spectrum(j))
            Next
            GL.End()
 
            Me.GlControl2.MakeCurrent()
 
            GL.ReadBuffer(ReadBufferMode.Front)
 
 
            For j As Integer = GlControl2.Height To 0 Step -255
 
                GL.RasterPos2(0, j - 1)
                GL.CopyPixels(0, j, GlControl2.Width, 255, PixelCopyType.Color)
 
            Next
 
            GL.Begin(BeginMode.Points)
            'For i As Integer = 0 To GlControl2.Height - 1
            For j As Integer = 0 To spectrum.Length - 1
                Dim r As Integer = spectrum(j) * 1
                Dim g As Integer = spectrum(j) * 3
                Dim b As Integer = spectrum(j) * 6
 
                If r > 255 Then r = 255
                If g > 255 Then g = 255 - (g - 255)
                If b > 255 Then b = 255 - (b - 255)
 
                If g < 0 Then g = 0
                If b < 0 Then b = 0
                GL.Color3(Color.FromArgb(r, g, b))
                GL.Vertex2(j, GlControl2.Height - 1)
            Next
            'Next
            GL.End()
 
 
            GlControl1.SwapBuffers()
            GlControl2.SwapBuffers()
 
        Else
            'do nuthin'
        End If
    End Sub
End Class
AttachmentSize
ScreenShot_1.JPG237 KB
ScreenShot_2.JPG251.37 KB
ScreenShot_3.JPG216.02 KB

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

1. Which operating system? I can't seem to reproduce this on my PC (either XP or linux).

2. In what way do they fail to redraw? Note that you should handle both GLControl1.Paint and GLControl2.Paint, puting the relevant code to each handler. The same should be done for the Resize event (keep GLControl1 as separate from GLControl2 as possible).

3. There are several methods to achieve this. For example, you can create a large texture and use TexSubImage and CopyTexSubImage to update and scroll it respectively. The texture is then displayed on a simple screen-sized quad.

This method minimizes system -> video memory transfers, which should give a nice speed boost. The downside is that it can get complicated if your window is larger than the max texture size of your system (you'll have to separate the display in many smaller textures). Fortunately, all recent cards support at least 2048x2048 textures, so it will only be a problem if you want to support old systems (Geforce 2 era and older).

4. As far as I know, CopyPixels involves a video -> system -> video memory transfer, which should be avoided at all costs. CopyTexSubImage on the other hand means a blazing-fast video -> video memory copy.

As a rule of thumb, pixel-level manipulations are slow in OpenGL (and DirectX). You'll get better performance by assembling whole rows of data and uploading them at once, compared to sending each pixel one-by-one.

eths's picture

1. > Which operating system?

Microsoft Windows XP Professional
5.1.2600 Service Pack 3 Build 2600
Microsoft Corporation

NVIDIA GeForce 6600
PCI\VEN_10DE&DEV_0141&SUBSYS_31261458&REV_A2\4&123D6358&0&0010
GeForce 6600, NVIDIA-kompatibel
NVIDIA GeForce 6600
256.00 MB (268,435,456 Bytes)
nv4_disp.dll
6.14.10.7801

Try opening the task manager and moving its form while the GL program is running. I could send you my project, if you wish.

2. > In what way do they fail to redraw?

When you move a window from another application across the GlControls, this can cause the error in 1) and also you can see remnants of the foreign window in the area which scrolls (see screen shot #3).

3. > use TexSubImage and CopyTexSubImag

Need to figure out how to do this - good fun - always nice to learn something new.

4. > CopyPixels involves a video -> system -> video

AFAIK and according to the book I've got here, CopyPixels does not use system memory.

For the waterfall, sooner or later I'll end having to set the color of each pixel in the top line individually, after that then I only want to move the line but not redraw it pixel for pixel.

Thanks!

Inertia's picture

Looks interesting, haven't seen spectrum analyzers for a while ^^

3. You can fake the scrolling by setting MatrixMode to Texture and translate it repeatedly. This will give the illusion that your texture is scrolling and avoids any copy, but you have to fine-tune the translation and your updates to the texture carefully, so that the illusion does not break.