Can ScreenPtr stand for an image buffer?

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

Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Can ScreenPtr stand for an image buffer?

Post by counting_pine »

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: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Can ScreenPtr stand for an image buffer?

Post by MrSwiss »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Can ScreenPtr stand for an image buffer?

Post by counting_pine »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Post by grindstone »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

@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: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Post by grindstone »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Post by grindstone »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Can ScreenPtr stand for an image buffer?

Post by grindstone »

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: 2958
Joined: Jun 02, 2015 16:24

Re: Can ScreenPtr stand for an image buffer?

Post by Tourist Trap »

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()
''---------------------------------------------------------()

Post Reply