Author Topic: Simple example of using pointers to draw on the screen.  (Read 5344 times)

0 Members and 1 Guest are viewing this topic.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
This example was written for GrahamK, who wants to impliment pointers into his programming language "Cobra", in this example I show you how to use a pointer to write to an array, and also to read from an array.

In further examples I will show you how to do other stuff with them.

Hopefully it will also be of use to those of you who would like to optimise your freebasic programs.
Using pointers is usually a faster way of accessing memory than straight forward array access.

Code: [Select]
' EXAMPLE OF USING POINTERS TO FILL AN ARRAY WITH A VALUE AND THEN USING POINTER
' TO PULL THE VALUE OUT OF THE ARRAY.
' IN THIS CASE THE VALUE IS A COLOUR SO WE USE IT TO DRAW A LINE.
'
'-------------------------------------------------------------------------------

'       REMOVE COMMENT ON LINE BELOW FOR WINDOWED MODE

        #DEFINE PTC_WIN
        #INCLUDE "TINYPTC.BI"

'       ALL VARIABLES MUST BE DECLARED.
'       -------------------------------

        OPTION STATIC
        OPTION EXPLICIT
       
       
'       SCREEN DIMENSIONS.
'       ------------------

        CONST   XRES = 640:'    WIDTH
        CONST   YRES = 480:'    HEIGHT
         
        DIM SHARED AS DOUBLE OLDTIME
        DIM SHARED AS INTEGER TICKS
        DIM SHARED AS INTEGER FPS
       
        'SCREEN BUFFER;
        DIM SHARED AS UINTEGER BUFFER ( XRES * YRES )       
        DIM SHARED AS UINTEGER GRADIENT( XRES )
       
'-------------------------------------------------------------------------------               
'       SUBS DEFINITIONS;       
'-------------------------------------------------------------------------------       

        DECLARE SUB FPSEC() : ' SUB TO DISPLAY CURRENT FPS IN WINDOW.
        DECLARE SUB LOADGRADIENT()
        DECLARE SUB DRAWGRADIENT()
       
'-------------------------------------------------------------------------------               
'       OPEN WINDOW;
'-------------------------------------------------------------------------------       

        If( PTC_OPEN( "POINTER EXAMPLE 1", XRES, YRES ) = 0 ) Then
        End -1
        End If
        OLDTIME=TIMER
       
        LOADGRADIENT()
       
'-------------------------------------------------------------------------------       
'       THE MAIN LOOP;
'-------------------------------------------------------------------------------       
DIM SHARED GADD AS DOUBLE
DIM SHARED GADD2 AS DOUBLE
        oldtime = timer
        while (1)                       
            DRAWGRADIENT()
            PTC_UPDATE @ BUFFER (0)
            ERASE BUFFER
            FPSEC()
           
        wend


'-------------------------------------------------------------------------------       
'       THE MAIN LOOP ENDS HERE.
'-------------------------------------------------------------------------------

SUB FPSEC()
            TICKS=TICKS+1
            IF TIMER-OLDTIME>=1 THEN
                FPS = TICKS
                print str(FPS)
                TICKS=0
                OLDTIME=TIMER
            END IF   

END SUB


SUB DRAWGRADIENT()
    '
    ' HERE WE ARE SETTING UP TWO POINTERS, WE WILL USE ONE TO LOOK AT
    ' THE CONTENTS OF THE ARRAY "GRADIENT", THE OTHER WILL LOOK AT THE
    ' ARRAY "BUFFER" WHICH IS IN EFFECT OUR SCREEN MEMORY.
    '
    DIM PP1 AS UINTEGER PTR
    DIM PP2 AS UINTEGER PTR
    '
    'LP IS USED IN THE LOOP
    '
    DIM LP AS UINTEGER
    '
    'YPOS IS USED AS AN OFFSET TO START DRAWING FROM.
    '
    DIM YPOS AS INTEGER
    '
    ' START DRAWING 100 PIXELS DOWN (WE * BY XRES TO GET THE RIGHT LOCATION ON THE SCREEN)
    '   
    YPOS = 100*XRES
    '
    ' POINT THE POINTERS AT THE ARRAYS;
    '
    PP1=@BUFFER(YPOS)
    PP2=@GRADIENT(0)
   
    FOR LP=0 TO XRES-1
        '
        ' THE VALUE AT PP1 IS EQUAL TO THE VALUE AT PP2
        '
        *PP1=*PP2
        '
        ' ADVANCE THE POINTERS;
        '
        PP1+=1
        PP2+=1
    NEXT
END SUB


SUB LOADGRADIENT()
    '
    ' THIS IS HOW WE DEFINE A POINTER;
    ' THE UINTEGER MEANS UNSIGNED INTEGER (ALWAYS A POSITIVE NUMBER, FASTER THAN SIGNED NUMBERS).
    DIM PP AS UINTEGER PTR
    DIM LP AS UINTEGER: ' WE NEED THIS LP FOR THE LOOP.
   
    'WE SET THE POINTER TO BE AT THE MEMORY ADDRESS OF THE FIRST ELEMENT IN ARRAY "GRADIENT()"
   
    PP = @ GRADIENT(0)
   
    FOR LP=0 TO XRES-1
        '
        ' USING THE PREFIX "*" WE ARE SAYING THAT THE VALUE AT PP.
        ' WE CAN USE THE POINTER LIKE THIS TO CHANGE WHAT IS IN THAT MEMORY ADDRESS.
        ' IN THIS CASE WE ARE JUST STORING SOME CALCULATED COLOUR VALUE.
        '
        *PP = RGB(125+124*SIN(LP*3.14/180),125+124*SIN(LP*3.14/193),125+124*SIN(LP*3.14/197))
        '
        ' HERE WE ADVANCE THE POINTER.
        ' WE COULD SAY +=2 ETC. ETC.. THE POINTER IS MOVED AUTOMATICALLY THE RIGHT DISTANCE
        ' WHETHER WE ARE WORKING IN WORDS, LONG WORDS, BYTES ETC BECAUSE WE HAD DEFINED THE
        ' LOCAL POINTER PP AS AN INTEGER, SO THE COMPILER KNOWS TO CONVERT TO THE RIGHT INCREMENT.
        '
         PP +=1
         
         'THE ABOVE CODE IS FASTER THAN;
         'GRADIENT(LP) =RGB(125+124*SIN(LP*3.14/180),125+124*SIN(LP*3.14/193),125+124*SIN(LP*3.14/197))
         'BECAUSE WE ARE DIRECTLY ACCESSING MEMORY.
    NEXT
   
END SUB
Shockwave ^ Codigos
Challenge Trophies Won:

Offline MrP

  • Atari ST
  • ***
  • Posts: 176
  • Karma: 18
    • View Profile
Cool example shocky... Didn't know that unsigned integers were faster to work with than their signed counterparts.... Nice tip..... I acces memory in much the same way in my graphics lib, Since I dont use the tinyptc framebuffer library, i started out with using the gfxlib that comes as standard in freebasic... I just get a pointer to the start of current screen memory and use pointers to write directly to the memory.....

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
If you're doing it that way Mr.P you'd be well advised to install Rbraz's excellent Ptc_ext library. This gives you all the benefits of being able to detect the mouse and some other stuff, it makes small exe files and has a much better refresh rate, in fact, perfect v-sync. You can still use your inline asm in exactly the same way, it will run a lot smoother using his new lib.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Btw, even though my own tests seem to indicate that unsigned numbers appear faster, the main reason for using them is that the maximum value it can hold is doubled.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline rdc

  • Pentium
  • *****
  • Posts: 1495
  • Karma: 140
  • Yes, it is me.
    • View Profile
    • Clark Productions
You can actually get a little bit more speed here by using memcpy from the crt.bi instead of a For-Next. You need to #include "crt.bi".

Code: [Select]
SUB DRAWGRADIENT()
    '
    ' HERE WE ARE SETTING UP TWO POINTERS, WE WILL USE ONE TO LOOK AT
    ' THE CONTENTS OF THE ARRAY "GRADIENT", THE OTHER WILL LOOK AT THE
    ' ARRAY "BUFFER" WHICH IS IN EFFECT OUR SCREEN MEMORY.
    '
    DIM PP1 AS UINTEGER PTR
    DIM PP2 AS UINTEGER PTR
    '
    'LP IS USED IN THE LOOP
    '
    DIM LP AS UINTEGER
    '
    'YPOS IS USED AS AN OFFSET TO START DRAWING FROM.
    '
    DIM YPOS AS INTEGER
    '
    ' START DRAWING 100 PIXELS DOWN (WE * BY XRES TO GET THE RIGHT LOCATION ON THE SCREEN)
    '   
    YPOS = 100*XRES
    '
    ' POINT THE POINTERS AT THE ARRAYS;
    '
    PP1=@BUFFER(YPOS)
    PP2=@GRADIENT(0)
   
    'Note the use of memcpy here instead of a for-next loop
    memcpy pp1, pp2, ubound(gradient) * sizeof(uinteger)
   
END SUB

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Good call RDC, that's faster :) I don't think that it will help Graham who is trying to put pointers into Cobra though. It's my bad mate, I should have left this in the Cobra forum, just figured it could help people who'd never used pointers.. Have some Karma though mate.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline DrV

  • ZX 81
  • *
  • Posts: 2
  • Karma: 3
  • For great justice
    • View Profile
    • drv.nu
Sorry for dragging this even farther off topic, but here's a relatively simple memory copy routine that's (possibly) faster than the CRT one (I can never resist the urge to write a bit of inline assembly :)):

Code: [Select]
sub fastmemcpy(byval dst as any ptr, byval src as any ptr, byval bytes as uinteger)
asm
mov ecx, [bytes]
mov esi, [src]
mov edx, ecx
shr ecx, 2 ' ecx = bytes / 4 = number of dwords to copy
and edx, 3 ' edx = 3, 2, 1, 0 bytes left over after dword copy
test ecx, ecx
mov edi, [dst]
jz bytecpy
rep movsd
bytecpy:
test edx, edx
jz endcpy
mov ecx, edx
rep movsb
endcpy:

end asm
end sub
 

Offline rdc

  • Pentium
  • *****
  • Posts: 1495
  • Karma: 140
  • Yes, it is me.
    • View Profile
    • Clark Productions
Cool, DrV, you are Da' Man!

Shockie, I did realize that this was a Cobra example, however, if he has external linking to apis, or is going to add it in the future, then method would be valid. He might also want to add an internal memcpy command, since this a common task in programming.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Have some good Karma DrV, that's a fantastic routine  :clap: Nice one. Source code is always welcome here!!

Rick, I'll make sure that Graham gets to see this topic and your suggestion :) It's great actually that he's doing his damndest to include as much stuff into his language as possible, I like that about him.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline GrahamK

  • Atari ST
  • ***
  • Posts: 118
  • Karma: 17
    • View Profile
Watching closely :D  :updance:

Always good seeing some nice asm code...