[fpc-pascal] Float packing

Karoly Balogh (Charlie/SGR) charlie at scenergy.dfmk.hu
Mon Nov 6 13:36:31 CET 2017


On Mon, 6 Nov 2017, Ryan Joseph wrote:

> I actually got the problem wrong and still haven’t figured it out so
> here’s another go.
> I have a number which I need to encode as an RGB value each component
> being 4 bytes (12 bytes total) so I need to extract each digit as a byte
> (and then each byte back to a digit). It’s basic low level computer
> science stuff I never learned well. The old version of GLSL I’m using
> (1.2) doesn’t support bit shifting (which I think I could use) so I need
> to do this using arithmetic.
> On Google I found a good method to have the compiler convert a word to
> an array of bytes using variant records such as:

I'm not particularly fond of this method, because this is not endian safe.
It won't work on bigendian CPUs (which are marginal, and a thing of the
past, sort of, but their heritage is still with us thanks to the network
byte order, which is bigendian, and some languages like Java, which use
bigendian internally).

> type
> 	TBytes = record
> 		case byte of
> 			0: (i : word);
> 			1: (u : array[0..3] of byte);
> 			2: (r, g, b, a: byte);
> 		end;
> so for the number 1234:
> var
>  c: TBytes;
> FillChar(c, sizeof(c), 0);
> c.i := 300;
> writeln(c.r, ' ', c.g, ' ', c.b, ' ', c.a);
> I  get: 44 1 0 0

A Word in Pascal is always two bytes. So I don't understand what you want

> How do I convert this back to 300 using arithmetic? I see you can add
> 255 to first value plus the next value (1) to get 300 but what’s the
> correct method to use I could make into a function?

You're seeing the bytes of a two byte "word" value in little endian, which
is the endianness of x86 and ARM CPUs by default. If you need to process
the data byte by byte, you need to swap the order of bytes around.

In your example:

writeln((c.g shl 8) + c.r);

should print "300";

If you change "i" to dword, For a 32bit value this would be:

writeln((c.a shl 24) + (c.b shl 16) + (c.g shl 8) + c.a;

But you cannot apply this method to floats, such byte-magic only works on
integers (well, you need to also swap around bytes of a float if you
process them as bytes, but that's beside the point here). You also cannot
extract the 10-base digits of an integer value like this (unless we're
talking about BCD numbers, which is again, an entirely different topic).

I still not entirely understand what you want to achieve, but to extract
the digits of a fractional number, you could simply do the following:

  a: single;

  // integer part
  writeln(trunc(a) mod 10000 div 1000);
  writeln(trunc(a) mod 1000 div 100);
  writeln(trunc(a) mod 100 div 10);
  writeln(trunc(a) mod 10 div 1);
  // fractional part
  writeln(trunc(a*10) mod 10);
  writeln(trunc(a*100) mod 10);
  writeln(trunc(a*1000) mod 10);
  writeln(trunc(a*10000) mod 10);

But anyway, I guess this is not so useful for you any more. So if you can
tell what *actually* you want to do, like convert a vec4 of GLSL float to
Pascal, or convert a 32bit RGBA value to a GLSL vec4, maybe that would be
more easy to help you with.

Also, are you trying to generate GLSL source with this, or you're
processing binary data returned by your shader code in a buffer?


More information about the fpc-pascal mailing list