comp.lang.ada
 help / color / mirror / Atom feed
From: Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org>
Subject: Re: Help with low level Ada
Date: Thu, 17 Mar 2011 10:55:36 -0700
Date: 2011-03-17T10:55:36-07:00	[thread overview]
Message-ID: <iltid5$nc8$1@tornado.tornevall.net> (raw)
In-Reply-To: <21e55933-291b-46a9-8659-3edf83d963b4@u3g2000vbe.googlegroups.com>

On 03/17/2011 07:31 AM, Syntax Issues wrote:
> unsigned ColorNormalize (vec3_t rgb){
> 	unsigned	c;
> 	float		max;
> 	...
> 	((byte *)&c)[0] = rgb[0] * max;
> 	((byte *)&c)[1] = rgb[1] * max;
> 	((byte *)&c)[2] = rgb[2] * max;
> 	((byte *)&c)[3] = 255;
> 	return c;
> }
> function Normalize
> 	(Red_Green_Blue : in Vector_Color)
> 	return Integer_Color
> 	is
> 	Result  : Integer_Color := 0;
> 	Maximum : Float_4       := 0.0;
> 	begin
> 		...
> 		return
> 			-- ???!!??!?!? Byte(Red_Green_Blue(1) * Maximum) +
> 			-- ???!!??!?!? Byte(Red_Green_Blue(2) * Maximum) +
> 			-- ???!!??!?!? Byte(Red_Green_Blue(3) * Maximum);
> 	end Normalize;

First, I'd probably do something like

type Color_ID is (Red, Blue, Green);

subtype Natural_Float_4 is Float_4 range 0.0 .. Float_4'Last;

type Vector_Color is array (Color_ID) of Natural_Float_4;

so I can say Red_Green_Blue (Red). (I presume that the components of 
Vector_Color cannot be negative; better to make that clear in the code and 
enforced by the language.)

One approach to this is

type Byte is mod 2 ** 8;

type Color_Bytes is record
    Red    : Byte;
    Green  : Byte;
    Blue   : Byte;
    Unused : Byte;
end record;
for Color_Bytes use
    Red    at 0 range 0 .. 7;
    Green  at 1 range 0 .. 7;
    Blue   at 2 range 0 .. 7;
    Unused at 3 range 0 .. 7;
end record;
for Color_Bytes'Size use Integer_Color'Size;

You may need to change the representation clause to get the components in the 
right places.

function Convert is new Ada.Unchecked_Conversion
    (Source => Color_Bytes, Target => Integer_Color);

Result := Color_Bytes'(Red    => Byte (Red_Green_Blue (Red)    * Maximum),
                        Green  => Byte (Red_Green_Blue (Green)  * Maximum),
                        Blue   => Byte (Red_Green_Blue (Blue)   * Maximum),
                        Unused => Byte'Last);

return Convert (Result);

You missed out the assignment of 255 to the 4th byte.

Another way is to use an array of 4 Bytes that you unchecked convert to the 
result type.

Finally, if you use a modular type from package Interfaces you can shift the 
products into their correct positions and "or" them together. And you can always 
imitate that by multiplying by a power of 2 and adding them together:

Result := Integer_Color (Red_Green_Blue (Red)    * Maximum) * 2 **  0 +
           Integer_Color (Red_Green_Blue (Green)  * Maximum) * 2 **  8 +
           Integer_Color (Red_Green_Blue (Blue)   * Maximum) * 2 ** 16 +
           255 * 2 ** 24;

The compiler will often replace these by shifts.

> float AngleMod (float angle){
> 	return (360.0/65536) * ((int)(angle * (65536/360.0))&  65535);
> }
> function Mod_Angle
> 	(Angle : in Float_4)
> 	return Float_4
> 	is
> 	begin
> 		return (360.0 / 65536.0) * (Integer_4_Signed(Angle * (65536.0 /
> 360.0)) ---???!?!?!&  65535);
> 	end Mod_Angle;

Bitwise "and" is defined for all modular types. The only wrinkle is what happens 
if Angle is negative. If that's not allowed (see Natural_Float_4 above), then 
it's fairly easy:

type Integer_4_Unsigned is mod Integer_4_Signed'Size;

return (360.0 / 65536.0) *
        Float_4 (Integer_4_Unsigned (Angle * (65536.0 / 360.0) ) and 65535);

Otherwise, you need to do some unchecked converting between signed and modular 
types of the same size:

function Convert is new Ada.Unchecked_Conversion
    (Source => Integer_4_Signed, Target => Integer_4_Unsigned);

return (360.0 / 65536.0) *
        Float_4 (Convert (Integer_4_Signed (Angle * (65536.0 / 360.0) ) ) and
                 65535);

(I presume that Integer_4_Signed is 4 bytes from its name, so the result of 
"and"ing that with 65535 will always be non-negative. In that case, there's no 
need to convert back to signed before converting to Float_4.)

> int NearestPowerOfTwo (int number, qboolean roundDown){
> 	int n = 1;
> 	if (number<= 0)
> 		return 1;
> 	while (n<  number)
> 		n<<= 1;
> 	if (roundDown){
> 		if (n>  number)
> 			n>>= 1;
> 	}
> 	return n;
> }

Shift operations are defined for the modular types defined in package 
Interfaces. As mentioned above, the same effect can often be obtained with 
multiplication and division by powers of 2, and the compiler will often replace 
them with shifts:

while N < Number loop
    N := 2 * N;
end loop;

if Round_Down and N > Number then
    N := N / 2;
end if;

You could also use the Log function from Ada.Numerics.Generic_Elementary_Functions:

type Big is digits 15;

package Math is new Ada.Numerics.Generic_Elementary_Functions
    (Float_Type => Big);

N := 2 ** Integer (Math.Log (Big (Number), 2.0) );

if N < Number then
    N := 2 * N;
end if;

if Round_Down and N > Number then
    N := N / 2;
end if;

-- 
Jeff Carter
"We use a large, vibrating egg."
Annie Hall
44



  parent reply	other threads:[~2011-03-17 17:55 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-17 14:31 Help with low level Ada Syntax Issues
2011-03-17 17:46 ` Shark8
2011-03-17 17:59   ` Jeffrey Carter
2011-03-20  3:45     ` Shark8
2011-03-17 17:55 ` Jeffrey Carter [this message]
2011-03-17 19:30   ` Syntax Issues
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox