Replace invalid characters with HTML entities
— with — ’ with ’ + with + × with x ç with ç “ with “ ” with ” ‘ with ‘ • with • – with - µ with µ † with † Fix C++ θ with θ Yen symbol instead of times Fix broken apos Bullet again E-circumflex
This commit is contained in:
parent
9e52de9586
commit
500e7f5654
353 changed files with 5091 additions and 5091 deletions
84
36-03.html
84
36-03.html
|
|
@ -37,20 +37,20 @@
|
|||
</CENTER>
|
||||
<P><BR></P>
|
||||
<H3><A NAME="Heading5"></A><FONT COLOR="#000077">Run-Length Slice Details</FONT></H3>
|
||||
<P>A couple of run-length slice implementation details yet remain. First is the matter of how error-term turnover is detected. This is done in much the same way as it is with standard Bresenham’s: The error term is maintained as a negative valve and advances for each step; when the error term reaches 0, it’s time to add an extra pixel to the current run. This means that we only have to test for carry after advancing the error term to determine whether or not to add an extra pixel to each run. (Actually, the code in this chapter tests for the error term being greater than zero, but the assembly code in the next chapter will use the very efficient carry approach.)
|
||||
<P>A couple of run-length slice implementation details yet remain. First is the matter of how error-term turnover is detected. This is done in much the same way as it is with standard Bresenham’s: The error term is maintained as a negative valve and advances for each step; when the error term reaches 0, it’s time to add an extra pixel to the current run. This means that we only have to test for carry after advancing the error term to determine whether or not to add an extra pixel to each run. (Actually, the code in this chapter tests for the error term being greater than zero, but the assembly code in the next chapter will use the very efficient carry approach.)
|
||||
</P>
|
||||
<P>The second and more difficult detail is balancing the runs so that they’re centered around the ideal line, and therefore draw the same pixels that standard Bresenham’s would draw. If we just drew full-length runs from the start, we’d end up with an unbalanced line, as shown in Figure 36.5. Instead, we have to split the initial pixel plus one full run as evenly as possible between the first and last runs of the line, and adjust the initial error term appropriately for the initial half-run.</P>
|
||||
<P>The second and more difficult detail is balancing the runs so that they’re centered around the ideal line, and therefore draw the same pixels that standard Bresenham’s would draw. If we just drew full-length runs from the start, we’d end up with an unbalanced line, as shown in Figure 36.5. Instead, we have to split the initial pixel plus one full run as evenly as possible between the first and last runs of the line, and adjust the initial error term appropriately for the initial half-run.</P>
|
||||
<P>The initial error term is advanced by one-half of the normal per-step fractional advance, because the initial step is only one-half pixel along the minor axis. This half-step gets us exactly halfway between the initial pixel and the next pixel along the minor axis. All the error-term adjustments are scaled up by two times precisely so that we can scale up this halved error term for the initial run by two times, and thereby make it an integer.</P>
|
||||
<P>The other trick here is that if an odd number of pixels are allocated between the first and last partial runs, we’ll end up with an odd pixel, since we are unable to draw a half-pixel. This odd pixel is accounted for by adding half a pixel to the error term.</P>
|
||||
<P>That’s all there is to run-length slice line drawing; the partial first and last runs are the only tricky part. Listing 36.1 is a run-length slice implementation in C. This is not an optimized implementation, nor is it meant to be; this listing is provided so that you can see how the run-length slice algorithm works. In the next chapter, I’ll move on to an optimized version, but for now, Listing 36.1 will make it much easier to grasp the principles of run-length slice drawing, and to understand the optimized code I’ll present in the next chapter.</P>
|
||||
<P>The other trick here is that if an odd number of pixels are allocated between the first and last partial runs, we’ll end up with an odd pixel, since we are unable to draw a half-pixel. This odd pixel is accounted for by adding half a pixel to the error term.</P>
|
||||
<P>That’s all there is to run-length slice line drawing; the partial first and last runs are the only tricky part. Listing 36.1 is a run-length slice implementation in C. This is not an optimized implementation, nor is it meant to be; this listing is provided so that you can see how the run-length slice algorithm works. In the next chapter, I’ll move on to an optimized version, but for now, Listing 36.1 will make it much easier to grasp the principles of run-length slice drawing, and to understand the optimized code I’ll present in the next chapter.</P>
|
||||
<P><A NAME="Fig5"><!-- </A><A HREF="javascript:displayWindow('images/36-05.jpg',412,327 )"> --><IMG SRC="images/36-05.jpg"><BR><!-- </A>
|
||||
<BR><A HREF="javascript:displayWindow('images/36-05.jpg',412,327)"> --><FONT COLOR="#000077"><B>Figure 36.5</B></FONT></A> <I>Balancing run-length slice lines: a) unbalanced; b) balanced.</I>
|
||||
</P>
|
||||
<P><B>LISTING 36.1 L36-1.C</B></P>
|
||||
<!-- CODE //-->
|
||||
<PRE>
|
||||
/* Run-length slice line drawing implementation for mode 0x13, the VGA’s
|
||||
320x200 256-color mode. Not optimized! Tested with Borland C++ in
|
||||
/* Run-length slice line drawing implementation for mode 0x13, the VGA’s
|
||||
320x200 256-color mode. Not optimized! Tested with Borland C++ in
|
||||
the small model. */
|
||||
|
||||
#include <dos.h>
|
||||
|
|
@ -69,7 +69,7 @@ void LineDraw(int XStart, int YStart, int XEnd, int YEnd, int Color)
|
|||
int WholeStep, InitialPixelCount, FinalPixelCount, i, RunLength;
|
||||
char far *ScreenPtr;
|
||||
|
||||
/* We’ll always draw top to bottom, to reduce the number of cases we have to
|
||||
/* We’ll always draw top to bottom, to reduce the number of cases we have to
|
||||
handle, and to make lines between the same endpoints draw the same pixels */
|
||||
if (YStart > YEnd) {
|
||||
Temp = YStart;
|
||||
|
|
@ -80,9 +80,9 @@ void LineDraw(int XStart, int YStart, int XEnd, int YEnd, int Color)
|
|||
XEnd = Temp;
|
||||
}
|
||||
/* Point to the bitmap address first pixel to draw */
|
||||
ScreenPtr = MK_FP(SCREEN_SEGMENT, YStart * SCREEN_WIDTH + XStart);
|
||||
ScreenPtr = MK_FP(SCREEN_SEGMENT, YStart * SCREEN_WIDTH + XStart);
|
||||
|
||||
/* Figure out whether we’re going left or right, and how far we’re
|
||||
/* Figure out whether we’re going left or right, and how far we’re
|
||||
going horizontally */
|
||||
if ((XDelta = XEnd - XStart) < 0)
|
||||
{
|
||||
|
|
@ -93,7 +93,7 @@ void LineDraw(int XStart, int YStart, int XEnd, int YEnd, int Color)
|
|||
{
|
||||
XAdvance = 1;
|
||||
}
|
||||
/* Figure out how far we’re going vertically */
|
||||
/* Figure out how far we’re going vertically */
|
||||
YDelta = YEnd - YStart;
|
||||
|
||||
/* Special-case horizontal, vertical, and diagonal lines, for speed
|
||||
|
|
@ -101,30 +101,30 @@ void LineDraw(int XStart, int YStart, int XEnd, int YEnd, int Color)
|
|||
if (XDelta == 0)
|
||||
{
|
||||
/* Vertical line */
|
||||
for (i=0; i<=YDelta; i++)
|
||||
for (i=0; i<=YDelta; i++)
|
||||
{
|
||||
*ScreenPtr = Color;
|
||||
ScreenPtr += SCREEN_WIDTH;
|
||||
ScreenPtr += SCREEN_WIDTH;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (YDelta == 0)
|
||||
{
|
||||
/* Horizontal line */
|
||||
for (i=0; i<=XDelta; i++)
|
||||
for (i=0; i<=XDelta; i++)
|
||||
{
|
||||
*ScreenPtr = Color;
|
||||
ScreenPtr += XAdvance;
|
||||
ScreenPtr += XAdvance;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (XDelta == YDelta)
|
||||
{
|
||||
/* Diagonal line */
|
||||
for (i=0; i<=XDelta; i++)
|
||||
for (i=0; i<=XDelta; i++)
|
||||
{
|
||||
*ScreenPtr = Color;
|
||||
ScreenPtr += XAdvance + SCREEN_WIDTH;
|
||||
ScreenPtr += XAdvance + SCREEN_WIDTH;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -152,38 +152,38 @@ void LineDraw(int XStart, int YStart, int XEnd, int YEnd, int Color)
|
|||
/* The initial and last runs are partial, because Y advances only 0.5
|
||||
for these runs, rather than 1. Divide one full run, plus the
|
||||
initial pixel, between the initial and last runs */
|
||||
InitialPixelCount = (WholeStep / 2) + 1;
|
||||
InitialPixelCount = (WholeStep / 2) + 1;
|
||||
FinalPixelCount = InitialPixelCount;
|
||||
|
||||
/* If the basic run length is even and there’s no fractional
|
||||
/* If the basic run length is even and there’s no fractional
|
||||
advance, we have one pixel that could go to either the initial
|
||||
or last partial run, which we’ll arbitrarily allocate to the
|
||||
or last partial run, which we’ll arbitrarily allocate to the
|
||||
last run */
|
||||
if ((AdjUp == 0) && ((WholeStep & 0x01) == 0))
|
||||
{
|
||||
InitialPixelCount--;
|
||||
}
|
||||
/* If there’re an odd number of pixels per run, we have 1 pixel that can’t
|
||||
be allocated to either the initial or last partial run, so we’ll add 0.5
|
||||
/* If there’re an odd number of pixels per run, we have 1 pixel that can’t
|
||||
be allocated to either the initial or last partial run, so we’ll add 0.5
|
||||
to error term so this pixel will be handled by the normal full-run loop */
|
||||
if ((WholeStep & 0x01) != 0)
|
||||
{
|
||||
ErrorTerm += YDelta;
|
||||
ErrorTerm += YDelta;
|
||||
}
|
||||
/* Draw the first, partial run of pixels */
|
||||
DrawHorizontalRun(&ScreenPtr, XAdvance, InitialPixelCount, Color);
|
||||
/* Draw all full runs */
|
||||
for (i=0; i<(YDelta-1); i++)
|
||||
for (i=0; i<(YDelta-1); i++)
|
||||
{
|
||||
RunLength = WholeStep; /* run is at least this long */
|
||||
/* Advance the error term and add an extra pixel if the error
|
||||
term so indicates */
|
||||
if ((ErrorTerm += AdjUp) > 0)
|
||||
if ((ErrorTerm += AdjUp) > 0)
|
||||
{
|
||||
RunLength++;
|
||||
RunLength++;
|
||||
ErrorTerm -= AdjDown; /* reset the error term */
|
||||
}
|
||||
/* Draw this scan line’s run */
|
||||
/* Draw this scan line’s run */
|
||||
DrawHorizontalRun(&ScreenPtr, XAdvance, RunLength, Color);
|
||||
}
|
||||
/* Draw the final run of pixels */
|
||||
|
|
@ -212,39 +212,39 @@ void LineDraw(int XStart, int YStart, int XEnd, int YEnd, int Color)
|
|||
/* The initial and last runs are partial, because X advances only 0.5
|
||||
for these runs, rather than 1. Divide one full run, plus the
|
||||
initial pixel, between the initial and last runs */
|
||||
InitialPixelCount = (WholeStep / 2) + 1;
|
||||
InitialPixelCount = (WholeStep / 2) + 1;
|
||||
FinalPixelCount = InitialPixelCount;
|
||||
|
||||
/* If the basic run length is even and there’s no fractional advance, we
|
||||
/* If the basic run length is even and there’s no fractional advance, we
|
||||
have 1 pixel that could go to either the initial or last partial run,
|
||||
which we’ll arbitrarily allocate to the last run */
|
||||
which we’ll arbitrarily allocate to the last run */
|
||||
if ((AdjUp == 0) && ((WholeStep & 0x01) == 0))
|
||||
{
|
||||
InitialPixelCount--;
|
||||
}
|
||||
/* If there are an odd number of pixels per run, we have one pixel
|
||||
that can’t be allocated to either the initial or last partial
|
||||
run, so we’ll add 0.5 to the error term so this pixel will be
|
||||
that can’t be allocated to either the initial or last partial
|
||||
run, so we’ll add 0.5 to the error term so this pixel will be
|
||||
handled by the normal full-run loop */
|
||||
if ((WholeStep & 0x01) != 0)
|
||||
{
|
||||
ErrorTerm += XDelta;
|
||||
ErrorTerm += XDelta;
|
||||
}
|
||||
/* Draw the first, partial run of pixels */
|
||||
DrawVerticalRun(&ScreenPtr, XAdvance, InitialPixelCount, Color);
|
||||
|
||||
/* Draw all full runs */
|
||||
for (i=0; i<(XDelta-1); i++)
|
||||
for (i=0; i<(XDelta-1); i++)
|
||||
{
|
||||
RunLength = WholeStep; /* run is at least this long */
|
||||
/* Advance the error term and add an extra pixel if the error
|
||||
term so indicates */
|
||||
if ((ErrorTerm += AdjUp) > 0)
|
||||
if ((ErrorTerm += AdjUp) > 0)
|
||||
{
|
||||
RunLength++;
|
||||
RunLength++;
|
||||
ErrorTerm -= AdjDown; /* reset the error term */
|
||||
}
|
||||
/* Draw this scan line’s run */
|
||||
/* Draw this scan line’s run */
|
||||
DrawVerticalRun(&ScreenPtr, XAdvance, RunLength, Color);
|
||||
}
|
||||
/* Draw the final run of pixels */
|
||||
|
|
@ -260,13 +260,13 @@ void DrawHorizontalRun(char far **ScreenPtr, int XAdvance,
|
|||
int i;
|
||||
char far *WorkingScreenPtr = *ScreenPtr;
|
||||
|
||||
for (i=0; i<RunLength; i++)
|
||||
for (i=0; i<RunLength; i++)
|
||||
{
|
||||
*WorkingScreenPtr = Color;
|
||||
WorkingScreenPtr += XAdvance;
|
||||
WorkingScreenPtr += XAdvance;
|
||||
}
|
||||
/* Advance to the next scan line */
|
||||
WorkingScreenPtr += SCREEN_WIDTH;
|
||||
WorkingScreenPtr += SCREEN_WIDTH;
|
||||
*ScreenPtr = WorkingScreenPtr;
|
||||
}
|
||||
/* Draws a vertical run of pixels, then advances the bitmap pointer to
|
||||
|
|
@ -277,13 +277,13 @@ void DrawVerticalRun(char far **ScreenPtr, int XAdvance,
|
|||
int i;
|
||||
char far *WorkingScreenPtr = *ScreenPtr;
|
||||
|
||||
for (i=0; i<RunLength; i++)
|
||||
for (i=0; i<RunLength; i++)
|
||||
{
|
||||
*WorkingScreenPtr = Color;
|
||||
WorkingScreenPtr += SCREEN_WIDTH;
|
||||
WorkingScreenPtr += SCREEN_WIDTH;
|
||||
}
|
||||
/* Advance to the next column */
|
||||
WorkingScreenPtr += XAdvance;
|
||||
WorkingScreenPtr += XAdvance;
|
||||
*ScreenPtr = WorkingScreenPtr;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue