Continuing issue using pointers etc...
Re: Continuing issue using pointers etc...
updated again. I tend to update frequently on new posts.
MaskColor is the transparent color
MaskColor is the transparent color
Re: Continuing issue using pointers etc...
ok, after looking over the code, here is my understanding:
Taking a raw image, and using the mask color, encode all the non-mask pixels into runs and put the runs and run info (length of run, start pos of run) into RLI
When blitting, first determine screen clipping, then blit the runs, pixel by pixel, using the clipping.
So this method is a more robust (clipping and variable mask color) blit than mine, uses the same idea of ignoring the transparency, but also RLE the image data. It doesn't appear to blend using the alpha to the background though, but I have trouble deciphering your actual blit statement:this is very sophisticated pointer usage (for me) and I get the concept, but could not write the code! could you explain the use of the "->" operator in relation to this code for me?
Nicely done! Have you done any speed tests compared to various PUT statements? Since it blits pixel by pixel it will end up being comparatively slow (I think) compared to straight PUT(pset), but might fare well against PUT(trans). It should be faster than PUT(alpha) because it doesn't blend.
Your above blit section could be faster by changing it to using memcpy... but only for the runs that are longer than a few pixels long.
Very sweet code, Mr. Dafhi! If it is OK with you, I think i will use it as a basis for my attempt at blitting since it already incorporates clipping (which is nice). With very little modification, I think I can convert it to utilizing z-levels and alpha blending since it is already blitting on a pixel by pixel method. But, it will force me to understand pointer stuff ALOT better than I currently do... I gotta stretch my brain some... I will have to change the above actual blit code to pre-calcing the y math ("DestLeft+ yDst*des->pitchBy" and "ySrcS*pitchBy" since these computations result in the same thing for every pixel on a scanline... so drag the speed down when calced on a per pixel basis - I can't stand that kind of speed loss... lol!
Taking a raw image, and using the mask color, encode all the non-mask pixels into runs and put the runs and run info (length of run, start pos of run) into RLI
When blitting, first determine screen clipping, then blit the runs, pixel by pixel, using the clipping.
So this method is a more robust (clipping and variable mask color) blit than mine, uses the same idea of ignoring the transparency, but also RLE the image data. It doesn't appear to blend using the alpha to the background though, but I have trouble deciphering your actual blit statement:
Code: Select all
For xSrcS = xSrcS To xSrcE
des->p32[xSrcS + DestLeft+ yDst*des->pitchBy] = p32[xSrcS + ySrcS*pitchBy]
Next
Nicely done! Have you done any speed tests compared to various PUT statements? Since it blits pixel by pixel it will end up being comparatively slow (I think) compared to straight PUT(pset), but might fare well against PUT(trans). It should be faster than PUT(alpha) because it doesn't blend.
Your above blit section could be faster by changing it to using memcpy... but only for the runs that are longer than a few pixels long.
Very sweet code, Mr. Dafhi! If it is OK with you, I think i will use it as a basis for my attempt at blitting since it already incorporates clipping (which is nice). With very little modification, I think I can convert it to utilizing z-levels and alpha blending since it is already blitting on a pixel by pixel method. But, it will force me to understand pointer stuff ALOT better than I currently do... I gotta stretch my brain some... I will have to change the above actual blit code to pre-calcing the y math ("DestLeft+ yDst*des->pitchBy" and "ySrcS*pitchBy" since these computations result in the same thing for every pixel on a scanline... so drag the speed down when calced on a per pixel basis - I can't stand that kind of speed loss... lol!
Re: Continuing issue using pointers etc...
my own blit routine which just is supposed to blit an image (which has been transparency skip encoded) is not working, once again due to my lack of understanding of pointer math etc:
In regards to a 'final' version, since the encoding of an image is not speed dependent, I am thinking it might be worth it to have the encoder test RLE pixel data vs. raw pixel data blit times (or, perhaps, estimated blit times) to determine which method is faster on a per image basis. This doubles the code in the encoding section, and will be twice as slow at encoding, but the actual blitting will end up using the fastest method depending upon the image pixel layout for each image.
Actually, thinking about it more, the RLE encoded image data version will ALWAYS be slower for the PSET version (because of memcpy being so fast for non-RLE data), but potentially faster only for the ALPHA blend version (since memcopy can't be used for a per pixel method).
Code: Select all
'-------------------------------------------------------------------------------
sub SpeedSpriteBlit_Ver1(buffer as ulong ptr, dx as ulong, dy as ulong)
' This Blit decodes and blits a SpeedSprite_Ver1 buffer
' assumes first 'pixel' is transparent encoded....
' which it will be the case AS LONG AS the top-left pixel of image is transparent
'
Union colour
As ULong clr
Type
As UByte b ' these are in reverse order BGRA instead of ARGB... is that correct? or should it be RGBA / ABGR ? I am so confused!
As UByte g
As UByte r
AS UByte a
End Type
End Union
dim as colour TempColor, tranny
dim as ulong buf_index = 1
dim as ulong ptr scr_row
dim as ulong numBytes = 0
dim as ulong imgpitch4 = ImagePitch\4, scrpitch4 = SCR_pitch\4
dim as any ptr drowy = SCR_address + dx * 4
'initialize - get first tranny
tranny.clr = buffer[buf_index] 'first byte of the buffer 'should' be a transparent encoded pixel R,G,B = x,y,RL
do
' decode tranny... R = x pos, G = y pos , B = pixels in strip (NOT bytes!), A = 0
dim as ubyte xpos = tranny.r, ypos = tranny.g, strippixels = tranny.b
scr_row = SCR_address + (tranny.g * SCR_pitch) + (tranny.r * 4)
numBytes = tranny.b * 4
buf_index += 1
memcpy (scr_row, (buffer+buf_index), numBytes)
buf_index += numbytes '--- this is pixels in strip * 4...
tranny.clr = buffer[buf_index]
loop until tranny.clr = rgba(255,255,255,0)
end sub
Actually, thinking about it more, the RLE encoded image data version will ALWAYS be slower for the PSET version (because of memcpy being so fast for non-RLE data), but potentially faster only for the ALPHA blend version (since memcopy can't be used for a per pixel method).
Re: Continuing issue using pointers etc...
I forgot to mention, I really like your method of obtaining the image data and screen data... it is slick and handy!
Here is my entire 'Blit vs PUT comparison test' program that I have been using... it will crash on the last part where it tries to Blit using the above routine of mine. Still shows the times of the different PUT methods (pset, trans, alpha) and my raw basic blit... I am blitting the image 100 times per pixel movement to simulate 100 sprite blits per frame[between the screenlock/unlocks] (boromir mentioned 100 sprites per frame I think, so that was where the 100 came from...)
I find it interesting that my basic blit is about 10% slower than PUT(pset) on larger sprites, but can be many times faster on smaller ones... don't exactly know why...
once again, forgive my 'sloppy' unstructured coding style (especially compared to your sophisticated style!)...
Here is my entire 'Blit vs PUT comparison test' program that I have been using... it will crash on the last part where it tries to Blit using the above routine of mine. Still shows the times of the different PUT methods (pset, trans, alpha) and my raw basic blit... I am blitting the image 100 times per pixel movement to simulate 100 sprite blits per frame[between the screenlock/unlocks] (boromir mentioned 100 sprites per frame I think, so that was where the 100 came from...)
I find it interesting that my basic blit is about 10% slower than PUT(pset) on larger sprites, but can be many times faster on smaller ones... don't exactly know why...
once again, forgive my 'sloppy' unstructured coding style (especially compared to your sophisticated style!)...
Code: Select all
Const NULL As Any Ptr = 0
#define RGBA_R( c ) ( CUInt( c ) Shr 16 And 255 )
#define RGBA_G( c ) ( CUInt( c ) Shr 8 And 255 )
#define RGBA_B( c ) ( CUInt( c ) And 255 )
#define RGBA_A( c ) ( CUInt( c ) Shr 24 )
#pragma once
#include once "crt/stddef.bi"
extern "C"
declare function memcpy (byval as any ptr, byval as const any ptr, byval as size_t) as any ptr
end extern
declare sub BasicBlit(img as any ptr, dx as ulong, dy as ulong)
declare sub EncodeSpeedSprite_Ver1(img as any ptr, buffer as ulong ptr)
declare sub SpeedSpriteBlit_Ver1(buffer as ulong ptr, dx as ulong, dy as ulong)
Function bmp_load( ByRef filename As Const String ) As Any Ptr
Dim As ulong filenum, bmpwidth, bmpheight
Dim As Any Ptr img
'' open BMP file
filenum = FreeFile()
If Open( filename For Binary Access Read As #filenum ) <> 0 Then Return NULL
'' retrieve BMP dimensions
Get #filenum, 19, bmpwidth
Get #filenum, 23, bmpheight
Close #filenum
'' create image with BMP dimensions
img = ImageCreate( bmpwidth, Abs(bmpheight) )
If img = NULL Then Return NULL
'' load BMP file into image buffer
If BLoad( filename, img ) <> 0 Then ImageDestroy( img ): Return NULL
Return img
End Function
ScreenRes 640, 480, 32
color RGB(0,0,0), rgb(255,255,255)
dim shared as ulong SCR_pitch
dim shared as any ptr SCR_address
Dim As Any Ptr img
screeninfo ,,,, SCR_pitch
SCR_address = screenptr
cls
' load the image
dim as string fname = "Test 5-64x31 flat tile.bmpx"
img = bmp_load( fname )
If img = NULL Then
Print "Image failed to load"
sleep
ImageDestroy( img )
end
end if
print
print " Image Loaded: ";fname
' Analyze Image
print
dim shared as integer ImageWidth, ImageHeight, ImageBytesPerPixel, ImagePitch
dim shared as any ptr ImageAddress
If 0 <> ImageInfo( img, ImageWidth, ImageHeight, ImageBytesPerPixel, ImagePitch, ImageAddress ) Then
Print "unable to retrieve image information."
Sleep
End
End If
print " Width (";ImageWidth;")"
print " Height (";ImageHeight;")"
print " Bytes / Pixel (";ImageBytesPerPixel;")"
print " Pitch (";ImagePitch;")"
print " Num of Pixels (";ImageWidth*ImageHeight;")"
print " raw size of image is ";ImageWidth*ImageHeight*ImageBytesPerPixel
print
print " Press a key to begin test..."
put (10,110),img,pset
sleep
' Test 1 - Straight PUT with pset mode (fastest Freebasic blit command) - Transparency Ignored!
dim as double t1 = timer
for x as ulong = 10 to 409 ' move 400 pixel positions
screenlock
for tst as ulong = 1 to 100 ' blit the image 100 times per 'frame' to simulate 100 sprites on screen at once
put (x,110),img,pset
next tst
screenunlock
'sleep 1
next x
locate 2,40 : print "Test Results:"
locate 3,40 : print using "PUT(pset) = ##.###"; timer - t1
sleep
line (10,110)-(409+ImageWidth,110+ImageHeight), rgb(255,255,255),BF 'erase sprite area
t1 = timer
for x as ulong = 10 to 409 ' move 400 pixel positions
screenlock
for tst as ulong = 1 to 100 ' blit the image 100 times per 'frame' to simulate 100 sprites on screen at once
put (x,110),img,trans
next tst
screenunlock
'sleep 1
next x
locate 4,40 : print using "PUT(trans) = ##.###"; timer - t1
sleep
line (10,110)-(409+ImageWidth,110+ImageHeight), rgb(255,255,255),BF 'erase sprite area
t1 = timer
for x as ulong = 10 to 409 ' move 400 pixel positions
screenlock
for tst as ulong = 1 to 100 ' blit the image 100 times per 'frame' to simulate 100 sprites on screen at once
put (x,110),img,alpha
next tst
screenunlock
'sleep 1
next x
locate 5,40 : print using "PUT(alpha) = ##.###"; timer - t1
sleep
line (10,110)-(409+ImageWidth,110+ImageHeight), rgb(255,255,255),BF 'erase sprite area
t1 = timer
for x as ulong = 10 to 409 ' move 400 pixel positions
screenlock
for tst as ulong = 1 to 100 ' blit the image 100 times per 'frame' to simulate 100 sprites on screen at once
BasicBlit(img,x,110)
next tst
screenunlock
'sleep 1
next x
BasicBlit(img,50,310)
locate 6,40 : print using "Basic Blit(pset) = ##.###"; timer - t1
sleep
' Allocate and initialize space for size of image color elements.
Dim SS1_buffer As ulong Ptr = CAllocate(ImageWidth*ImageHeight,4)
EncodeSpeedSprite_Ver1(img, SS1_buffer)
line (10,110)-(409+ImageWidth,110+ImageHeight), rgb(255,255,255),BF 'erase sprite area
t1 = timer
for x as ulong = 10 to 409 ' move 400 pixel positions
screenlock
for tst as ulong = 1 to 100 ' blit the image 100 times per 'frame' to simulate 100 sprites on screen at once
SpeedSpriteBlit_Ver1(SS1_buffer, x, 110)
next tst
screenunlock
'sleep 1
next x
SpeedSpriteBlit_Ver1(SS1_buffer, 90, 310)
locate 7,40 : print using "Speed Blit(trans) = ##.###"; timer - t1
sleep
'
' print out SS1_buffer
'
dim as ulong buf_index = 0,tempcolor = 0
do
buf_index += 1
tempcolor = SS1_buffer[buf_index]
print using "#####: R### G### B### A###";buf_index;rgba_r(tempcolor);rgba_g(tempcolor);rgba_b(tempcolor);rgba_a(tempcolor)
loop until SS1_buffer[buf_index] = rgba(255,255,255,0)
print buf_index
sleep
end
'-------------------------------------------------------------------------------
'-------------------------------------------------------SUBROUTINES-------------
'-------------------------------------------------------------------------------
sub BasicBlit(img as any ptr, dx as ulong, dy as ulong)
' BasicBlit is just a pset
'
dim as ulong ptr image_end, img_row, scr_row
dim as ulong numBytes = ImageWidth * 4
img_row = ImageAddress
scr_row = SCR_address + (dy * SCR_pitch) + (dx * 4)
image_end = ImageAddress + ((ImageHeight-1) * ImagePitch)
dim as ulong imgpitch4 = ImagePitch\4, scrpitch4 = SCR_pitch\4
do
memcpy (scr_row, img_row, numBytes)
img_row = img_row + imgpitch4
scr_row = scr_row + scrpitch4
loop until img_row > image_end
end sub
'-------------------------------------------------------------------------------
sub EncodeSpeedSprite_Ver1(img as any ptr, buffer as ulong ptr)
' This version just iterates through the image, copying over the RGBA values to the buffer,
' EXCEPT if the value has an Alpha of '0' (totally transparent) in which case it finds the
' next non-transparent pixel and saves this location in the R & G (x & y respectively) of
' the copied over transparent pixel... basically RLE's only the transparent pixels...
'
' MUST CAllocate enough space into buffer before calling!
'
dim as ulong buf_index = 0, tranny = 0, reggy = 0, last_tranny = 0
dim as ulong TempColor
For y As ulong = 0 To ImageHeight - 1
Dim row As ulong Ptr = ImageAddress + y * ImagePitch
For x As ulong = 0 To ImageWidth - 1
TempColor = row[x]
if RGBA_A(TempColor) = 0 then
' if transparent then...count it
tranny += 1
if tranny = 1 then ' .. if first tranny then stop counting reggy and save it!
' --- hopefully it is grabbing 4 bytes (32 bit) value here...???
TempColor = buffer[last_tranny]
' this next line assumes that reggy is less than 255 - all the pixels on same line...
buffer[last_tranny] = rgba(RGBA_R(TempColor),RGBA_G(TempColor),reggy,0)
reggy = 0
end if
else
' if NOT transparent, then....
if tranny > 0 then ' if currently counting transparent pixels...
' then ran into a regular pixel... so make the Transparent coded pixel...
buf_index += 1
last_tranny = buf_index
buffer[buf_index] = rgba(x,y,0,0)
tranny = 0
end if
' just a regular pixel color, so save it into buffer
buf_index += 1
reggy += 1
buffer[buf_index] = TempColor
end if
next x
if reggy > 0 then 'was still accumulating regular pixels when hit end of line.
' so make the last trans pixel say only reggy amount of pixels and make new trans pix for next line...
TempColor = buffer[last_tranny] '--- hopefully it is grabbing 4 bytes (32 bit) value here...???
' this next line assumes that reggy is less than 255 - all the pixels on same line...
buffer[last_tranny] = rgba(RGBA_R(TempColor),RGBA_G(TempColor),reggy,0)
reggy = 0
dim as ulong hold_y = y+1
if hold_y < ImageHeight then
buf_index += 1
buffer[buf_index] = rgba(0,y+1,0,0) ' new trans pixel pointing to beginning of next line
last_tranny = buf_index
end if
end if
next y
' put in 'end of sprite' delimiter...
buf_index += 1
buffer[buf_index] = rgba(255,255,255,0) ' no other color in buffer will be transparent white...
end sub
'-------------------------------------------------------------------------------
sub SpeedSpriteBlit_Ver1(buffer as ulong ptr, dx as ulong, dy as ulong)
' This Blit decodes and blits a SpeedSprite_Ver1 buffer
' assumes first 'pixel' is transparent encoded....
' which it will be the case AS LONG AS the top-left pixel of image is transparent
'
Union Colour
As ULong clr
' these are in reverse order BGRA instead of ARGB...
' is that correct? or should it be RGBA / ABGR ? I am so confused!
Type
As UByte b
As UByte g
As UByte r
AS UByte a
End Type
End Union
dim as colour TempColor, tranny
dim as ulong buf_index = 1
dim as ulong ptr scr_row
dim as ulong numBytes = 0
dim as ulong imgpitch4 = ImagePitch\4, scrpitch4 = SCR_pitch\4
dim as any ptr drowy = SCR_address + dx * 4
'initialize - get first tranny
tranny.clr = buffer[buf_index]
do
' decode tranny... R = x pos, G = y pos , B = pixels in strip (NOT bytes!), A = 0
dim as ubyte xpos = tranny.r, ypos = tranny.g, strippixels = tranny.b
scr_row = SCR_address + (tranny.g * SCR_pitch) + (tranny.r * 4)
numBytes = tranny.b * 4
buf_index += 1
memcpy (scr_row, (buffer+buf_index), numBytes)
buf_index += numbytes '--- this is pixels in strip * 4...
tranny.clr = buffer[buf_index]
loop until tranny.clr = rgba(255,255,255,0)
end sub
Re: Continuing issue using pointers etc...
I coded the thing around 2006. I hardly understand it now but from looking at a few things and comparing with recent ideas, I've merged the best of 2 eras. Doubt I attempt a new one anytime soon though :D
I've updated the post with a few optimizations. Yes of course you're welcome to use it
With regard to why your blit is faster on smaller bitmaps, your blit probably has a small overhead
pointer info - (updated: thanks fxm)
I've updated the post with a few optimizations. Yes of course you're welcome to use it
With regard to why your blit is faster on smaller bitmaps, your blit probably has a small overhead
pointer info - (updated: thanks fxm)
Code: Select all
' 4 examples of pointer->member access
type mytype
as single x=rnd,y=rnd
end type
dim as mytype a(1)
dim as mytype ptr p = @a(0)
? "val", "address"
? " ---------", "--------"
'1
? p->x, @p->x
'2
? (*p).x, @(*p).x
'3
with *p
? .x, @.x
end with
'4 - next array element
with p[1]
? .x, @.x
end with
sleep
Last edited by dafhi on Jun 13, 2017 19:12, edited 1 time in total.
Re: Continuing issue using pointers etc...
will look at your optimizations! thank you!dafhi wrote:I've updated the post with a few optimizations. Yes of course you're welcome to use it
that makes perfect sense - I don't have boundary checking/clipping going on and that in itself is a few clock cycles... I am quite sure this is the culprit.With regard to why your blit is faster on smaller bitmaps, your blit probably has a small overhead
yay! will study and play... I need to learn this stuff because I think it lends itself to much faster algos... and I like speed...pointer info
Re: Continuing issue using pointers etc...
Nope, not necessarily speed, more flexibility.leopardpm wrote:I think it lends itself to much faster algos... and I like speed...
An example in ASM:
Code: Select all
ASM
mov rax, qword ptr [value] ' direct variable access
' now with ptr access ... same operation
mov rax, qword ptr [value] ' get address, then, get value
mov rax, [rax] ' ptr needs 2 x mov
End ASM
Re: Continuing issue using pointers etc...
hmmm, interesting... so are you saying that (even though my current blit routine is broken...) instead of using pointers in my routine, it could be faster by doing it another way? The whole pointer business drives me crazy, I never know if I am supposed to be 'dereferencing' a pointer first or what... if I can avoid using them AND make just as faster or faster code, then I will surely do that!MrSwiss wrote:Nope, not necessarily speed, more flexibility.leopardpm wrote:I think it lends itself to much faster algos... and I like speed...
An example in ASM:Code: Select all
ASM mov rax, qword ptr [value] ' direct variable access ' now with ptr access ... same operation mov rax, qword ptr [value] ' get address, then, get value mov rax, [rax] ' ptr needs 2 x mov End ASM
Re: Continuing issue using pointers etc...
? *(p).x, @*(p).xdafhi wrote:pointer infoCode: Select all
' 4 examples of pointer->member access type mytype as single x=rnd,y=rnd end type dim as mytype a(1) dim as mytype ptr p = @a(0) ? "val", "address" ? " ---------", "--------" '1 ? p->x, @p->x '2 ? *(p).x, @*(p).x '3 with *p ? .x, @.x end with '4 - next array element with p[1] ? .x, @.x end with sleep
is not the correct syntax.
The good syntax is:
? (*p).x, @(*p).x
See the bug report:
#811 *(ptr).field should give an error
(Operator Precedence)
Re: Continuing issue using pointers etc...
Depends on your needs mainly, if you have a lot of allocate/deallocate stuff, ptr is maybe better.
Resizing is another such thing, because the MEM-Block, might be at a different location afterwards.
On more static defined allocations, arrays may be a advantage. (don't know any fixed rule)
Resizing is another such thing, because the MEM-Block, might be at a different location afterwards.
On more static defined allocations, arrays may be a advantage. (don't know any fixed rule)
Re: Continuing issue using pointers etc...
About:
Precedence rule between:
'operator ()' (procedure call)
and:
'operator *' (value of)
is not verified.
Simple example:
It seems that a similar parsing bug also exists for the pointers to procedure pointer:
Precedence rule between:
'operator ()' (procedure call)
and:
'operator *' (value of)
is not verified.
Simple example:
Code: Select all
Sub s (Byval i As Integer = 0)
End Sub
Dim As Sub (Byval As Integer = 0) ps = @s
Dim As Sub (Byval As Integer = 0) Ptr pps = @ps
ps(0) ' OK
(*pps)(0) ' OK
' *pps(0) ' NOK
' *(pps(0)) ' NOK
*(pps)(0) ' should be NOK <=== parsing bug ?
(*pps)() ' OK
*pps() ' should be NOK <=== parsing bug ?
' *(pps()) ' NOK
*(pps)() ' should be NOK <=== parsing bug ?
Re: Continuing issue using pointers etc...
@Jeff,
I have not been able to test yet (due to lack of recent build) one of your last commits "fbc: fix sf.net # 811 *(ptr).field should give an error", but does it also take into account the post just above ("... similar parsing bug also exists for the pointers to procedure pointer") ?
I have not been able to test yet (due to lack of recent build) one of your last commits "fbc: fix sf.net # 811 *(ptr).field should give an error", but does it also take into account the post just above ("... similar parsing bug also exists for the pointers to procedure pointer") ?
Re: Continuing issue using pointers etc...
@fxm
Sorry I forgot to upload lastest version. Done soon.
Done. https://users.freebasic-portal.de/sarg/ ... astest.zip
Sorry I forgot to upload lastest version. Done soon.
Done. https://users.freebasic-portal.de/sarg/ ... astest.zip
Re: Continuing issue using pointers etc...
fxm wrote: ↑Dec 07, 2022 6:25 @Jeff,
I have not been able to test yet (due to lack of recent build) one of your last commits "fbc: fix sf.net # 811 *(ptr).field should give an error", but does it also take into account the post just above ("... similar parsing bug also exists for the pointers to procedure pointer") ?
I just tested it.
It's OK.
(Thanks SARG)
Re: Continuing issue using pointers etc...
Attention users:
The old '#811 *(ptr).field should give an error' bug is now fixed for fbc version 1.10.0 (and later).
I noticed that some used this wrong expression '*(ptr).field' in their code.
They will need to replace it with the valid expression: '(*ptr).field'
Same problem for a pointeur to procedure-pointer 'Ptr_to_ProcPtr'.
Use:
'(*Ptr_to_ProcPtr)()' instead of '*Ptr_to_ProcPtr()'
'(*Ptr_to_ProcPtr)(...)' instead of '*(Ptr_to_ProcPtr)(...)'
(this post because who reads the 'changelog.txt' file besides me ?)
The old '#811 *(ptr).field should give an error' bug is now fixed for fbc version 1.10.0 (and later).
I noticed that some used this wrong expression '*(ptr).field' in their code.
They will need to replace it with the valid expression: '(*ptr).field'
Same problem for a pointeur to procedure-pointer 'Ptr_to_ProcPtr'.
Use:
'(*Ptr_to_ProcPtr)()' instead of '*Ptr_to_ProcPtr()'
'(*Ptr_to_ProcPtr)(...)' instead of '*(Ptr_to_ProcPtr)(...)'
(this post because who reads the 'changelog.txt' file besides me ?)