uLib  User mode C/C++ extended API library for Win32 programmers.
_gradcolor.asm
Go to the documentation of this file.
1 ;
2 ; GradientColor....
3 ; This file contains both 32 and 64 bit versions of the functions.
4 ; Copyright (c) Love Nystrom.
5 ;
6 TITLE 32/64 bit assembly routines.
7 
8 IFDEF RAX
9  _WIN64 = 1
10 ELSE
11  _WIN64 = 0
12  .686P
13  .XMM
14  .MODEL FLAT
15 ENDIF
16 
17 ;==============================================================================
18 ; Common x86/x64 - Constants and parameterless functions
19 ;==============================================================================
20 
21 _TEXT SEGMENT
22 ; Common code and data...
23 _TEXT ENDS
24 
25 ;==============================================================================
26 IF (_WIN64 eq 0) ; 32 bit version
27 ;==============================================================================
28 ECHO === 32-BIT ASSEMBLY (ML) ===
29 
30 ; __stdcall
31 ; Argument-passing: Right to left. By value, unless pointer or reference.
32 ; Stack-maintenance: Called function pops the stack.
33 ; Name-decoration: An underscore (_) is prefixed to the name. The name is
34 ; followed by the at sign (@) followed by the number of bytes (in decimal)
35 ; in the argument list. In other words, a function declared as
36 ; int func( int a, double b ); is decorated as: _func@12
37 
38 _TEXT SEGMENT
39 
40 PUBLIC _GradientColor
41 ;
42 ; EXTERN_C COLORREF GradientColor( COLORREF c1, COLORREF c2, WORD Ix, WORD Length )
43 ;
44 ; GradientColor procuces a smooth color crossfade from c1 to c2.
45 ; Length is the desired run length from c1 to c2, and Ix is the 0-based step nr.
46 ;
47 ; BYTE r1 = GetRValue( c1 );
48 ; BYTE g1 = GetGValue( c1 );
49 ; BYTE b1 = GetBValue( c1 );
50 ; int dr = int(GetRValue( c2 )) - r1;
51 ; int dg = int(GetGValue( c2 )) - g1;
52 ; int db = int(GetBValue( c2 )) - b1;
53 ; int N = Length-1; // Divisor need to comply with Ix 0..Length-1
54 ; int r = int(r1) + ((dr * int(Ix)) / N);
55 ; int g = int(g1) + ((dg * int(Ix)) / N);
56 ; int b = int(b1) + ((db * int(Ix)) / N);
57 ; return RGB( byte(r), byte(g), byte(b) );
58 
59 ; PONDER: This could probably get much faster by use of some SIMD ops.
60 ; AGH, can't use SIMD since there's no packed div..
61 
62 _GradientColor PROC ;; Implementation 1, plain CPU, no MMX
63  enter 0,0
64  push ebx
65  push ecx
66  sub esp, 8 ; [esp] = N = Length-1
67 
68  mov ebx, [ebp+8] ; c1
69  mov ecx, [ebp+12] ; c2
70  ; int N = Length-1; // Divisor need to comply with Ix 0..Length-1
71  mov eax, [ebp+20] ; Length
72  dec eax
73  mov [esp], eax ; [esp] = N = Length-1
74  xor eax, eax
75  mov [esp+4], eax ; [esp+4] = Result
76 
77  ;; Red
78  ; BYTE r1 = GetRValue( c1 );
79  ; int dr = int(GetRValue( c2 )) - r1;
80  movzx ax, cl ; r2
81  movzx dx, bl ; r1
82  sub ax, dx ; r2-r1
83  ; int r = int(r1) + ((dr * int(Ix)) / N);
84  imul word ptr [ebp+16] ; Ix
85  idiv word ptr [esp] ; N
86  add al, bl
87  mov byte ptr [esp+4], al ; r
88  ;; Green
89  shr ebx, 8 ; c1
90  shr ecx, 8 ; c2
91  movzx ax, cl ; g2
92  movzx dx, bl ; g1
93  sub ax, dx ; g2-g1
94  imul word ptr [ebp+16] ; Ix
95  idiv word ptr [esp] ; N
96  add al, bl
97  mov byte ptr [esp+5], al ; g
98  ;; Blue
99  shr ebx, 8 ; c1
100  shr ecx, 8 ; c2
101  movzx ax, cl ; b2
102  movzx dx, bl ; b1
103  sub ax, dx ; r2-r1
104  imul word ptr [ebp+16] ; Ix
105  idiv word ptr [esp] ; N
106  add al, bl
107  mov byte ptr [esp+6], al ; b
108 
109  mov eax, [esp+4] ; [Result]
110  add esp, 8
111  pop ecx
112  pop ebx
113  leave
114  ret ; __cdecl
115 _GradientColor ENDP
116 
117 IF 0 ;; FIXME: Saturation problem in 'div bh' when result would be > 255
118 ;; Meanwhile use the C++ version in GdiUtil.cpp
119 
120 PUBLIC _ScaleColorRef@12 ; COLORREF __stdcall ScaleColorRef( COLORREF rgb, BYTE mul, BYTE div );
121 
122 _ScaleColorRef@12 PROC ; Linetest OK
123  ; Sadly, it can't be done in MMX since there's no packed div.
124 
125  push ebx
126  push esi
127  mov esi, [esp+12] ; rgb
128  xor edx, edx ; result
129  mov bl, [esp+16] ; mul
130  mov bh, [esp+20] ; div
131 
132  mov al, bl
133  add al, bh
134  cmp al, 2
135  ja L0
136  ; If mul+div <= 2, return color unmodified.
137  ; E.g: mul or div == 0, mul and div == 1
138  mov eax, esi
139  jmp L3
140 L0:
141  mov ecx, 3 ; loop cnt
142 L1:
143  mov eax, esi ; Get color component into AL
144  or al, al ; Test color component
145  jz L2 ; Skip muldiv by zero color
146  mul bl ; AX <- AL * r8
147  cmp bh, 1 ; Test divisor
148  jbe L2 ; div <= 1, so don't div
149  div bh ; AL <- AX / r8, AH <- AX % r8
150 L2:
151  mov dl, al ; Get scaled color component
152  shl edx, 8 ; Shift scaled comp up
153  shr esi, 8 ; Shift to next color comp
154  loop L1
155 
156  mov eax, edx
157  shr eax, 8 ; Undo the last color shift
158 L3:
159  pop esi
160  pop ebx
161  ret 12
162 _ScaleColorRef@12 ENDP
163 ENDIF
164 
165 _TEXT ENDS
166 
167 ;==============================================================================
168 ELSE ; 64 bit version
169 ;==============================================================================
170 ECHO === 64-BIT ASSEMBLY (ML64) ===
171 
172 ; Extern C assembly routines does NOT get an added underscore with MSVC + ML64.
173 ; Hence the x64 assembly routines must be named _exactly as the C prototypes_,
174 ; or, in case of C++ class members, the mangled C++ identifiers.
175 ;
176 ; Fastcall is used regardless of prototype declaration!
177 ; Arguments -> RCX, RDX, R8, R9, then stack.
178 ;
179 ; The four register args are backed by unused stack cells.
180 ; Ergo, after std prologue the fifth argument is at [RBP+48].
181 ;
182 ; Normal fastcall stack cleanup convention (function pop args) is *not used*.
183 ; Functions end with 'ret 0' even if they had stack args.
184 ;
185 ; RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile.
186 ; RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are nonvolatile
187 ; and must be saved and restored by a function that use them.
188 ;
189 ; frame$ = 10h ; Offset from rbp to first shadow arg after 'enter 0,0'
190 ; x64 fastcall arguments:
191 ; rcx = arg1 (rbp+10h)
192 ; rdx = arg2 (rbp+18h)
193 ; r8 = arg3 (rbp+20h)
194 ; r9 = arg4 (rbp+28h)
195 ; [rbp+30h] = arg5
196 
197 _TEXT SEGMENT
198 
199 PUBLIC GradientColor
200 ;
201 ; COLORREF GradientColor( COLORREF c1, COLORREF c2, WORD Ix, WORD Length )
202 ;
203 GradientColor PROC
204  ; ecx = c1
205  ; edx = c2
206  ; r8w = Ix
207  ; r9w = Length
208 
209  mov r10d, edx ; r10d = c2
210  sub rsp, 8 ; [rsp] = result (need bytewise access).
211 
212  dec r9w ; r9w = N = Length-1
213  xor eax, eax
214  mov [rsp], eax ; [rsp] = Result
215 
216  ;; Red
217  movzx ax, r10b ; r2
218  movzx dx, cl ; r1
219  sub ax, dx ; ax = dr = r2-r1
220  imul r8w ; *Ix
221  idiv r9w ; /N
222  add al, cl
223  mov byte ptr [rsp], al ; R
224  ;; Green
225  shr ecx, 8 ; c1
226  shr r10d, 8 ; c2
227  movzx ax, r10b ; g2
228  movzx dx, cl ; g1
229  sub ax, dx ; g2-g1
230  imul r8w ; *Ix
231  idiv r9w ; /N
232  add al, cl
233  mov byte ptr [rsp+1], al ; G
234  ;; Blue
235  shr ecx, 8 ; c1
236  shr r10d, 8 ; c2
237  movzx ax, r10b ; b2
238  movzx dx, cl ; b1
239  sub ax, dx ; b2-b1
240  imul r8w ; *Ix
241  idiv r9w ; /N
242  add al, cl
243  mov byte ptr [esp+2], al ; B
244 
245  mov eax, [rsp] ; [Result]
246  add rsp, 8
247 
248  ret ; Caller balances the stack
249 GradientColor ENDP
250 
251 _TEXT ENDS
252 ENDIF ; _WIN64
253 END