Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 21

Thread: Smooth in-memory image display - what's the best method?

  1. #11
    Yup, that works perfectly. Here's my code (it just cycles through all of my frames for now):

    *Brian

    Uses "UI"
    Uses "gdip"
    Uses "File" 
     
    ' -- ID numbers of controls
    Begin ControlID
      %cCanvasDB 
      %tAnimationTimer
    End ControlID 
                     
    Global Images(1000) As DWord                 
    Global nFiles    As Long
    Global nFrame      As Long
                     
    ' -- Create dialog here
    Function TBMain()
      Local hDlg As DWord 
      Local i As Long
      Dim sFiles()  As String
    
      ' Load all images from the directory
      nFiles = DIR_ListArray(sFiles, APP_ScriptPath & "frames\", "*.jpg", %FILE_NORMAL Or %FILE_ADDPATH) 
     
      If nFiles Then 
        For i = 1 To nFiles   
          Images(i) = GDIp_LoadImageFromFile(APP_SourcePath + "frames\frame (" & Trim$(Str$(i-1)) & ").jpg")
        Next i 
      Else
        Beep
        Exit Function
      EndIf
       
      Dialog New Pixels, 0, "TCT Demo",-1,-1, 720, 480, _
                                        %WS_POPUP Or %WS_VISIBLE Or _
                                         %WS_CLIPCHILDREN Or %WS_CAPTION Or _
                                         %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg
       
      ' -- Place controls here
      Control Add Canvas, hDlg, %cCanvasDB, "", 0, 0, 720, 480   
      Dialog Show Modal hDlg, Call dlgProc
     
    End Function
     
    ' -- Callback for dialog
    CallBack Function dlgProc() As Long 
      Local i As Long
      
      ' -- Test for messages
      Select Case CBMSG
        Case %WM_INITDIALOG
        ' -- Put code to be executed after dialog creation here
          Dialog Set Timer CBHNDL, %tAnimationTimer, 50, %NULL 
          DrawGraphics(CBHNDL, 1) 
          nFrame = 1    
    
        Case %WM_TIMER
          DrawGraphics(CBHNDL, nFrame)
          nFrame = nFrame + 1
          If nFrame > 792 Then
            nFrame = 1
          EndIf     
          
        Case %WM_CLOSE
        ' -- Put code to be executed before dialog end here
          For i = 1 To nFiles
            GDIp_DisposeImage(Images(i))
          Next i
     
      End Select 
    End Function
       
    Sub DrawGraphics(ByVal hDlg As DWord, ImageIndex As DWord)
      Dim pGraphics As DWord
      Dim hDC       As DWord
    
      Canvas_Attach(hDlg, %cCanvasDB, %TRUE)
    
    '  Canvas_Clear(Rgb(0,0,0), %CANVAS_FILLSTYLE_SOLID)
      hDC = Canvas_GetDC
      pGraphics = GDIp_CreateFromHDC(hdc) 
      GDIp_DrawImage(pGraphics, Images(ImageIndex), 1, 1)   
      Canvas_Redraw 
      GDIp_DeleteGraphics(pGraphics)
    End Sub
    

  2. #12
    Eros,

    As an update, the method you describe in your last example of this thread works *great*. The frames of my application are extremely smooth, and I can control them extremely accurately. It looks really really sharp.

    Thanks again for your suggestions and help - another win for TB!

    *Brian

  3. #13
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    Great!

    You know ... we are very curious
    Maybe one day you will show us some screen shots of your creations (if not something reserved).

    Ciao
    Eros
    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

  4. #14
    Eros,

    Well, in some sense, screen shots of this application are not very interesting, as they just consist of whatever JPEG frame is being displayed at the moment. In other words, the app simply displays the frames from a directory of JPG images - there are no controls in the window. So I'm not going to put up a screenshot. However, I can describe the application and I've put the full source code (to both the embedded piece and the PC side) below so you can see what I've done.

    Basic Application Idea:

    I needed an application that would load up a directory full of JPG images, and play them back (i.e. display a particular one) based on the input from a small embedded board (a chipKIT DP32, which is a PIC32 based board programmed with the Microchip PIC32 version of Arduino, connected via USB). As a user turns a knob on the embedded board, the application needs to quickly and seamlessly display the proper image based on the knob position. The images are captured from a medical imaging device, and this whole thing is basically a way for us to show off a 'simulation' of the main medical device we make at trade shows, without bringing along a lot of messy equipment to actually do live imaging.

    There is a button on the DP32 board, which, when pressed, displays frame 0, which is a 'special' JPG image. (it shows an overlay of the body part being imaged). We also need to give the impression to the user that the system is 'live', so I dither back and forth a couple of frames no matter where you have the knob. This gives the impression that things are moving.

    The application looks for a directory called 'frames', and reads in all of the JPG files from that directory. The really sweet thing is that due to the method used to read in the frames and the canvas object used to display them, there is zero flicker, and the response is instant. It's fantastic. It also uses surprisingly little RAM.

    I'm actually running this whole application on a $60 USD Windows 8 tablet (with HDMI output so we can display it on a big screen) and the tablet can keep up with the knob position no problem. It has plenty of horsepower to make everything nice and smooth. I currently only have about 700 frames, but we'll be taking more images soon and that will likely at least triple. The images I'm using are at the screen resolution of the tablet (800 x 1280).

    I've only spent a limited amount of time on this, but ThinBasic allowed me to pull it off beautifully. Since this first prototype went so smooth (and was far under-budget) there are now plans to turn this application into a full training simulator that we could use to train people on how to use our device. Since the computer is aware of how fast the user is turning the knob, we can easily throw up warnings if they're moving too fast or too slow, or treating the wrong region, etc. There are lots of possibilities.

    So here's the sketch I'm running on the chipKIT DP32 board:
    #define BTN3  1
    
    void setup() {
      Serial.begin(9600);
      pinMode(A3, INPUT);
      digitalWrite(A3, LOW);
      pinMode(BTN3, INPUT);
      digitalWrite(BTN3, LOW);
    }
    
    void loop() {
      int sensorValue = analogRead(A3);
      if (digitalRead(BTN3) == HIGH)
      {
        sensorValue = sensorValue + 1024;
      }
      Serial.println(sensorValue, DEC);
      delay(10);  // Run this at about 100 Hz
    }
    

    And here's the full ThinBasic application:

    ' Application written to demo mulitple JPEG images smoothly animated
    ' using a hardware input device to determine which frame to display.
    '
    ' A small chipKIT development board (DP32) is connected to an analog
    ' potentiomenter, and sends analog readings from the pot (from 0 to 1023)
    ' up to the PC every 10ms. 
    ' If BTN3 is pressed on the DP32, 1024 is added to the ADC value before
    ' sending it up to the PC.
    ' A simple sketch is running on the DP32 to provide this functionality.
    '
    ' Written by Brian Schmalz, with lots of help and ideas from the 
    ' fantastic ThinBasic forum.
    Uses "UI" 
    Uses "COMM"
    Uses "GDIP"
    Uses "FILE"
                            
    Begin ControlID
      %cCanvas
      %tAnimationTimer
    End ControlID                
    
    %TIMER_DELAY        = 10        ' Timer delay (in milliseconds, not very accurate below about 100)
    %MAXIMUM_ADC_VALUE  = 1023      ' From DP32, maximum value from pot position
    %MAX_ORBIT_FACTOR   = 1         ' Number of frames to add to and substract from CurrentFrame to show orbit
    $FRAME_DIRECTORY    = "Frames"  ' Name of directory where all of our frames are contained
                            
    Global hImg(1)      As Long     ' Array of images (frames) to display
    Global CurrentFrame As Long     ' Index into hImg() of which frame to display right now
    Global LastFrame    As Long     ' The last frame  number we displayed
    Global hComm        As Long     ' COM port handle that DP32 is talking to us on
    Global nFileCount   As Long 
                     
    Function TBMain()
      Local hDlg As DWord
      Local i As Long      
      Local nWidth, nHeight As Long
      Local sFramesFileNames() As String
      Local sComPort As String
      
      ' Grab the proper com port number for this PC from the file
      sComPort = FILE_Load(APP_SourcePath & "comport.txt")
      If (Len(sComPort) = 0) Then
        Beep
        Exit Function
      EndIf
                                                                
      ' Read in all *.jpg file names from Frames directory
      nFileCount = DIR_ListArray(sFramesFileNames, APP_SourcePath & $FRAME_DIRECTORY & "\", "*.jpg", %FILE_NORMAL Or %FILE_ADDPATH)
      If (nFileCount = 0) Then
        Beep
        Exit Function
      EndIf
                
      ' Sort the array of file names so they're in the right order
      Array Sort sFramesFileNames(), AsFiles          
                
      ' Make sure hImg array is the right size for the number of frames we have
      ReDim hImg(nFileCount)
                             
      ' Load each jpg file into a GDIp grapihcs image
      For i = 1 To nFileCount    
        hImg(i) = GDIp_LoadImageFromFile(sFramesFileNames(i))
        If hImg(i) = %NULL Then
          Beep
          Exit Function
        End If
      Next i
      
      ' Look up dimensions of the first frame, and make our window that size
      GDIp_GetImageSizeFromFile(sFramesFileNames(1), nWidth, nHeight)
      
      ' Open up the com port
      hComm = COMM_FreeFile  
      ' Open the com port listed in the comport.txt file. Would be cool to look up in registry where
      ' DP32 board is (com port) and use that instead. 
      COMM_Open("\\.\COM" & sComPort, hComm)
      If Err <> 0 Then
        Beep
        Exit Function
      End If
                           
      ' This appears to be necessary to 'start things going' on the DP32
      COMM_Send(hComm, " ")
      
      ' Because our tablet is 800 x 1024, we use those values for this window
      Dialog New Pixels, 0, "Demo App", -1, -1, 800, 1280, _
                         %WS_POPUP Or %WS_VISIBLE Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg
    
      Control Add Canvas, hDlg, %cCanvas, "", 0, 0, nWidth, nHeight
      ' This is the big deal - the reason we like to use a canvas. Because of the "TRUE" parameter, which 
      ' stands for "wait until a Canvas_Redraw" call to update the canvas, and it make very very smooth updates.
      Canvas_Attach(hDlg, %cCanvas, TRUE)
      Canvas_Scale Pixels
      Canvas_Redraw 
    
      Dialog Show Modal hDlg, Call dlgCallback 
    End Function  
      
    callback function dlgCallback() as long
      Local i                   As Long   ' index variable
      Local pGraphics           As DWord  ' Points to our graphics thing
      Local hDC                 As DWord  ' Handle to some graphics thing
      Local ADCValue            As Long   ' Numerical value that the ADC on the DP32 board sends us (position of pot)
      Static sAccumulator       As String ' String we build up from DP32, then convert into ADCValue
      Local nBytes              As Long   ' Number of bytes DP32 just sent us
      Local sBuffer             As String ' String of bytes DP32 just sent us  
      Static OrbitFactor        As Long   ' Cylical offset in frame count to give impression of orbiting              
      
      ' -- Test for messages
      Select Case CBMSG
    
        Case %WM_INITDIALOG
        ' -- Put code to be executed after dialog creation here
          Dialog Set Timer CBHNDL, %tAnimationTimer, %TIMER_DELAY, %NULL 
          CurrentFrame = 1
          LastFrame = 1  
          sAccumulator = ""
    
        Case %WM_TIMER
          ' Pull in all buytes from the DP32
          nBytes = COMM_Get(hComm, %COMM_RXQUE)
          If nBytes > 0 then
            COMM_Recv(hComm, nBytes, sBuffer)
            
            For i = 1 To nBytes
              ' If we have a CR, then parse the number
              If Mid$(sBuffer, i, 1) = Chr$(13) And Len(sAccumulator) > 0 Then
                ' Convert from string that DP32 sent us to number
                ADCValue = Val(sAccumulator)
    
                ' Always clear out our buffer once we've found a value
                sAccumulator = ""
                
                ' Pick off the state of the BTN3 from the DP32
                If (ADCValue > %MAXIMUM_ADC_VALUE) Then
                  CurrentFrame = 1
                  ADCValue = ADCValue - 1023
                Else
                  ' Limit scaled ADC value to 1 to %MAXIMUM_ADC_VALUE
                  If ADCValue > %MAXIMUM_ADC_VALUE Then
                    ADCValue = %MAXIMUM_ADC_VALUE
                  End If
                  If ADCValue < 1 Then
                    ADCValue = 1
                  End If                                       
                  
                  ' Scale CurrentFrame to ADCFilteredValue
                  CurrentFrame = (ADCValue * nFileCount)/%MAXIMUM_ADC_VALUE 
                  
                  ' Limit CurrentFrame to 1 to %NUMBER_OF_FRAMES taking into account MAX_ORBIT_FACTOR
                  If CurrentFrame > (nFileCount - %MAX_ORBIT_FACTOR) Then
                    CurrentFrame = (nFileCount - %MAX_ORBIT_FACTOR)
                  End If
                  If CurrentFrame < 2 + %MAX_ORBIT_FACTOR Then
                    CurrentFrame = 2 + %MAX_ORBIT_FACTOR
                  End If                                       
      
                  OrbitFactor = OrbitFactor + 1
                  If (OrbitFactor > %MAX_ORBIT_FACTOR) Then
                    OrbitFactor = -%MAX_ORBIT_FACTOR
                  EndIf
                  
                  ' Add in 'orbit factor'
                  CurrentFrame = CurrentFrame + OrbitFactor           
                EndIf                           
              Else
                sAccumulator = sAccumulator + Mid$(sBuffer, i, 1)
              End If
            Next i
            
            ' Check to see if the displayed frame needs to change
            If CurrentFrame <> LastFrame Then      
              LastFrame = CurrentFrame
    
              hDC = Canvas_GetDC
              pGraphics = GDIp_CreateFromHDC(hdc)
                      
              GDIp_DrawImage(pGraphics, hImg(CurrentFrame), 1, 1)
             
              '---Release GDI image
              GDIp_DeleteGraphics(pGraphics)
              
              ' Allow the update to happen 
              Canvas_Redraw 
            End If
          End If
                
        Case %WM_CLOSE
          COMM_Close(hComm)
    
      End Select
    End Function
    
    Oh, and this app is working perfectly as a bundled application that starts up right when the tablet boots. My next task is to figure out how to put the tablet in a kiosk-type mode, where the window boarder doesn't show up at all, and it's just the JPG images that take up the whole screen.

    Thanks so much for this fantastic language-

    *Brian

  5. #15
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    Hi Brian,

    thanks a lot for sharing all those interesting details and the script source code. It can greatly help others having similar needs.
    Very interesting problem and clever solutions. I really like when software is used to help real life situations.

    Wish the best for the future of your system.

    Great
    Eros
    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

  6. #16
    Super Moderator Petr Schreiber's Avatar
    Join Date
    Aug 2005
    Location
    Brno - Czech Republic
    Posts
    7,128
    Rep Power
    732
    Brian,

    thanks for sharing, it always make my day to see thinBasic is used to help someone.

    I had a look at your code, I found few places you can optimize - if you want!

    a)
    Retrieving OS desktop resolution can be achieved via:
    DESKTOP GET SIZE TO width, height
    
    ...so you can retrieve it dynamically to allow porting your app easily once tablets with different resolution come.

    b)
    Cycling variables can be done easily in ThinBASIC. Compare the original:
    OrbitFactor = OrbitFactor + 1
    If (OrbitFactor > %MAX_ORBIT_FACTOR) Then
      OrbitFactor = -%MAX_ORBIT_FACTOR
    EndIf
    
    ...to simple:
    orbitFactor = CYCLE_Next(orbitFactor, -%MAX_ORBIT_FACTOR, %MAX_ORBIT_FACTOR, 1)
    
    c)
    Normalizing value to specific bounds, like you do it here:
    If ADCValue > %MAXIMUM_ADC_VALUE Then
      ADCValue = %MAXIMUM_ADC_VALUE
    End If
    If ADCValue < 1 Then
      ADCValue = 1
    End If
    
    ...can be achieved this way:
    ADCValue = MinMax(ADCValue, 1, %MAXIMUM_ADC_VALUE)
    
    ...and the same for CurrentFrame.

    d)
    Shortcut for doing this:
    CurrentFrame = CurrentFrame + OrbitFactor
    
    ...is this one:
    CurrentFrame += OrbitFactor
    
    e)
    Carriage Return is built-in, so instead of:
    Chr$(13)
    
    ...you can use directly:
    $CR
    
    Petr
    Last edited by Petr Schreiber; 24-09-2015 at 09:16.
    Learn 3D graphics with ThinBASIC, learn TBGL!
    Windows 10 64bit - Intel Core i5-3350P @ 3.1GHz - 16 GB RAM - NVIDIA GeForce GTX 1050 Ti 4GB

  7. #17
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    Wow Petr

    you just recalled from my oooold neurons memory of that days when we developed all those nice functions

    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

  8. #18
    Super Moderator Petr Schreiber's Avatar
    Join Date
    Aug 2005
    Location
    Brno - Czech Republic
    Posts
    7,128
    Rep Power
    732
    ... and sure more will come!


    Petr
    Learn 3D graphics with ThinBASIC, learn TBGL!
    Windows 10 64bit - Intel Core i5-3350P @ 3.1GHz - 16 GB RAM - NVIDIA GeForce GTX 1050 Ti 4GB

  9. #19
    Petr,

    Thanks! Those are all great tips, I'll put them in my code right away.

    Do you know if there's an easy way to scale an image once I've loaded it into memory? It would be best if I took the screen resolution dynamically at run time (as you suggest) and then scaled the images as I'm displaying them. Is there a way with GDIp?

    *Brian

  10. #20
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    A quick way is to delete/recreate the Canvas control at every Window re-size the same size as the window client area.
    Than re-draw image into the newly created canvas having the same client area size of the window.

    See below example in which I set the window re-sizable and at every re-size (%WM_SIZE message) the canvas control is killed and recreated.
    Than image draw takes place in a DC of the same size of the window client area.
    The rest is done by GDI+

    Execute the script and try to re-size the window and see.

    (you need to have an \image\ sub directory in which to have some JPG image to be loaded)

    Uses "UI"Uses "gdip"
    Uses "File"
      
    ' -- ID numbers of controls
    Begin ControlID
      %cCanvasDB 
      %tAnimationTimer
    End ControlID
                      
    Global Images() As DWord                
    Global nFiles   As Long
    Global nFrame   As Long
                      
      '----------------------------------------------------------
      '---Dialog Callback for the main window
      '----------------------------------------------------------
      Function TBMain()
        Local hDlg As DWord
        Local i As Long
        Dim sFiles()  As String
       
        ' Load all images from the directory
        ' ---CHANGE AS NEEDED---
        nFiles = DIR_ListArray(sFiles, APP_ScriptPath & "images\", "*.jpg", %FILE_NORMAL Or %FILE_ADDPATH) 
       
       
        If nFiles Then
          ReDim Images(nFiles)
          For i = 1 To nFiles
            Images(i) = GDIp_LoadImageFromFile(sFiles(i))
          Next i 
        Else
          Beep
          Exit Function
        EndIf
          
    '    Dialog New Pixels, 0, "GDI+ and Canvas Demo",-1,-1, 720, 480, _
    '                                        %WS_POPUP Or %WS_VISIBLE Or _
    '                                        %WS_CLIPCHILDREN Or %WS_CAPTION Or _
    '                                        %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg
    
    
        Dialog New Pixels, 0, "thinBasic using GDI+", -1, -1, 720, 480, _
                            %WS_OVERLAPPEDWINDOW Or %WS_CLIPCHILDREN, _
                            0 To hDlg
          
        Dialog Show Modal hDlg, Call dlgProc
        
      End Function
    
    
      '----------------------------------------------------------
      '---Dialog Callback for the main window
      '----------------------------------------------------------
      CallBack Function dlgProc() As Long
        Static idxImage As long
        Local cx, cy    As Long
      
        '---
        Select Case CBMSG
          Case %WM_INITDIALOG
      
            'Dialog Get Client CBHNDL To cx, cy
             
            ''---Place controls here
            'Control Add Canvas, CBHNDL, %cCanvasDB, "", 0, 0, cx, cy   
      
            '---
            Dialog Set Timer CBHNDL, %tAnimationTimer, 10, %NULL
            
            idxImage = 1    
            Image_Draw(CBHNDL, idxImage) 
          
          Case %WM_SIZE
            '---At every window resize ... delete canvas control and recreate it the same size as the window client area
            Dialog Get Client CBHNDL To cx, cy   
            '---Place controls here
            Control Kill CBHNDL, %cCanvasDB
            Control Add Canvas, CBHNDL, %cCanvasDB, "", 0, 0, cx, cy   
          
          Case %WM_TIMER
            Image_Draw(CBHNDL, idxImage)
            idxImage += 1
            If idxImage > UBound(Images) Then
              idxImage = 1
            EndIf    
             
          Case %WM_CLOSE
            Images_Dispose
        
        End Select
      End Function
    
    
      '----------------------------------------------------------
      '---
      '----------------------------------------------------------
      Function Images_Load() As Long
      End Function
    
    
      '----------------------------------------------------------
      '---
      '----------------------------------------------------------
      Function Images_Dispose() As Long
        Local lIdx As Long
        
        '---Clear allocated memory for images
        For lIdx = 1 To UBound(Images)
          GDIp_DisposeImage(Images(lIdx))
        Next i
    
    
      End Function
            
      '----------------------------------------------------------
      '---
      '----------------------------------------------------------
      Function Image_Draw(ByVal hDlg As DWord, ByVal ImageIndex As DWord)
        Dim pGraphics   As DWord
        Dim pThumbnail  As DWord
        Dim hDC         As DWord
        Local cx, cy    As Long
       
        If ImageIndex < 1 Or ImageIndex > UBound(Images) Then
          Exit Function
        End If
        
        Canvas_Attach(hDlg, %cCanvasDB, %TRUE)
      
      
        Canvas_Clear(Rgb(0,0,0), %CANVAS_FILLSTYLE_SOLID)
        hDC = Canvas_GetDC
        pGraphics = GDIp_CreateFromHDC(hdc)
    
    
        Dialog Get Client hDlg To cx, cy
        '---Create a thumbnail the same size of the dialog client size
        pThumbnail = GDIp_GetImageThumbnail(Images(ImageIndex), cx, cy)
         
        'GDIp_DrawImage(pGraphics, Images(ImageIndex), 1, 1)   
        GDIp_DrawImage(pGraphics, pThumbnail, 1, 1)   
      
        Canvas_Redraw
      
        GDIp_DisposeImage(pThumbnail)
        GDIp_DeleteGraphics(pGraphics)
    
    
      End Function
    
    Last edited by ErosOlmi; 30-09-2015 at 07:17.
    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

Page 2 of 3 FirstFirst 123 LastLast

Similar Threads

  1. Method to get Sprite-Pixel?
    By ReneMiner in forum TBGL module by Petr Schreiber
    Replies: 2
    Last Post: 19-11-2012, 17:10
  2. display 2 textures
    By Lionheart008 in forum TBGL module by Petr Schreiber
    Replies: 2
    Last Post: 29-07-2009, 19:31
  3. Improved donations method
    By ErosOlmi in forum Web and Forum
    Replies: 3
    Last Post: 03-12-2008, 18:40
  4. Flexible display
    By ErosOlmi in forum Technology
    Replies: 1
    Last Post: 02-11-2008, 21:53
  5. smooth and solid
    By kryton9 in forum TBGL General
    Replies: 2
    Last Post: 25-04-2007, 20:40

Members who have read this thread: 1

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •