Can ScreenPtr stand for an image buffer?

General FreeBASIC programming questions.
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 02, 2015 10:51

Hello, all in the title once again.

I want to use ScreenPtr as an operand in Put operations. Reminder : Put can be seen as an operation between A and B such as in this assignation: "A = A Put B" .
When A is screen , no reference is needed, just leave a blank, but to use B as screen also and do screen = screen Put screen or, B = B Put screen, blank seems not working. So I've tried to use 'ScreenPtr' in place of 'blank' but it didn't work neither.

What is wrong with this?

Code: Select all

''
'' Tries to use ScreenPtr [=screenWorkpage] as screen Imagebuffer
''

ScreenRes 400, 400, 16, 1     ''Sets one graphics page
ScreenSet 0, 0      ''workpage = 0, andalso is visible page
Circle (200, 160), 100, RGB(100, 200, 200),,,,F  ''Drawing circle on workpage

Dim As Any Ptr workpage0ImageBuffer = ImageCreate(400, 400,,16)
Get  (0,0)-(399,399) , workpage0ImageBuffer  ''Saves this screen in a image buffer

''Method 1
    ? "... Should show a black form surrounded by 2 inflated blue borders"
    Put ScreenPtr, (20,-20),workpage0ImageBuffer  , Xor  ''Does nothing
Sleep

''Method 2
    ? "... Should show a black form surrounded by 2 inflated blue borders"
    Put  (20,-20),workpage0ImageBuffer  , Xor     ''Writes and operate on screen
Sleep
counting_pine
Site Admin
Posts: 6211
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Can ScreenPtr stand for an image buffer?

Postby counting_pine » Jul 02, 2015 11:20

Screenptr does not have a header like an image buffer - it's a pointer to the pixel data, with the same format that you get with the pixdata return parameter on ImageInfo.
Omitting the first parameter directs the operation to the screen, similarly to other graphics commands like pset.
Sadly, there's no way to use the screen as the source of a Put operation. (Sadly, because Get doesn't provide the same safeguards, and is easy to misuse.)
If we were to implement it, I guess syntactically we could reuse the Screen keyword instead of an image pointer. (But not Screenptr.)
MrSwiss
Posts: 3542
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Can ScreenPtr stand for an image buffer?

Postby MrSwiss » Jul 02, 2015 11:27

Short answer: NO

Screen Ptr is usually used to read information, from Screen (Buffer).

To write to Screen (actually to the Screen Buffer) you'd use a form of Put ...
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 02, 2015 11:34

Ok, thanks.

counting_pine wrote: (Sadly, because Get doesn't provide the same safeguards, and is easy to misuse.)

With get I find this:

Code: Select all

'Get  ScreenPtr, (0,0)-(399,399) , workpage0ImageBuffer  ''---->Crashes
Get  workpage0ImageBuffer, (0,0)-(399,399) , ScreenPtr   ''---->This is fine


Now other issue found as collateral effect of demo code posted above. If I add only one char to the string printed on screen the program crashes :

Code: Select all

'' A single "X" added to the string below induces crash

''Method 1
    ? "X... Should show a black form surrounded by 2 inflated blue borders"
    Put workpage0ImageBuffer, (20,-20), ScreenPtr, Xor  ''Does nothing
Sleep

Code: Select all

"Aborting due to runtime error 1 (illegal function call) at line 37 = Put..."

Why is so?
counting_pine
Site Admin
Posts: 6211
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Can ScreenPtr stand for an image buffer?

Postby counting_pine » Jul 02, 2015 13:43

Tourist Trap wrote:Now other issue found as collateral effect of demo code posted above. If I add only one char to the string printed on screen the program crashes :

Code: Select all

'' A single "X" added to the string below induces crash

''Method 1
    ? "X... Should show a black form surrounded by 2 inflated blue borders"
    Put workpage0ImageBuffer, (20,-20), ScreenPtr, Xor  ''Does nothing
Sleep

As I said, you cannot use ScreenPtr as an image pointer. The results are undefined. It's reasonable for it to crash sometimes, and it's reasonable for it to not crash sometimes.

The way Get works currently, it's often possible to write to ScreenPtr without a crash. All Get really does is set memory, so if you give it a large enough block of writable memory, it will write to it without crashing. The first bytes/pixels will be formatted to contain an image header, and the pixels/bytes afterwards will contain the pixels it gets. If the region has the same width as the screen, then you will see a coherent image, but offset a few bytes/pixels from where you might expect.

But if the image containing the region - including the image header - needs more memory than the screen has, then you will write outside the bounds of the screen. This might crash or cause other unexpected behaviour.

But I don't know why I'm explaining all this. The short version is simply that ScreenPtr is not an image, and you can't use it as one. And don't ask us why strange behaviour happens if you try, because it's undefined behaviour and could technically do anything, e.g. crash, reformat your hard disk, etc.
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 02, 2015 17:05

Thanks for the long version. It is very informative, and really needed since I will keep playing around with ScreenPtr for a few hours.

counting_pine wrote:But I don't know why I'm explaining all this. The short version is simply that ScreenPtr is not an image, and you can't use it as one. And don't ask us why strange behaviour happens if you try, because it's undefined behaviour and could technically do anything, e.g. crash, reformat your hard disk, etc.

As a short version, as I feel it I would call all this buffer overflow.
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 02, 2015 21:14

Sorry if I'm not done with this matter. 2 things more :

1
I would have another question relative to screen. How can I retrieve the current work page number as set in Screen _workpageNum, _visiblePage? And by the way, the number of pages set in ScreenRes _w, _h, _d, _numberofPages.

I've read about ScreenInfo, or even ScreenControl, that seems not able to return this info.

2
It's about this help page : http://www.freebasic.net/wiki/wikka.php ... KeyPgPcopy .
Syntax:
declare function Pcopy ( byval source as long = -1, byval destination as long = -1 ) as long

The return value is not explained. Leave aside the fact that it has type LONG, what this result mean has been omitted...
grindstone
Posts: 737
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Postby grindstone » Jul 03, 2015 9:54

There really seems to be no feature to get the number of defined screens, but there's a workaround:

Code: Select all

Dim value(100) As Integer

ScreenRes 640,480,32,5
For x As Integer = 0 To UBound(value)
   ScreenSet x,x
   value(x) = ScreenPtr
Next
For x As Integer = 0 To UBound(value)
   Print x;" ";value(x)
   If value(x) = value(x+1) Then 'if the pointer is repeated, the screen doesn't exist
      Exit For
   EndIf
Next
Sleep

Regards
grindstone
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 03, 2015 15:27

@GrindStone,

Thanks for this effort. Unfortunately I was starting using it on production when I found a problem that can be a rather annoying limitation. You can't use your routine to get the total amount of pages without you change the current working screen which becomes the very last page. And I see of course no way to get the current work page at moment of routine call in order to reset it after a call to your routine, so that is limitating . Unless adding a lot of additional management (wrap screenset ..etc) which I would like not to do.

It's sad because it was a really pretty workaround, very useful.

I've crafted the example below to show that. Just uncomment one of the calls to GetScreenLayerAmount().

Code: Select all

#Include "fbgfx.bi"
ScreenRes 500, 400, 8, 4

Static Shared As UByte MAXLAYERAMOUNT :
   MAXLAYERAMOUNT = 100
Declare Function GetScreenLayerAmount() As Integer
Declare Sub DrawingTest(_StringArray() As String, ByVal PageNum As ULong)
Static Shared As Integer _WIDTH
Static Shared As Integer _HEIGHT
Static Shared As Integer _DEPTH

Static Shared As UByte LayerAmount
   LayerAmount = GetScreenLayerAmount()
Static Shared As Any Ptr LayerImageBuffer(1 To LayerAmount)

'///Main


For _pagenum As Integer = 0 To GetScreenLayerAmount()-1
     ScreenSet _pagenum, _pagenum

     Dim As String stringArray(1 To 2)

    ? "MAIN PRINT: This is page number "; _pagenum + 1 & " on " ; 4  'GetScreenLayerAmount()
   
    Draw String (0, 40*_pagenum+40), _
    "MAIN DRAW STRING:This is page number " & _pagenum + 1 & " on " & 4 'GetScreenLayerAmount()
   
    DrawingTest(stringArray(), _pagenum)
    Sleep
Next _pagenum

Sleep: End 0

'///Sub
Sub DrawingTest(_StringArray() As String, ByVal PageNum As ULong)
    ScreenInfo _WIDTH, _HEIGHT, _DEPTH

    ? "SUB PRINT : This is page number "; PageNum + 1 & " on " ; 4 'GetScreenLayerAmount()
   
     Draw String (100, 40*PageNum+50), _
    "SUB DRAW STRING:This is page number " & PageNum + 1 & " on " & 4 'GetScreenLayerAmount()

End Sub 'DrawingTest()
 
Function GetScreenLayerAmount() As Integer
   ''Credits go to GrindStone for this useful piece
   Dim As Integer layerSignal(MAXLAYERAMOUNT)
   Dim As Integer layerIndex

   For layerIndex = 0 To UBound(layerSignal)
       ScreenSet layerIndex
       layerSignal(layerIndex) = Cast(Integer, ScreenPtr())

      If layerIndex > 1 Then
         If layerSignal(layerIndex) = layerSignal(layerIndex-1) Then
             'if the pointer is repeated, the screen doesn't exist
             layerIndex += 1
             Exit For
         EndIf
      EndIf
   Next layerIndex

   ReDim Preserve LayerImageBuffer(1 To layerIndex - 1)
   Return layerIndex - 1
End Function 'INT ScreenLayerAmount := GetScreenLayerAmount()
grindstone
Posts: 737
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Postby grindstone » Jul 04, 2015 9:36

TouristTrap wrote:And I see of course no way to get the current work page at moment of routine call

But it's so easy! There is an unambiguous assignment of screennumber and screenpointer. You only have to memorise the initial screenpointer, determine, to which screen it belongs and reset the current screen to this number afterwards:

Code: Select all

Function GetScreenLayerAmount() As Integer
    ''Credits go to GrindStone for this useful piece
    Dim As Integer layerSignal(MAXLAYERAMOUNT)
    Dim As Integer layerIndex
      Dim As Integer currentScreenNumber
      Dim As Any Ptr currentScreenPtr
      
    currentScreenPtr = ScreenPtr '<<<<< get current (initial) screen pointer
   
    For layerIndex = 0 To UBound(layerSignal)
       ScreenSet layerIndex
       layerSignal(layerIndex) = Cast(Integer, ScreenPtr())
         
         '<<<<< test if the current screen pointer belongs to the initial screen
         If layerSignal(layerIndex) = currentScreenPtr Then
            currentScreenNumber = layerIndex '<<<<< memorise screen number
         EndIf
     
      If layerIndex > 1 Then
        If layerSignal(layerIndex) = layerSignal(layerIndex-1) Then
             'if the pointer is repeated, the screen doesn't exist
             layerIndex += 1
             Exit For
        EndIf
      EndIf
    Next layerIndex
   
    ScreenSet currentScreenNumber '<<<<< reset to initial screen

    ReDim Preserve LayerImageBuffer(1 To layerIndex - 1)
    Return layerIndex - 1
End Function 'INT ScreenLayerAmount := GetScreenLayerAmount()
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 04, 2015 12:34

You guy are very competent. It was not so obvious. There is the visible page, and the work pages. And the game between pointers for each of them is not so clearly explained in the documentation that I've read very extensively.

I would just change one statement for it seems that the address is already an integer so why convert it. Don't know if good practice however.

Code: Select all

       'layerSignal(layerIndex) = Cast(Integer, ScreenPtr())
        layerSignal(layerIndex) = ScreenPtr


Besides that, I'm still on deep investigation about ScreenPtr. I still don't see how one may use its content as pixel data. I've been able to catch successfully pixel data of a 'Image', but screenPtr even casted to UByte Ptr, doesn't fit . Or I'm missing something. Here anyway is a little demo made to exhibit clearly I hope, pixel data area from inside an image, and how to manipulate. It is partly a reformulation of the help files (Imageinfo , Put ..etc.)

Code: Select all

#Include "fbgfx.bi"

ScreenRes 600, 350, 8
'Calculation of Size of such a screen PixelData=UByte(datasize)
   Dim As Integer w, h, d, bpp, pitch, datasize
    ScreenInfo w, h , d, bpp, pitch
   
    dataSize = (((w * bpp + &hF) and not &hF) * h) ''from documentation
    dataSize = -(Int(-w/16))*16 * h * d / 8        ''from what I'm understanding     
   
    ? "Screen " & w &"x"& h &"x"& d
    ? "Screen Pixel Data size" , dataSize
   
Dim As UByte Ptr PixelData
    PixelData = Callocate(dataSize, SizeOf(UByte))


''Create and initialize 2 void images
Dim As FB.IMAGE Ptr _img1
    _img1 = ImageCreate (w, h, , d)
Dim As  FB.IMAGE  Ptr _img2
    _img2 = ImageCreate (w, h, , d)

''Create the pixelData arrays
Dim As UByte  _img1PixelData()
   ReDim _img1PixelData(1 To datasize)
Dim As UByte  _img2PixelData()
    ReDim _img2PixelData(1 To datasize)

''FB.IMAGE STRUCTURE
''    --------------------------------------------------------------
''   !   PUT_HEADER   !           PIXELDATA                        !
''   --------------------------------------------------------------
'' ^               ^
''@img_          @pixeldata
''Given the image address
''We have to skip the PUT_HEADER block to get the pixel data address

Dim As UByte Ptr _img1PixelDataPtr
_img1PixelDataPtr =  _
CPtr(UByte Ptr, _img1)+IIf(_img1->Type=FB.PUT_HEADER_NEW,SizeOf(FB.PUT_HEADER),SizeOf(FB._OLD_HEADER))

Dim As UByte Ptr _img2PixelDataPtr
_img2PixelDataPtr =  _
CPtr(UByte Ptr, _img2)+IIf(_img2->Type=FB.PUT_HEADER_NEW,SizeOf(FB.PUT_HEADER),SizeOf(FB._OLD_HEADER))


For _i As Integer = 1 To 2

    ? :? IIf(_i=1, "    IMAGE 1", "    IMAGE 2")
    ?
    ? "    FB.IMAGE STRUCTURE "
    ? "    ------------------------------------------------------------- "
    ? "   !   PUT_HEADER   !                 PIXELDATA                  ! "
    ? "    ------------------------------------------------------------- "
    ? "   ^                ^"
    Locate CsrLin, 4 : ? IIf(_i=1, @ _img1, @ _img2)
    Locate CsrLin -1, 21 : ? IIF(_i=1, @ _img1PixelDataPtr, @ _img2PixelDataPtr) 

Next _i



Get (0,0)-(w-1, h-1), _img1
? : ? : ?
Color 11
? "  >This screen (not this information insert) will be stored in _image1."
? "  >Then screen cleared."
? "  >Finally _image1 pixel datas copied to_image2, and _image2 displayed"
? "  >PRESS ANY KEY"
Sleep
Cls

'Q1
   For _i As Integer = 0 To dataSize - 1
       _img2PixelDataPtr[_i] = _img1PixelDataPtr[_i]
   Next _i

'Q2
    Put (0, 0), _img2    , PSet
   
Sleep : End 0
grindstone
Posts: 737
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Postby grindstone » Jul 04, 2015 15:19

I would just change one statement for it seems that the address is already an integer so why convert it. Don't know if good practice however.

Code: [Select all] [Expand/Collapse] [Download] (Untitled.bas)
'layerSignal(layerIndex) = Cast(Integer, ScreenPtr())
layerSignal(layerIndex) = ScreenPtr
You don't have to convert it categorical (though it's definitely no good practice), for a pointer is nothing else than an integer number. The code will work anyway, but you will get a compiler warning "suspiceous pointer assignment". To avoid the explicit conversion as well as the compiler warnings simply dim the array as pointer:

Code: Select all

Dim As Any Ptr layerSignal(MAXLAYERAMOUNT)


'Q1
'_img2PixelDataPtr = _img1PixelDataPtr '' Why is this not working in place of below loop ?
The assignment itself works, but it makes no sense.

You have copied the contents of the screen to the image buffer at _img1:

Code: Select all

Get (0,0)-(w-1, h-1), _img1
Then you have cleared the screen:

Code: Select all

Cls
That means, you have set all pixels of the graphics memory to the background colour.

To restore the screen contents, you have to copy them (the whole contents, not only the pointer) from the image buffer to the screen memory:

Code: Select all

Put (0,0), _img1  , PSet
so the end of your example code simply should read:

Code: Select all

...
? "  >Finally _image1 pixel datas copied in _image2, and _image2 displayed"
? "  >PRESS ANY KEY"
Sleep
Cls
Put (0,0), _img1  , PSet
Sleep : End 0

'Q2
'Why x must have offset = -5 in Put ?

Except for special purposes you shouldn't calculate the pointers by yourself like you did at _img1PixelDataPtr, for FB will do it for you, safer and exacter than you ever could do.

Regards
grindstone
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 04, 2015 17:50

grindstone wrote:To restore the screen contents, you have to copy them (the whole contents, not only the pointer) from the image buffer to the screen memory

Thanks. Pointers are difficult stuff and syntax. I think I've fixed the end part of the previous code now. Only one thing would be greatest :assigning the whole data in one row, where a loop is used for the moment.

However, if I take ScreenPtr as a pointer to screen pixel data, and copy its content to an image, to finally display this image which is then a screen copy, I have a problem. The datas seem all to be there, but the image is sheared. Here is the demo code :

Code: Select all

''
''Copying screen to an image via pixel data chanel
''

#Include "fbgfx.bi"

Static Shared As Integer w, h, d, bpp, pitch
Declare Function GetGraphicsParameter() As Integer
Declare Function DataSize() As Integer
Function GetGraphicsParameter() As Integer
    ScreenInfo w, h , d, bpp, pitch
End Function 'INT := GetGraphicsParameter()
Function DataSize() As Integer
    GetGraphicsParameter()
     DataSize = (((w * bpp + &hF) and not &hF) * h) ''from documentation
    DataSize = -(Int(-w/16))*16 * h * d / 8        ''from what I'm understanding     
End Function 'INT := DataSize()

''-----------------------------------------------------Init()
''Initialize graphics screen
    ScreenRes 600, 350, 8

''Create and initialize 1 image which fits screen dimensions
   Static Shared As FB.IMAGE Ptr  _img
     GetGraphicsParameter()
    _img = ImageCreate (w, h, , d)

''Create an pointer to hold the address of the pixel data
   Static Shared As UByte Ptr _imgPixelDataPtr
''Following the documentation..
_imgPixelDataPtr =  _
CPtr(UByte Ptr, _img)+IIf(_img->Type=FB.PUT_HEADER_NEW,SizeOf(FB.PUT_HEADER),SizeOf(FB._OLD_HEADER))

''-----------------------------------------------------Main()
    ? "Screen " & w &"x"& h &"x"& d
    ? "Screen Pixel Data size" , DataSize()

   For _i As Integer = 0 To 30
       Circle (w\2, h\2), (( w + h - Abs( w - h) ) / 2 +_i)/3
       Paint (w\2, h\2), 1, 15
   Next _i

   Color RGB(10, 10, 10)
    ? :? "   SCREEN"
    ?
    ? "   SCREENPTR SUPPOSED STRUCTURE "
    ? "               -------------------------------------------- "
    ? "   <NO HEADER>!                 PIXELDATA                  ! "
    ? "               -------------------------------------------- "
    ? "              !         DataSize =                         ! "
    ? "               -------------------------------------------- "
    ? "              ^"
   Color RGB(14,14,14)
     Locate CsrLin - 3, 40 : ? DataSize()
    Locate CsrLin + 2, 12 : ? ScreenPtr

   Color RGB(11, 11, 11)
    ? :? "   IMAGE"
    ?
    ? "   FB.IMAGE STRUCTURE "
    ? "    ------------------------------------------------------------- "
    ? "   !   PUT_HEADER   !                 PIXELDATA                  ! "
    ? "    ------------------------------------------------------------- "
    ? "   !                !    DataSize() =                            ! "
    ? "    ------------------------------------------------------------- "
    ? "   ^                ^"
   Color RGB(14,14,14)
     Locate CsrLin - 3, 40 : ? DataSize()
    Locate CsrLin + 2, 4 : ? @ _img
    Locate CsrLin -1, 21 : ? @ _imgPixelDataPtr 

''Copy screen data values to image pixel data section
For _i As Integer = 0 To dataSize - 1
    _imgPixelDataPtr[_i] = *(CPtr(UByte Ptr, ScreenPtr) +_i)
Next _i

? : ? : ?
Color 15
? "  >ScreenPtr values have been copied to image pixel data section."
? "  >Then screen will be cleared."
? "  >Finally the image will be put on screen"
? "  >PRESS ANY KEY"
Sleep

Cls
    Put (0, 0), _img    , PSet
   
Sleep : End 0

''------------------------------------------------------End()


grindstone
Posts: 737
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Postby grindstone » Jul 05, 2015 16:42

However, if I take ScreenPtr as a pointer to screen pixel data, and copy its content to an image, to finally display this image which is then a screen copy, I have a problem. The datas seem all to be there, but the image is sheared.
Once more: Let FB do the image operations for you. If you absolutely want to handle with the video data, then do it complete. If you read them 1:1 from the memory you have also to restore them 1:1.

Some additional points:
    You don't have to declare variables as 'Static' in the main program. Just use the 'Dim' - statement.
    The 'RGB' - statement doesn't work with colour depths below 24 bit.
    If you place subs or functions above the main programm you don't have to declare them.
    And yes: Pointers are wayward.

Code: Select all

''
''Copying screen to an image via pixel data chanel
''

#Include "fbgfx.bi"

Dim Shared As Integer w, h, d, bpp, pitch

Function GetGraphicsParameter() As Integer
   ScreenInfo w, h , d, bpp, pitch
End Function 'INT := GetGraphicsParameter()
Function DataSize() As Integer
   GetGraphicsParameter()
   DataSize = 32 + (((w * bpp + &hF) And Not &hF) * h) ''from documentation
   'DataSize = -(Int(-w/16))*16 * h * d / 8        ''from what I'm understanding (that's wrong)
End Function 'INT := DataSize()

''-----------------------------------------------------Init()
''Initialize graphics screen
ScreenRes 600, 350, 32

''Create and initialize 1 image which fits screen dimensions
Dim Shared As FB.IMAGE Ptr  _img
GetGraphicsParameter()

_img = Callocate (DataSize)

''Create an pointer to hold the address of the pixel data
Dim As UByte Ptr _imgPixelDataPtr
''Following the documentation..
_imgPixelDataPtr =  CPtr(UByte Ptr, _img)

''-----------------------------------------------------Main()
? "Screen " & w &"x"& h &"x"& d
? "Screen Pixel Data size" , DataSize()

For _i As Integer = 0 To 30
   Circle (w\2, h\2), (( w + h - Abs( w - h) ) / 2 +_i)/3,RGB(128,128,128)
Next _i
Paint (w\2, h\2), RGB(0,0,255), RGB(128,128,128)

Color RGB(100, 255, 100)
? :? "   SCREEN"
?
? "   SCREENPTR SUPPOSED STRUCTURE "
? "               -------------------------------------------- "
? "   <NO HEADER>!                 PIXELDATA                  ! "
? "               -------------------------------------------- "
? "              !         DataSize =                         ! "
? "               -------------------------------------------- "
? "              ^"
Color RGB(255,255,0)
Locate CsrLin - 3, 40 : ? DataSize()
Locate CsrLin + 2, 12 : ? ScreenPtr

Color RGB(0, 255, 255)
? :? "   IMAGE"
?
? "   FB.IMAGE STRUCTURE "
? "    ------------------------------------------------------------- "
? "   !   PUT_HEADER   !                 PIXELDATA                  ! "
? "    ------------------------------------------------------------- "
? "   !                !    DataSize() =                            ! "
? "    ------------------------------------------------------------- "
? "   ^                ^"
Color RGB(255,255,0)
Locate CsrLin - 3, 40 : ? DataSize()
Locate CsrLin + 2, 4 : ? @ _img
Locate CsrLin -1, 21 : ? @ _imgPixelDataPtr

Dim As UByte Ptr sp = ScreenPtr

''Copy screen data values to image pixel data section
For _i As Integer = 0 To pitch * h
   _imgPixelDataPtr[_i] = sp[_i]
Next

? : ? : ?
Color RGB(255,255,255)
? "  >ScreenPtr values have been copied to image pixel data section."
? "  >Then screen will be cleared."
? "  >Finally the image will be put on screen"
? "  >PRESS ANY KEY"
Sleep

Cls

ScreenLock 'for writing to screen memory you have to lock the screen
For _i As Integer = 0 To pitch * h
    sp[_i] = _imgPixelDataPtr[_i]
Next
ScreenUnLock

DeAllocate _img

Sleep : End' 0

''------------------------------------------------------End()


Regards
grindstone
Tourist Trap
Posts: 2880
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Postby Tourist Trap » Jul 05, 2015 17:43

First, a big thanks Grindstone. I really wanted to understand this subject, and help files won't go in depth. I agree to your corrections but have now some little comments.

Code: Select all

Sleep : End' 0

About the End return value, it is in the documentation. Apparently End won't clean the things properly unless returning a value. Seriously, I don't understand why that and I'm just following the help file here. And I've noticed others programs ending this way.

Code: Select all

'DataSize = -(Int(-w/16))*16 * h * d / 8        ''from what I'm understanding (that's wrong)

Of course, but here again following the doc, each row is "padded" with some 16 bits or something like that. So what does it mean? That's rather unclear, and I've translated this by : each row is 16*n format...

Code: Select all

''Following the documentation..
_imgPixelDataPtr =  CPtr(UByte Ptr, _img)

Obviously you're right again, but documentation says that for accessing pixel data (for customizing Put method and so on) you have to skip header named PUT_HEADER , which by itself is a mystery.

grindstone wrote:Some additional points:
You don't have to declare variables as 'Static' in the main program. Just use the 'Dim' - statement.

Ok, Static is just a keyword I like. I've decided using it for global variable just as a convention - if of course no bad side effect is to be expected.

grindstone wrote:The 'RGB' - statement doesn't work with colour depths below 24 bit.

Yes Grindstone, you can use RGB statement even for 8 bits. At least for 8 bits just write RGB( X, X, color from 0 to 15). The 2 first places are not used as far as I've been testing.

grindstone wrote:If you place subs or functions above the main programm you don't have to declare them.

Yes, I'm just doing this for posting code. My goal is to divide the source in as much include as necerssary for clarity.

Now Grindstone, as I didn't know if I would get a so quick and clean answer, I've been making this tool for screenPtr study !
The 2 last functions of the whole code can hold a custom ScreenPtr reader.

Code: Select all

''
''SCanning Screen and ScreenPtr comparatively
''

#Include "fbgfx.bi"

Static Shared As Integer w, h, d, bpp, pitch
Declare Function GetGraphicsParameter() As Integer
Declare Function DataSize() As Integer
Function GetGraphicsParameter() As Integer
    ScreenInfo w, h , d, bpp, pitch
    Return Cast(Integer, ScreenPtr())
End Function 'INT := GetGraphicsParameter()
Function DataSize() As Integer
    GetGraphicsParameter()
     DataSize = (((w * bpp + &hF) and not &hF) * h) ''from documentation
End Function 'INT := DataSize()

Type CROSSHAIR
   Declare Sub DecreaseSweeperLength()
   Declare Sub IncreaseSweeperLength()
   Declare Sub DrawMethod(ByVal _CenterColor As ULong =-1)

    As UInteger _sweeperLength = 0
    As UInteger _length = 10
    As Single _x = 0
    As Single _y = 0
    As Single _dx = 0
    As Single _dy = 0
    As ULong _color = RGB(15, 15, 15)
End Type 'CROSSHAIR
Sub CROSSHAIR.DecreaseSweeperLength()
     This._sweeperLength -= 1 * ((This._sweeperLength <= 4)+1)
End Sub 'CROSSHAIR.DecreaseSweeperLength()
Sub CROSSHAIR.IncreaseSweeperLength()
    This._sweeperLength += 1 * ((This._sweeperLength > 100)+1)
End Sub 'CROSSHAIR.IncreaseSweeperLength()
Sub CROSSHAIR.DrawMethod(ByVal _CenterColor As ULong =-1)
   Dim As UInteger _l = This._length

   If Abs(This._length) < 4 Then _l = 4
   With This
       Line (._x-4, ._y-._sweeperLength)-(._x+4, ._y-._sweeperLength), ._color
       Line (._x-4, ._y+._sweeperLength)-(._x+4, ._y+._sweeperLength), ._color
           Line (._x-_l, ._y)-(._x-4, ._y), ._color
           Line (._x+4, ._y)-(._x+_l, ._y), ._color
           Line (._x, ._y-_l)-(._x, ._y-4), ._color          
           Line (._x, ._y+4)-(._x, ._y+_l), ._color
           Line (._x-4, ._y-4)-(._x-4, ._y+4), ._color
           Line (._x-4, ._y-4)-(._x+4, ._y-4), ._color
           Line (._x-4, ._y+4)-(._x+4, ._y+4), ._color
           Line (._x+4, ._y+4)-(._x+4, ._y-4), ._color
   End With 'This

   If _CenterColor <>-1 Then
      Circle (This._x, This._y), _l, _CenterColor
      Circle (This._x, This._y), 0.7*4, _CenterColor + 1+Rnd*4
      Line (This._x-0.7*_l, This._y-0.7*_l)-(This._x+0.7*_l, This._y+0.7*_l), _CenterColor
      Line (This._x-0.7*_l, This._y+0.7*_l)-(This._x+0.7*_l, This._y-0.7*_l), _CenterColor
   EndIf
   
End Sub 'CROSSHAIR.DrawMethod()
Declare Function DrawBackGround(ByVal ImageToDraw As FB.IMAGE Ptr =0) As Integer
Declare Sub ViewReport()
Enum _MOVEDIRECTION
    _noMove = 0
    _up = 1
    _down = 2
    _left = 3
    _right = 4
    _fastUp = 1
    _fastDown = 2
    _fastLeft = 3
    _fastRight = 4
End Enum '_MOVEDIRECTION
Declare Function MoveCross(ByVal Movdir As _MOVEDIRECTION = 0) As Integer
Declare Function UserAccessToScreenPtr1() As ULong
Declare Function UserAccessToScreenPtr2() As ULong

''-----------------------------------------------------Init()
''Initialize graphics screen
    ScreenRes 600, 350, 8, 4

''Get this screen address
   Static Shared As Any Ptr mainScrPtr
    mainScrPtr = ScreenPtr()

   Static Shared As UByte activeScreen
    activeScreen = 0

''Set BackGround
     GetGraphicsParameter()
   Color ,RGB(bpp*8, bpp*8, 3*bpp)
   Cls
    ? "Screen " & w &"x"& h &"x"& d
    ? "BPP " & bpp
    ? "PITCH " & pitch
    ? "PixelData_Row size " &  -(Int(-w/16))*16
    ? "PixelData size " & DataSize()
    ? : ? "[ESC] to quit"
    ? "[SPACE] to see sweeped area"
    ? "[ENTER]/[BACK]"
    ? "to Deploy/Shrink sweeper"
    
   For _i As Integer = 0 To 30
       Circle (w\2, h\2), (( w + h - Abs( w - h) ) / 2 +_i)/3
       Paint (w\2, h\2), 1, 15
   Next _i
    View ( 1 , h*0.9 ) - ( w-2, h-2 ), RGB(d*5/8, d*5/8, d*5/8), RGB(d*1/8, d*1/8, d*1/8)
    View Screen
''Store BackGround
   Static Shared As FB.IMAGE Ptr backGroundImage(0 To 4)
    backGroundImage(0) = ImageCreate(w, h, , d)
    backGroundImage(1) = ImageCreate(w\2, h\2, , d)
    backGroundImage(2) = ImageCreate(w\2, h\2, , d)
    backGroundImage(3) = ImageCreate(w\2, h\2, , d)
    backGroundImage(4) = ImageCreate(w\2, h\2, , d)
    Get (0,0)-(w-1, h-1), backGroundImage(0)
    Get (0,0)-(w\2-1, h\2-1), backGroundImage(1)
    Get (w\2, 0)-(w-1, h\2-1), backGroundImage(2)
    Get (w\2, h\2)-(w-1, h-1), backGroundImage(3)
    Get (0, h\2)-(w\2-1, h-1), backGroundImage(4)

''ResultImage
   Static Shared As FB.IMAGE Ptr resultImage
    resultImage = ImageCreate(w, h, , d)

''Naive ProcessedImage
   Static Shared As FB.IMAGE Ptr processedImage
    processedImage = ImageCreate(w, h, , d)

''User ProcessedImage
   Static Shared As FB.IMAGE Ptr userProcessedImage(1 To 2)
    userProcessedImage(1) = ImageCreate(w, h, , d)
    userProcessedImage(2) = ImageCreate(w, h, , d)

''Set CrossHair
   Static Shared As CROSSHAIR cross
   With cross
        ._x = w\2
        ._y = h\2
        ._length = 20
        ._color = RGB(d*15/8, d*15/8, d*15/8)
        ._sweeperLength = 20
   End With 'cross
   cross.DrawMethod()

''ProcessingCursorImage
   Static Shared As FB.IMAGE Ptr ProcessingCursorImage
    processingCursorImage = ImageCreate(5, 2*cross._sweeperLength+1, , d)

''-----------------------------------------------------Main()
resultImage = BackGroundImage(0)
Do

   If MultiKey(FB.SC_ENTER) Or MultiKey(FB.SC_D)Then
       While InKey<>"" : Wend
       cross.IncreaseSweeperLength
   EndIf   

   If MultiKey(FB.SC_BACKSPACE) Or MultiKey(FB.SC_S) Then
       While InKey<>"" : Wend
       cross.DecreaseSweeperLength
   EndIf   

   If MultiKey(FB.SC_SPACE) Then
      While InKey<>"" : Wend
       Sleep 100

      Select Case resultImage
         Case BackGroundImage(0)
            ScreenSet 1,1
             activeScreen = 1
              resultImage = processedImage
              Sleep 100
              Exit Select
         Case processedImage
            ScreenSet 2,2
             activeScreen = 2
             resultImage = userProcessedImage(1)
             Sleep 100
             Exit Select
         Case userProcessedImage(1)
            ScreenSet 3,3
             activeScreen = 3
             resultImage = userProcessedImage(2)
             Sleep 100
             Exit Select
         Case Else
            ScreenSet 0,0
             activeScreen = 0
             resultImage = BackGroundImage(0)
             Sleep 100
      End Select 'resultImage
   
   EndIf

   If MultiKey(FB.SC_UP) Then
       MoveCross(_up)
   ElseIf MultiKey(FB.SC_DOWN) Then
       MoveCross(_down)
   ElseIf MultiKey(FB.SC_LEFT) Then
       MoveCross(_left)
   ElseIf MultiKey(FB.SC_RIGHT) Then
       MoveCross(_right)
   ElseIf Multikey(FB.SC_RSHIFT) Andalso MultiKey(FB.SC_UP) Then
       MoveCross(_fastUp)
   ElseIf Multikey(FB.SC_RSHIFT) Andalso MultiKey(FB.SC_DOWN) Then
       MoveCross(_fastDown)
   ElseIf Multikey(FB.SC_RSHIFT) Andalso MultiKey(FB.SC_LEFT) Then
       MoveCross(_fastLeft)
   ElseIf Multikey(FB.SC_RSHIFT) Andalso MultiKey(FB.SC_RIGHT) Then
       MoveCross(_fastRight)
   Else
       MoveCross(_noMove)
   EndIf

   
Loop Until MultiKey(FB.SC_ESCAPE)
   
   'DeAllocate  mainScrPtr   'Not to be done since it is ScreenPtr here
    DeAllocate resultImage
    DeAllocate processedImage
    DeAllocate userProcessedImage(1)
    DeAllocate userProcessedImage(2)
    DeAllocate backGroundImage(0)
    DeAllocate backGroundImage(1)
    DeAllocate backGroundImage(2)
    DeAllocate backGroundImage(3)
    DeAllocate backGroundImage(4)
   
Sleep : End 0
''------------------------------------------------------End()
Function DrawBackGround(ByVal ImageToDraw As FB.IMAGE Ptr =0) As Integer

   If ImageToDraw = backGroundImage(0) Or ImageToDraw = 0 Then
       Put (0, 0) , backGroundImage(1), PSet
       Put (w\2, 0) , backGroundImage(2), PSet
       Put (w\2, h\2) , backGroundImage(3), PSet
       Put (0, h\2) , backGroundImage(4), PSet
   Else
       Put (0,0), ImageToDraw, PSet
   EndIf

   Return -1
End Function 'INT := DrawBackGround(FB.IMAGE)
''---------------------------------------------------------()
Sub ViewReport()

   View ( 1 , h*0.9 ) - ( w-2, h-2 ), RGB(d*5/8, d*5/8, d*5/8), RGB(d*1/8, d*1/8, d*1/8)
           Draw String (0,0), Str(cross._x)
           Draw String (0,10), Str(cross._y)
           Draw String (0,20), "Active Screen " & activeScreen

          'Note : Point(x,y) still referes to parent window
           Draw String (40, 0), "Color = " & Point(cross._x, cross._y, backGroundImage(0))

            Draw String (139, 0), "main ScreenPtrColor = " & _
                     Point(cross._x, cross._y, mainScrPtr)
            Draw String (139, 10), "current ScrPtrColor = " & _
                     Point(cross._x, cross._y, ScreenPtr())
          Draw String (139, 20), "(naive access)"

          Draw String (349, 00), "user1 ScreenPtrColor = " & UserAccessToScreenPtr1()
           Draw String (349, 10), "user2 ScreenPtrColor = " & UserAccessToScreenPtr2()
           Draw String (349, 20), "(byte array access)"

   View Screen

End Sub 'ViewReport()
''---------------------------------------------------------()
Function MoveCross(ByVal Movdir As _MOVEDIRECTION = 0) As Integer
    GetGraphicsParameter()
   While InKey<>"" : Wend
   ScreenLock

   Select Case Movdir
      Case _MOVEDIRECTION._up
          DrawBackGround(resultImage)
          cross._y -= 1
          cross.DrawMethod()
         If cross._y - 1 < 0 Then cross._y += 1
      Case _MOVEDIRECTION._fastUp
          DrawBackGround(resultImage)
          cross._y -= 2
          cross.DrawMethod()
         If cross._y - 1 < 0 Then cross._y += 2
      Case _MOVEDIRECTION._down
          DrawBackGround(resultImage)
          cross._y += 1
          cross.DrawMethod()
          If cross._y > 0.89*h  Then cross._y -= 2
           cross.DrawMethod()
      Case _MOVEDIRECTION._fastDown
          DrawBackGround(resultImage)
          cross._y += 2
          cross.DrawMethod()
          If cross._y > 0.89*h  Then cross._y -= 4
           cross.DrawMethod()
      Case _MOVEDIRECTION._left
          DrawBackGround(resultImage)
          cross._x -= 1
          cross.DrawMethod()
           If cross._x - 1 < 0 Then cross._x += 1
      Case _MOVEDIRECTION._fastLeft
          DrawBackGround(resultImage)
          cross._x -= 2
          cross.DrawMethod()
           If cross._x - 1 < 0 Then cross._x += 2
      Case _MOVEDIRECTION._right
          DrawBackGround(resultImage)
          cross._x += 1
          cross.DrawMethod()
           If cross._x > w  Then cross._x -= 2
          cross.DrawMethod()
      Case _MOVEDIRECTION._fastRight
          DrawBackGround(resultImage)
          cross._x += 2
          cross.DrawMethod()
           If cross._x > w  Then cross._x -= 4
          cross.DrawMethod()
      Case Else
          DrawBackGround(resultImage)
          cross.DrawMethod()
   End Select 'Movdir

   Sleep 5

    processingCursorImage = ImageCreate(5, 2*cross._sweeperLength+1, , d)
   
   For s As Integer = -cross._sweeperLength To cross._sweeperLength
    PSet processedImage, (cross._x, cross._y+s), Point(cross._x, cross._y+s, mainScrPtr)
    PSet userProcessedImage(1), (cross._x, cross._y+s), UserAccessToScreenPtr1()
    PSet userProcessedImage(2), (cross._x, cross._y+s), UserAccessToScreenPtr2()
   Next s
   
   If cross._x<w-5 And _
      cross._y-cross._sweeperLength > 0 And _
      cross._y+cross._sweeperLength < h Then
       Get    processedImage, _
              (cross._x+1, cross._y-cross._sweeperLength+1)- _
             (cross._x-1, cross._y+cross._sweeperLength-1), _
            processingCursorImage
   EndIf
   
    Put (cross._x-2, cross._y-cross._sweeperLength), processingCursorImage, Xor

    ViewReport()

    cross.DrawMethod(Point(cross._x, cross._y, backGroundImage(0)))

   ScreenUnLock
   Return -1
End Function 'INT := MoveCross(_MOVEDIRECTION [=0])
''---------------------------------------------------------()
Function UserAccessToScreenPtr1() As ULong
   Dim As UByte Ptr ubyteScrPtr
    ubyteScrPtr = CPtr (UByte Ptr, mainScrPtr)
   
   Return ubyteScrPtr[cross._x\pitch*cross._y+cross._y]
End Function 'ULONG := UserAccessToScreenPtr1()
Function UserAccessToScreenPtr2() As ULong
   Dim As UByte Ptr ubyteScrPtr
    ubyteScrPtr = CPtr (UByte Ptr, mainScrPtr)
   
   Return ubyteScrPtr[cross._x\pitch*cross._y+cross._y]
End Function 'ULONG := UserAccessToScreenPtr2()
''---------------------------------------------------------()


Return to “General”

Who is online

Users browsing this forum: No registered users and 6 guests