flat assembler
Message board for the users of flat assembler.

Index > OS Construction > drawing a line on the screen?

Author
Thread Post new topic Reply to topic
Redragon



Joined: 27 Nov 2004
Posts: 101
Location: U.S.
Redragon 14 Mar 2005, 03:05
ive already got protected mode, and all of that up and going.. what i was wondering is, is how to draw a basic line on the screen, for instance using them to make buttons, things like that.. (in fasm) thanks everyone!
Post 14 Mar 2005, 03:05
View user's profile Send private message Reply with quote
Dex4u



Joined: 08 Feb 2005
Posts: 1601
Location: web
Dex4u 14 Mar 2005, 17:04
In the Cdpod code is code that draws line's etc, the X Y of the line in the cdpod code is hard coded, so you will need to change this to use var for X Y.

You can get "CdPod.zip" here: http://board.flatassembler.net/topic.php?t=2164&start=50
Post 14 Mar 2005, 17:04
View user's profile Send private message Reply with quote
bogdanontanu



Joined: 07 Jan 2004
Posts: 403
Location: Sol. Earth. Europe. Romania. Bucuresti
bogdanontanu 15 Mar 2005, 00:12
I was going to post some Bresenham code for a general line draw; it will be in Solar OS next version anyway.

But for buttons you mainly need horizontal, vertical and eventually diagonal lines. That is already available and pretty easy to do yourself Wink
Post 15 Mar 2005, 00:12
View user's profile Send private message Visit poster's website Reply with quote
Pharabee



Joined: 18 Nov 2003
Posts: 16
Location: Sukabumi,Indonesia
Pharabee 01 Apr 2005, 07:59
I only have this for MASM32. It slow, real slow. But this is simple.
Code:

                invoke GetDeltaXY,x,y,x2,y2
        mov nDX,edx
        mov nDY,eax
        invoke GetHypotenusa,nDX,nDY
        mov hyp,eax
                
        cmp hyp,0
        jle brs
        
        mov ecx,hyp
        
        @@:
        push ecx
                invoke GetPosLine,nDX,nDY,hyp,ecx
                add edx,x
                add eax,y
                invoke YourPixelFunction,edx,eax,color
        pop ecx
        dec ecx
        jnz @b
        
        brs:
        ret

GetPosLine proc nDX:dword,nDY:dword,hyp:dword,nPos:dword
        LOCAL x,y:dword
        
        fild nDX                
        fidiv hyp               
        fimul nPos              
        fistp x                 
        
        ; (nPos*nDX)/hyp
;       xor edx,edx             ; 1
;       xor eax,eax             ; 1
        
;       mov eax,nDX             ; 1
;       mul nPos                ; 42
;       div hyp                 ; 42
;       mov x,eax               ; 1
                
        fild nDY                
        fidiv hyp               
        fimul nPos              
        fistp y                 
        
        ; (nPos*nDY)/hyp
        
;       xor edx,edx             ; 1
;       xor eax,eax             ; 1
        
;       mov eax,nDY             ; 1
;       mul nPos                ; 42
;       div hyp                 ; 42
;       mov y,eax               ; 1
        
        mov edx,x               
        mov eax,y               
        
        ; FPU           = 169 Clock cycle
        ; No FPU        = 177 Clock cycle
        ret
GetPosLine endp         ; Result on edx:eax

GetDeltaXY proc x:dword,y:dword,x2:dword,y2:dword
        
        mov edx,x2
        sub edx,x
        mov eax,y2
        sub eax,y
        
        ret
GetDeltaXY endp         ; Result on edx:eax

GetHypotenusa proc nDX:dword,nDY:dword
        LOCAL res:dword
        
        xor edx,edx
        
        mov eax,nDY
        mul eax
        mov res,eax
        mov eax,nDX
        mul eax
        
        add res,eax
        fild res
        fsqrt
        fistp res
        mov eax,res
        
        ret
GetHypotenusa endp      ;
    

_________________
How to Get work Fast:
10% Skill, 90% honesty.
Post 01 Apr 2005, 07:59
View user's profile Send private message Visit poster's website Reply with quote
joachim_neu



Joined: 22 Dec 2003
Posts: 139
joachim_neu 01 Apr 2005, 08:11
well, i'm doing this at the moment, too. the problem i got was not the mathematic but if the X-difference was smaller than the Y-difference my code built me this:

Code:
X
 X

  X

   X
    


instead of this:

Code:
X
 X
 X
  X
  X
   X
    


... but i think i'll do it with offsets and operating directly in the video-ram. that should be faster, but complexer, too, i think.

J!N
Post 01 Apr 2005, 08:11
View user's profile Send private message Visit poster's website Reply with quote
MCD



Joined: 21 Aug 2004
Posts: 602
Location: Germany
MCD 01 Apr 2005, 09:25
joachim_neu wrote:
well, i'm doing this at the moment, too. the problem i got was not the mathematic but if the X-difference was smaller than the Y-difference my code built me this:

Code:
X
 X

  X

   X
    


instead of this:

Code:
X
 X
 X
  X
  X
   X
    


... but i think i'll do it with offsets and operating directly in the video-ram. that should be faster, but complexer, too, i think.
First, I cannot recommend operating in the video RAM directly:
It's usually much slower than writing it first to an offscreen buffer. Copy the result to the video RAM as a last step.

And to your problem with the falsely drewn lines: The algorythm you use is easy to understand, but it needs some unpretty correcting from the raw mathematical formulas:
IF X1-X2 > Y1-Y2 THEN
do exactly the kind of algorythm you are using now
ELSE
do the line algorythm, but advance on the Y coordinates instead of
advancing on the X coordinates on each next pixel.
END IF
1 tip: You should furthermore check if your line algorythm doesn't produce "(floatin point) divide by 0" exceptions when drawing exact horizontal or vertical lines, because all line algorythm I know use some kind of dividing to calculate some DeltaY/DeltaY ratio.

Anyway, as bogdanontanu noticed, the Bresenham algorythm is better.

_________________
MCD - the inevitable return of the Mad Computer Doggy

-||__/
.|+-~
.|| ||
Post 01 Apr 2005, 09:25
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 01 Apr 2005, 11:50
first - don't call a putpixel routine, that will be *very* slow - do the pixel plotting directly. Next, google for "bresenham" if you need an algorithm that draws proper lines.
Post 01 Apr 2005, 11:50
View user's profile Send private message Visit poster's website Reply with quote
tom tobias



Joined: 09 Sep 2003
Posts: 1320
Location: usa
tom tobias 01 Apr 2005, 12:27
f0dder wrote:
first - don't call a putpixel routine, that will be *very* slow - do the pixel plotting directly. Next, google for "bresenham" if you need an algorithm that draws proper lines.

Neither the Bresenham algorithm, nor any other "fast" method of drawing a line, will overcome the principle difficulty: accessing the hardware, i.e. video controller, directly. Unfortunately, EACH video controller is different. Most are proprietary and will not release the information needed to access the "secret" registers to illuminate specific pixels at particular times. Older video controllers are better documented, if you have a Trident controller you may be able to get the information you need. Ferraro's book (1993) describing the programming of video controllers will be useful for accessing a Trident controller, and Michael Abrash's book could also offer some ideas for other controllers. Both books have been out of print for several years. Smile
Post 01 Apr 2005, 12:27
View user's profile Send private message Reply with quote
PopeInnocent



Joined: 01 Jan 2004
Posts: 18
Location: USA
PopeInnocent 01 Apr 2005, 21:16
"The Zen of Graphics Programming" by Michael Abrash dedicates 4 chapters (IIRC) to the Bresenham line drawing algorithm. One of the interesting things he does in the later chapters is that he separates the calculation of the line (the Bresenham algorithm) from the actual (device-dependent) rendering.

I'll see if I can dig up some 16-bit code I wrote way back when based on Abrash's methods.

Quote:
Unfortunately, EACH video controller is different.


That's why VESA VBE was invented. Smile
Post 01 Apr 2005, 21:16
View user's profile Send private message Reply with quote
MCD



Joined: 21 Aug 2004
Posts: 602
Location: Germany
MCD 04 Apr 2005, 07:32
Okay, it took me a day, but here I finally got a bresenham line drawing approach. Unfortunately, I have little time, so it's not finished. It especially lacks a (complementary) part that draws lines whith |Y2-Y1| > |X2-X1|, let's call them vertical lines. You will also have to check for this in a arbitrary line drawing procedure. Furthermore it lacks any out-of-screen-border checks.
Code:
;edx: X1
;ebx: Y1
;ecx: X2
;eax: Y2
;esi: # of bytes from pixel(X,Y) to pixel(X,Y+1)
;edi: base offset of buffer to draw to
;ebp: color
Line:
        push    eax ecx edx ebx esi edi
        sub     ecx,edx         ;Calc deltaX:= (X2-X1) & check if (X1;Y1) and (X2;Y2) coords must be swapped - in the same instruc
        jae     .DontXchCoords
        neg     ecx             ;Swapping deltaX results in changing its sign
        xchg    eax,ebx         ;But Y coords are swapped the usual way
    .DontXchCoords:
        sub     eax,ebx         ;deltaY:= Abs(Y2-Y1)
        imul    ebx,esi         ;Calc ofs of first pixel:= Y1*#OfBytesBetween2ConsecutiveVertPixels + X1*4
        add     edx,ecx
        lea     edi,[edi+edx*4+4]
        add     edi,ebx
        cdq
        xor     eax,edx
        sub     eax,edx
        xor     esi,edx         ;Negate #OfBytesBetween2ConsecutiveVertPixels...
        sub     esi,edx         ;...if line goes upwards, this is when Y2 < Y1
        mov     edx,ecx         ;Init total pixel counter with -deltaX
        not     edx
        mov     ebx,ecx         ;deltaX in ebx
        shr     ecx,1           ;Init step counter with deltaX/2
    .PutPixel:
        mov     [edi+edx*4],ebp ;I guess you guess it
        inc     edx             ;Inc total pixel counter until line ends
        jz      .Done
        sub     ecx,eax         ;Decrease step counter by step size
        jnc     .PutPixel       ;Start new step if end of current step reached
        add     edi,esi         ;Go 1 pixel down or up
        add     ecx,ebx         ;Add deltaX to step counter
        jmp     .PutPixel
    .Done:
        pop     edi esi ebx edx ecx eax
        ret
    

It seems quiet speed optimized for me, but there may still be several improvements. (jump hints, but PIV only Sad ). The only thing I know is that the complete memory addressing [edi+edx*4] doesn't slow it down, but is even a bit faster than [edi] and doing the rest with more instructions (Tested, about 14%). I guess MMX/SSE won't bring much here.

_________________
MCD - the inevitable return of the Mad Computer Doggy

-||__/
.|+-~
.|| ||
Post 04 Apr 2005, 07:32
View user's profile Send private message Reply with quote
Pharabee



Joined: 18 Nov 2003
Posts: 16
Location: Sukabumi,Indonesia
Pharabee 09 Apr 2005, 07:21
MCD wrote:
Okay, it took me a day, but here I finally got a bresenham line drawing approach. Unfortunately, I have little time, so it's not finished. It especially lacks a (complementary) part that draws lines whith |Y2-Y1| > |X2-X1|, let's call them vertical lines. You will also have to check for this in a arbitrary line drawing procedure. Furthermore it lacks any out-of-screen-border checks.
Code:
;edx: X1
;ebx: Y1
;ecx: X2
;eax: Y2
;esi: # of bytes from pixel(X,Y) to pixel(X,Y+1)
;edi: base offset of buffer to draw to
;ebp: color
Line:
        push    eax ecx edx ebx esi edi
        sub     ecx,edx         ;Calc deltaX:= (X2-X1) & check if (X1;Y1) and (X2;Y2) coords must be swapped - in the same instruc
        jae     .DontXchCoords
        neg     ecx             ;Swapping deltaX results in changing its sign
        xchg    eax,ebx         ;But Y coords are swapped the usual way
    .DontXchCoords:
        sub     eax,ebx         ;deltaY:= Abs(Y2-Y1)
        imul    ebx,esi         ;Calc ofs of first pixel:= Y1*#OfBytesBetween2ConsecutiveVertPixels + X1*4
        add     edx,ecx
        lea     edi,[edi+edx*4+4]
        add     edi,ebx
        cdq
        xor     eax,edx
        sub     eax,edx
        xor     esi,edx         ;Negate #OfBytesBetween2ConsecutiveVertPixels...
        sub     esi,edx         ;...if line goes upwards, this is when Y2 < Y1
        mov     edx,ecx         ;Init total pixel counter with -deltaX
        not     edx
        mov     ebx,ecx         ;deltaX in ebx
        shr     ecx,1           ;Init step counter with deltaX/2
    .PutPixel:
        mov     [edi+edx*4],ebp ;I guess you guess it
        inc     edx             ;Inc total pixel counter until line ends
        jz      .Done
        sub     ecx,eax         ;Decrease step counter by step size
        jnc     .PutPixel       ;Start new step if end of current step reached
        add     edi,esi         ;Go 1 pixel down or up
        add     ecx,ebx         ;Add deltaX to step counter
        jmp     .PutPixel
    .Done:
        pop     edi esi ebx edx ecx eax
        ret
    

It seems quiet speed optimized for me, but there may still be several improvements. (jump hints, but PIV only Sad ). The only thing I know is that the complete memory addressing [edi+edx*4] doesn't slow it down, but is even a bit faster than [edi] and doing the rest with more instructions (Tested, about 14%). I guess MMX/SSE won't bring much here.


Hi good job. I like this. I take this on my code.

_________________
How to Get work Fast:
10% Skill, 90% honesty.
Post 09 Apr 2005, 07:21
View user's profile Send private message Visit poster's website Reply with quote
MCD



Joined: 21 Aug 2004
Posts: 602
Location: Germany
MCD 11 Apr 2005, 09:41
Thanks, it's rather KISS. I've not finished the vertical part yet, because I'm very busy at the moment and a difficult problem arose: In order to also the vertical main loop fast, I would need one more general register, because the "INC EDX" instruction must be changed to something like "ADD EDX,SomeOtherRegisterX", but unfortunately we don't have any register left. Furthermore all registers used in the main loop are really needed, e.g. cannot be written with less registers. So I have currently different options:

-Use the stack to push and pop 1 register in the part of the main loop where the next step is being taken.
-Do the above, but with a temp variable in either code or data segment, not in the stack.
-For god's sake Evil or Very Mad save to a temporal variable and sacrify this goddamnned ESP register, but I guess Windows doesn't like this approach Very Happy

Well I should also test then which one is the fastest.

_________________
MCD - the inevitable return of the Mad Computer Doggy

-||__/
.|+-~
.|| ||
Post 11 Apr 2005, 09:41
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.