"Convolve". Applies a convolution matrix and divides
with d.
Attention: Crashes in 3.0.4 due to a bug (use src
workaround or the inofficial patch).
This function was documented in the PDF documentation of Filter Factory 3.00,
but removed in the documentation of 3.0.4, because it had a bug which was not fixed. It was described in the 3.0.4 *.wri file, though.
Syntax:
cnv(m11,m12,m13,m21,m22,m23,m31,m32,m33,d)
Synonyms
cnv0
cnv1
What it does:
Applies a convolve (weighted) matrix and divides with d:
+-----+-----+-----+ | m11 | m12 | m13 | +-----+-----+-----+ | m21 | m22 | m23 | +-----+-----+-----+ | m31 | m32 | m33 | +-----+-----+-----+
Attention! In FilterFactory 3.0.4, cnv() will crash when running in a
protected mode environment since the not existing border pixels (e.g. x=-1) are
taken from memory which causes a memory access violation. Without protected
mode, the values for the border pixels will be unexpected because the memory in
the border areas is not initialized/assigned. Use the src() workaround or use
the inofficial patch 3.1.x which will fix the cnv() bug.
Both variants are using the neighbor pixel values at the borders instead of 0.
Workaround:
cnv(m11,m12,m13,m21,m22,m23,m31,m32,m33,d)
can also be written as:
(src(x-1,y-1,z)*m11 + src(x ,y-1,z)*m12 + src(x+1,y-1,z)*m13 + src(x-1,y ,z)*m21 + src(x ,y ,z)*m22 + src(x+1,y ,z)*m23 + src(x-1,y+1,z)*m31 + src(x ,y+1,z)*m32 + src(x+1,y+1,z)*m33 ) / d.
Registers
eax = result
ebx = difference to the next pixel
ecx = beginning of the current row (inside CANVAS)
edx = current position (inside CANVAS)
edi = (reserved for the constant pool "EDI memory")
esi = Temp variable for multiplying factors
(At cnv_v3: Additionally temp variable for condition checks)
[esp-$4] = At cnv_v3: backup of the edx value
Original Machine Code (in OPER resource) of Filter Factory 3.0 and 3.0.4 for Photoshop/Win32
8B 04 24 | mov eax,[esp] (param_d) | result = param_d; |
0B C0 | or eax,eax | . |
0F 84 AC 00 00 00 | jz +$000000ac (@div_zero) | if (param_d == 0) goto @div_zero; // return 0 |
8B 8F A8 45 00 00 | mov ecx,[edi+$000045a8] (CANVAS) | ecx = CANVAS; |
8B 47 58 | mov eax,[edi+$58] (z) | . |
2B 47 5C | sub eax,[edi+$5c] (zmin) | . |
03 C8 | add ecx,eax | ecx += z-zmin; |
8B 47 4C | mov eax,[edi+$4c] (y) | . |
48 | dec eax | . |
2B 47 50 | sub eax,[edi+$50] (ymin) | . |
F7 A7 A0 45 00 00 | mul dword ptr [edi+$000045a0] (ROW_SIZE) | . |
03 C8 | add ecx,eax | ecx += (y-ymin - 1) * ROW_SIZE; |
8B 47 40 | mov eax,[edi+$40] (x) | . |
48 | dec eax | . |
2B 47 44 | sub eax,[edi+$44] (xmin) | . |
8B 5F 60 | mov ebx,[edi+$60] (Z) | . |
2B 5F 5C | sub ebx,[edi+$5c] (zmin) | ebx = Z-zmin; |
F7 E3 | mul ebx | . |
03 C8 | add ecx,eax | ecx += (x-xmin - 1) * ebx; |
2B C0 | sub eax,eax | result = 0; |
8B D1 | mov edx,ecx | edx = ecx; // (1) |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 24 | imul esi,[esp+$24] (param_m11) | . |
03 C6 | add eax,esi | result += [edx] * param_m11; // [edx] == src(x-1,y-1,z) |
03 D3 | add edx,ebx | edx += Z-zmin; // next pixel |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 20 | imul esi,[esp+$20] (param_m12) | . |
03 C6 | add eax,esi | result += [edx] * param_m12; // [edx] == src(x ,y-1,z) |
03 D3 | add edx,ebx | edx += Z-zmin; // next pixel |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 1C | imul esi,[esp+$1c] (param_m13) | . |
03 C6 | add eax,esi | result += [edx] * param_m13; // [edx] == src(x+1,y-1,z) |
03 8F A0 45 00 00 | add ecx,[edi+$000045a0] (ROW_SIZE) | ecx += ROW_SIZE; |
8B D1 | mov edx,ecx | edx = ecx; // next line |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 18 | imul esi,[esp+$18] (param_m21) | . |
03 C6 | add eax,esi | result += [edx] * param_m21; // [edx] == src(x-1,y ,z) |
03 D3 | add edx,ebx | edx += Z-zmin; // next pixel |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 14 | imul esi,[esp+$14] (param_m22) | . |
03 C6 | add eax,esi | result += [edx] * param_m22; // [edx] == src(x ,y ,z) |
03 D3 | add edx,ebx | edx += Z-zmin; // next pixel |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 10 | imul esi,[esp+$10] (param_m23) | . |
03 C6 | add eax,esi | result += [edx] * param_m23; // [edx] == src(x+1,y ,z) |
03 8F A0 45 00 00 | add ecx,[edi+$000045a0] (ROW_SIZE) | ecx += ROW_SIZE; |
8B D1 | mov edx,ecx | edx = ecx; // next line |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 0C | imul esi,[esp+$0c] (param_m31) | . |
03 C6 | add eax,esi | result += [edx] * param_m31; // [edx] == src(x-1,y+1,z) |
03 D3 | add edx,ebx | edx += Z-zmin; // next pixel |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 08 | imul esi,[esp+$08] (param_m32) | . |
03 C6 | add eax,esi | result += [edx] * param_m32; // [edx] == src(x ,y+1,z) |
03 D3 | add edx,ebx | edx += Z-zmin; // next pixel |
0F B6 32 | movzx esi,[edx] | . |
0F AF 74 24 04 | imul esi,[esp+$04] (param_m33) | . |
03 C6 | add eax,esi | result += [edx] * param_m33; // [edx] == src(x+1,y+1,z) |
99 | cdq | . |
F7 3C 24 | idiv dword ptr [esp] (param_d) | result /= param_d; |
@div_zero: | @div_zero: | |
83 C4 28 | add esp,$28 (= 10x pop) | . |
50 | push eax | return result; |
In the beta version 3.00a, cnv crashes if d=0. Also, inRect.top instead of ymin, and inRect.left instead of xmin was be used.
Version 3.00a (beta version) | Version 3.00b (internal build), 3.00 (final), and 3.0.4 |
mov eax,DWORD PTR [esp] or eax,eax je @@end-1 ; If d=0, the program will crash (jump between an instruction) mov ecx,DWORD PTR [edi+0x45a8] ; *CANVAS mov eax,DWORD PTR [edi+0x58] ; z sub eax,DWORD PTR [edi+0x5c] ; zmin add ecx,eax mov eax,DWORD PTR [edi+0x4c] ; y dec eax sub eax,DWORD PTR [edi+0x88] ; inRect.top mul DWORD PTR [edi+0x45a0] ; ROW_SIZE add ecx,eax mov eax,DWORD PTR [edi+0x40] ; x dec eax sub eax,DWORD PTR [edi+0x84] ; ; inRect.left mov ebx,DWORD PTR [edi+0x60] ; Z sub ebx,DWORD PTR [edi+0x5c] ; zmin mul ebx add ecx,eax sub eax,eax mov edx,ecx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x24] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x20] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x1c] add eax,esi add ecx,DWORD PTR [edi+0x45a0] mov edx,ecx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x18] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x14] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x10] add eax,esi add ecx,DWORD PTR [edi+0x45a0] mov edx,ecx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0xc] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x8] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x4] add eax,esi cdq idiv DWORD PTR [esp] @@end: add esp,0x28 push eax |
mov eax,DWORD PTR [esp] or eax,eax je @@end mov ecx,DWORD PTR [edi+0x45a8] ; *CANVAS mov eax,DWORD PTR [edi+0x58] ; z sub eax,DWORD PTR [edi+0x5c] ; zmin add ecx,eax mov eax,DWORD PTR [edi+0x4c] ; y dec eax sub eax,DWORD PTR [edi+0x50] ; ymin mul DWORD PTR [edi+0x45a0] ; ROW_SIZE add ecx,eax mov eax,DWORD PTR [edi+0x40] ; x dec eax sub eax,DWORD PTR [edi+0x44] ; xmin mov ebx,DWORD PTR [edi+0x60] ; Z sub ebx,DWORD PTR [edi+0x5c] ; zmin mul ebx add ecx,eax sub eax,eax mov edx,ecx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x24] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x20] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x1c] add eax,esi add ecx,DWORD PTR [edi+0x45a0] mov edx,ecx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x18] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x14] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x10] add eax,esi add ecx,DWORD PTR [edi+0x45a0] mov edx,ecx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0xc] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x8] add eax,esi add edx,ebx movzx esi,BYTE PTR [edx] imul esi,DWORD PTR [esp+0x4] add eax,esi cdq idiv DWORD PTR [esp] @@end: add esp,0x28 push eax |