У меня есть список целых чисел, полученных с помощью кода C ++ и представляющих различные окружения D3DCOLORVALUE и т.д …
Какой правильный способ получить те же цвета из этих чисел в Delphi?
Например, используя программу на C ++ (Visual Studio 2012), вызвав библиотечную процедуру на C ++ (отдельный файл dll), я могу получить следующие значения:
-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, оригинальный код: (некоторые значения, содержащиеся в массиве, показаны выше)
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];
Тогда в Delphi XE6 используя
PInteger (@ColorsArray [index * sizeOfVertices + 6])^
Я получаю те же значения, но в Delphi цвета черный или ноль. Иногда получаются отрицательные числа, понятно, что в C ++ можно представить цвет с отрицательным значением, но в Delphi не работает.
Как я могу преобразовать значение цвета, полученное в формате D3DCOLORVALUE, в TColor Delphi?
Значения используются для получения цветов объектов в
D3DMATERIAL9, D3DCOLORVALUE Ambient (Ambient color RGB)
FLOAT r;
FLOAT g;
FLOAT b;
FLOAT a;
Эта функция делает цвет:
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;
}
Но в Delphi это не работает, полученный цвет неправильный.
Сравнение цветов с помощью решения @Dsm:
Слева: полученный цвет Справа: требуемый цвет
Я сделал простой пример, чтобы проиллюстрировать различия:
Первый цвет соответствует основанию столбца, а второй цвет соответствует столбцу. Рисунок с платформой — это пример со средством просмотра библиотеки с правильными цветами для этой версии, а рисунок справа — это изображение часов в Visual Studio 2012, показывающее, что содержимое массива одинаково, а значение полученное с использованием приведения также то же самое, но при преобразовании этих чисел в цвета они не дают одинакового результата.
Это похоже на то, что оригинальный C ++ извлекает цвет, зная внутреннюю структуру массива записей. В вашем коде вы не должны использовать (int32_t *), потому что это создает указатель на константу, и вы просто хотите преобразовать число с плавающей точкой в uint_32_t, поэтому я думаю, что вы хотите удовлетворить свой тестовый код просто
ambient := uint32_t(-1.44852785e-016);
diffuse := uint32_t(1.57844226e+11);
etc;
Это не компилируется в Delphi (недопустимый тип), поэтому вместо этого вам нужно сделать что-то вроде
var
p : pointer;
iFloat : single;
iColour : TColor;
begin
iFloat := 1.57844226e+11;
p := @(iFloat);
iColour := TColor(p^);
diffuse := iColour;
end;
который дает красный цвет.
Обратите внимание, что все ваши цвета выглядят одинаково, потому что вы начинаете с нескольких похожих адресов.
Выражается как функция, это может стать
function FloatToColor( const pVal : single ) : TColor;
var
p : pointer;
iFloat : single;
begin
iFloat := 1.57844226e+11;
p := @(iFloat);
Result := TColor(p^);
end;
Исходя из того, что $ FF появляется не в том месте, мне пришло в голову, что эти значения могут быть в формате CMYK. В тестах я обнаружил, что это был модифицированный формат CMYK — больше формата YMCK, если хотите, поэтому, чтобы получить правильные цвета, мне пришлось поменять роль красного и синего.
Там нет истинного преобразования из CMYK в RGB, но следующее является приблизительным.
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;
Обратите внимание, что я использую RGB (b, g, r), а не ожидаемый RGB (r, g, b) для учета обратного порядка цветов.
Других решений пока нет …