[ Pobierz całość w formacie PDF ]
.FWidthjge @vplotdonecmp ecx,0jl @vplotdonecmp ecx,[eax].FHeightjge @vplotdonepush eaxpush edxmov eax,[eax].FLineLenmul ecxmov edx,eaxpop ecxpop eaxadd edx,ecxshl ecx,1add edx,ecxadd edx,[eax].lpvbitsmov ecx,[edx]and ecx,0ff000000hmov ebx,Colorand ebx,0ffffffhxor ecx,ebxmov [edx],ecx@vplotdone:pop ebxend;Just for fun, here is a basic airbrush routine.It is not optimized, but does illustrate how I tend to test ideas, and uses many of the ideas discussed earlier.When used, the airbrush routine produces a circle of the desired color and radius, centred on X,Y, whose effect on the original image lessens as the perimeter of the circle is approached.procedure TFrame.AirBrush(FX,FY,Radius,Color:integer);assembler;var X,Y,X0,Y0,X1,Y1,Xd,Yd,R2,D2,newColor:integer;{the variables declared are all of the constant values which will be usedX,Y centre of airbrush plotX0,Y0 bottom left coordinate of square to scan = X-Radius,Y-RadiusX1,Y1 top right coordinate of square to scan = X+Radius,Y+RadiusXd,Yd current point being consideredR2 square of the RadiusD2 square of the distance of current point Xd,Yd from centrenewColor holds the color value for current point as it is being constructed}asmjmp @airstart{define subroutines}@airpointok:{checks point Xd,Yd is valid, if valid edx = address, if not edx = 0}push ecxmov ecx,Ydcmp ecx,0jl @airpointerrorcmp ecx,[eax].FHeightjge @airpointerrorpush eaxmov eax,[eax].FLineLenmul ecxmov edx,eaxpop eaxmov ecx,Xdcmp ecx,0jl @airpointerrorcmp ecx,[eax].FWidthjge @airpointerroradd edx,ecxshl ecx,1add edx,ecxpop ecxadd edx,[eax].lpvbitsret@airpointerror:pop ecxmov edx,0ret@airblend:{takes the intensity of R,G or B, 0 -> 255, ecx = current value, edx = new value and blends them according to current value of D2, the square of the distance from X,Y.returns value in ecx}push eaxpush edxmov eax,D2mul ecxmov ecx,eaxpop edxmov eax,R2sub eax,D2mul edxadd eax,ecxxor edx,edxmov ecx,R2div ecxmov ecx,eaxpop eaxret@airstart:{initialize all variables}mov X,edxmov Y,ecxsub edx,Radiusmov X0,edxmov Xd,edxadd edx,Radiusadd edx,Radiusmov X1,edxsub ecx,Radiusmov Y0,ecxmov Yd,edxadd ecx,Radiusadd ecx,Radiusmov Y1,ecxmov ecx,Radiuscmp ecx,0jle @airdonepush eaxmov eax,Radiusimul eaxmov R2,eaxpop eax@airloop:{start of main loop}mov ecx,Xdpush eaxsub ecx,Xmov eax,Ydsub eax,Yimul eaxmov D2,eaxpop eax{D2, square of the distance of current Xd,Yd from centre now calculated and stored}call @airpointokcmp edx,0je @airpointdone{now know current point OK and have it's address in edx}mov ecx,[edx]push edxpush ecx{get pixel color value and save pixel address and color on stack}and ecx,0ff000000hmov newColor,ecx{grab fourth byte of color value and store in newColor)pop ecxpush ecxand ecx,0ff0000hshr ecx,16mov edx,Colorand edx,0ff0000hshr edx,16call @airblend{recover color value but maintain stack status, isolate Red value and shift right so that Red intensity is in range 0->255 to keep subroutine @airblend happy.Do same with color value to be applied.Call @airblend to blend these color values according to status of R2 and D2, returning modified value in ecx}shl ecx,16{shift back to position of red intensity}mov edx,newColorxor edx,ecxmov newColor,edx{update newColor}{now do this again for the Green values}pop ecxpush ecxand ecx,0ff00hshr ecx,8mov edx,Colorand edx,0ff00hshr edx,8call @airblendshl ecx,8mov edx,newColorxor edx,ecxmov newColor,edx{and again for Blue}pop ecxand ecx,0ffhmov edx,Colorand edx,0ffhcall @airblendmov edx,newColorxor ecx,edxpop edxmov [edx],ecx{finally recover address of pixel, and update using newColor}@airpointdone:{and we end with the standard loop control checks}mov ecx,Xdinc ecxmov Xd,ecxcmp ecx,X1jle @airloopmov ecx,X0mov Xd,ecxmov edx,Ydinc edxmov Yd,edxcmp edx,Y1jle @airloop@airdone:end;Implementing routines for drawing squares and circles should now be within your grasp.Triangles can be tricky though.Nevertheless you have in your hands all of the tools required.Debugging your codeTo conclude this article a few words about debugging seem in order.It is very easy to set up watches, program break's, and traverse Delphi programs a line at a time.The same is true, even when using assembler.All one needs to do, is add the four 32bit general registers eax, ebx, ecx and edx to one's watch list, and see the effect of each line of assembler.When dealing with the stack try numbering each push, giving the same number to each corresponding pop.It is usually best to do this before running the code for the first time.Where possible break down complex algorithms into small relatively simple sub-routines, and make as much use as possible of local variables.Both these courses of action will hinder your code's performance, but you are more likely to produce code that works.and finallyEnough has been covered in this article, for you to explore the possibilities of assembler.However the majority of assembler instructions actually available to you, have been ignored.Should you wish to learn more, may I suggest Borland's Turbo Assembler, just for the manuals, and Wrox's Assembly Language Master Class, which is in my opinion the finest book of its type available.Neither of these products directly address the use of assembler in Delphi, nor in Windows 95, but both give a good grounding in assembler algorithm design
[ Pobierz całość w formacie PDF ]