1
votes

I have a list of integers, obtained through C ++ code and which representing different D3DCOLORVALUE ambient, etc...

What is the correct method to obtain the same colors, from this numbers, in Delphi?.

For example, using a program in C ++ (Visual Studio 2012), by calling a library routine in C ++ (separate dll file) I can obtain the following values:

-1.44852785e-016 = 2770796799 (represent the color)
 1.57844226e+11  = 1376977151 (represent the color)
-1.98938735e+034 = 4168431103 (represent the color)
 3.39617733e+038 = 4294967295 (represent the color)

@Rudy Velthuis, The original code is: (some values contained in the array are those shown above)

int32_t index = ifcObject->indicesForFaces[0];

uint32_t    ambient  = ((int32_t*) vertices)[index * (vertexElementSize / sizeof(float)) + 6],
            diffuse  = ((int32_t*) vertices)[index * (vertexElementSize / sizeof(float)) + 7],
            emissive = ((int32_t*) vertices)[index * (vertexElementSize / sizeof(float)) + 8],
            specular = ((int32_t*) vertices)[index * (vertexElementSize / sizeof(float)) + 9];

Then in Delphi XE6 using

PInteger (@ColorsArray [index * sizeOfVertices + 6])^

I get the same values but, in delphi the colors are black or null. Sometimes negative numbers are obtained, it is understood that in C ++ it is possible to represent a color with a negative value but in delphi does not work.

How can I convert a color value, obtained in D3DCOLORVALUE format, to a Delphi's TColor?

That the values are used to obtain the colors of objects in D3DMATERIAL9, D3DCOLORVALUE Ambient (Ambient color RGB)

FLOAT r;
FLOAT g;
FLOAT b;
FLOAT a;

This function make the color:

void    SetColor(
                D3DCOLORVALUE   * iColor,
                uint32_t        color
            )
{
    iColor->r = (float) (color & ((unsigned int) 255 * 256 * 256 * 256)) / (256 * 256 * 256);
    iColor->r /= 255.f;

    iColor->g = (float) (color & (255 * 256 * 256)) / (256 * 256);
    iColor->g /= 255.f;

    iColor->b = (float) (color & (255 * 256)) / 256;
    iColor->b /= 255.f;

    iColor->a = (float) (color & (255));
    iColor->a /= 255.f;
}

But in Delphi it does not work, the color obtained is wrong.

Comparison of colors with the @Dsm solution:

Left: Color obtained Right: Desired color

enter image description here enter image description here

enter image description here enter image description here

I have made a simple example to illustrate the differences:

enter image description here

The first color corresponds to the foot of the column and the second color corresponds to the column. The figure with the platform is the example with the library viewer, with the correct colors for that version and the figure on the right is an image of the watch in Visual Studio 2012 to show that the content of the array is the same and the value obtained with the cast is also the same but, when converting these numbers to colors they do not give the same result.

1
C++ standard library doesn't contain a single thing related to graphics, so it has no notion of color. What library did you use to get the values?HolyBlackCat
Casting a floating point value to a int32_t * (IOW, to a pointer!) is pretty suspicious. Who on earth wrote that code?Rudy Velthuis
From Lights and Materials (Direct3D 9) : Ambient light color takes the form of an RGBA value, where each component is an integer value from 0 to 255. This is unlike most color values in Direct3D.LU RD
If that was your original code, why didn't you post that instead of the weird and probably wrong cast to int32*? The original code casts a pointer to, well, a pointer, assuming that vertices is an array, and not a float to a pointer.Rudy Velthuis
@LURD: those are the named colours. But any combination of R, G and B is possible.Rudy Velthuis

1 Answers

2
votes

This looks like the original C++ extracts the colour knowing intimately the internal structure of an array of records. In your code you should not use (int32_t*) because that creates a pointer to a constant, and you just want to cast the float to a uint_32_t, so I think what you want to satisfy your test code is just

ambient := uint32_t(-1.44852785e-016);
diffuse := uint32_t(1.57844226e+11);
etc;

That doesn't compile in Delphi (invalid typecast), so instead you need to do something like

var
  p : pointer;
  iFloat : single;
  iColour : TColor;
begin
  iFloat := 1.57844226e+11;
  p := @(iFloat);
  iColour := TColor(p^);
  diffuse := iColour;

end;

which gives a red colour.

Note that all your colours appear similar because you are taking the start of several similar addresses.

Expressed as a function this might become

function FloatToColor( const pVal : single ) : TColor;
var
  p : pointer;
  iFloat : single;
begin
  iFloat := 1.57844226e+11;
  p := @(iFloat);
  Result := TColor(p^);
end;

Edit

Based on the fact that $FF appears in the wrong place, it occurred to me that these values might be CMYK format. In tests I found that it was a modified CMYK format - more a YMCK format, if you will, so to get the correct colours I had to reverse the roles of red and blue.

There is no true conversion from CMYK to RGB, but the following is approximate.

function CMYKtoRGB( const pValue : TColor) : TColor;
var
  c,m,y,k,r,g,b : byte;
begin
  c := GetCValue( pValue );
  m := GetMValue( pValue );
  y := GetYValue( pValue );
  k := GetKValue( pValue );

  //r := $FF xor c;
  r := $FF - c;
  b := $FF - y;
  g := $FF - m;
  if k <> $FF then
  begin
    k := $FF - k;
    r := r * k;
    g := g * k;
    b := b * k;
  end;
  Result := RGB( b, g, r );
end;

function FloatToColor( const pVal : single ) : TColor;
var
  p : pointer;
  iFloat : single;
begin
  iFloat := pVal;
  p := @(iFloat);
  Result := CMYKtoRGB(TColor(p^));
end;

Note that I use RGB( b, g, r) rather than the expected RGB( r, g, b) to account for the reversed colour order.