Конференция "Начинающим" » ЧИсла меньше машинного эпсилон
 
  • dmk © (01.05.18 04:03) [0]
    Всем привет!

    Подскажите пожалуйста, как сравнить такие числа, если тип числа double?

     DoubleEpsilon := 2.22044604925031e-16;  
     X := -9.30880643132136e+18;
     if Abs(X) < DoubleEpsilon then X := 0.0;



    Все, что меньше эпсилона вообще не воспринимается :(
  • dmk © (01.05.18 04:12) [1]
    Сравнение с NaN, NegInfinity, PosInfinity не помогает.
    Знаки сравнения на это число не реагируют.
  • kilkennycat © (01.05.18 10:33) [2]

    > если тип числа double

    сделать типом Extended


    > DoubleEpsilon := 2.22044604925031e-16;

    а если посмотреть, что получается после присваивания?
  • kilkennycat © (01.05.18 10:38) [3]
    а вообще, сравнение таких чисел делают с помощью SameValue, CompareValue, IsZero
  • dmk © (01.05.18 14:11) [4]
    DoubleEpsilon как раз еще воспринимается, а вот X := -9.30880643132136e+18 уже нет.
    Для Double это EFloatingOverflow. Проблема в том, что Exception не генерится.
    Получается при вычислении тангенса в некоторых случаях.
  • Sha © (01.05.18 17:37) [5]
    можно не допускать, чтобы при вычислениях числа становились слишком малыми, умножая их на некоторый коэффициент
  • KilkennyCat © (01.05.18 18:45) [6]
    а если использовать сторонний математический юнит?
  • Германн © (02.05.18 02:31) [7]

    > Все, что меньше эпсилона вообще не воспринимается

    А -9.30880643132136e+18 никак не меньше эпсилона.
  • Германн © (02.05.18 02:39) [8]
    Ну т.е. от слова совсем. :)
  • dmk © (02.05.18 13:59) [9]
    Германн ©   (02.05.18 02:31) [7]
    Я Abs использую.
  • Dimka Maslov © (02.05.18 21:04) [10]
    1. Убедиться, правомочно ли мы сравнивает минус 16-тую степень с плюс 18-той.
    2. Если нет, то можно, зная формат хранения вещественных чисел выдрать из них мантиссу и экспоненту, привести к одной степени и сравнивать уже их
  • KilkennyCat © (03.05.18 01:22) [11]

    > выдрать из них мантиссу и экспоненту

    а выдерится ли из результата, оказавшийся меньше эпсилонного?
    и кстати, а вообще, результат вычислений может быть меньше машинного эпсилона?
  • dmk © (03.05.18 03:01) [12]
    >и кстати, а вообще, результат вычислений может быть меньше машинного эпсилона?
    Да. И Exception не срабатывает. Срабатывает, когда пытаешься сложить 2 числа.
  • KSergey © (03.05.18 10:31) [13]
    > dmk ©   (01.05.18 14:11) [4]
    > DoubleEpsilon как раз еще воспринимается, а вот X := -9.30880643132136e+18 уже нет.
    > Для Double это EFloatingOverflow. Проблема в том, что Exception не генерится.

    Вот это не понял. Могли бы пояснить?
    Double принимает диапазон от  2.23e-308 до 1.79e+308

    У вас всего +18 степень. В чем беда?

    > DoubleEpsilon := 2.22044604925031e-16;  
    >  X := -9.30880643132136e+18;
    >  if Abs(X) < DoubleEpsilon then X := 0.0;
    >
    > Все, что меньше эпсилона вообще не воспринимается :(

    Поясните, пожалуйста, смысл термина "не воспринимается". Я его не понимаю.
    Что происходит в приведённом вами коде? и напишите что вы ожидали. Так будет понятнее
  • dmk © (03.05.18 12:21) [14]
    >KSergey ©   (03.05.18 10:31) [13]
    Вы невнимательно читаете.
    Получающееся число меньше машинного эпсилона. И не ноль и не NaN.
    Оно не ошибочно. Оно есть, но при сложении или вычитании генерируется исключение.

    >Double принимает диапазон от  2.23e-308 до 1.79e+308
    Это если основание 1.79. В моем случае основание -9.308......, а значит и диапазон другой.
    Это же плавающая точка :)
  • Dimka Maslov © (03.05.18 13:09) [15]

    > dmk ©   (03.05.18 12:21) [14]

    -9.30880643132136e+18 или же всё таки
    -9.30880643132136e-18;
  • KSergey © (03.05.18 13:16) [16]
    > dmk ©   (03.05.18 12:21) [14]
    > >KSergey ©   (03.05.18 10:31) [13]
    > Вы невнимательно читаете.

    Чувак, я читаю внимательно.
    Тебе ответ нужен или разборки кто внимательно или не внимательно читает?

    Ты написал вот что:

    > dmk ©   (01.05.18 04:03) 
    >  DoubleEpsilon := 2.22044604925031e-16;  
    >  X := -9.30880643132136e+18;

    Теперь скажи, что я читаю невнимательно? и, главное, зачем ты про это пишешь?
  • dmk © (03.05.18 13:23) [17]
    >Dimka Maslov ©   (03.05.18 13:09) [15]
    >-9.30880643132136e+18 или же всё таки
    >-9.30880643132136e-18;

    -9.30880643132136e+18 = 0.00000000000000000930880643132136.
    Вроде так.

    >KSergey ©   (03.05.18 13:16) [16]
    Значит не понимаете о чем речь.


    X := Tan(X)
    E := DoubleEpsilon;

    X = 0.00000000000000000930880643132136;
    E = 0.000000000000000222044604925031;

    //1.0 + X = Exception
    //1.0 + E = No Exception
  • KSergey © (03.05.18 13:31) [18]
    > dmk ©   (03.05.18 13:23) [17]
    > -9.30880643132136e+18 = 0.00000000000000000930880643132136.
    >
    > Вроде так.

    В чего это вдруг??

    -9.30880643132136e+18 = -9308806431321360000
  • KSergey © (03.05.18 13:41) [19]
    > dmk ©   (03.05.18 13:23) [17]
    > X := Tan(X)
    > E := DoubleEpsilon;
    >  
    > X = 0.00000000000000000930880643132136;
    > E = 0.000000000000000222044604925031;
    >  
    > //1.0 + X = Exception
    > //1.0 + E = No Exception

    Чета неправда.
    Или вопрос опций компилятора.

    Вот программа, только что скомпилировал, запустил:

    var X, E: Double;
    var z: Double;

    begin

      X := 0.00000000000000000930880643132136;
      E := 0.000000000000000222044604925031;

      z := 1.0 + X;

      writeln(z);

    end.



    Выдаёт:

    1.00000000000000E+0000

    Никаких Exception нет.
  • dmk © (03.05.18 13:42) [20]
    Delphi в отладчике CPU пишет -9.30880643132136E18
    В переменной -9.30880643132136e+18

    В любом случае переполнение разрядной сетки.
  • dmk © (03.05.18 13:43) [21]
    У меня это происходит при округлении:

    function Round(F: double): int64;
    asm
     .NOFRAME

     cvtsd2si rax, F
    end;
  • KSergey © (03.05.18 13:52) [22]
    > dmk ©   (03.05.18 13:42) [20]
    > Delphi в отладчике CPU пишет -9.30880643132136E18
    > В переменной -9.30880643132136e+18

    Славно.
    А нули-то при этом куда надо рисовать? куда я написал, ведь правда?

    > В любом случае переполнение разрядной сетки.

    Разрядной сетки чего? какой "разрядной сетки"?
    Я же уже приводил диапазон для Double, вы почему невнимательно читаете?
    впрочем, я почитал про "основание" в [14]
    уу.....

    Это называется мантисса, а не основание, и это важно.
  • KSergey © (03.05.18 13:53) [23]
    нда..
    вот бы еще понять как приведённый код на asm связан с исходным вопросом...
  • KSergey © (03.05.18 13:54) [24]
    кстати, возвращаемое значение из функции объявлено как int64
    это вас не удивляет? 1E+18 не лезет в int64
  • KilkennyCat © (03.05.18 13:58) [25]

    > z := 1.0 + X;
    >
    >   writeln(z);
    >
    > end.
    >
    > Выдаёт:
    >
    > 1.00000000000000E+0000


    совпадает с описанием машинного эпсилона в вики. значит, гуд.
  • KSergey © (03.05.18 14:04) [26]
    телепатирую:

    вы вызвали стандартную функцию Round() для числа  -9.30880643132136E18
    И она рванула "переполнение".
    Ну так это понятно: ибо диапазон для int64  
    От -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807
    т.е. грубо говоря -9.2E+18 до +9.2Е+18

    А вы в него пытаетесь запихать -9.3E+18

    Оно выходит за границы int64, отсюда и взрыв

    Ведь так?
  • Dimka Maslov © (03.05.18 14:31) [27]

    > -9.30880643132136e+18 = 0.00000000000000000930880643132136.


    Да ну? С какой радости?
  • KSergey © (03.05.18 14:56) [28]
    Автору стоит рекомендовать почитать статью
    http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374
  • dmk © (03.05.18 15:35) [29]
    Ну да, неправильно понял из-за разницы в отладочном окне.
    Там просто E18 написано, а не +. В переменной +18.
    Учитывая, что тангенс у меня в диапазоне -2Pi..2PI - не ожидал, что число вылезет в обратную сторону после умножения на K.

    Это просто масштабирование.
    K := (gFactor * Aspect); //Масштаб(%) * соотношение сторон

    Это просто графики функций:
     //Графики
     repeat
       DX := (X * gFactor) + cX;
       NA := NormalizeAngle(A) * DegToRadD;

       sinY := Sin(@NA) * K;
       cosY := Cos(@NA) * K;
       tanY := Tan(@NA) * K;
       cotY := Cot(@NA) * K;

       with RT^ do
       begin
         FloatPixel(DX, cY + sinY, crLtYellow, 255, Alpha);
         FloatPixel(DX, cY + cosY, crLtGreen, 255, Alpha);
         FloatPixel(DX, cY + tanY, crLtBlue, 255, Alpha);
         FloatPixel(DX, cY + cotY, crLtRed, 255, Alpha);
       end;

       X := (X + StepX); //Шаги в радианах
       A := (X * RadToDegD); //Угол для вычисления функции
     until (X > R);


    И вот где cY + tanY вылезает Exception.
  • dmk © (03.05.18 15:43) [30]
    Это просто графики функций:
    https://yadi.sk/i/Y_w_IWJg3VF9fL

    Проверял как считаются. Если gFactor > 500% - происходит Exception.
    А мне надо до 100000%, чтобы отклонения посмотреть.
    Это свой расчет SinCosTanCot.
  • dmk © (03.05.18 16:03) [31]
    Извиняшки. Это я дурак. Tan(90°) не определен. Cosec(0°) тоже не определен.
    Потому и ошибка. Я не обрабатываю эту ситуацию в своей функции ;)
  • KSergey © (03.05.18 16:05) [32]
    Как это всё связано с изначальным вопросом - вот бы понять.
    Впрочем, не важно.

    Что же до приведённого куска кода - очевидно, что ошибок в нём нет, ошибки (если они вообще есть) - где-то в других частях кода.
    К тому же мы не знаем что за секретная функция FloatPixel и какие значения принимают переменные cY и  tanY в момент возникновения проблемы. От нас это зачем-то скрывают, но посочувствовать я готов.
  • KSergey © (03.05.18 16:06) [33]
    Ура, вот всё и разрешилось.
    А то "не понимаете, не понимаете" :)
  • dmk © (03.05.18 17:04) [34]
    >что за секретная функция FloatPixel
    Она не секретная. Просто пиксел распределяется на 4 пиксела
    и получается сглаженная линия. Удобно функции рисовать.
    Типа AntiAliasing'а.

    procedure FloatPixel(X, Y: double; dColor: TColorRef; dAlpha, dOpacity: byte);
    var
     fX, fY, sX, sY: double;
     x0, y0, x1, y1: integer;

    begin
     //Координата отсчетного пиксела
     if (X < 0.0) then
     begin
       x0 := Trunc(X - 1.0);
       x1 := (x0 + 1); //Пиксел справа
       fX := Abs(Frac(X)); //Дробная часть сдвигается в пиксел справа
       sX := (1.0 - fX); //Остаток в стартовом пикселе
     end
     else
     begin
       x0 := Trunc(X);
       x1 := (x0 + 1); //Пиксел справа
       sX := Frac(X); //Дробная часть сдвигается в пиксел справа
       fX := (1.0 - sX); //Остаток в стартовом пикселе
     end;

     if (Y < 0.0) then
     begin
       y0 := Trunc(Y - 1.0);
       y1 := (y0 + 1); //Пиксел снизу
       fY := Abs(Frac(Y)); //Дробная часть сдвигается в пиксел снизу
       sY := (1.0 - fY); //Остаток в стартовом пикселе
     end
     else
     begin
       y0 := Trunc(Y);
       y1 := (y0 + 1); //Пиксел снизу
       sY := Frac(Y); //Дробная часть сдвигается в пиксел снизу
       fY := (1.0 - sY); //Остаток в стартовом пикселе
     end;

     //Отсчетный пиксел
     if FClipRegion.PtInRegion(x0, y0) then
       FBlendPixel(PAddress32(x0, y0), dColor, dAlpha, Round((fX * fY) * dOpacity));
     //Пиксел справа
     if FClipRegion.PtInRegion(x1, y0) then
       FBlendPixel(PAddress32(x1, y0), dColor, dAlpha, Round((sX * fY) * dOpacity));
     //Пиксел снизу
     if FClipRegion.PtInRegion(x0, y1) then
       FBlendPixel(PAddress32(x0, y1), dColor, dAlpha, Round((fX * sY) * dOpacity));
     //Пиксел по диагонали справа внизу
     if FClipRegion.PtInRegion(x1, y1) then
       FBlendPixel(PAddress32(x1, y1), dColor, dAlpha, Round((sX * sY) * dOpacity));
    end;


    БлендПиксел тоже не секретный. Смешивает содержимое буфера с цветом.
    Получается смешанный пиксел.
    procedure BlendPixel(dA: QWord; AColor: TColorRef; Alpha, Opacity: byte);
    var
     A: word;
     ADif: word;
     WR, WG, WB: word;

    begin
     //Прозрачность канала
     A := (((Alpha + 1) * Opacity) shr 8);
     //Для исходного пиксела нужно обратное насыщение
     ADif := (A xor $FF) + 1;
     //Коррекция на единицу для корректного деления на 256
     A := (A + 1);

     //Расчет компонентов пиксела наложения
     WR := TBgrPixel(AColor).r * A;
     WG := TBgrPixel(AColor).g * A;
     WB := TBgrPixel(AColor).b * A;

     //Смешиваем цвета
     TBgrPixel(PDWord(dA)^).r := ((TBgrPixel(PDWord(dA)^).r * ADif + WR) shr 8);
     TBgrPixel(PDWord(dA)^).g := ((TBgrPixel(PDWord(dA)^).g * ADif + WG) shr 8);
     TBgrPixel(PDWord(dA)^).b := ((TBgrPixel(PDWord(dA)^).b * ADif + WB) shr 8);
    end;


    Есть версия на асме:
    procedure BlendPixel(dA: QWord; AColor: TColorRef; Alpha, Opacity: byte);
    const
     ShufMask: uint64 = $0100010001000100;

    asm
     .NOFRAME

     pxor mm0, mm0 //<- APixel
     pxor mm1, mm1 //<- AColor
     movq mm2, ShufMask //Формирование маски умножения

     punpcklbw mm0, [dA] //Преобразуем байты в слова
     psrld mm0, 8 //Преобразование старших бит в младшие

     movd mm5, AColor
     punpcklbw mm1, mm5 //Преобразуем байты в слова
     psrld mm1, 8 //Преобразование старших бит в младшие

     movzx eax, Alpha //Вычислим прозрачность альфа-канала
     inc eax //Прибавим единицу, чтобы корректно разделить на 256
     movzx r8d, Opacity //Компонента прозрачности
     mul eax, r8d //Умножаем
     shr ax, 8 //Делим на 256
     mov dx, ax
     xor dx, $FF //<- ADif - величина цвета обратная альфе

     inc edx //Прибавим единицу, чтобы корректно разделить на 256
     movd mm3, edx
     pshufb mm3, mm2 //<- mm3: формируем маску разницы ADif

     inc eax //Прибавим единицу, чтобы корректно разделить на 256
     movd mm4, eax
     pshufb mm4, mm2 //<- mm2: формируем 64-битную альфа-маску

     pmullw mm1, mm4 // AColor * Alpha = lpBR, lpBG, lpBB
     pmullw mm0, mm3 // APixel * ADif
     paddusw mm0, mm1 //APixel + AColor
     psrlw mm0, 8 //(APixel + AColor) div 256

     packuswb mm0, mm0 //Транслируем слова в байты
     movd [dA], mm0
    end;


    У меня еще куча версий такой фукнции, в том числе и через вектора,
    но думаю сможете и сами реализовать.
  • dmk © (03.05.18 17:07) [35]
    ФлоатПикселом удобно Безьешку рисовать. Она же дробная получается.
  • dmk © (03.05.18 17:08) [36]
    Вот вам сразу бленд-сканлайн:
    procedure BlendColorScLineMMX(dA: QWord; dLen: dword; AColor: TColorRef; Alpha, Opacity: byte);
    const
     ShufMask: uint64 = $0100010001000100;

    asm
     .NOFRAME

     xor r10, r10
     mov r10d, dLen

     movq mm2, ShufMask //Формирование маски умножения

     pxor mm1, mm1 //Очистка старших битов
     movd mm5, AColor //Цвет наложения
     punpcklbw mm1, mm5 //Разложим байты в слова 32 -> 64 бита
     psrld mm1, 8 //Сдвиг вправо для очистки старших бит

     movzx eax, Alpha //Вычислим прозрачность альфа-канала
     inc eax //Прибавим единицу, чтобы корректно разделить на 256
     movzx r11d, Opacity //Компонента прозрачности
     mul eax, r11d //Умножаем
     shr ax, 8 //Делим на 256
     mov dx, ax
     xor dx, $FF //<- ADif - величина цвета обратная альфе

     inc edx //Прибавим единицу, чтобы корректно разделить на 256
     movd mm3, edx
     pshufb mm3, mm2 //<- mm3: формируем маску разницы ADif

     inc eax //Прибавим единицу, чтобы корректно разделить на 256
     movd mm4, eax
     pshufb mm4, mm2 //<- mm2: формируем 64-битную альфа-маску

     pmullw mm1, mm4 //AColor * Alpha = lpBR, lpBG, lpBB
     movq mm5, mm1 //Сохраним для повторения

    @NextPixel:
     pxor mm0, mm0 //Очистим для формирования маски следующего пиксела
     punpcklbw mm0, [dA] //Читаем 32 бита //Транслируем байты в слова
     psrld mm0, 8 //Сдвиг вправо для очистки старших бит

     movq mm1, mm5 //В mm5 сохраненный цвет наложения
     pmullw mm0, mm3 // APixel * ADif
     paddusw mm0, mm1 //APixel + AColor
     psrlw mm0, 8 //mm0 div 256

     packuswb mm0, mm0 //Транслируем слова в байты
     movd [dA], mm0  //Пишем обратно

     add dA, 4
     dec r10
     jnz @NextPixel
    end;
  • dmk © (03.05.18 17:12) [37]
    А это супер-секретный PtInRegion:

    type
     PRegion = ^TRegion;
     TRegion = record
       private
         rX: integer; //Позиция слева
         rY: integer; //Позиция сверху
         rEX: integer; //Позиция справа
         rEY: integer; //Позиция снизу
         rW: integer; //Ширина включая первую точку
         rH: integer; //Высота включая первую точку
     end;

    function TRegion.PtInRegion(x, y: integer): boolean;
    begin
     if (x >= rX) and (x <= rEX) then Result := (y >= rY) and (y <= rEY) else Result := false;
    end;
  • kilkennycat © (03.05.18 20:33) [38]

    > dmk ©  

    а готового всего этого нет? или это практики ради?
  • dmk © (03.05.18 21:17) [39]
    >а готового всего этого нет? или это практики ради?
    Готового чего?

    Если про пиксели, то это я из своего класса подергал.
    Есть. Много. Почти все на асме. Работает шустро.
    Тут видео: https://yadi.sk/i/I_NwsFF-3UcVzK
    Это 3D-шечка. Движок делаю небольшой.
  • dmk © (03.05.18 21:19) [40]
    В видео рендер в одном потоке. В многопоточном варианте раза в 3-10 быстрее.
    Зависит от процессора.
  • dmk © (03.05.18 21:22) [41]
    Тут еще немного видео:
    https://yadi.sk/i/R2eitAvY3SJRKH
  • Redmond (05.05.18 00:24) [42]
    Супер! Когда же уже разработка будет доступна для простых смертных? :3
    И надо бы-то наваять сайт проекта, хоть на Юкозе или (логичнее) на SourceForge'е...

    А вот бы вы сделали быструю функцию (можно без исходников, в dll) которая могёт быстро отрисовать битмап на другом битмапе как "quad-2-quad"...
  • dmk © (05.05.18 10:30) [43]
    >которая могёт быстро отрисовать битмап на другом битмапе

    Это тоже самое, что вверху, только в цикле:
    //Первый байт пиксела $FF000000 - альфа накладываемого изображения
    procedure BlendDataScLine(sA, dA: QWord; dLen: dword; dOpacity: byte);
    const
     ShufMask: uint64 = $0100010001000100;

    asm
     .NOFRAME
     xor r10, r10
     mov r10d, dLen

     movq mm6, ShufMask //Формирование маски умножения
     mov r8, dA //Адрес назначения

    @NextPixel:
     pxor mm0, mm0 //Очистка регистров умножения
     pxor mm1, mm1 //Очистка регистров умножения

     punpcklbw mm0, [sA] //Читаем исходный (налогаемый) пиксел
     punpcklbw mm1, [r8] //Читаем конечный пиксел
     psrld mm0, 8 //Сдвиг вправо для очистки старших бит
     psrld mm1, 8 //Сдвиг вправо для очистки старших бит

     //Смешиваем альфу с прозрачностью .........
     pextrw eax, mm0, 3 //Извлечем альфу из 4-го слова исходного пиксела sA
     inc eax //Прибавим единицу, чтобы корректно разделить на 256
     movzx r11d, dOpacity //Компонента прозрачности
     mul eax, r11d //Умножаем
     shr ax, 8 //Делим на 256
     mov dx, ax //<- ADif - величина цвета обратная альфе
     xor ax, $FF //Инвертируем альфу

     //Формируем маски умножения
     inc eax //Прибавим единицу, чтобы корректно разделить на 256
     movd mm2, eax
     pshufb mm2, mm6 //<- mm2: формируем 64-битную альфа-маску

     inc edx //Прибавим единицу, чтобы корректно разделить на 256
     movd mm3, edx
     pshufb mm3, mm6 //<- mm3: формируем маску разницы ADif

     //Смешиваем пикселы
     pmullw mm1, mm2 //dA Pixel * Alpha = lpBR, lpBG, lpBB
     pmullw mm0, mm3 //sA Pixel * ADif
     paddusw mm0, mm1 //sAPixel + dAPixel
     psrlw mm0, 8 //mm0 div 256

     packuswb mm0, mm0 //Транслируем слова в байты
     movd [r8], mm0  //Пишем обратно

     add r8, 4 //dA + 4
     add sA, 4 //sA + 4
     dec r10
     jnz @NextPixel
    end;


    Рисует один битмап на другом с альфой и прозрачностью.
    procedure TBitmap64.DrawSprite32(dSprite: TBitmap64; dX, dY: integer; dOpacity: byte);
    var
     x, y: integer;
     dR, IR: TRegion;
     fi: boolean;
     sA, dA: QWord;
     fX, fY: integer;

    begin
     //Регион спрайта
     dR := Region(dX, dY, dSprite.Width, dSprite.Height);

     if RegionIntersect(CR, dR, @IR) then
     begin
       //Регион полность в регионе отсечения
       fi := (IR.W = dSprite.Width) and (IR.H = dSprite.Height);

       //Регион виден полностью
       if fi then
       begin
         fX := dX;
         fY := dY;

         //Адрес начала строки спрайта
         sA := dSprite.PAddress32(0, 0);
         //Адрес начала строки вывода спрайта
         dA := PAddress32(fX, fY);

         for y := 0 to dSprite.Height - 1 do
         begin
           //Смешиваем строки
           BlendDataScLine(sA, dA, dSprite.Width, dOpacity);
           //Следующая скан-линия спрайта
           Inc(sA, dSprite.ScLen);
           //Следующая скан-линия вывода
           Inc(dA, ScLen);
           //Строка вывода
           Inc(fY);
         end;
       end
       else
       //Регион виден не полностью
       begin
         fX := dX;
         fY := dY;
         x := 0;
         y := 0;

         //Отсечение по X слева
         if (dX < FClipRegion.X) then
         begin
           fX := FClipRegion.X;
           x := (FClipRegion.X - dX);
         end;

         //Отсечение по Y сверху
         if (dY < FClipRegion.Y) then
         begin
           fY := FClipRegion.Y;
           y := (FClipRegion.Y - dY);
         end;

         //Адрес начала строки спрайта
         sA := dSprite.PAddress32(x, y);
         //Адрес начала строки вывода спрайта
         dA := PAddress32(fX, fY);

         for y := IR.Y to IR.EY do
         begin
           //Смешиваем строки
           BlendDataScLine(sA, dA, IR.W, dOpacity);
           //Следующая скан-линия вывода
           Inc(dA, ScLen);
           //Следующая скан-линия вывода
           Inc(sA, dSprite.ScLen);
           //Строка вывода
           Inc(fY);
         end;//for
       end;
     end;
    end;
  • dmk © (05.05.18 11:11) [44]
    Вот результат работы BlendDataScLine:
    https://yadi.sk/i/EDIiJHfL3VNJAY

    Адрес пиксела вычисляется так:
    function TBitmap64.PAddress32(x, y: integer): QWord;
    begin
     Result := FBitmap.MemAddr + (y * FBitmap.ScanLength) + (x shl 2);
    end;


    Тут работы на пару вечеров, если вы программист :)
    А dll будет позже. Пока пилю. Я же не программер. Просто хобби.
  • Redmond (06.05.18 14:30) [45]
    Не, "quad-2-quad" - это полное аффинное преобразование. С:
    Произвольный 4-х-угольник в произвольный 4-х-угольник.
  • dmk © (06.05.18 16:15) [46]
    Можно и так. Только исходников пока нет.
 
Конференция "Начинающим" » ЧИсла меньше машинного эпсилон
Есть новые Нет новых   [118667   +39][b:0][p:0.002]