 ***************************************************************************
<>

                       3d coding TAT (Tricks And Tips) 
                           rendering & engine ideas
                                 by TAD 1998

                      cakeypig@darkplace.freeserve.co.uk

<>
 ***************************************************************************

        NOTE:   Please view this from DOS because some of the extra
                symbols from the character set (128-255) have been
                used for the line drawing and other things.

                   = squared (raised to the 2nd power, x = x*x


                ***********************************************
                *** WARNING: this document is over 400Kb !! ***
                ***********************************************


 Wot the hell ?

          In this document is various TAT (Tips And Tricks) for gaining
        an extra slice of the speed cake and my own personal thoughts
        about 3-d engines, rendering techniques (new and old) and a
        collection of dubious maths formulas. These mostly connected
        coding methods have been used/devised or developed over many
        years (some as long a go as 1988/1989 if not before) and
        some are, well, still in their early stages because while
        writing this document some new ones leapt into the open space
        between my two ears.
          Alone these tricks won't produce the ultimate 3D engine, but
        they will definitely give a few extra CLK-cycles here and there.
        I haven't seen any other document which describes engine
        tricks and techniques, only polygon filling or a few scraps
        about line/polygon clipping or BSP data structure at best, so
        this document might be a first.
          This lack of engine information might be due to the fact
        that most programmers are very protective of their binary
        offspring and are paranoid about other people ripping their
        tricks off. As 3d programming takes a large amount of work
        and many coders are very competitive they do not wish
        for others to catch them up or overtake them, sad isn't it ?


 Disclaimer

          If this document or any of it's ideas causes damage to
        either your optic nerve, eyeball or neurological system
        resulting in excessive drooling, dizziness or confusion then
        I will NOT be held responsible. I make no guarantees that
        any of the described techniques actually work, even if they
        do large parts may be absent or incorrect. These are only
        my personal observations and current thoughts about 3d.

                !!! USE THIS AT YOUR OWN RISK !!!


 What it's Not

          This document is NOT an in-depth tutorial for rendering
        techniques NOR is it a reference list of mathematical
        formulas or algorithms. So if you are searching for the
        back-face-culling algorithm or 2-d axis rotational matrix
        stuff or perspective... then look elsewhere....
          This is by no means a complete investigation of 3d
        engines, 3d modelling, shading or texture mapping. It does
        not contain all the answers to your questions, but perhaps
        highlights some problems that you may be unaware of. Do NOT
        expect to find an entire 3-d engine source code located in
        this doc, also don't think this is a complete engine design
        spec or an entire algorithm Because it's not.


 What it is

          This is just my own theories and current ideas about 3d
        engines or 'renderers' as some like to call them. From the
        earliest BattleZone up to the latest Unreal or Quake2 there
        is always a large crowd of followers for whom 2d just won't
        cut it anymore. Today the craze is 3d, but I think the
        future is 4d where entire levels are dynamically reshaped
        and remodelled during play. If this turns out to be true
        then BSP (Binary Space Partition) trees may be old hat
        because they are pre-calculated, static representations of
        items (usually polygons) within a finite space, and so are
        unable to be shaped over time.
          I hope to present some new and/or dynamic techniques in
        this document file which will allow this 4-d flexibility.
        This dynamic reshaping is due to method being able to work
        in real-time rather than being pre-calculated and static.
        Also I hope to describe some of the trendy buzz-phrases in
        a very simple, easy-to-read format. There will be holes in
        my explanation, mistakes or bugs in my working theories, but
        they are simply that, working theories. Some of the methods
        are so new that I hadn't even thought them up before I
        started this huge document.
                                                enjoy.....

Ŀ
                                  CONTENTS                                 


  #0:   Introduction/Waffle

  #A:   Patchwork Landscapes

  #B:   Non-Linear (curved) Landscapes
                B1:     Circles
                B2:     Sub-division & Mid-points
                B3:     Fractional Curves
                B4:     Parabolic Curves

  #C:   Voxel Landscapes

  #D:   The "Planet" Method
                D1:     More of the same..
                D2:     Grid based Planets
                D3:     3d-Linked Lists & Dynamic Neighbours
                D4:     Tokenised Grids & Shared Items
                D5:     Movable Items & Monsters
                D6:     Background Tails
                D7:     Coarse Area Nets

  #E:   Sorting out the performance problem
                E1:     Delta Sorting
                E2:     Minimal access - Index tables
                E3:     Squatting Objects

  #F:   Render Attribute Trees (RAT's)
                F1:     Groups and Trees
                F2:     Freedom vs. Lists
                F3:     Environment Webs & Plants
                F4:     OCT-Trees
                F5:     Spinning the Web
                F6:     Caught in the Web
                F7:     Multi-Attribute Sieves
                F8:     Recommended Reading

  #G:   "NOAH" - Flood fill rendering

  #H:   The missing Link ? "INLET" rendering.
                H1:     CAVE'd or VEX'd ?
                H2:     CONVEX Rulez
                H3:     CONVEX - SO WHAT ?
                H4:     Is that a light-bulb ?
                H5:     Where's these LINKED-LISTS ?
                H6:     Two way system
                H7:     Bonus
                H8:     Yeah, but what about CONCAVE ?
                H9:     Remember that central pillar ?
                H10:    What about depth sorting & Overdraw ?
                H11:    Pixel clipping distant objects
                H12:    Texture clipping speed up
                H13:    Problems, Problems
                H14:    Convex Bonuses
                H15:    Convex Downers
                H16:    Summary

  #I:   Volume Meshes (Distorted Cube Arrays)
                I1:     Terminology
                I2:     A Similar Method
                I3:     DOOM 3 ?
                I4:     Now the catch

  #J:   S-BUFFER (Span buffer techniques)
                J1:     Initialisation
                J2:     Time to Clip ?
                J3:     Fences, Water & Tints
                J4:     The Speed Issue
                J5:     The Right Direction ?

  #K:   Line clipping & Polygon edge clipping
                K1:     Border clipping
                K2:     Creating the outcode bits
                K3:     Clipping Similar Triangles
                K4:     Slope Based Edge Intersection
                K5:     Divide And Conquer (the CLKs)
                K6:     Bresenham vs. Incremental
                K7:     Binary Sub-Division Clipper
                K8:     Combined Incremental Clipper
                K9:     Custom Outcode Clipping

  #L:   Polygon drawing & clipping
                L1:     Convex Half-Space Clipping
                L2:     SUTHERLAND-HODGMAN Algorithm
                L3:     A small improvement ?
                L4:     Recycling 3-Section Lines
                L5:     Recycled Edge Co-ordinates
                L6:     Z-Cropping Polygons
                L7:     Hidden Surfaces & Drawing
                L8:     Half-Space Seams & Convex Culling

  #M:   Trapezoidal Decomposition
                M1:     Problems
                M2:     Improvements


  #N:   Group Vertex clipping
                N1:     The good news
                N2:     The bad news

  #O:   Smooth Lines & Anti-Aliasing
                O1:     Smooth & Fast Bresenham
                O2:     Recursive Terrain Mapping
                O3:     Atomic Lumps & Bumps
                O4:     Stop Dithering ?

  #P:   Plants, Trees and Forests
                P1:     A common theme
                P2:     Ring or loop Trees
                P3:     Threaded Trees
                P4:     Multi-way Trees
                P5:     Side Links & Lop-Sided Trees

  #Q:   Convex Polyhedra, Planes and Surface-details
                Q1:     Surface Plane Detail
                Q2:     When I'm cleaning windows...
                Q3:     Convex Polyhedra & Compass Bubbles
                Q4:     Tessellation, Tiles and Blocky Pixels
                Q5:     'Checkerboard' or Grid Based Textures
                Q6:     One Big Texture, Many Mappings
                Q7:     'Horizon' Z clipping
                Q8:     Dynamic Details & Model Simplification
                Q9:     MIP Faces & Component Models
                Q10:    Primitive Component Models

  #R:   Projections and Corrections
                R1:     The Angle Grinder
                R2:     Round the Bend
                R3:     Hint, Hint, Intel
                R4:     Faster Perspective/Projection
                R5:     Combining Rotations & Projection

  #S:   Unfolding Polyhedra & Mapping Adjacent Faces
                S1:     Unfolding
                S2:     Neighbours and Trees
                S3:     3d models, 2d belts

  #T:   Our 3d world is flat
                T1:     Normal Shading
                T2:     Pointless Shading ?
                T3:     Regional Light-Sources
                T4:     Last Orders ?
                T5:     Here's One I lit earlier
                T6:     Multiple Light-Sources
                T7:     Static Kinship Lighting Tables
                T8:     Problems
                T9:     Here comes the sun..
                T10:    Delta Illumination
                T11:    Texture Light mapping
                T12:    2d screen filters

  #U:   Distant Horizons
                U1:     International Interpolation
                U2:     MIP-Terrain-Maps
                U3:     Real-time Creation
                U4:     Volume Blinds
                U5:     Flat Arial Maps
                U6:     Sprites & Crosses
                U7:     MIPs & Bits
                U8:     Squashed Horizons
                U9:     Moving the Earth
                U10:    Silhouettes
                U11:    Field of Vision Slices

  #V:   Tips And Tricks
                V1:     Need more MHZ ?
                V2:     Crashing the Cache
                V3:     Moral of the story

  #W:   Gallons Into Pint Pots

  #Y:   Terminology & Incorrect Phrases

  #Z:   Final words
                Z0:     The Crystal Fool
                Z1:     So Long, Fare-well..

#############################################################################
Ŀ
 #0:                        Introduction/Waffle                            

#############################################################################


 Who is it for ?

          These code & tricks are intended for 80x86 assembly-language
        coders (all 10 of us) who choose not to use a high-level
        language but enjoy getting our hands dirty with the low-level
        nitty-gritty stuff. Although many of the techniques can be
        applied to other languages without too much fuss (many if not
        all of the examples are in pseudo-code) coding 3d stuff
        should demand the fastest methods to give the greatest
        level of detail at the lowest possible hardware requirement.

                "A programmer who is scared of assembly....
                         is like a pilot who is scared of flying.."

        No matter how fancy your compiler optimisation options are
        they can not really compete with pure 80x86.

                "Using a high-level language for games
                        is like driving with the hand-brake on."

 Typos & mistakes

          I am sure that a great number of mistakes and spelling errors
        can be found in this document. Possibly some of the methods I
        have described won't work because of 'em or there are no doubt
        flaws in the given pseudo-code which prevents it from working.
        This document is NOT meant to be a source-code-library, but
        as an incentive to spark off your own improvements and code
        ideas. Personally I reckon that using someone else's
        3d library is a backwards step and does nothing to advance
        the state-of-the-art goal posts because let's face it, the
        3d engine is already 2nd hand and past it's sell by date.


 Does this stuff work ?

          Well, maybe. Some of the ideas are still too vague or
        perhaps too flawed to be implemented directly, so a variable
        amount of development time will no doubt be needed to
        fully realise them. Many of the methods and tricks included
        in this document are merely extensions of my own observations
        about 3d objects, projection and data classification.
        When I first programmed some 3d code way back in 1989/1990
        I had VERY little resources and almost zero access to the
        well known clipping, line drawing and polygon drawing
        techniques so about 90% of this was learnt the hard way.
          Many (all) of these techniques are only intended to be
        motivation for either improving traditional algorithms or
        to be the spark of a yet-to-be-discovered method. The text
        has written in a mostly jargon free way, but now and again
        a phrase pops in for a quick visit :)


 Wording and Definitions

          Some of the wording of subjects and ideas may be
        incorrect to some extent and my mathematical knowledge
        is basic, so the reader is asked to overlook some small
        errors or mistakes. Many of the trendy buzz-words have
        been explained in a brief way so that a basic understanding
        can be quickly gained without too much maths jargon or
        techno-babble (which some 'professional' programmers seem
        to get their rocks off on) personally I think that a simple,
        easy-to-understand describe helps create an easy-to-code
        algorithm because you can spend more time on optimising and
        development rather then remembering what a "4d quasi-jerp"
        or "non-rational-polar-hyper-exponent" actually does.
          I have tried where possible to describe things in a logic
        and easy to read structure with many iffy ASCII diagrams
        to illustrate. The same technique is sometimes described in
        a number of ways and the wording of one element might be
        exchanged with another, this will hopefully help any
        confused readers by giving a different approach to a subject.

        At the end of this quickly growing document I have included
        a short glossary of terms which should help the baffled.


 Mentality of a coder

          I find that going right back to the basic definitions and
        re-reading some of the most primitive code & algorithms can
        help inspire me develop new ways of looking at complex problems
        or new techniques. These days many new programmers seem to
        skip past most of the fundamental programming techniques. With
        floating-point instructions and 32-bit registers some argue
        that the older stuff like division algorithms or multi-byte
        precision using ADC etc.. is obsolete. But I strongly disagree
        because many of the primitive techniques were developed on
        slug-like processors and so were optimised far more than most
        of today's offerings. Even the classic "repeated-subtraction
        to-do-a-division" is important, not to replace the CPU's
        IDIV and DIV instructions but it is the hidden technique
        behind the Bresenham line drawing (although no-one has ever
        mentioned this, it IS repeated subtraction for DIVISION and
        NOT like most books like to call it DECISION based.)

          If you try to code a game/3d engine from a mathematical
        point then I reckon you have chosen the wrong starting point.
        Think from a CPU view-point and what instruction it likes
        and dislikes, choose those which it likes (MOV, ADD etc..)
        and minimise those it does not (FSQRT etc..).
        LUT (Look-Up Tables) can not only be a good source of speed-up
        but they have two other bonuses, 1) they normally free up more
        registers than by the calculation approach. 2) they do allow a
        certain amount of flexibility at initialisation time. So very
        complex rules and optimisations can sometimes be built in the
        look-up tables when they are created this removes some tests
        which the calculation approach needs.
        3) disk space is usually saved, depending on whether your
        program builds the tables or they are included at assembly time.

          If you are really serious about writing lightning fast 3d code
        then I would first suggest thinking about the overall view
        of your engine, what it needs to do (and most importantly what
        it DOES NOT need to do), scribble down all the restrictions
        and the amount of flexibility you want in your engine. This way
        the places where a corner can be cut will hopefully be seen
        at the beginning. Sometimes it is very easy to get bogged down
        in the instruction optimisation. Trying to shave another 1 CLK
        cycle off that pixel drawing routine might be a small reward
        and can be misplaced if your line drawing is still sluggish.
        A trap which I have fallen in many times when writing code is
        attempting to optimise the code as you write it. As you type
        instructions you may realise a better way, so you go back and
        delete the previous few lines for a better method and then you
        see another optimisation, before you know it your source code
        is shrinking in size rather than growing ! So just get the rough
        outline of your code typed in and then you can optimise it
        much more easily because you can see the program flow a lot
        more clearly and you will end up with working code MUCH sooner.

          Sometimes it is very easy to fall into the low-level trap
        (not seeing the forest for the trees), this is where I
        believe a more global, "group" approach can give the best
        gains. Instead of rejecting a single polygon, try and reject
        entire objects, rooms, even sub-levels if you can. This way
        a vast amount of calculation and processing can be avoided
        without counting each CLK cycle. And then when you do groom
        your code for tweaks and optimisation tricks, your engine
        will leave all the rest standing ! Sometimes an entirely
        new/different way of approaching the same old problem
        (like using some not-so-obvious algorithms) can produce better
        optimisation than following the traditional rendering method
        path as written in most books.

          The fastest way to draw something .... is NOT to draw it !

          I know the above phrase looks stupid, but it is the actual
        goal for all programmers when they optimise. The goal is not
        to use the fastest instructions but NO instructions at all.

          The problem of "overdraw" can seriously reduce performance
        I remember once reading an article written by a team from
        a games software house who had written a number of 3d games and
        they stated "trying to calculate what can be seen would make
        the games run at an unplayable rate... so we simply draw the
        most distant objects first and then overdraw with nearer ones."
        But I reckon this situation has now been reversed due to the vast
        increase in polygon/textures workload which is now demanded for
        an "average" 3d engine. As the levels have doubled and doubled
        in terms of polygons and complexity, the need for pre-processed
        level and more fanciful storage/sorting techniques has become
        a much more important issue than ever before and will be vital
        in the near future.


#############################################################################
Ŀ
 #A:                        Patchwork Landscapes                           

#############################################################################

          This is a way to describe a 3d landscape (hills and valleys)
        using a 2d array to define the height at regular intervals.
        When most people think about patchwork landscapes they often
        think of games like Virus or (one of my favourites) Hunter.
        But I think other games used similar methods a few years
        before Virus. I think the old Spectrum game "Combat Lynx"
        used a filled 3d landscape and no doubt other games before
        that did as well..

          It is possibly the most simple landscape to create, just
        take a 2d array of numbers to represent the height of each
        corner point and draw them at equal intervals on the screen.
        A lot of games use 2 of these arrays, one for height and
        one for colour. This doubles the amount of storage needed but
        allows for a landscape to be shaded and designed far more
        than a simple use-the-height-as-colour approach using 1 array.

          The great advantage of this form of modelling is that
        a small number of points can represent a vast landscape area
        just by making the spacing between each corner reasonably
        large in size. But the bigger the spacing the rougher the
        landscape will look.

          One disadvantage is that hills and valleys tend to look
        very sharp and angular because straight lines are drawn
        between two corners and filled with colour (or a texture).
        This might look okay for nearly flat landscapes or for
        sharp mountain peaks, but it looks lousy for hills. As
        flat polygons are mostly used to draw each map cell this
        means lighting is usually very flat too (only using a
        single colour for the entire polygon.

          Each map polygon doesn't have to be filled in this
        "Flat-Shading" way other techniques such as Gouraud or
        Phong shading can be use to simulate the shading
        differences between pixels in the same polygon. You could
        sub-divide each polygon when you come to render it and
        draw 4 polygons instead of just 1, this would help create
        more visible detail without the need to store extra
        vertices for the mid points. This can lead onto fractal
        like techniques where the small detail in the landscapes
        are created in REAL-TIME rather than being stored like
        the corner vertices. The distance to the polygon can be
        used to control the amount of sub-division and fractal
        generation it uses. i.e.. Closer (large) polygons can be
        sub-divided more to give much more detail whereas further
        (small) polygons might only have a single sub-division
        or none at all.

          Another way to make landscapes and terrain look much
        more realistic is to draw curves between two map corner
        points instead of straight lines. This can cause problems
        with clipping, hidden surface removal (not to mention the
        maths involved to calculate the curve !).

#############################################################################
Ŀ
 #B:                    Non-Linear (curved) Landscapes                     

#############################################################################

          Instead of simply using "Linear Interpolation" (drawing
        a straight line between 2 points) when drawing each map
        polygon which gives a sharp looking landscape, we could
        use Splines or Bezier-Curves instead. But they require
        far more work than a simple straight line because the
        slope between two pixels can change by varying amounts so
        that clipping them inside the screen boundary edges can be
        more difficult and SLOWER. I haven't look too much into
        these kinds of curves as the few descriptions and source
        I have seen are too bulky and slow for a fast 3d terrain.
        They tend to leave gaps between two points on a curve
        which must be connected with a straight line also they
        work in a random-access like way (or more correctly a binary
        tree way) so the address of these pixels on the curve must
        be recalculated. What we actually want to do is to move from
        pixel to neighbouring pixel using the least number of
        computations as possible for the other axis. This means that
        we want to increment along one axis a pixel at a time and
        calculate the other axis co-ordinates from there.

          Bezier curves seem to use a stack based sub-division
        method to create a number of points on the desired curve.
        After a number of these sub-divisions short lines are drawn
        between them to give the appearance of a continuous curve.


#B1: Circles

          The best known curve is a circle or arc of a circle. This
        has the properties of having a fixed radius from one point
        (the origin) and having a constant change of slope from one
        pixel to the next. Circles can be drawn in two ways. Either
        using the parametric equation:

                        x = radius * COS (angle)
                        y = radius * SIN (angle)

        which can also be used for ellipses, like this:

                        x = horz_radius * COS (angle)
                        y = vert_radius * SIN (angle)

          But both these equations give a random placement of pixels
        around the circumference of the circle or ellipse. This means
        that recalculation of each pixel is required. Also gaps or
        pixel overdraw can occur with this method.

          A much better method is to use  R = X + Y  equation
        for a circle. This may look much slower than the 2 multiplys
        used for the parametric method, but it can be performed
        using a SUBtract and 2 ADDitions. The advantage of this method
        is that we can calculate one axis value given the other.
        This means that we can easily scan-convert it and draw
        horizontal lines for a filled circle. First rearrange it
        to give the value of X for any given Y line.

                        X = R - Y

          We take the square-root (SQRT) of X to give X, now we have:

                    
                X =  R - Y        same as:     X = SQRT(R*R + Y*Y)

          In pseudo-code it would be:

                R = radius of the circle

                for Y = 0 to R step 1
                        X = SQRT(R*R-Y*Y)
                        line (-X,+Y) to (+X,+Y)
                        line (-X,-Y) to (+X,+Y)
                next Y

          As the Y variable only changes by 1 and R*R doesn't change
        inside the loop a few speed ups can be made. I will use the
        names XX to represent X and RR for R" and so on.. We also
        know that the first value of X will be equal to R because
        X=sqrt(R*R-Y*Y) and as Y=0 this means X=SQRT(R*R-0*0).
        Also as Y increases X will decrease. Looking at sequential
        squares and square-roots we can work out that each square
        number changes by 2 * n + 1 where n is the current SQRT.
        (If you don't understand where the 2n+1 comes from write
        down the first 10 square numbers and find the difference
        between each one, it should increase by 2 for each number)

                 number       square number      difference
                         
                 0                0
                 1                1                      1
                 2                4                      3
                 3                9                      5
                 4               16                      7
                 5               25                      9
                 6               36                     11
                 7               49                     13
                 8               64                     15
                 9               81                     17


          We can use this 2n+1 fact for finding the next and previous
        square numbers without having to do a multiply or a SQRT
        within the main loop.

        Here is a working QBASIC listing to demonstrate:

-----------------------------------------------------------------------------
                SCREEN 13
                XC = 160 : YC = 100

                R = 90
                RR = R * R

                X = R
                XX = RR

                YY = 0 * 0

                FOR Y = 0 TO R STEP 1
                        LINE (XC-X, YC-Y)-(XC+X, YC-Y)
                        LINE (XC-X, YC+Y)-(XC+X, YC+Y)

                        YY = YY + (Y + Y + 1)

                        LL = RR - YY

                        WHILE XX > LL
                                X = X - 1
                                XX = XX - (X + X + 1)
                        WEND

                NEXT Y
-----------------------------------------------------------------------------

          The above can be optimised much further, it is left
        to the reader as an exercise (heh heh). A clue is to
        only 45 degrees of a circle and using (Y,X) co-ordinates
        to plot the other 45 degrees.


#B2:Sub-division & Mid-points

          I have already said in the patchwork section about taking
        a flat polygon and sub-dividing it down into a number of
        smaller polygons so that a greater range of shading can
        be drawn. The quickest sub-division is the mid-point. This
        is just the average co-ordinates of the two end vertices.
        This average must be performed on each co-ordinate axis, so
        for 2d sub-division 2 of these averages must be performed.

                e.g.
                              x1 + x2                 y1 + y2
                        xc =           yc = 
                                 2                       2

          This gives the 'mid-point' of the two end points (x1,y1)
        and (x2,y2) as co-ordinates (xc,yc). Even though we have
        sub-divided these co-ordinates it is still a LINEAR-
        INTERPOLATION between them. If you draw a straight from
        (x1,y1) to (x2,y2) then (xc,yc) would also be on the line
        exactly at the centre (the mid-point). This isn't too helpful
        for drawing curves is it ? But this type of averaging is
        used in Bezier curves (where a number of average are used
        to produce a new point) and could possibly be used in line
        drawing (the line is split into 2 halves using the centre
        point which is plotted and then these are split into 2 and
        so on...)


#B3:Fractional Curves

          There is one thing which you must know in order to draw
        curves, You MUST have 3 or more points to define a curve
        otherwise it is simply be a straight-line (2 points) or a
        single pixel (1 point). Given two end points of a map cell's
        edge it does appear that we can not draw a curve unless
        we define a 3rd vertex which means more storage and more
        processing for rotation and projection.
          But why don't we use a neighbouring cell vertex to
        be the 3rd point ? It would be nice to shape the curve
        using the neighbouring cell vertices from BOTH sides rather
        than just one. So now we have 4 vertex points (which is
        another favourite number for programmers 8)
        Even Bezier curve method seems to use 4 control points to
        define the curve, as 3 is not a quick number to divide by.

                                   V                       vertices
                e.g.             ..o..                  
                               ..     ..                   1  (Ax,Ay)
                            B .         .  C               2  (Bx,By)
                             o-----*-----o                 3  (Cx,Cy)
                            /      M      \                4  (Dx,Dy)
                           /               \
                          /                 \
                         /                   \
                        /                     \
                       o                       o
                     A                           D

          In the above diagram we have 4 vertex points A,B,C and D
        and we want to draw the B..C line section. We know that
        it must be shaped by the neighbouring sections A..B and C..D
        We can find the mid-point M co-ordinates of section B..C
        by doing this:

                      Bx + Cx                 By + Cy
                Mx =           My = 
                         2                       2

          But the point (Mx,My) lies directly on the B..C line
        section. What we want to do is push it up away from the
        mid-point M and towards point V. We can see that both the
        neighbouring line sections A..B and C..D are pointing
        upwards, this means that By > Ay and that Cy > Dy. We can
        simply use the length of each one and adjust the mid-point
        M by some fraction of the two. The easiest is a division
        by a power of 2, so lets use 8.

                      By + Cy     By - Ay     Cy - Dy
                My =  +  + 
                         2           8           8

          The same could also be done for the X co-ordinate of
        point M, like this (but using only 1 variable axis means we
        can step along one axis 1 pixel at a time).

                      Bx + Cx     Bx - Ax     Cx - Dx
                Mx =  +  + 
                         2           8           8

          This fractional method (moving the mid-point by a
        scaled down amount of the surrounding map cells) can be
        applied in both directions over the 2d map array, so that
        a map cell is shaped from north-to-south and from east-to-west
        this would give a cushion affect where the cell is shaped
        from it's four surrounding neighbour which is what we want.
        This technique (with a little care) can be used repeatedly
        to sub-divide again and again, using the M point with the
        (Mx,My) co-ordinates to be an end vertex. I have        coded a few
        little test programs in QBASIC to check out the algorithm
        and it does work. It is best to use map cell lengths which
        of a power of 2 (128, 256, 1024 etc..). Use a buffer of the
        same length and sub-divide the mid-point of the two ends
        and then the mid-points between these 2 halves and so on...

  o--------------------------------------------------------------o

  o------------------------------1-------------------------------o pass 1

  o--------------2---------------o-----------------3-------------o pass 2

  o------4-------o-------5-------o-------6---------o-------7-----o pass 3


#B4:Parabolic Curves

          Another way to draw curves quickly which I have recently
        figured out from a scrap of info which hinted at this
        method but gave absolutely NO source code or formula.
        ("...parabolic approximation...using 2 Adds per pixel...")
        After a spark of inspiration and head scratching I worked
        this method out, I'm not sure if this is how the person who
        hinted at this technique found it or whether this is what
        they meant but here goes ....

          A parabolic curve is like the trajectory of an object
        fired out of a cannon and affected by gravity. (I'm not
        even going to think about drawing an ASCII diagram :) We can
        easily perform a "fake-G" function by using two variables
        one for speed and one for the change in speed. In essence
        we do a cheap acceleration or deceleration of one axis
        co-ordinate while we simply step the other by a set amount.
        A parabola can be drawn with the following formula:

                e.g.
                             x"
                        y = 
                             4a

          The above calculation could be done within the loop
        for every X co-ordinate, but it can be done using the
        hinted at 2 ADDs. Here is a QBASIC example:

                        screen 12

                        a = 100

                        i = 1 / (2*a)
                        s = 0
                        y = 0

                        for x = 0 to 100
                                pset (x,y)
                                s = s + i
                                y = y + s
                        next x

          Yep, it's THAT easy. The only complication is the fraction
        part of i, s and y need to be kept, so either floating-point
        or fixed-point numbers must be used.

                         DANGER, DANGER WILL ROBINSON
                        
          There are two minor problems with the 2 ADD method.

        1) Accumulative errors will occur for many loop iterations

        2) there is a divide to calculate the 1/(2*a) term


        Point 1) don't do very long lines or recalculate after a
        number of times. You could possibly round the increment
        either up or down this may help a little.

        Point 2) you can build a small table of 1/(2*a) for every
        value of a you wish and look-up the value instead of doing
        a divide every time. You could also do the rounding when
        the table is generated so gaining a few more CLK cycles.
        Remember the table MUST be either in a floating-point or
        a fixed-point format to describe the fraction !


#############################################################################
Ŀ
 #C:                          Voxel Landscapes                             

#############################################################################

          I believe this technique was first used for medical
        purposes (ultra-sound or something...). In many ways it
        is identical to patchwork landscapes where only a
        coarse resolution is used to describe every 100th or
        1000th point height across the landscape. The problem
        with patchwork is that to get a reasonable looking
        landscape you need to use many corner points to allow
        a good level of resolution and decent fine detail. But
        the more vertex corner points are used the greater the
        storage and the greater the CPU workload. It's a bit
        like digitising sounds as digital samples. Use too few
        samples and the sound is terrible, use too many and
        memory rapidly sky rockets.

          Unlike patchwork, in Voxel landscapes the height difference
        between corners are interpolated in a NON-LINEAR
        fashion. That is, they are curved to give the impression
        of a smooth, rolling landscape rather than a bed of nails.
        The important thing to remember is that these curved edges
        between corner vertices are calculated and drawn in REAL-TIME.
        So given 3 or 4 vertex points a quick curve is approximated
        and drawn to the desired scale. The sub-divisions between
        each vertex are NOT stored, but must be calculated.
        This does require more CPU time than a flat patchwork
        landscape, but the result is usually much more realistic
        and it is possible to get away with less corner points
        unlike the patchwork method which often needs many corner
        points to help iron out the jagged spikes.

          I think the word 'Voxel' means Volumetric Pixel or something
        like that =)


#############################################################################
Ŀ
 #D:                         The "Planet" Method                           

#############################################################################

          For want of a better description I will use the title
        "Planet Method" to describe what is possibly the most
        obvious way to define a 3d environment. When first
        learning to program 3d stuff every programmer starts off
        by drawing a polygon and then building an object from
        a number of polygons. Now he/she wants to take the next
        step and build a 3d world with more than one thing in it.
        The inky black background of space is normally chosen
        and suddenly lots of space ships are zooming about. And
        maybe a few circles are drawn here and there as planets.
        So now we have built a game universe from these movable
        objects and each of them are made up from polygons. We
        have placed 3d object models randomly in the world.

             This is what I mean by the "Planet method".

          If we want to draw a more Earth bound scene then
        instead of space ships we could draw houses or trees.
        All we need is the world co-ordinates of each object
        together with a 3d shape and we could quickly make a
        dense forest by drawing the same polygon tree again
        and again in different places.

          This method does have advantages over a huge-
        list-of-polygons approach where each and every polygon
        is just defined in a very, very, very big list.
        For a start the same object can be reused any number
        of times (as in the above example of a forest). And
        secondly it is a form of hierarchy which allows rapid
        rejection or acceptation of objects from our view-point.
        If the world position of an object is not within our
        view-point's range and direction then we don't need
        to bother checking all the object's polygons. On the
        other hand if an object's world position is visible
        from our view-point then we can draw each polygon.
        So in affect we can reject many polygons and vertices
        simply by processing the object's world position.
        You can think of the world position as being the
        parent and the vertices and polygons as the children.

          It is possible to take this hierarchical method a stage
        further and describe sub-objects as children from a
        main object. For example a huge mile long space-ship
        could be built from say, 10 large objects (the engines,
        the wings, the hull, the cockpit). Now if the you were
        able to fly very close up to an engine then most of the
        rest of the ship will be clipped off the screen. We could
        now draw the sub-objects (the fine detail polygons/lines)
        on the engine object. And the player says, "Wow, look at
        all the detail on these ships, think about all those
        polygons this engine is drawing...." and the programmer
        sits back and grins widely thinking "I've only drawn a
        few sub-objects... this player is a right clown."
        We have quickly rejected large groups of polygons simply
        be rejecting large objects (e.g. the ship's wing, tail
        and so on..) Only when an object is visible do we consider
        drawing it's finer detail on it's surfaces.

          This 'planet' technique is sometimes used for drawing
        the scenery (trees, houses etc..) It was used years
        ago on slow computers, but is often used these days for
        monsters and movable objects within the 3d world.

          The problem with this free placement of objects in
        the 3d universe is that the objects often need to be
        sorted in decreasing order of relative distance from
        our view-point so that the most distant objects can
        be drawn before closer ones.


#D1:More of the same..

          With this placement of the same object again and again
        (like trees) it is possible to do some cheats. Instead of
        rotating, projecting and drawing each 3d tree from it's
        3d model for every single tree in the forest why try one
        of these tricks:

        1) rotate and project the 3d tree once then simply scale
           it up or down for trees at different distances.
           (this reduces the rotation, hidden surface and projection
            calculations to a minimum amount)

        2) store pre-rotated and pre-projected polygon lists for
           boring objects like trees, stones or asteroids.

        3) scan the tree into an off-screen bitmap buffer then
           scale this bitmap as a sprite onto the screen.

        4) simply use a 2d bitmap sprite and scale it onto the screen
           (this was used in DOOM, Wolfenstein and System-Shock for
            objects and creatures).


        method 1) this allows recolouring (or re-texturing) of each
        object which is important to make trees look similar but
        NOT identical to each other. The good thing about this
        technique is that a tree 3d object can be drawn correctly
        from any angle once and then repeatedly drawn onto the
        view screen. But ALL the trees face in the same direction.

        method 2) this is good for non-descript items which just
        help to flesh out the 3d environment but are not really
        important. In the case of an asteroid field or a forest
        a reasonable amount of speed can be obtained. The downside
        is that memory is eaten up unless you only have a few
        pre-calculated polygon lists. For spherical shaped object
        or highly symmetric ones this is reasonable.

        method 3) the bitmap buffer must be cleared, built up and
        finally scaled on the screen which takes time to do, also
        the bitmap can not be recoloured unless a pixel-by-pixel
        method is used which is far slower than using a polygon
        list and changing the colour of each polygon.

        method 4) This is a much faster way than building up the
        bitmap in real-time, but it suffers from having to store
        all the pre-drawn images in memory and again a pixel-by-pixel
        method must be used to recolour or shade images.


#D2:Grid based Planets

          Rather than a vast list of every 'planet' object in the
        world, we can employ a simple, but effective technique to
        localise these moveable 3d models. The problem of maintaining
        a single list of everything it that is can take a large
        amount of processing time, most of which is unnecessary.
        What we really want is do is only handle those items within
        a certain range from our view-point. This means that things
        on the opposite side of the world are ignored so that much
        closer ones can be given more attention. There are various
        ways to do this from processing a sorted list of objects
        to one of the simplest, the grid based method which follows..

          Using a grid based map (either a 2d or 3d array) it is
        very easy to start at a certain place and immediately find
        the surrounding neighbours in any direction. To visit all
        the neighbours at a range of 3 cells we can either scan
        a 7x7 square with our starting point at the middle or
        we can scan a circular area with a radius of 4. The scanning
        can be done extremely quickly by using a list of displacements
        from a starting point. This doesn't have to be done in real
        time so can be pre-calculated before hand. A circular area
        with a radius of 4 could look something like this:

                
                             3  4  5          
                
                          2  18 19 20 6       
                
                       1  17 31 32 33 21 7    
                
                       0  16 30 X  34 22 8    
                
                       15 27 37 36 35 23 9    
                
                          14 26 25 24 10      
                
                             13 12 11         
                

          The 'X' marks the origin (our start point) and the numbers
        represents the order in which these neighbouring cells
        could be visiting for rendering or processing NME's etc..
        Please note how these cells are numbered, this is the order
        in which they should appear in our "visiting" list.
        Basically the furthest cells are defined first followed by
        the next closest and finally the adjacent cells. This way
        it is very easy to draw the more distant objects first and
        then to overdraw them with closer ones.

          If you want to work outwards from the origin then number
        these cells in the opposite order, starting at the surrounding
        cells, then their surrounding cells and finally the outer
        ones. This outwards method does have a few advantages that
        the inwards one doesn't. 1) It is possible to clip distant
        objects behind closer ones using an "S-BUFFER" (span buffer)
        technique (only drawing in the background gaps left by the
        closer objects). 2) We can choose where we stop in the list
        more easily. This can be useful for moving the horizon
        cut-off point for low-detail on slower PC's.

          Another method could be to define the radiating cells as a
        number of lists each one representing a certain radius.
        Because each list defines 360 degrees you could reject 50% or
        more of the cells based on viewing angle (this won't work if
        you can change your X-axis angle by looking up/down).

          It is also possible that you wish to scan outwards in
        straight lines rather than an expanding spiral. This would
        allow you to direct the map scanning and so ignoring any
        map cells behind your view point. I believe this is a basic
        form of "Ray Casting", tracing lines or 'rays' across a
        map until either an obstruction is hit or the horizon cut-off
        distance has been passed.

          "Okay", you might say, "but where is the planets then ?"
        Well we can define a link from each map cell to a list of
        objects ("planets") which are positioned in the cell. This
        means given just the cell we can use it's link and find what
        objects it contains. This is not only useful for rendering
        the environment and any furniture it contains but it can
        help speed up collision detection and movement algorithms.
        If you use a linked-list approach to describe the items
        within a map cell then it means you can nuke an entire cell
        simply by zapping the link from the cell, so by breaking
        the chain of linked-list items.

          But if maps are big and/or are 3-dimensional then this can
        begin to take up vast amounts of memory. For example,
        imagine a 50x50x50 grid which uses a double-word for each
        contents link. This would take up 500,000 bytes and that's
        ONLY the links, add on top of this the terrain/texture data
        for each cell and it soon become apparent the memory cost.
        In the most optimistic scheme the texture details could take
        6 bytes each (1 byte for each face of a cell cube) that
        brings to total to 1,250,000 (over 1 meg) and remember this
        is just a 50x50x50 map which is small compared to the size
        of many recent games.


#D3:3d-Linked Lists & Dynamic Neighbours

          You might have worked out that most of the previous 50x50x50
        map array is probably going to waste because a great deal of
        all those 125,000 cells are only being used as walls, floors
        or ceilings. The problem is that a cell can have a variable
        number of data components which need to be described (the
        textures, surface type, lighting, damage, contents list for
        the planted objects and so on..). The very minimum amount
        of data that a map cell would require could be as low as a
        single byte and the maximum could run into 100's of bytes.
        We can't allow dynamic sizes of cells within the grid
        because it would not then be an array and we would have no
        quick way to navigate a path from cell-to-cell which is
        THE main reason why we are using an array.

          One solution could be to create neighbour links of either
        a 2d linked-list or a 3d linked-list. This would certainly
        help navigation through the array but has two large problems.
        1) Linked-lists are SERIAL data structures, we can NOT
           randomly access the Nth item without following N-1 links.
        2) Memory requirements would sky-rocket. For example the
           50x50x50 array would require 3,000,000 bytes JUST for the
           links (3d = 6 faces = 6 links * 4 bytes * 50x50x50) which
           is over 2.8 Megs !!

          This neighbour-link method is similar to the "INLET" method
        described elsewhere in this document (see that for more info).


#D4:Tokenized Grids & Shared Items

          But as we already know a lot of the 50x50x50 array is going
        to waste just by being used for walls or the padding between
        unused areas and rooms. There is a good, more memory friendly
        solution to the navigation and dynamic cell size problem that
        doesn't need the neighbour links. It's SO simple it hurts =)

          We can define the map as being a 50x50x50 array of single
        element links and use just one link to point to the variable
        sized contents/cell data list. The navigation is once again
        a matter of stepping through the array using a constant
        step size. And so the pre-calculated "visiting" spiral list
        technique can be applied to the map again. The map array
        has returned to being a random-access data structure and
        so the Nth element is simply N*step bytes away (in this
        case 4 bytes per cell).

          The dynamic storage can be quickly used, modified and
        most useful of all, can be RECYCLED (within reason).
        Because our 50x50x50 map array is built from links
        (or should that be pointers ?) and the dynamic cell data
        structure can be anywhere in memory, we can re-use the
        same cell data just by using the cell's address more than
        once.
          In the below greatly simplified diagram we have a
        9x7 map array. Within the array we have a single link to
        a description elsewhere in memory which lists it's "contents"
        (the inhabitants, lighting, environmental structures and
        possibly background sound effects) which are present in
        a cell.

             Array of Pointers (single Links)        Cell  Description
            
            0  0  0  0  0  0  0  0  0         0  Solid Wall, rock
             1  floor
            0  2  2  2  2  0  0  0  0         2  ledge
             3  lift
            0  2  4  4  2  6  0  0  0         4  lava
             5  floor + rock
            0  0  4  3  2  0  0  0  0         6  Wall + switch
        
            0  0  4  1  1  1  0  0  0 
        
            0  0  4  1  5  1  0  0  0 
        
            0  0  0  0  0  0  0  0  0 
        

          Doing it this way means a very large area can be filled
        with the same cell description link over and over again
        without the need to have multiple copies of identical
        floor, wall, ceiling textures and other more interesting
        stuff. Objects and creatures could be defined within the
        cell description as well..


#D5:Movable Items & Monsters

          There is a problem with the recycling method and it is
        due to the fact that one cell's contents can be shared
        by any number of other cells which use the same token or
        link address. What happens when you want to move an item ?
        If you delete it from the description then it disappears
        from every other occurrence of it on the map as well.
        Sometimes this is desirable (changing a lake of water to
        lava, a dark square to a light one or a large step into a
        small, climbable one) but on occasions it is not.
        If we placed one monster in the floor (1) description above
        then we would end up with five monsters instead of just one.
        It seems that the advantage of tokenising has prevented us
        from placing individual items on the map. One solution could
        be to define two links for every map square, one for the
        environmental details (wall, floors, lighting etc..) and
        one for the creature in the map cell. But this would double
        the amount of storage needed for the map and what happens
        when we want two or three monsters on the same cell ?
          One answer could be to define a link in the cell description
        and use that to point to the first monster and give the
        monster a link to the second monster and so on...
                              Ŀ
                 >ĳCell Description
                              
            0  5  2        Roof:  Rock    
               Floor: water   
                               Light: 40%     
                              Ĵ     Ŀ
                               Inhabitant     > Monster 1 
                                   
                                                           
                                                           v
                                                     Ŀ
                                                      Monster 2 
                                                     

          This way we could add monsters to a cell description
        just by adding it to the end (or inserting at the beginning)
        of the linked-list.

                But the ABOVE METHOD IS STILL WRONG !!!!!!!

          It may allow an unlimited number of monsters to share
        the same map cell but it suffers from the same problem
        as before, namely when you modify one cell description
        ALL the other instances of it are modified too.
        You could fudge it and whenever you use the "inhabitant"
        link for the list of monsters you check to see if the
        true map location of cell (the array square address)
        matches the monster's map address and use it, otherwise
        the cell has been recycled and used elsewhere. This would
        mean keeping the array address of the square which the
        monster is standing on together with the monster's data
        structure and an extra compare when rendering a cell, but
        it would keep the map array down to a single link per cell
        size.
                     0   1   2   3   4   5      map location
                
                    A  B  C  C  B  E  map array tokens/links
                
                                
                             v   v                item      location
                <<             ĿĿ
        Ŀ           >> Monster 1    2   
        Cell Description                    
                                            ĿĿ
         Roof:  Sky                          Monster 1    3   
         Floor: Gravel                      
         Light: 80%                         ĿĿ
        Ĵ                     Gold Key     2   
           Inhabitant   >         
        

          In the above diagram we have two cells sharing exactly
        the same cell description. This means that BOTH share
        the same "Inhabitant" link and list as well. So the two
        monsters and the gold key seem to appear twice on the
        map, this is where the 'location' field comes into play
        in the item's data structure. We compare each one
        against the actual address on map array and only allow
        those which have the correct location. In the above
        example the cell description is used by map cells 2 and 3
        where cell 2 has Monster 1 and the Gold key and cell 3
        has Monster 2 in it. We can get to the cell description
        from two different paths and so it is possible for the
        "Inhabitant" link to fork off into two path also. The
        location field is used to determine which.


#D6:Background Tails

          There is another way to solve this junction problem
        where two map array links can lead to the same destination.
        If we have a spare bit in our map token/link then we can
        use it to indicate a vacant or occupied cell and then use
        just the item links to chain cohabiting items/creatures
        together. Now at the end of this inhabitants linked-list
        chain we point back to the cell description (the background).
        Doing it this way means we don't have to worry about
        splitting from the cell description for the different map
        locations which share the same cell description, we just
        point the tail of our item/creature list to the same end.

                     0   1   2   3   4   5      map location
                
                    A  B  C  C  B  C  map array tokens/links
                
                                       >Ŀ
              <   >Ŀ         
        Ŀ                   Ŀ   
         Monster 1                     Monster 1    v
                              
        Ŀ                                  
         Gold Key                                    
                                          
              >><         
                                <
                        Ŀ
                        Cell Description
                                        
                         Roof:  Sky     
                         Floor: Gravel  
                         Light: 80%     
                        

          In the above diagram we have the same items but this
        time we use the tail of the inhabitants to point to the
        same cell description ending. You may have noticed that
        map cell location 5 using the same 'C' cell description
        but this time no items or creatures are in the chain
        so it points directly to the cell description.
        To simplify the cell description structure (because there
        can be hundreds or thousands of them) I used a single flag
        bit to indicate an inhabitants link OR a pure cell
        description link. This means we can quickly check to see
        if a cell is empty or not. It does create an extra test
        in the rendering algorithm but this is offset by the
        saving made by not having to compare the 'location' fields.

          Depending on how your renderer works this background-last
        order might be good or bad. If you draw from front-to-back
        then this is good because the background is the last item
        in the chain. If you draw in the opposite order then you
        may need to place these items on a stack and then pop them
        to obtain the correct background-first order.


#D7:Coarse Area Nets

          This is another useful (and very similar) method for
        localising 'planet' objects on a large and/or highly memory
        intensive map. Going back to the 50x50x50 array with it's
        125,000 cells it is obvious that the maximum number of items
        (creatures, objects) we would want to place within it will
        be far lower than 125,000. In the case of creatures only
        1/100th or less could be our limit. It seems wasteful to
        have such a high resolution array for such a relatively
        few number of items, so why not define a 25x25x25 array or
        just a 5x5x5 array instead ?

          The basic idea is to place a far lower resolution array
        over the memory-guzzling one and use for example 1 of these
        coarse net sections to represent 2x2 or 4x4 of the underlying
        map cells. Each net section is very similar to the map cell
        except the spacing between each corner is far bigger and it
        only describes movable or static items such as creatures or
        collectable objects and the like, NOT scenery graphics.

          There is no real problem from only using a 2d CAN
        ("Coarse Area Net") array to partition a 3d map array apart
        from the extra work involved checking that items are on
        the same layer. e.g. if your 3d map used (X,Y,Z) co-ordinates
        but your 2d CAN used (X,Z) then you would need to check the
        (Y) co-ordinate of the occupied net section to make sure
        items are not above or below your map position.

          This grid based method can also be applied to non-grid
        based maps where the environmental structures do not stick
        to the rigid cell boundaries of a map. Where the vertices
        of walls, floors, ceilings and so on can be placed on at
        any arbitrary co-ordinate value these vertices can too be
        chopped up into groups using the "Coarse Area Net" method.
        This could be one possible way to prevent having to rotate
        the entire level's vertices, we only need to rotate the
        few that are contained with the nearest local net sections.


#D8:Occupied Sub-Nets

          The old tree syndrome seems to have infecting every 3-d
        programming idea including this one. The problem of using
        a low resolution grid is that it divides space very poorly
        with any number of items forced to share the same cell.
        But using a high resolution grid means wasting memory.
        Using a 16-bit number for the co-ordinates means 65536
        different values can be defined. Using this for a 2-d grid
        would mean 65536*65536 grid (4,294,967,296 cells !!).
        As I have mentioned before only a small fraction of all these
        cells will actually be used for items.

          The idea of this method is take the best of both low and
        high resolution grids without incurring the huge memory waste.
        First use a very coarse grid. This will be the root grid.
        Find where in this grid items are and then create a sub-grid
        for each occupied cell. This means that only the coarse cells
        which are used will have a finer high resolution sub grid and
        all those empty root cells won't have any siblings, so saving
        a large amount of memory.



#############################################################################
Ŀ
 #E:               Sorting out the performance problem                     

#############################################################################

          Whether you use the incredibly slow BUBBLE, RADIX or
        QUICKSORT method there is a lot of work to be done for
        each render cycle and the greater the number of polygons
        the greater the amount of sorting. As ALL forms of
        sorting involve lots of memory accessing this can be
        very costly in terms of CPU time. Techniques such as
        BSP (Binary Space Partition) can be used to cut down
        on the depth-sorting workload, but unless your 3d engine
        is completely deserted then you will need to sort the
        objects and inhabitants into their order of distance.

          As far as I know BSP only works with stationary
        polygons (or at least polygons which don't move in relation
        to one another).
        This isn't much good for moving things is it ?

#E1:Delta Sorting

          One solution is what I call "Delta" sorting, using the
        previously sorted list as the starting point for the next
        sort. This can be extremely effective because objects
        tend to mostly change by small amounts so only a few
        items need to be re-sorted into order. In the very worst
        case of a 180 turn the entire list needs to be resorted
        but this tends to happen very rarely. And when it does you
        could reverse the entire list and apply a small amount
        of sorting. Using the change in viewing/rotation angles
        might be one way of estimating the amount of re-sorting
        which needs to be done. You could also keep this sort
        list updated by checking each object whenever it moves.
        If an object stays still then it's a fair assumption that
        it doesn't change it's position within the sort list, so
        won't need sorting.

          I have mentioned elsewhere in this document about
        "group" algorithms (hierarchical data structures). These
        are very efficient ways of organising data because it
        allows a quick scale to be imposed on a large amount of
        data. This can help us speed up 3d objects and sorting.
        Imagine having 3 (crude) monster 3d models each with
        2 arms, 2 legs, 1 head, 1 torso and 2 weapons. This means
        a total of 24 parts and if we use a cube for each part
        then we suddenly we have 144 polygons and thats BEFORE we
        add the background, add more monsters or define decent
        3d models. We need to sort these 144 polygons into some
        form of order before we can begin to draw them.

          But why break each monster down into polygons ? Instead
        sort each monster's world position and then sort their body
        parts individually. This is in affect the same as a radix
        sort algorithm where the most significant digits are sorted
        first and then the less significant ones. Of course this
        'sibling sort' (where objects are only sorted within their
        own level) may cause glitches when one monster is close to
        another and the nearest one's arm should be behind the next.

          If you do want proper depth-sorting for close monsters
        or objects that properly order tangled arms or legs then
        I would use another 'delta' trick. Instead of starting
        at the very first item in the sort list and searching
        for the place to insert a polygon (or whatever)
        or searching from the central point in either direction,
        why not try searching from the last inserted item. This
        should help speed things up a lot because we are going to be
        sorting fairly local groups of items such as monsters
        or furniture etc... where their co-ordinates only occupy
        a mere fraction of the entire sort range. (i.e. all of a
        monster/s body parts are located within a short distance
        from it's main torso).

          e.g.

                0 .............................. max    <- sort range

                     abcdef
                               mnopqrstuvw

                         ghijkl
                                    xyz

          In the above diagram we need to sort 4 objects:

                      object             items
                               
                        1               abcdef
                        2               ghijkl
                        3               mnopqrstuvw
                        4               xyz

          Each object has a varying number of items from 3 to 11
        and each of these 26 items must be inserted somewhere
        in our sort list. As I said before a 'group' approach
        can be useful to some problems and it can to this one.
        We can take each object at a time and insert each item
        into the correctly sorted place in the list. As the
        items that make up each object tend to be very close
        to each other we can use the first item's place to
        start searching from. In the case of object 2 we would
        insert item 'g' and then search from that place for
        all the other items (h,i,j,k and l). As you can
        hopefully see this should be much faster than beginning
        at any fixed position (like the start or the middle).

          The above method can be made a little more clearer
        by thinking of sorting in a hierarchical way. We can
        sort the world position of each object and use these
        starting places as origins for the sorting of each
        object's items.

          One advantage over the radix sort is that it is
        very easy to implement this kind of 'delta-sort' on
        linked-lists, we just keep a pointer to our last
        modified position in the chain. Where as radix sort
        (I think) needs to resort the entire list every time
        and must be able to randomly-access the sorting list.
        Linked-lists lend themselves very easily to local
        transitions (moving forwards or backwards by one element
        at a time).

          Also remember that if we sort all the object's world
        positions into order first before we sort each one's items
        then we will be inserting object in a mostly sequential
        way, so the previous insertion point is a handy place to
        start searching from.


#E2:Minimal access - Index tables

          It should be obvious that sorting and the reordering
        of data structures must involve the least number of
        memory accesses as possible. One way to rearrange
        chunks of data quickly is by using an 'index' or
        'pointer' table and only ever sort the entries in that
        and don't ever swap big areas of memory around.
        Only the entries in the table are modified, not the
        data structure to which they point. This does have
        a few drawbacks.

                1) a large enough table must be allocated
                   for the maximum number of items to sort.

                2) you must read a pointer from the table
                   before each sort field can be compared.

                3) Insertion & deletion takes far more time
                   then a linked list method.

        e.g.
                BubbleSort:
                                src = table[n]
                                flag = 0
                        for n = 1 to Number_Of_Entries-1
                                dst = table[n+1]
                                if dst[distance] > src[distance] then
                                                table[n] = dst
                                                table[n+1] = src
                                                flag = 1
                                src = dst
                        next n

                if flag = 1 then goto Bubblesort


          The above bubble sort is SLOW, but it hopefully shows
        how the index 'table' of pointers works. The good thing
        about this method is that each data structure can be
        of varying sizes as long as the [distance] field remains
        at a constant displacement.

          Another way is to use linked-lists to chain all the
        objects to be sorted together. For collision detection
        and movement this can be useful because we can quickly
        discover neighbouring objects. A disadvantage with
        using linked-lists is that binary-searches or other
        random-access techniques can not be used because it
        is a serial structure (to find the Nth link you must
        follow N elements). So the index method is good for
        this reason, to find the Nth element we just index
        into the table, also on 80x86 CPUs the index table
        will cache in much better as only a single dword is
        needed for each entry and they are continuous in
        memory which just how the CPU likes it 8) The linked-list
        method is slower for locating a certain element in the
        chain because the CPU must jump about through memory
        and this doesn't cache very well.


#E3:Squatting Objects

          Another technique which can be employed to help speed
        up sorting is to place tags on the map to indicate where
        objects or creatures are. If parts of the 3d environment
        does not change position in relation to one another
        (99% don't) then as we rotate, project and sort the
        environment we are sorting the objects/creatures (tags) too.
        This can give rise to an extra performance gain in
        way of clipping. If a creature or object is in a room
        and the room is totally clipped (or hidden from our view)
        then we can reject both at the same time without the
        need to check the object/creature. We can associate
        places with their inhabitants and visa versa. In affect we
        have reduced objects and any movable items to that of just
        vertices. Once these position tags have been processed
        like the rest of the background we can decide whether an
        item needs to be processed any further, otherwise we can
        reject the 3d model and all it's vertices and polygons.

          Another reason for tagging what items are in certain
        locations is collision detection and movement. Together
        with the sort list we can confine our collision
        detection to neighbouring items rather than checking each
        and every one. For example if we had 100 items and we
        needed to check for item-to-item collision then it means
        a vast 4950 checks !!! (99+98+97....+2+1). If we confine our
        checks to neighbouring items then only 99 are needed.
        As our sorted item list of objects/creatures is based on
        distance this isn't too difficult. And if we only check
        objects within the same or neighbouring rooms (checking for
        closed doors etc..) and we only check items which HAVE moved
        then this can save even more processing time =)





#############################################################################
Ŀ
 #F:                    Render Attribute Trees (RAT's)                     

#############################################################################

          This is an idea I've had for sometime. It was developed
        after a number of attempts to think of a way to reduce the
        amount of polygons (and CPU workload) in a more global way
        rather than the usual one-by-one basis. Even when you use
        a quick hidden surface check there is still an incredible
        amount of CPU work to do. If a level is made up from many
        1000's of polygons/surfaces then what we want is to quickly
        reduce this large number down to 100's or less.


#F1:Groups and Trees

          The idea of a "group" (or more correctly a "hierarchical")
        approach may hold the secret to new fast renderers. This is where
        I feel most time could be devoted when writing a 3d engine.
        EVERY graphic book I have seen (2d and 3d) focus their eye
        on the individual components rather than the whole picture.
        The few good books usually give you a good description of the
        'atomic-level' of a 3d engine, likes lines, polygons and
        textures if you are VERY lucky. And in the closing chapters may
        say something like "armed with the previous building-blocks it
        should be relativity easy to produce a full blown game etc..."
        With the exception of perhaps BSP (Binary Space Partition) tree
        structures there is very little said the larger issues.
        There is a large amount of work just getting a filled polygon
        on the screen, rotating it, etc.. so sometimes the low
        level of the polygon is where they stop. It's a bit like
        describing a tree in terms of individual leaves. Now imagine
        an entire forest and count all those leaves !!! :(
          All levels and objects are not made from existential polys
        but do share a large amount of relative or exclusive properties.
        (2 Polygons share an identical edge, the front excludes the
        back, the left excludes the right and so on...) The only time
        when the subject of front and back is used is when describing
        hidden surface removal or possibly shading. I would say 80%
        or more of 3d objects are rigid (walls do not buckle, floors
        do not fold inside out and most computer people do not sheer)
        so objects and their components can be thought of as being
        made up from uncrushable polyhedron (a cube for a head, tall
        boxes for legs or narrow coffins for doors etc..). Given
        this information it should be possible to devise some
        hierarchical/tree based system to describe objects AND entire
        levels. To put it simply, we want to discard entire rooms
        and their contents and only render the local stuff which
        relates to our view point & direction in the 3d world.

  NOTE: I'm not talking about BSP (Binary Space Partition) tree
        structures, but some form of hashing/rendering attribute
        search.

          A good example of this is a goldfish inside a bowl inside
        a room inside a certain level inside a building ... etc...
        You wouldn't want to draw the goldfish and all it's polygons
        every time would you ? The most obvious method is to use a
        'contents' list for each parent structure. It could look
        like this:-

                         3d world
                          /    \
                         /      \
                        /        \
                  BUILDING2     BUILDING1
                                   /\
                                  /  \
                                 /    \
                            level 2    level 1
                                         /\
                                        /  \
                                       /    \
                                      /      \
                                     /        \
                                  room 2      room 1
                                   /             \
                                  /               \
                                 /                 \
                                /                   \
                             table                 goldfish bowl
                                                        \
                                                         \
                                                          \
                                                           \
                                                         goldfish

          I know the above diagram might look similar to BSP trees
        but I'm talking about something completely different.
        A BSP tree would place individual polygons at each tree node
        (branch) or at each tree leaf. This "RAT" (Render Attribute
        Tree) method sub-divides the entire 3d environment down into
        smaller and smaller regions where the topmost 'root' node
        is the entire 3d world (or universe) and each level down the
        tree is a sub-region contained within it's parent region.
        The "RAT" method in this case has been used to describe a
        Russian Dolls approach (smaller things inside larger ones).
        So the attribute by which the tree is navigated would be
        a 'contents' or 'inside' one, but other attributes could be
        used instead like direction from the view-point.
        By beginning somewhere in the tree we can easily discard
        very large sections of the 3d environment. Also we can limit
        the how far down the tree we traverse when rendering a
        scene (we only bother with the drawing rooms if the building
        itself is visible).

          The basic idea is to specify a search attribute or guide
        which employs a lost-cost CPU calculation or rule that
        fragments our 3d environment into small, CPU friendly chunks.
        Another attribute could be the INCLUSIVE or EXCLUSIVE
        properties of convex polyhedra where a front (facing us)
        polygon excludes the back face. In the case of 3d levels entire
        rooms could be included or excluded depending on whether a
        door or window was visible (and open of course).

          This tree diagram should remind you of the directory
        structure used in DOS or Windows etc.. The great advantage
        of it is the ability to discard large portions of items
        quickly and correctly. For example if we were in "room2"
        then we only need to draw a table as no other items share
        the same parent ("room2"). Likewise if we were on level2
        then room2, room1, the table, goldfish would be ignored.

          A separate "render attribute tree" would be pre-built for
        each rigid object or level (by the object/level editor).
        Now the engine can use the viewpoint and object orientation
        to create a number of "sieve" parameter(s) which are used
        to guide it through the render tree more quickly than
        checking each and every polygon. At the start the entire
        object must be considered as possibly being visible, then
        after a polygon or so has been classified as hidden or visible
        the tree kicks in. If this polygon is visible then it must
        be now be at the front (facing the view plane) we can now
        reject ALL the polygons on the opposite side to it OR we
        could accept those polygons which share it's direction.
        In essence we use the pre-defined relationships between the
        various components of a object/level to group them together.
        In the simplest example, a cube, the front would exclude the
        back, the top excludes the bottom, the left the right, the
        bottom the top and so on.. It's as simple as that !
        One implementation could be to create a polygon list for
        every possible viewing angle, but this would be far too
        expensive in terms of memory. In effect this list would be
        a lazy form of hidden surface removal. As most engines use
        far more then 360 degrees for each of the viewing angles (X, Y
        and Z) this adds up to a whole heap of RAM, so is useless :(

          Imagine the below shape folded into a cube with it's
        6 faces (a to f). Cut out this shape to form a cube or
        try using a light-bulb box and label the faces a to f.

                e.g.                    Ŀ
                                         a 
                                    Ŀ
                                     e  b  f 
              flattened cube >   
                                         c 
                                        Ĵ
                                         d 
                                        

          We could create the following EXCLUSION lists.

                       Face          EXCLUDE
                              
                        a               c
                        b               d
                        c               a
                        d               b
                        e               f
                        f               e

          If we take face b as being the front and say that its
        visible then it would exclude face d (because you can't
        see the front and the back at the same time). We check
        face a, if thats visible then exclude face c. This continues
        until all the faces have been checked or excluded.
        Of course if the first face b had been hidden then the
        excluded items would be need to be inverted to become
        inclusions instead, so making face d visible.
        The exclusion of faces could easily be done using a bytemap
        or bitmap flag system to denote either HIDDEN or VISIBLE
        polygons/surfaces. This flag map would first need to be
        cleared before each render cycle. This extra CPU time would
        be reclaimed by the savings in the hidden surface checks
        which often use a few multiplications. Where as an
        INCLUDED/EXCLUDED face would require a true/false flag test.
        You might have to employ a 3rd state (UNSURE) to describe each
        polygon face. Whenever this state is found the polygon is
        checked with the normal hidden-surface test (back-face culling)
        then it could include/exclude other polygons. The very first
        polygon should be marked as UNSURE to force a visibility check.

          It should be easy to see that the more complex the object
        the greater the saving 'should' be. In the cube example
        only a single face/polygon made up the exclude/include list
        but for far more detailed objects like an open box for
        example more than one face/polygon can be rejected or
        accepted this way.

        Efficient data/level definitions can reduce all the repetitive
        calculation and data processing that most other "one-by-one"
        programs/3d engines use. Optimising a level rendering algorithm
        should produce a greater performance gain than optimising the
        heavily used polygon scan-converting code, simply because
        the fewer surfaces passing through the polygon drawer the better.
        Another area worth spending time on is the clipping/surface
        rejection. Again the smaller the number of polygons that you need
        to process and draw, the faster your 3d engine will run.


#F2:Freedom vs. Scope Lists

          One of the advantages of using a 3d based environment is that
        the player can explore and view from an almost infinity number
        of angles and places. But this also means that the graphics
        engine must cope with a great deal of flexibility. The kind of
        game in which a 3d engine is going to be used should dictate
        the level data structures and rendering technique used. For
        example a racing or track based game such as Screamer, Motorhead
        or any other of the latest circuit driven ones are much
        easier to program in terms of their level design than a more
        general and flexible exploration engine like that used in Quake
        or Unreal. By using a track based game engine it is possible to
        design a level in a linear way using nothing more complex than
        a circular list. Even the few tracks which allow the player to
        choose between two possible paths can be modelled in this way.
        All that is needed is another list which can followed instead
        of the normal circuits path, then at the end of this list it
        can be pointed back to rejoin the circuit again.

          Because a track has only one start and one finish point we can
        apply quite a lot of pre-processing to it. We can store the
        track as a tokenised list of buildings, sign-posts, road types
        and other hazards. This means that as the player's vehicle moves
        along the track we can use a tail and head approach to guide
        the engine to render only a very small section from a circuit
        instead of processing the entire thing in one go. The 'tail'
        could be our view-point and the 'head' could be the distant
        horizon. So any building, object or polygon behind our view or
        further then the horizon is ignored. If a track is defined in
        a building-block way using a list of world co-ordinates and
        object tokens (a bit like the planet method) then as each
        building/structure comes into the visible body-section of the
        track (between head and tail) we can transform the vertices
        and draw the polygons. This way we are not transforming unused
        vertices or processing polygons on the other side of the track.
        I will call this method of rendering the "scope" method as only
        a very small region of a level (circuit) is processing at any
        one time. In essence the renderer is fitted with blinkers, this
        prevents it from seeing too much of the map and so speeds it up.

          Games such as Quake, Quake 2 and Unreal are unable to employ
        this "scope" method because their environments are interconnected
        on a far, far greater scale than any racing game I have seen
        (so far). They do not conform to a simple looping circuit which
        has a single path to follow along the twisting, linear track but
        have a web of connected rooms, sub-rooms and open areas. This
        means the player can choose to follow any of these possible paths
        and not just drive forwards or backwards in their vehicle.
        This freedom is good for the player but bad for the programmer.
        As I have said elsewhere in this large document CPU's really
        like sequential data and dislike parallel or branching data
        structures because some form of selection process is needed to
        direct an algorithm along a certain pathway and this takes time.
        The advantages of using a "scope list" can not easily (if at all)
        be applied to these freedom based environments and when attempted
        can cause if not coding headaches, large storage problems.

          As there are a vast number of possible paths through these
        highly interconnected environments there is a vast number of
        scope-lists to represent each one. Their paths will cross
        in many places where one list runs north-south and another
        runs east-west, of course there can be many more directions
        than the 4 compass points. Also as current gaming environments
        have taken the step from a 2d based map (i.e. Doom, Wolfenstein)
        to a true 3d one, they need to able to handle vertically joined
        areas (rooms upon rooms for example). So instead of a 1-d
        linear list we have something like a 3-dimensional web. To call
        this tricky is a slight understatement.


#F3:Environment Webs & Plants

          It might first seem that a true 3d environment must be
        defined and processed in it's entirety because of the
        immense number of possible viewing angles and view points,
        but is it possible to use a number of "plants". Instead of
        constructing an entire world one polygon at a time, we can
        place buildings, structures and various other natural
        items on the landscape. So given a list of world positions
        and a building we could easily draw a whole city or town.
        Place a few trees and a large, blue, wobbly lake and you
        have Milton Keynes (heh heh). This "Plant" idea is NOT the
        same as the "Planet" one, because the planets can move, but
        plants can not (they are static in the game world) unless
        they are Triffids (Eck ! =).

          By using just the building's/structure's world co-ordinates
        (which is normally the object's origin) we only have to deal
        with a set of (X,Y,Z) co-ordinates. Then afterwards when we
        come to draw one of these environmental object models we can
        rotate, transform and project all it's vertices around this
        world position. And yet again the hierarchical data structure
        appears in this object placement method of describing a
        scene. These world (X,Y,Z) co-ordinates can be thought of as
        the parent origin vertices with the object model's vertices being
        their siblings. Now if we can reject the world (X,Y,Z)
        position (too far away or behind the view-point) then we can
        reject the whole object model too. We have "pruned the plants".


#F4:OCT-Trees

          It would be nice to process only some of these world (X,Y,Z)
        model origins to speed things up even further. Rather than
        rotate and check each one we would like to be able to scan
        the local, surrounding areas and choose these within range.
        We could use a 2d or 3d array map to divide the world into
        smaller regions (see Grids and Coarse Area Nets). But I will
        attempt to describe another method, that of "3d Linked-Lists"
        or "Environment Webs". The idea is simple, for every world
        (X,Y,Z) position create a multi-directional node and use it
        point to it's surrounding neighbours. Within the data structure
        of a node there are a number of pointers or 'links' which
        are used to direct the renderer to the closest neighbouring
        object in a particular direction. A normal linked-list is
        a 1-dimensional version of this, it directs a program left-to-
        right or north-to-south (etc..) through a sequential list.
        A 2-dimensional linked-list (or should that be linked-array ?)
        can guide a program in four directions (north, south, east, west)
        this is suitable for a 2d map or a 3d map, but a 3-dimensional
        "web" (linked-list) would perhaps be better as we could follow
        up and down links as well..

          I believe "Oct-Trees" are 8 sided tree (I guess) and are used
        to describe the relative placement of neighbouring items with
        respect to the current one. I haven't seen ANY info about these
        structures so please read this with a pinch of salt. It is
        probable that they only describe the placement of items in a
        2-dimensional way.

                e.g.       NW   N   NE
                             \    /
                              \  /
                               \/
                         W  E
                               /\
                              /  \
                             /    \
                           SW       SE
                                S


#F5:Spinning the Web

          Now there is the problem of creating this 3-dimensional "web".
        Given just a list of world (X,Y,Z) co-ordinates how can we build
        the links between items ? If these items can be placed any at
        position along these three axiss it means that any one item
        can be at any angle or any distance to any other. So how many
        links do we need ? Do we need 360 for the X-Z plane and another
        360 for the Y-Z plane for example ?

          Well it would be very impractical to use 720 links for every
        plant-node as most of these will be unused, so I suggest using
        just 6 links (like the face of the worn out cube example).

          Starting at a particular item in the list we can allocate a
        node structure and then search for the closest item to it.
        It's direction is also found and used to select one of the
        possible node's link fields.


#F6:Caught in the Web

          But this 3d web suffers from the same problem as navigating
        a path through a tree structure, that of having to select between
        a number of node links. Because the direction which each link
        represents won't precisely match our rendering direction it
        is possible that the renderer will be forced to choose between
        two close paths. Suppose that we only had 4 links from each node
        to choose from and each link was at 90 degrees to each other.

                e.g.           90'  / desired direction
                                  /
                                 /
                                /
                      180'  0'
                                
                                
                                
                               270'


          Now we want to follow a 45 degree path, so which path link
        should be use ? Remember that these north, south, east, west
        links point to the closest item which is probably NOT absolutely
        north, south, east or west of our current one. So it might be
        at 80 degrees or 101 degrees instead of 90 degrees.
          Another problem is that you may take what you believe is the
        best route link but may in fact have to back-track in the
        opposite direction to locate the item you want. This can cause
        you to revisit the same item twice or any number of times.


#F7:Multi-Attribute Sieves

          The main characteristic about a 3d engine is it's flexibility
        and this is sadly also it's performance hurdle. For a scrolling
        2d game there are at most four possible directions to move in
        and only a very small, rigid window over the game world to
        draw. These are very linear, we know what part of the game
        world needs to be updated and how it should look. In most cases
        the most difficult part is moving or scrolling the screen
        bitmap which can be done using the hardware panning registers
        and then redrawing the new edges of the map on the screen.

          In the case of 3d the rotation and perspective means that
        neighbouring pixels and surfaces do not have any local coherence
        which can be to exploited, we can't simply pan the screen and
        draw a new edge. Polygons change in size, angle, shape and
        direction so everything must be recalculated in real time.
        Most/all 3d map levels have an interconnected structure to them
        this means there is no one linear way to navigate through
        them.

          It would be nice to just specify the view angles, view position
        and be given the resulting polygon list from a pre-defined
        data structure of the level. But this is sadly not possible.
        As far as I know data structures such as lists, trees and
        arrays can only be used for one, single purpose. For example a
        polygon list build for one particular direction will not work
        for another direction (except perhaps a 180 degree turn where
        the list is scanned backwards).

        The renderer is a form of multi-attribute sieve.


#F8:Recommended Reading

          Most other 3d docs list a number of 3d programming books
        which they recommend, but I can not, because I don't have a
        single 3d programming book ! Most of my limited knowledge has
        been figured out the slow, painful way (late nights & aspirin)

          You may think that your code is breaking new ground, pushing
        back the frontiers of programming, but in reality a thousand
        other programmers have done it years before you. If you ever
        need an Ego-check then visit your library and take out a
        dusty 1970's book on algorithms or computer graphics and soon
        you will be saying, "Wow, this geezer was a smart cookie before
        I was even born !!"

          You won't find the ultimate 3d engine in a book, but in
        your head. The problem is finding a suitable download lead.

                                        have fun ...

#############################################################################
Ŀ
 #G:                    "NOAH" - Flood fill rendering                      

#############################################################################

          When I first thought about 3d engines and ways to render levels
        I did get too close to the problem and was unable to see any
        further than my polygon nose. Sometimes its beneficial to adapt
        techniques from unrelated problems to the current one even if
        the connection is not obvious. I reckon most programmers when
        learning 3d stuff try to modify existing 2d methods to work in
        the 3rd dimension. A good example of this it tiled (or grid-
        based) levels. The entire game world area is divided into
        equally spaced cells and each cell can represent a wall, a hill
        a door or whatever. Games like Wolfenstein, System-Shock,
        Raise of the Triads and even both Tomb Raider games appear to
        use this method in some form. It has some advantages:

          1) levels are easier to design.
          2) components can be used again and again simply by using
             the identical cell code for a door, wall etc..
          3) rendering can be sped up as walls meet at 90 and
             spacing is constant.

        But also has some disadvantages:

          1) levels look very much alike
          2) rooms all look like breeze-blocks

        Games which are platform orientated seem to like this map/cell
        approach because designers can just count the cells between
        two platforms knowing that a player can or can not make the
        leap to the other side.

          One of the reasons why the map/cell method is used in 3d games
        is because it automatically fixes a local relationship between
        neighbouring cells in terms of distance and direction. A speed
        advantage is gained because we simply choose a starting cell and
        render from that point. We scan across the map from our starting
        point and render the walls/doors etc.. as we go. As the adjoining
        level structures are described in the adjoining map cell almost
        all the searching and depth sorting can be minimise a great deal.
        You could think of this cell (or 2d "array") rendering as a
        form of flood-fill algorithm where we trace along the wall edges
        and stop at closed doors or other obstacles. Of course you
        would also need to consider cells/areas behind your view point
        as also being a kind of boundary where rendering also stops.
        I have not seen any 3d engines (not even part of one) but I
        hazard a guess that a form of filling is used. Wolfenstein and
        Doom to my knowledge used "Ray Casting" to render the view
        point, so you could describe that as a form of render fill,
        again beginning at the starting cell and working outwards from
        the view point.

          But a problem with the flood-fill idea of drawing a 3d scene
        is that it is possible that overdraw can occur when we follow
        a wall which goes around the back of a closer wall. This is
        because a standard flood-fill algorithm will simply keep
        flooding in the same direction until it encounters a wall/door
        boundary. In the worst possible case it may have filled
        entirely to the far side of the level before a dead end is met.
        You could use a limiting check for distance or number of
        cells filled and then halt the rendering at that point, but
        still the problem of overdraw may occur because we could be
        tracing distant walls before checking whether a closer one
        obscures it.

          For example if we start at the left edge of the screen and
        trace along a map following wall/door boundaries then it is
        possible that we end up behind a wall on the right of the
        screen or we may even drift left completely beyond our view.
        What we need to do is only continue to fill if a part of the
        connected cell can actually be seen from our viewpoint.

          Another approach could be to scan outwards from our starting
        cell in a circle (or semicircle as only 180 can be seen).
        This does have the advantage that ALL the walls/obstructions
        at a certain distance will be found at the same time (at the
        same distance from us) this should help avoid the dead-end
        fill problem and hopefully sorting will be minimised too.
        I guess this is how "Ray-Casting" was developed. Like an
        expanded radar ping from the centre, anything which it hits
        halts the current ray in that direction. A simple approach
        could be to start 320 rays from our view point (1 for each
        horizontal X co-ordinate on our screen) and only continue to
        trace along the map if no obstruction has been met, otherwise
        we simply draw what we encountered taking into account the
        distance we have traced along the map and delete the ray.


#############################################################################
Ŀ
 #H:               The missing Link ? "INLET" rendering.                   

#############################################################################

          Another idea which has held my short attention span for
        some time is convex, linked rooms or "inlet rendering" as I
        like to call it. This looks the most promising form of
        rendering at the moment (mostly because I am unable to come up
        with a better method) and elegantly it squats many-a-fly
        with the same rolled up newspaper. The method behind it is
        very easy, linked-lists ! but the power and promise of very
        fast rendering with extra features thrown in with minimum
        effort makes it worth investigating. It can easily be used
        for lifts in buildings, water effects, force fields, coloured
        lighting and a heap of other stuff that I haven't got round
        to hype up yet 8)

          This originally came out of extending the "Noah" rendering
        (flood-fill) method, but this will (hopefully) allow true
        3d environments with smoked/coloured glass and water effects
        without too much work. The main problem with flood-filling is
        that of tracing the map boundary, the objects within each
        cell must be decoded and the appropriate action taken. With
        true 3d levels (rooms above and below) storage can sometimes
        be a real problem. The obvious way is to extend the 2d map
        array into 3 dimensions, so instead of a 2d array we have
        a 3d array. If levels are designed to fill entirely within
        a cube shaped map array then this isn't too bad, but most
        levels have large areas of empty space beyond the real
        environment (such as behind the walls in a corridor) this
        can lead to a lot of wasted memory space. One solution is
        to use this space in the 3d level array for sub-levels or
        secret transporter destination rooms.

          Now I will describe how linked-lists levels might work.
        Think of the easiest 3d environment, yeah, our old friend
        "the cube". But this time we are inside the cube and imagine
        that there is NO outside to it, the interior of the cube
        is the entire game universe. This only needs 6 surfaces.
        Usually the cube's interior is never seen and so never
        defined only the 6 exterior surfaces/polygons are defined and
        rendered. But in INLET RENDERING the opposite is true.
        We only ever see the inside, never the outside. Imagine being
        trapped inside a bubble, there is only 1 surface and no
        matter in which direction you look you will always see a wall
        and the wall always disappears beyond your peripheral view
        (around your head, where your eye can't see). Bubbles are
        hard to draw so lets return to the simpler cube. An important
        thing to note about the cube is that it is CONVEX in every
        direction.

#H1:CAVE'd or VEX'd ?

          In my understanding CONVEX is something which is like a
        bubble or cube - the angles between two interior surfaces
        are always less or equal to 180. Or if you stood and looked
        directly along each interior surface then they would slope
        upwards and over your head. If we walked along each one
        of the below surface lines then we would always meet an
        adjoining surface which slopes upwards like the inside of
        a bubble or cube.

        This means that NO surface is hidden by any other surface
        - this means NO depth-sorting yippee ! 8)

         CONVEX.
        
                          side cross-section view
                                         ________________
                <Ŀ         \               \
                                        \               \
                              ^           \               \
                                          \              /
                 view >                   \  view >   /
                              \__________/

         CONCAVE
        
          And CONCAVE volumes have interior surfaces which have one
        or more angles which are more than 180

                          side cross-section view
                          <Ŀ
                                       _____________________
                <x            \                    \
                                        \                    \
                              ^           \               x____\
                                          \              /
                 view >                   \  view >   /
                              \__________/


          In both the above diagrams 'x' marks an angle of more
        than 180. If we walked along each surface then we would
        meet a part of the volume where it dips away underneath
        our feet like a hole in the ground. This means that a
        surface can be hidden from certain view points in the
        volume, and this means depth sorting :(

#H2:CONVEX Rulez


          I haven't seen any mathematical proof for the following
        statement, it is just common sense which I believe to be true
        (until proven otherwise) - don't sue me ;).


?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?

          A CONVEX volume NEVER needs depth-sorting because no
        surfaces are ever hidden by other surfaces. For every position
        within the convex volume and for every direction this is true.
        So no matter what position within the convex volume and no
        matter which direction you are facing you will never see a
        partially hidden or completely hidden surface
        (except those behind you, of course).

?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?-?

          The above is NOT true for CONCAVE volumes because for
        certain positions and directions we can see a surface which
        ends at the top of a hill where the connected surface can not
        be seen (it is hidden behind the hill). Of course if we move
        further around the volume then that surface will appear.

#H3: CONVEX - SO WHAT ?


          Most other 3d engines need some form of depth sorting or
        BSP structure which can handle polygons/surfaces which are
        partially or entirely obscured by others. This happens when
        a CONCAVE environment needs to be modelled like a door-frame
        which connects one room to another.

                e.g.
                                plan view
                     Ŀ    Ŀ
                                           a             
                                                      back
                    c V >   room 1    door     room2    
                                        Ŀ              wall
                                           b             
                         


          In the above H shaped diagram both room1 and room2 are convex
        and so is the door-frame which connects both. If we are at
        the viewpoint V then some kind of depth-sorting is required so
        that the back wall of room2 is drawn before any others. This
        way the closest walls are drawn last. In this tiny example a
        total of 12 walls need to be sorted, of which 3 would be
        considered as hidden (a, b and c).

          It's the door-frame which makes the above diagram CONCAVE.

#H4:Is that a light-bulb ?


          We could just define our levels as 1 convex room, but that
        would be very crap. Suppose we kept the above H shaped
        level with two rooms connected by a doorway and we already know
        it's a concave shape, but lets close the door to seal off the
        other room. Now we have a CONVEX room !! which is good news
        from a rendering point. But if we added an alcove to our sealed
        off room or a recessed area in one of the walls then we would
        be back with a CONCAVE volume again :(


#H5:Wheres these LINKED-LISTS ?

          The "Noah" method flooded each area and followed those which
        a connection into another area could be made. But what happens
        if we have very large rooms or open areas ? This flood-fill
        would be very costly. We would be filling a large area even
        though we didn't need to, all we want to the find where the
        wall boundaries are. One way could be to modify the flood-fill
        to only follow edges this is very simple to do. It is often
        called an "Edge-follow" or "Boundary Trace" algorithm.
        But it does cause a problem which anyone who has ever written
        a version of the classic Pac-man will know too well.
        The problem of islands within a map, where two or more walls
        are not connected together. Imagine that you are inside a room
        with a central pillar and you walked around the room keeping
        a wall by your left side. After a while you are back to the
        starting point, but you still haven't found the central post.
        This would occur in the circular list method, we would never
        get to the central-post and so we wouldn't draw it :(

          Ignoring the 'island' problem for a moment I will comment
        on a method which is similar to the edge-follow method but
        uses linked-lists for speed. What we need to do is follow
        the walls which mark the environment's boundary. This is a
        case of tracing the path of connected polygon surfaces.

        In the case of a cube we could trace like this :-

                            b
                        Ŀ
                                
                           ^    
                       a       c             plan view
                          view  
                        
                             d

          First we could draw polygon wall a and then wall b and finally
        wall c. We don't bother with wall d because it is behind our
        viewpoint and so ignored.

          As we don't want to have to search lots of polygons to find
        which one connects to polygon a along it's edge then we can
        used a LINKED-LIST. For each edge of a polygon we store a pointer
        link which is the address of the connected polygon which shares
        the same edge.

                                 clockwise right
                     Polygon         'Link'
                           
                        a               b
                        b               c
                        c               d
                        d               a

          So each 'Link' points to the neighbouring right wall.

        NOTE: we have created a circular list of the entire volume
              simply be pointing the last edge of polygon wall d
              back to polygon wall a.

          Now all we need is the address of a starting wall and then
        render each one and use this link to immediately find it's
        neighbouring wall. As a bonus we can even use the same edge
        slope to draw the next wall without having to recalculate it.
        This should help remove pixel gaps between connected walls.

#H6:Two way system


          There is a problem with the above 'circular' link method.
        What happens if we need to find the neighbouring wall to
        the left of the current one ? We could search the entire list
        until we found one whose link is that of our current one
        but this can be slow if there are many walls in the chain.

          It is much better to use another link which points to the
        left neighbour. So now we can follow the links clockwise
        to find the next right wall OR anti-clockwise to find the
        next neighbouring left wall. Now our 3d engine can be given
        a starting wall address and it can trace walls left or right
        until either the screen clipping limit has been crossed or
        the Z view plane had been encountered, at this stage we can
        stop rendering.

                            b
           plan view    Ŀ
                                
                           ^    
                       a       c
        ----------------  view  -------------- view/projection Z plane
                            Ŀ      (the 2d screen !)
                                         
                                         
                                         
                                    
                                
                                
                                
               

          In the above diagram we are facing north and if we only
        have the address of wall b to render the environment our
        engine could do something like this :-

                Start_Wall = b

          If we handle walls in a left to right order this will
        mean our left & right links will be the StartVertex and
        EndVertex respectively.

               StartVertex          EndVertex
                        o>o

                               ^
                               
                              view

          In this pseudo-code I will deal with DOOM like walls where
        they are always vertical as this makes explaining things
        easier because we can think of the 3d environment as being
        viewed from above as the plan-view of a series of connected
        lines.

          First make sure our starting wall is visible (i.e.. facing
        in our direction) and if not then follow the chain of links
        until we find one that is. This deals with a change of
        direction (when we turn our heads) and so makes sure our
        'Start_Wall' is always pointing to a visible wall facing
        us. Of course this could be handled in your movement code
        and only ever checked when our direction/position is changed.

                WHILE Start_Wall is not Visible
                   Start_Wall = Start_Wall[ left_link ]
                WEND

          Now that we have corrected any invisible starting wall
        (caused by a change of direction) we can begin to render.
        We can begin in either a left or right order, I will do
        clockwise first but the order is not important. We could
        have searched for a starting wall which was outside our left
        view edge and drawn each wall until we ended up outside the
        right view edge, but it is often very useful to know what
        wall you are facing (activating buttons, shooting etc..)

                Current_Wall = Start_Wall


                WHILE Current_Wall is visible...
                      AND is not right clipped...
                      AND does not cut Z viewing plane

                           Draw_and_Clip_Polygon( Current_Wall )
                           Current_Wall = Current_wall[ right_link ]
                WEND

          And a similar thing can be done for an anti-clockwise
        order (draw until we reach the left view edge of the screen).

                Current_Wall = Start_Wall

                WHILE Current_Wall is visible...
                      AND is not left clipped...
                      AND does not cut Z viewing plane

                        Draw_and_Clip_Polygon( Current_Wall )
                        Current_Wall = Current_Wall[ left_link]
                WEND

          That's basically it ! We just follow each link until we
        encounter a clipped wall (either viewing-window clipped or
        Z view-plane clipped). The linked-list approach makes this
        possible with the minimum of fuss and CPU time. We could
        even totally remove walls by taking them out of the chain
        or possibly insert new ones for dented walls or a nice
        time-n-space portal effect.


#H7:Bonus

          There are a few more goodies which are made available
        by using the linked-list method.

        1) memory consumption isn't too bad, just an extra
           link-list address for each polygon edge, this is far
           better than the map/array method as no memory is wasted.
           It allows much bigger levels simply by placing vertices
           further apart and to any value not just to the map-cell
           boundary.

        2) Vertices CAN be moved to allow for morphing of levels
           As long as rooms are still CONVEX after the vertices
           have been moved. This can be overcome by building large
           rooms out of triangle shaped parts - this makes it
           impossible to create CONCAVE rooms, so they are still
           CONVEX which is good news 8)


#H8:Yeah, but what about CONCAVE ?

          Remember the "light bulb" question ? The problem of a
        CONCAVE level was side-stepped by closing the door and
        hiding from the problem (hee hee). But in fact this is an
        elegant solution and even allows other groovy effects for
        free. Remember that the door-way was the cause of the
        problem, so shutting it allowed us to pretend that it was
        just another polygon wall like all the others.
        So the room is made convex. We can describe the door as
        a transparent wall made of glass like a window, or "INLET".

          The room is rendered as normal, polygon by polygon until
        an "INLET" is found. It is stored in a list, if the polygon is
        transparent it isn't drawn, it's neighbouring link is used
        and rendering continues until the entire room has been done.
        Now the list of INLETs is examined and  possibly rendered
        depending on whether it is open or closed as in the case of
        a door. The INLET is a link to a connected room which shares
        the same door or window. We can then draw each inlet'd room
        until we have no more inlets left.

          Another way to describe this method is to imagine an
        artist painting a picture of a room. He draw and paints all
        the three visible walls leaving a small unpainted rectangle
        for a window, then he paints the floor and ceiling. Now he
        returned back to the window and draw the scene outside
        (sky, trees etc..) but he only paints the parts of the
        scenery which can be seen through the window.
        By painting the entire room before the outside the artist
        has entirely removed any overdraw and greatly reduced the
        region through which distant objects can be seen. Also
        after completing the room he knows where and how much
        further rendering needs to be done. (or not in the case of
        low-detail for slow PC's). You can then think of the window
        as a tiny self contained picture in it's own right.

          The basic rules for following an INLET polygon are :-

                1) It must be visible (facing us)

                2) some part of it must be visible on the screen
                   (not totally clipped/hidden by a closer surface)

                3) the INLET must be open
                   (we can't see through an closed door)

          and possibly for speed reasons :-

                4) within our horizon clipping limit.
                   (we could use a solid-fill to black out the any
                    inlet beyond a certain Z cut-off distance or
                    better still draw a solid "horizon" texture).


#H9:Remember that central pillar ?

          So the INLET rendering method breaks down a level into small
        CONVEX volumes. This means that (hopefully) no depth-sorting
        is needed as NO surface in a volume can be hidden by any other
        surface.

          We have also seen that using two circular linked-lists we
        can quickly trace along the walls or boundaries of an area by
        using a pointer to each one's neighbour.

          But there is a problem, how can we handle rooms with
        pillars or islands in their middles where none of the
        boundary walls connect to them ? In fact a room with a pillar
        or island is NOT a convex room, is it CONCAVE ! Just like
        being inside a doughnut shaped room. Part of the outer wall
        is obscured by the central part at almost every angle.

               ##############################
               #Ŀ#   #  = null-space
               #                          #
               #   doughnut shaped room   #        where it is impossible
               #-------Ŀ---------#        to go, so no surfaces
               #       ########         #        are needed to be
               #       #central         #        defined.
               #       ##post##         #
               #       ########         #
               #----------------#
               #                          #
               #            X             <-------- walls
               ##
               ##############################


          In the above diagram we have a total of 8 walls, 4 interior
        walls and the 4 exterior walls of the central-post. If we
        stood at point X and looked north then it obviously means
        that we couldn't see the far north wall of the room so it
        can not be convex. Lets add some walls parallel to the centre
        post corners (marked by ------) this divides the room into
        4 parts and each of which is now CONVEX  (yippee).
        But having 4 walls means we can't see much of the room, so
        lets make them transparent, like they're made from perfect
        glass and turn them into INLETs.

          So what we have really done is to turn a concave room
        into 4 convex sub-rooms. We can think of each of the "INLETS"
        as being a window into other rooms (just like a door or
        window). If an inlet is invisible (facing away from us)
        then we don't bother rendering the adjoining room to
        which it points (we see through a hidden window can we ?).


#H10:What about depth sorting & Overdraw ?

          Now that we have rendered the starting convex room that
        we are standing in and found all the INLETs (if any), we
        still need to draw them. There are some important things
        to notice about each INLET.

                1) the same room can be reached by more than one
                   INLET link (e.g. a window & door in the same wall)

                2) the INLET might be further away then the
                   current room in which it was found.
                   (because we are rendering out from the view-point)

                3) the view of a room through an INLET will be
                   confined to the area of the INLET polygon.
                   (the window/door edges mark the clipping edges)

                4) when a connected room is found by the INLET then
                   it might require a lot of searching to find
                   a visible wall. (We would have to follow each
                   wall starting at the back side of the INLET polygon
                   and working either clockwise or anti-clockwise
                   until we found a visible wall.)

          In the first case it can be useful if an entire room's
        vertices are rotated and projected all in one go (instead of
        calculating each wall as we trace it). Then we could just
        re-use the same 2d co-ordinates for a shared room. Possibly
        removing the need to repeat the hidden surface checking and
        facing wall check (see case 4).

          In the second case this may not always be true.
        It is possible to be in a small room underneath a much
        larger one. But case 3) should still remove any need to
        perform depth-sorting. It 'should' never suffer from the
        flood-fill problem due to the convex construction of the level.
        I'm unsure whether any sorting of the listed inlets will
        ever be needed, I still need to try a proto-type 3d engine !!

          In the third case this is not a problem, but a *BONUS*.
        Where a simple depth-sorted (The Painter's algorithm ?)
        method would draw the most distant objects first and possibly
        overdraw them with closer ones, we don't. The inlets take
        care of depth-sorting and has hierarchical properties (we
        only trace rooms which are connected to our view point).
        The portion of the room beyond the inlet will be restricted
        to the inlet's polygon edges as anything beyond them as
        obscured by the closer walls (the wall which surround the
        inlet). So the inlet polygon can be used as a clipping window.
        The only complication is that the clipping region is NOT
        a rectangle, but possibly a concave polygon ?. So pixel
        clipping is required on each horizontal line span. The
        clipping is just a Xmin to Xmax left/right clip. This can
        be done in the scan-converting part of the engine.
        It might be worthwhile first checking the rectangular
        clipping screen boundary for accepted/clipped edges and then
        perform the pixel span checking.
          This can be improved by keeping the xmin, ymin, xmax and
        xmax limits for the inlet polygon and using them as a
        rectangular clipping region. As inlets are likely to be
        a fraction of the entire screen/window area this should
        reject far more lines before needing to check pixel spans.

          In the fourth case an improvement could be made using a
        dynamic line-of-sight link which the engine could modify
        as it renders. This may not help newly inlet'd rooms as
        the dynamic link might be pointing to the opposite side
        of the room to what we want. A possibly solution would be
        to have central navigation nodes in the centre of each
        room. The node would need to be multiway to be able to
        direct the rendering ray to the correct wall for
        the desired viewing direction. It would not only need
        north, south, east, west directions but also up and down
        ones.
          Another solution could be to create "spoke-tables"
        for each room, one for the X-Z plane (horizontal) and one
        for the Y-Z plane (vertical). As we know that each room
        is a closed convex volume we also know it extends for
        360 in all directions, so given a viewing direction, the
        spoke-table's length we can soon locate a wall for any
        particular direction (or at least find a neighbouring one).

                                    90                   table
                                Ŀ            
                                    b                 0       a
                         "INLET"                      1       b
           view >      180 c      a  0          2       c
                                    d                 3       d
                                
                                   270

          If we were viewing through the inlet c and wanted to
        find the wall at an angle of 50 We divide by this
        angle down into an index and look-up the wall in the
        spoke-table. But how ?

          In the above diagram we have 4 sides which means
        that if we take 360 and divide it by 4 then each wall
        would have an equal share of 360 / 4 = 90. If we
        just divided our viewing angle by 90 then there is a
        problem. Take a look this :

                                    90
                                 Ŀ
                                      xx/
                                    xx / 
                              50 xx  /    0
                                     /   
                                    /    
                                 45     

          So using the formula:

                                              number of walls
                index = viewing angle   *    
                                                    360

          would give:

                0  =   50 * 4 / 360


          but as 50 is more than 45 (half the angle between
        two walls) what we really want is 1 as our index. So lets
        add a rounding up part to the formula:
                                                  
                                       180            number of walls
        index = viewing angle +   *  
                                 number of walls            360
                                                  

          So in the 50 example this would give:


                1  =  ( 50 + 180 / 4 ) * ( 4 / 360)

          Now we can just index into the circuit-table and
        discover that at 50 that wall b is the closest. For
        very small rooms with only a few walls this method
        might prove to be slower than following the wall links
        around the chain. But it does remove the need to
        check each wall in the chain for visibility (if it is
        facing us) and for large convex areas with many walls
        this might prove to be faster than the dynamic
        line-of-sight link method for newly encountered rooms.

        There may be problems with this as a room's walls might
        not have a equal share of the 360 arc unlike the above
        example of a cube (where each wall has a 90 share of 360).
        This method might be good for very large rooms with many
        walls. As the spoke-table is a complete 360 structure and
        we can reuse the same table for all the inlets which lie
        on the same plane (in the same room).

          This spoke-table might be useful for path-finding
        a route through a map for A.I. routines and so on....


#H11:Pixel clipping distant objects

          This is probably the easiest part of the technique and
        most CPU intensive task of the rendering. You must compare
        the start and end X co-ordinates of each polygon scan line
        against the clipping left and right X co-ordinates on the
        same screen scan line and possibly clip the polygon texture
        and/or shading co-ordinates.

        e.g.
                In the below diagram the polygon line with
                pixels "abcdefghijklmn" needs to be clipped
                inside the left limit.

       Scan line
           left        right

         140                       < each scan line it's own limits
         141       abcdefghijklmn   
         142                       
         143                          < NOTE: not vertical !!



  NOTE:         Although the left & right clipping limits begin
                as straight lines (equal to the screen limits)
                and form a rectangular clipping region, it
                can NOT be assumed that they stay this way.
                And it can NOT be assumed that they form a
                straight line, as parts of polygons might encroach
                inside one side anywhere.
                So each horizontal scan line must be tested on
                an individual, pixel co-ordinate basis.

          ALL the pixels between these X-min and X-max values
        are YET to be drawn. They are simply the clipping span
        through which all further INLETs or polygons must be
        checked and clipped. As each polygon has it's edges clipped
        against these left/right limits it modifies the limits
        itself, further reducing the span length and decreasing
        the size of the render inlet.

          Some things need to be considered when drawing polygons:

        1) whether it is visible

        2) if any part of it is clipped inside the INLET edges
           (this modifies the Xmin and Xmax limits and decreases
            the difference between them).

        3) does it break the inlet into two parts ?
           this happens when a polygon is drawn which lies in
           the middle of an inlet span with further inlets to
           either side.
           (I haven't got round to this yet as it is a bitch of
            a problem. One solution is to create another INLET)

        4) if the polygon is an inlet itself, pointing to another
           room.


#H12:Texture clipping speed up

          In the pixel clipping section of each polygon it's
        texture must sometimes be clipped inside the left/right
        inlet limits. For each polygon line there are 6 possible
        situations for clipping. The clipping of co-ordinates
        in texture-space can be slow often requiring a multiply
        and possibly a divide (yuck !).

                      x min             x max

case 1:        abcdefg                 
case 2:              abcdefg            
case 3:                    abcdefg     
case 4:                             abcdefg
case 5:                                   abcdefg
case 6:             abcdefghijklmnopqrstuvwxyz
                                       


         Actions:
        
        case 1: completely left of limits, so reject entire line

  **    case 2: clip left

        case 3: accept entire line without clipping

 ***    case 4: clip right

        case 5: completely right of limits, reject entire line

****    case 6: clip both ends


        ** the clip can be avoided by indicating that the span
           should be drawn from right-to-left. This avoids having
           to clip the texture co-ordinates against the left
           edge. Only the screen left X co-ordinate needs to be
           clipped which is just a MOV instruction.

       *** the same applies to this, only the screen right X
           co-ordinates needs to be clipped, not the texture
           and the drawing can occur normally from left-to-right.

      **** er... Damn, damn, damn !
           the left texture co-ordinates need to be clipped
           and both the left & right screen co-ordinates too.
           This works out to 1 texture clip & 2 MOV's in the
           best case. We can just clip the texture co-ords of
           the left edge and draw from left-to-right WITHOUT
           needing to clip the right texture co-ords.

          Possibly more work is required for shaded textured
        polygons when clipping (to work out the shading points
        for the clipped horizontal line span). problems... problems...


#H13:Problems, Problems

          The inlet region might not remain a convex shape. Certain
        forms of concave shapes are okay unless they divide a
        scan-line into two individual horizontal parts. The only
        solution I can see at present is to build up another
        inlet for the newly created spans.

        e.g.
                _________                     ___________ _____
                \       /                     \          / \   \
                 \     /                       \        /   \   \
                  \ B  \                        \  B   /    /    \
                  /     \                        \    /  A /  B  /
                 /     / \                       /    \   /     /
                /_____/_A_\                     /______\_/_____/

                concave, but ok.               concave, but divided
                polygon A merely               by polygon A into 2
                shrinks the right edge         parts.


          In the worst solution a total of 4 inlets could be created
        by a single polygon lying entirely within an inlet.

        e.g.    _____________________
               /      ______         \    Polygon B is the INLET
              /      /      \        /    region and polygon A is
             / INLET \   A  /   B   /     the polygon to be drawn.
             \        \____/       /
              \    B              /
               \_________________/

          But in fact only 2 inlets need to be created. We can extend
        the top and bottom of polygon A to meet the left or right edge
        of polygon B. This would create a 'C-shaped' inlet and a small
        window as well, something like this:-

                _____________________
               /      _______________\
              /      /      \        /
             / INLET \   A  /   C   /
             \        \____/_______/
              \    B              /
               \_________________/


NOTE:
        There are a few problems with this.

        a) if we divide up the inlet then we possibly need to
           divide any neighbouring polygons/inlets as well.

        b) we may end up creating inlets which we don't really
           need to as all the neighbouring polygons might be
           solid colour/texture. In this case the entire inlet
           has been filled so this inlet is deleted and no more
           are created.


                  The are about 4 situations which may occur.
                 

        1) the neighbouring polygon connected to A might fill up ALL
           the horizontal lines spans and so close the inlet B.
           (it can then be removed from our inlet list)

        2) some neighbouring polygons might only fill one or more
           sides around polygon A. This would shrink the inlet
           on one or mores sides and we would be left with 1 inlet.
           (which is what we want).

        3) the neighbouring polygons to A might also be inlets
           themselves, so two or more new inlets will need to be
           created and the current one discarded.

        4) polygon A might be an inlet itself. This has two possible
           sub-cases.
           4a) All the surrounding polygons fill the inlet B
               (this reduces the inlet to the area of polygon A)

           4b) some/all the surrounding polygons are also inlets.
               (at the worst possible case ALL the surrounding
                polygons are also inlets, so ALL require new inlets
                to be created.)


          I have not explored the possibilities of combining two
        neighbouring inlets which share an identical end point
        along the same scan-line. This can happen when a concave
        room is sub-divided into convex ones where many invisible
        inlets are used to connected these sub-volumes and when
        two inlets break up the same solid wall. An "S-Buffer"
        technique might be useful in this case to try and reduce
        the number of inlets and broken texture spans.
        (See the "Span-Buffer" section for more info)

          Also I have not mentioned movable objects such as monsters
        or vehicles which themselves might conceal a background
        wall texture or even part of an inlet. In the very worst
        case the inlets will degenerate down into single, horizontal
        line spans. And these themselves might be sub-divided
        into two parts.

#H14:Convex Bonuses

          There are a number of advantages created when breaking up
        a concave volume (a room or open space etc..).

                1) depth-sorting 'should' be removed
                   (speeding up the engine)

                2) collision detection should be easier
                   (knowing what convex sub-room a player or
                    monster is standing in reduces the number
                    of polygons to check)

                3) movement will be easier to test for
                   (A.I. code can use the inlets of each room
                    to know where the exits & entrances are.
                    Also you only need to check the polygons
                    which make up your current room.)

                4) linked-list allow for easy re-direction
                   (lifts can be done simply by changing the
                    inlets links to it's door).

                5) very complex, interconnected environments
                   can be made by gluing together a number of
                   of convex rooms.

#H15:Convex Downers

          But of course there are always some disadvantages:

                1) more polygons are created for the inlet sides
                   (these are the perfect glass walls which join
                    two connecting convex volumes)

                2) certain restrictions on map design are imposed
                   (well actually the level editor remove these
                    restrictions turning concave areas into convex)


          In case 1) it may first seem like an increase in workload
        but remember the savings from not doing depth-sorting and
        all the smart hierarchical clipping which the inlet method
        performs. Even if a BSP of some kind was used instead there
        would still be an increase in workload because polygons are
        often split by BSP trees to resolve partition crossing.


#H16:Summary

          The use of linked-list is the key component to this type
        of 3d rendering. I've used them in a way to describe the
        connected relationship between joined walls/polygons. This
        removes all need to search or depth-sort many polygons.

          This method of edge-connection could possibly be extended
        to solve some of the speed problems for complex 3d objects
        (like monsters or vehicles in this 3d world). A number of
        visible (facing us) polygons for every convex part could be
        used and updated after each render cycle. For example in
        the case of a monster it would need to be broken down into
        a number of convex components (the head, the torso, each arm,
        each leg, each hand etc..) and for each convex part we
        store a visible polygon address. This will be our starting
        point for drawing each component. We pre-build the edge-links
        for each polygon/surface and use them during rendering just
        like the linked-list room approach, but instead of describing
        interior surfaces we describe the exterior ones (the skin).
        In the example of a head we could start with drawing the nose
        then follow the edge links for the cheeks, the eyes, the
        mouth etc.. We continue this until we discover a hidden
        surface or a clipped polygon, at this point we stop and
        resume at some other edge until we have followed them all.
        In the case of the head this would be after following past
        the forehead, under the chin and around past each ear. We
        do NOT follow the links around the back of the head because
        those polygons are hidden from our view.

                e.g.
                              _______x________
                            x/                \ x
                           x/                  \_x
                          |                      |
                 ears     |                      |  ears
                          |_     top of head    _|
                            |                  |
                             \                /
                              \_____    _____/
                                   \   /
                        cheek       \_/      cheek

                                    nose


          In the above work of art, the ears would be the last things
        drawn and all other connected polygons would be ignored


 NOTE:
          I am not sure whether there would be any saving in workload
        using this method for convex objects as they normally only
        have 6 sides or a few more. The actual saving might not be
        worth pursuing, although I haven't tested this yet.


#############################################################################
Ŀ
 #I:               Volume Meshes (Distorted Cube Arrays)                   

#############################################################################

#I1:Terminology:


        VOLUME  - a 3d area with a width, a height and a depth
                  the space inside an object's skin.

        LAYER   - something of a single thickness
                  (like a page from a book, or floor from a building
                   or in this section a floor or ceiling array)

        MESH    - a single 2d layer of connected cells
                  which can be moved and bent into different
                  shapes just like a wire fence meshing.


#I2:A Similar Method

          Another way to render a scene which shares some of the
        inlet methods and it's convex volume ideas is this:

        1) begin with an equally spaced array of cube cells
           (like the NOAH flood-fill or Wolfenstein map)

                e.g.            plan view

                        +---+---+---+---+---+...
                        |   |   |   |   |   |
                        |   |   |   |   |   |
                        +---+---+---+---+---+...
                        |   |   |   |   |   |
                        |   |   |   |   |   |
                        +---+---+---+---+---+...
                        |   |   |   |   |   |
                        |   |   |   |   |   |
                        +---+---+---+---+---+...
                        .   .   .   .   .   .

        NOTE:   each vertex is shared by FOUR map cells.


        2) now distort the corner vertex points into something like
           a "volume mesh" of neighbouring cells.
           (i.e.. grab a vertex and move it north, south, west, east,
            up or down)

                e.g.             plan view

                        +---+---+---+---+---+...
                        |   |   |   |   |   |
                        |   |   |   |   |   |
                        +---+---+---+---+---+...
                        |   |   |   |   |   |
                        |   |   |    |  |   |
                        +---+---+--   |/+---+...
                        |   |   |  ---+ |   |
                        |   |   |    /  |   |
                        +---+---+---+---+---+...
                        .   .   .   .   .   .

          Of course you can also drag the vertex point of the
        the other layers to create sloping floors and ceilings,
        small tunnels or a high cathedral roof. This would need
        2 mesh layers (one for the floor and one for the ceiling).
        You don't have to keep the vertices vertical, you can move
        one in or out to create sloped walls.

          This has some attractive features and is probably quite
        a bit easier to implement than proper inlet rendering.
        For a start we know how many sides each cell has and how
        many cells can be connected this it 4 (6 if multi-storey).
        Also as the vertices are shared by 4 neighbouring cells
        this can greatly cut down on the number of rotation and
        perspective transformations.
          Yet again we find ourselves back in the domain of the
        all-mighty CUBE. Each cell is (if you haven't guessed)
        a cube with 8 vertices and 6 faces. If we apply the inlet
        idea of perfect glass windows to connect neighbouring cells
        then we have the basics of a complex scene renderer.
        We can knock down cell walls to create long corridors or
        vast areas. If we use a 3d array (more than 2 mesh layers)
        then we can also create vertical lift shafts, holes in
        the ground and rooms above rooms.


#I3:DOOM 3 ?

          With a single layer mesh it 'might' be possible to write
        a simple DOOM render engine where walls are ALWAYS vertical
        only their X and Z co-ordinates change. All that is needed
        is to specify the floor and ceiling height of each cell,
        then stairs, cliffs and ledges can be done. You may also
        want to store a lighting level for each cell for dark
        rooms and blinking lights. And a floor type could be
        described as well. (lava, water, gravel etc..). Crushing
        ceiling and lifts might also be desired.
          But this list of parameters for every map cell is
        starting to get very big especially if you have a large
        map. Also it takes time to process each of these
        parameters (blink the lights, move the lift...). If you
        create very large lifts for example with many small
        volumes joined together then you are doing all the lift
        code for each volume individually. Also what happens if
        you wish to turn a vast area into a pool of lava or
        create multiple crushing ceiling with a single switch ?
        One way would be to create a list of each cell to be
        changed this way we could just process the list and
        modify the attribute of each cell (turn it to lava etc).
        A much better solution is to define a small number of
        region descriptions which define the floor type, lift
        position, lighting level and so on.. and then store a
        byte index within the map mesh. This way we can process
        ALL the regions once (possibly every game loop) and then
        for each cell in our mesh we just look-up the region's
        status.

        e.g.

           the map-mesh                   region descriptions
                                        
        +---+---+---+---+---+...
        | A | A | A | - | - |            A - lift, height etc..
        |   |   |   |   |   |            B - lava, health -10, light 150%
        +---+---+---+---+---+...         C - water
        | B | A | D | C | - |            D - normal floor
        |   |   |   |   |   |            E - crushing ceiling, blinks
        +---+---+---+---+---+...
        | B | A | E | - | - |
        |   |   |   |   |   |
        +---+---+---+---+---+...
        .   .   .   .   .   .


          So in the above diagram we define "region" tokens within
        each cell on map-mesh (our array). Each token is used
        to index into the region descriptions to discover what
        type of flooring, lighting, injury and possibly animation
        should be done. In this way many unconnected cells can
        be sync'd together or given identical attributes. In the
        above diagram the A token is used to describe a T-shaped
        lift which can be updated once by processing description A.
        If we changed it's description to say lava, then the entire
        lift has become a red-hot platform of heat. Nice eh ?

#I4:Now the catch

          Like all semi-good ideas, there is a catch or two.

          Some depth-sorting might be required because the vertices
        can be at different angles to one another and their position
        within the mesh won't guarantee correct depth-sorting.

          Designing a level will be harder because we must start off
        with an equally spaced grid of 3d cells and them deform it
        to make a more interesting environment. But what happens when
        the designer wants to create a structure of some kind and
        needs a vertex in the middle of a volume cells ? they can't :(

          One solution would be to insert vertices along both
        (or all 3) axiss and split any sides which cross it. But this
        would create a vast amount of work, not only for the
        level-editor but would probably slow down the engine as
        there would be more vertices to handle and more polygons.

          Another solution is to go back to the inlet method of
        describing connected cells using links from each window/door
        side which points to it's neighbour. But this would remove
        some of the advantages of using an array.. And at the same
        time it would remove some of it's restrictions too.

          Or you could describe object tokens within the mesh and
        draw 3d objects whenever for each occupied mesh cell.

                                         Oh well, life eh ?

#############################################################################
Ŀ
 #j:                  S-BUFFER (Span buffer techniques)                    

#############################################################################

          After reading the few snippets of info about this method
        it is perhaps one of the more easy to understand rendering
        methods. The idea behind it is the build a list of
        horizontal line spans (or vertical ones) which can be quickly
        used to draw the screen in a continuous manner, drawing one
        line span after the other until the entire screen has been
        drawn. I believe that the X-ngine used in Terminator Future
        Shock and Skynet used this technique (this is only a guess).
        With the usual depth-sorting and polygon drawing there is
        sometimes a large amount of pixel overdraw as more distant
        objects are partially (or entirely) hidden by closer ones.
        These days polygons have a heavy 'per-pixel' workload
        (texture mapping and shading) so the least number of these
        overdrawn pixels the better. Even with the latest super
        Pentium powered Cray wanna-be the video system on PC's
        compared to the system memory well, sucks BIG-TIME !! If you
        are lucky it's ONLY a 50% reduction in performance but
        it is normally far worse than this :(

          To give you an example I tested my Pentium 233 using
        Display-Doctor to give an indication of performance. For
        system memory it gave 112 Mb/sec, but on the video-system
        it gave only 15 Mb/sec which is 'slightly' slower wouldn't
        ya say ?

          Imagine we have 3 polygons at various depths from our
        view-point.

                e.g.
                                aaaaaaaaa               < most distant

                            bbbbbbbb

                                ccccccccccccccccccccc   < closest

                                    ^
                                view point      (plan view)

          The resulting screen scan-line after the above 3 polygon spans
        would look something like this:

                            bbbbccccccccccccccccccccc

                                  (front view)

          You should note that all the pixels from polygon 'a' have
        been completely overdrawn by the b and c polygon line spans.
        So instead of drawing 3 horizontal line spans on the screen
        we can just draw 2 (one of which is clipped, span 'b').
        The essence of the S-BUFFER algorithm is to build up a
        complete set of span-lists by clipping the co-ordinates of
        each span as it is inserted into the list. The order in which
        these spans are clipped and entered is unimportant because
        overlapping spans are either replaced by later ones or
        rejected because they are entirely behind previous ones.
        Take this method and apply it to every horizontal line on
        your screen and you basically have the S-BUFFER technique.
        You should hopefully end up with a list of horizontal line
        spans which represent all the clipped polygons spans and
        WITHOUT any overdrawing of pixels.

          A good side effect of this build-then-draw strategy is
        that it is possible to get away with only having a single,
        physical screen page (like VGA mode 13h). The old traditional
        method for sprites or polygons was to erase the entire screen
        and then draw the objects in their new positions. This could
        (and usually would) lead to a flickery display or 'tears' in
        objects as the video raster beam interrupts the drawing of
        them. For really good quality, NO-FLICKER animation two video
        pages are needed. One is displayed while the other off-screen
        one is being built up. After this the pages are swapped over
        and the just-built page is displayed while the next is built.
        The S-BUFFER techniques makes it possible to get away with a
        single screen page because nothing is being erased or partially
        drawn, everything is being overwritten in a top-to-bottom
        order. This might cause a slight glitch or tear because we are
        drawing to the physically displayed screen memory but it does
        mean that for video modes with a single page drawing can occur
        very quickly. No doubt it will be slightly faster then building
        an off-screen buffer image and block copying it onto the physical
        screen page.


#J1:Initialisation

          The S-Buffer needs to be set up before each render-cycle
        so each horizontal line's list needs to be emptied. But
        instead of creating a lot of null lists why not build
        a list of spans for a background 'horizon' bitmap this way
        we don't have the clear the screen before drawing the
        spans, also only the visible parts of the background
        will be drawn rather than the entire bitmap and having
        some parts overdrawn by the horizontal line spans.

          If these background spans are given a pseudo depth like
        all the other spans then this can be used as a detail level
        control. Simply move the background Z distant and all the
        landscape and object's polygons will be clipped up it.


#J2:Time to Clip ?

          There is a modest performance gain which can be found
        in the span clipping part when spans are entered in the
        span-lists. Imagine that we are drawing texture-filled
        polygons, so each horizontal span will have 3 co-ordinates
        for each end point (more if shading is performed).

                Left end-point                  Right end-point
                               
                Screen (X)                      Screen (X)
                Texture (U,V)                   Texture (U,V)

          Now we already have a horizontal line span in our
        S-buffer and we need to clip and insert another one which
        partially covers the first.

                e.g.
                        aaaaaaaaaaaaaa          < span 1

                                 bbbbbbbbbbbbb  < span 2

          So we must clip the part of span 1 which is hidden
        behind span 2. This would require clipping of the right
        Screen (X) and Texture(U,V) co-ordinates. The Screen (X)
        is not a problem and can be done with a simple MOV
        instruction, but it's the clipping in texture-space to
        find the right clipped (U,V) co-ordinates which is the
        performance bottleneck. In the worst case 2 multiplies
        and 2 divides !! and remember this is just ONE span on
        ONE line. You can imagine if lots more polygon lines
        are drawn there will be many instances when the
        texture (U,V) co-ordinates must be clipped.

          In the above description the texture (U,V) clipping was
        done at the same time as inserting the span into the
        S-Buffer, but we can also clip as we draw each horizontal
        line span onto the screen. Although some more work must
        be done during the drawing stage it can save a great
        deal of time. For example say we inserted another span, 3
        which completely covered both the 1 and 2 spans.

                e.g.
                        aaaaaaaaaaaaaa                  < span 1

                                 bbbbbbbbbbbbb          < span 2

                    cccccccccccccccccccccccccccccc      < span 3

          Now both span 2 and the just clipped span 1 is now
        completely hidden by span 3, this means that the right
        clipping of span 1 texture-co-ordinates (U,V) has been
        clipped for nothing. If we added more and more spans then
        it is possible that more and more previous spans will
        be totally or partly hidden. Lets face it, this is the main
        characteristic of having many, many overlapping line spans
        that the S-BUFFER algorithm relies on.

          All we need to do is to clip the screen (X) co-ords
        of the span and keep a record of it's original X coord.
        This way after ALL the horizontal line spans have been
        built up in the S-Buffer we can set about clipping and
        drawing each texture-filled line. This does add a little
        more work in the drawing stage but has saved more in the
        span insertion stage, and don't forget the savings when
        spans are totally hidden by closer ones. This means we
        only ever clip the texture (U,V) co-ordinates for visible
        or partly clipped spans and NOT for totally overdrawn ones.
        To perform this clipping at draw time we need to keep either
        the original (unclipped) screen X co-ordinates of the span
        or a clipping length (where 0 = no clipping) together with
        the normal S-Buffer information. This extra storage is only
        about 2 words per horizontal span.

          All in all I think that this is a good solution as it
        simplifies the insertion stage and adds a very small amount
        of extra work to the drawing stage, so it balances up the
        two. As most of the data handling is done in the insertion
        stage this should create a shorter and faster processing
        pipeline (and that can't be bad :).

          This later clip stage can also be used to quickly insert
        spans which cross the left and right screen edges. Once all
        of the inserting has been done it is highly probable that
        these partly off-screen spans have already been replaced
        by others in the S-BUFFER.


#J3:Fences, Water & Tints

          The basic S-BUFFER (span buffer) rendering technique
        in it's simplest form is a two stage process. The first stage
        builds up a list of horizontal (or vertical etc...) line
        spans. This list is a series of both screen and texture-space
        co-ordinates which represent the ends of each scan-converted
        polygon line. During this stage NO pixels (or texels) are drawn
        only their co-ordinates are calculated and stored in the span
        buffer lists. Overlapping line regions are either clipped or
        replaced by later line-spans which are added to these lists.
        The second stage is the "filler" part. This takes the
        resulting span lists from stage one and fills between the
        end points with pixels.

          Now this S-BUFFER method can be extended to include
        transparent or semi-transparent material such as water, windows
        or even force-fields. I have previously described how new
        line-spans are added into the span buffer lists and how it
        is possible that older line-spans can be overwritten or
        partially covered by newer ones. But instead of just losing
        the older pixels in a span why not use the new span to
        colour or shade them ?

                e.g.
                        aaaaaaaaaaaaaa                  < span 1

                                 bbbbbbbbbbbbb          < span 2

                    ====================                < span 3

          In the above diagram we have 3 spans where 1 is the
        oldest and span 3 is a semi-transparent span. Instead of
        removing/clipping span 1 and 2 we could shade or tint
        them using our new span 3. This would modify half of
        span 2 (the bbb... line) and all of the clipped part of
        span 1 (the aaa... line).

          You don't have to stop at just shading or colouring
        you could use this method for water or fencing effects
        where a number of texture bitmaps are overlaid. In the
        case of water this is normally a wrap-around scrolling
        texture bitmap which colours other spans blue and perhaps
        has a few frames of animated white specks on top.

          Here is a short list of ideas for span modifiers:

                1) colour/tint  - just like coloured filters
                                  (emergency lighting etc..)

                2) shade        - reduces lighting amount
                                  (like fog, mist)

                3) fences       - overlay 2 or more textures
                                  (water ripples, rain, static fxs)

                4) Lensing      - curved lens like effects
                                  (magnifying glass)

                5) Mirroring    - flipping the X or Y axis


#J4:The Speed Issue

          The problem with using newer spans to modify older ones
        is the issue of speed. With each new span comes the task
        of processing all the older ones underneath it. Where as
        purely opaque spans would clip or replace older spans, so
        by reducing the number of them, these colour tinting/shading
        spans do not, they just modify the previous ones.
        In affect we need to revisit and update old spans to gain
        the span effects we want. If a highly complex scene is being
        rendered with small polygons then this can get quite slow.

          One solution could be to create a separate S-BUFFER for the
        shading/tinting effect(s) rather than trying to combine both
        at the same time. This way the insertion process will have
        fewer checks because solid spans will be contained in their
        own S-BUFFER and the modifying shade/tint ones in their own.


#J5:The Right Direction ?

          The good thing about the S-BUFFER technique is that the
        direction of the view-point is not important. It deals
        with hidden surfaces by clipping their texture and screen
        co-ordinates rather than overdrawing their pixels. In other
        words we can scan items in a random order without regard
        to depth sorting. We could start at the most distant item
        and place it's spans into the S-BUFFER first and as other
        spans are added they may be covered or not. At the end we
        have the correct line span lists which we can simply fill
        with pixels without overdraw. The same result is found by
        choosing the closest item and adding that to the S-BUFFER
        first or in fact any item in any order, the final result
        is identical no matter what the order is.

          But inserting spans into the S-BUFFER takes time, so the
        lower the number that we need to insert the better. If we
        begin with the closest item and add it's spans then this
        should work out faster because new spans will be further
        away and are much more likely to be hidden, so they will
        never be inserted into the S-BUFFER lists. The other
        advantage of this view --> horizon order is that the span
        modifiers (colour, shade, water, fences etc..) will be
        processed with each new span added rather than going back
        and updating older spans.

          At this moment in time I think that the 'INLET' method
        can, if not solve, greatly speed up this process.
        As it is already a view-2-horizon (slab-casting) method
        then some/all of the depth sorting problems have already
        been taken care of.

#############################################################################
Ŀ
 #K:               Line clipping & Polygon edge clipping                   

#############################################################################

          Every book that I have ever seen that deals with the subject
        of line clipping and polygon scan-converting describes the
        same old, identical copy of the "Cohen-Sutherland" method.

          I will try and describe this method, but I have written this
        off the top of my head without access to the algorithm so it
        might have some mistakes. There is another algorithm called
        "Sutherland & Hodgman" ? but I think that's 3d clipping
        using 6 planes rather than 2d (screen) clipping.

          The basic idea behind the "Cohen-Sutherland" clipper
        is to assign a 4 bit "outcode" for each 2d vertex (or 6 bit
        outcode for 3d vertices) and then to accept, reject or clip
        every line between two of these vertices. These bits in the
        outcode describes which one of the 9 zones a vertex is in.
        The area around the "view-port" (clipping window/screen) is
        divided into 9 zones using the minimum & maximum clipping
        limits to define their co-ordinates.

          Take a single vertex at position (x,y) then create
        a 4-bit outcode using these xmin, ymin, ymax and ymax values

                e.g.

                        outcode = 0

                        if y < ymin then outcode + 0001 binary
                        if y > ymax then outcode + 0010 binary
                        if x < xmin then outcode + 0100 binary
                        if x > xmax then outcode + 1000 binary

> X              x min         x max
 
                               |             |
                               |    above    |
                               |             |
                    0101       |     0001    |        1001
 v                              |             |
 Y                              |             |
  y min ------------------------Ŀ---------------------
                                             
                                             
                     0100            0000            1000
                                  view port  
                     left                            right
                                             
  y max ----------------------------------------------
                                |             |
                                |             |
                     0110       |     0010    |        1010
                                |             |
                                |             |
                                |    below    |
                                |             |

          Now if this outcode is 0000 binary then the vertex is
        entirely within the view-port so it can be drawn. Otherwise
        it lies outside the clipping view-port region.

          Okay, now lets look at a line which requires 2 vertices
        (one for each end). We create a 4-bit outcode for each end
        of the line then we can either ACCEPT, REJECT or CLIP the line.

                e.g.

                        outcode1        = 1st vertex(x1,y1) zone code
                        outcode2        = 2nd vertex(x2,y2) zone code

THE GOOD:       if outcode1 AND outcode2 <> 0000 binary then REJECT

                        (both end points are outside the view-port, and
                         share 1 or 2 outcode bits. This means the line
                         is entirely above, below, left or right of the
                         view-port and does NOT cross into the view-port.
                         The entire line can be rejected & not drawn)

THE BAD:        if outcode1 OR outcode2 = 0000 binary then ACCEPT

                        (both end points are within the view-port, so
                         the entire line can be drawn without clipping)



THE UGLY:       otherwise CLIP

                        (this is the worst case as clipping MUST be
                         performed on the line as it may OR may not
                         cross the view-port. Even after this clipping
                         it is possible that the line is completely
                         outside the view-port. In the worst case a
                         maximum of 4 clips needs to be done, one for
                         x1, one for y1, one for x2 and one for y2.
                         ALL the algorithms that I have read about
                         create a new outcode for every x or y
                         co-ordinate clipped so in the worst case
                         we are clipping 4 times and creating outcodes
                         5 times !)

          I will not describe the "Cohen-Sutherland" clipper because
        as I have already said I haven't got any reference to it and
        also because I want to describe my method which I think is
        more efficient then re-creating outcodes after each boundary clip.
        The Cohen-Sutherland clipper must examine end of the two end
        vertices to discover which zone a line starts in and which
        zone the line ends in. So in effect they are doing this:-

                1) determine the zone where each vertex is
                2) create an outcode for each vertex

                3) determine if it needs clipping
                4) now determine the zone from the outcodes
                5) find the intersection of the X or Y axis
                6) create a new outcode for the clipped axis
                7) if we can't ACCEPT or REJECT the line then goto 4)

          As you can see we it seems to ping-pong back and forwards
        between zones and outcodes. I think that the original
        algorithm was recursive (maybe) which makes it worse !

 
                                My clipper
 

#K1:Border clipping

          Sadly, no-one else to my knowledge has ever presented a
        different method to the Cohen-Sutherland algorithm, I hope
        to address this with the following code. I can see some
        advantages in the Cohen-Sutherland method, namely the
        ACCEPT or REJECT cases for entire polygons, but for me the
        CLIP part has been neglected in every book I've seen.

          In my line-drawing routine I support clipping WITHOUT the
        need to create outcodes for each end-point. I also use the
        line's slope to both speed up clipping and drawing and in
        many respects this removes the need for outcodes. My belief
        is that once some calculation or classification has been
        performed then why do it again ? Just the previous knowledge
        and some tricks should be enough. Some programmers hate the
        very idea of using special-case routines and prefer to use
        a much slower, more general routine, but for things like
        graphics and especially video-games I think they are wrong.

                Don't follow the generals, be special !!

          First of all lets define a line using two vertices (x1,y1)
        and (x2,y2), then if we use vertex 1 (x1,y1) as our starting
        point and take vertex 2 (x2,y2) as our ending point, then
        the line can point in any one of the 360+ degree directions.

          The end vertex (x2,y2) can be in any one of the below regions
        (it can also be exactly ON the X or Y axis, in these cases a
        custom vertical or horizontal routine is normally used).
        Knowing what region a line points in can greatly speed up
        the line drawing and clipping.

        Remember (x1,y1) is the centre origin (our start point).


> X AXIS                   0, -Y
                                    ^
                                    
                                    
v                                    
                                     
Y AXIS                       -X, -Y    +X, -Y
                                     
                      -X,0  <>  +X, 0
                                     
                                     
                             -X, +Y    +X, +Y
                                     
                                     
                                     
                                     v
                                   0, +Y


          We can sift out the horizontal and vertical cases by
        comparing the x and y co-ordinates. In these cases clipping
        and drawing can be done without any slopes calculation.

                e.g.

                        if x1 = x2 then goto Line_is_Vertical
                        if y2 = y2 then goto Line_is_Horizontal

          We can force an upwards pointing line into downwards
        pointing one simply by swapping the start (x1,y1) and the
        end (x2,y2) points over. This way we always start at
        the top-most point and only need to draw in one direction
        (downwards). You could use the X-axis in the same way and
        force lines to only go from left-to-right or right-to-left.
        But I'll stick to a top-2-bottom direction.

                e.g.
                        if y2 < y1 then swap x1,x2
                                        swap y1,y2


          This means we are starting at the topmost vertex, this
        removes the whole 180 degree of upwards pointing cases.
        The end vertex (x2,y2) is in one of the below regions.
        (Remember we have already sifted out the horizontal & vertical
        cases so the line can NOT lie ON the X or Y axis lines.)

                            <> X AXIS
                                     
                                     
                             -X, +Y    +X, +Y
                                     
                  right-to-left            left-to-right
                                     
                                     v
                                  Y AXIS

          At this stage we can reject some totally clipped cases.
        Because we know the top (Y1) and the bottom (Y2) co-ordinates.

                e.g.
                        if y1 > ymax then goto REJECT   (totally below)
                        if y2 < ymin then goto REJECT   (totally above)

          We can determine which region the end vertex (x2,y2) is in
        simply by comparing the X co-ordinates. From here we break
        into two separate cases for left and right pointing slopes
        this does repeating the clipping code but it can be custom
        made and also removes some slope drawing direction tests
        which a general clipper would use.

                e.g.
                        if x1 > y2 then goto Right_facing
                                   else goto Left_facing


-----------------------------------------------------------------------------

          Below is the WORST possible case of a line, it needs to
        be clipped against 4 boundaries

                T = top clip            make y1 = ymin & x1 = X intercept
                L = left clip           make x1 = xmin & y1 = Y intercept

                B = bottom clip         make y2 = ymax & x2 = X intercept
                R = right clip          make x2 = xmax & y2 = Y intercept

             (x1,y1)          LEFT          RIGHT
                     ***                     
                        ***                  
       TOP     T**
                              *L*             
                                ***          
                                   ***       
                                      ***    
                                         *** 
                                            *R*
                                              ***
                                                 ***
       BOTTOM  B**
                                                       ***
                                                          ***
                                                              (x2,y2)

          Now that we have found the direction that the line ends in
        we can actually begin to test & clip it. Firstly we can reject
        two totally clipped cases.

                e.g.

        Right_facing:
                if x1 > xmax then goto REJECT           (totally right)
                if x2 < xmin then goto REJECT           (totally left)

          The above 2 checks reject lines which are totally left or
        totally right of the clipping region. At this point we can
        work out the X and Y lengths of the line, these will be used
        for the clipping operations later on.

                XL = 1 + x2 - x1
                YL = 1 + y2 - y1

          Now we can check and clip each vertex and each axis in
        turn. After each axis clip a simple test is performed to
        determine if the intercept value makes the entire line
        miss the clipping region completely. This happens when
        two vertices aren't in neighbouring, orthogonal zones.
        (eg 1000 & 0001, 0100 and 0010) where the REJECT fails.
        It is possible for different lines in these zones to be
        completely clipped or partially clipped. In these cases
        the X or Y axis intercept can be used to determine if
        the line cuts through the viewing window or is outside.

        e.g.

             xmin              xmax

                                
                    0001  aa            1001
                            aa  
                              aa
                        bb      aa   
                          bb     aa v
          bbaa  ymin
                            ^ bb     aa
                    0000       bb      aa
                                 bb      aa
                   viewing         bb
                   window                   1000
                                
          bbaa  ymin
                                

            xmin                xmax

          In the above diagram the two line a and b both have the
        same slope and are both in the same clipping zones
        (0001 and 1000) but one cuts through the viewing-window
        and one does not. If we were clipping the top most Y
        co-ordinate to the ymin boundary then you should be able
        to see the 3rd 'bb' line section is inside <= xmax
        where the 6th 'aa' section is outside > xmax.

          The following code will check and clip a line against
        the clipping rectangle.

                topclip = ymin - y1
                if topclip > 0 then y1 = ymin
                                    x1 = x1 + (topclip * XL / YL)
                                    if x1 > xmax then goto REJECT

                botclip = y2 - ymax
                if botclip > 0 then y2 = ymax
                                    x2 = x2 - (botclip * XL / YL)
                                    if x2 < xmin then goto REJECT

                leftclip = xmin - x1
                if leftclip > 0 then x1 = xmin
                                     y1 = y1 + (leftclip * YL / XL)
                                     if y1 > ymax then goto REJECT

                rightclip = x2 - xmax
                if rightclip > 0 then x2 = xmax
                                      y2 = y2 - (rightclip * YL / XL)
                                      if y2 < ymin then goto REJECT

                .... the line has been successfully clipped ...
                .... and so now you can draw the line !!! ....

          We already know that the line begins on the left
        and ends on the right and also (y1) is the topmost
        point and (y2) is the bottom most point.

-----------------------------------------------------------------------------

          And this is the other region clipping algorithm, this
        time it deals with left facing lines. This means some
        of the clipping lengths and co-ordinates are reversed
        but the idea is the same. We know that the line faces
        downwards and ends to the left of the starting point.

                e.g.

        Left_facing:

                if x1 < xmin then goto REJECT
                if x2 > xmax then goto REJECT

                XL = 1 + x1 - x2                <--- NOTE: reversed x2,x1

                topclip = ymin - y1
                if topclip > 0 then y1 = ymin
                                    x1 = x1 - (topclip * XL / YL)
                                    if x1 < xmin then goto REJECT

                botclip = y2 - ymax
                if botclip > 0 then y2 = ymax
                                    x2 = x2 + (botclip * XL / YL)
                                    if x2 > xmax then goto REJECT


                rightclip = x1 - xmax
                if rightclip > 0 then x1 = xmax
                                      y1 = y1 + (rightclip * YL / XL)
                                      if y1 > ymax then goto REJECT

                leftclip = ymin - x2
                if leftclip > 0 then x2 = xmin
                                     y2 = y2 - (leftclip * YL / XL)
                                     if y2 < ymin then goto REJECT

        ... draw the line ! ....

          And that's my clipping method, no need to generate the
        outcodes or regenerate them with each clip, just use the
        region and the line's slope. This type of clipper is
        reasonably good for polygons and if they are drawn in a
        top-to-bottom manner than you can avoid having to perform
        the bottom edge clipping and instead clip the polygon
        height (the number of scan lines).


#K2:Creating the outcode bits

          If you do use the outcode method then the following tip
        might be handy. Instead of using the standard compare, jump
        and OR instructions:
                e.g.
                        AX = X co-ordinate
                        BX = Y co-ordinate

 1                      MOV     DL, 0           <-- outcode = 0
 1                      CMP     AX, xmax
 1                      JLE     @@1
 1                      OR      DL, 1000b       ; outside right
                @@1
 1                      CMP     AX, xmin
 1                      JGE     @@2
 1                      OR      DL, 0100b       ; outside left
                @@2:
 1                      CMP     AX, ymax
 1                      JLE     @@3
 1                      OR      DL, 0010b       ; outside bottom
                @@3:
 1                      CMP     AX, ymin
 1                      JGE     @@4
 1                      OR      DL, 0001b       ; outside top
                @@4:
====
 9 .. 13 CLKs (Pentium)
13 .. 17 CLKs (486)

          Use the CF (carry flag), RCL and the SETC instructions:

                e.g.
 1                      CMP     AX, xmax            1
 1                      SETC    DL                 4/3
 1                      CMP     AX, ymin            1
 1                      RCL     DL, 1               3
 1                      CMP     BX, ymax            1
 1                      RCL     DL, 1               3
 1                      CMP     BX, ymin            1
 1                      RCL     DL, 1               3
 1                      XOR     DL, 1010b       ; invert bottom + right bits
====
 10 CLKs (Pentium)
17 .. 18 CLKs (486) ** worse **

          This removes all those nasty conditional jump
        instructions which can seriously damage your speed 8)

        There is also a way to remove the final XOR instruction,
        but I'll leave that to the reader (heh heh, king neg).


#K3: Clipping Similar Triangles

          In the previous example of clipping I have used the old
        properties of similar-triangles to find the intersection
        point of a triangle along a straight line but I failed to
        describe how it works so I better do this now.

                                       xmin    (x2,y2)

                               xclip Ĵ    oX     
                                           oo .     
                e.g.             (xi,yi) oo   .     
                                        oX     .     
                                      oo      .  y length
                                    oo        .     
                                  oo          .     
                                oo            .     
                              Xo................     
                                         
                      (x1,y1)
                               x length Ĵ

          In the above diagram we have a line (x1,y1) to (x2,y2)
        and the X-axis boundary (xmin) to which the line needs to
        have it's left side clipped to. We need to find the
        co-ordinates (xi,yi) which is the point at which the line
        intercepts the vertical xmin boundary.

          The xi co-ordinate is simply the xmin value and the yi
        can be found using the following formula:

                       (y2 - y1)  *  xclip
                yi =   +  y1
                            (x2 - x1)

          where:
                        xclip = xmin - x1

          This just demonstrates clipping against the left boundary
        edge of the clipping region but the same technique can be
        applied to each of the other 3 sides (right, top and bottom
        edges).


#K4: Slope Based Edge Intersection

          The normal approach to clipping is to test and clip one
        boundary edge at a time so the entire clipping process is
        performed in 4 individual steps. The order I usually do
        these steps is top, bottom, left then right. Even a number
        of the very well known algorithms work in this 4 stage
        way. But there is a problem for 50% of line cases, it is
        to do with the order of these clipping steps.

          Consider just 2 of the normal 4 clipping boundary edges
        (top and right) and the order of clipping is top then right.

                                                  A
                                               oo
                        above                oo
                                           oo
                   oo
                                       oo
                                     oo
                       inside       oo        right
                                  oo 
                                oo   
                              D

          In the above diagram the line A..D needs to be clipped
        inside the top and right boundary edges. But in the top first
        then right clipping order the line would first be clipped
        against the top (ymin) limit at point B like this:

        stage 1)                    xmax
                                                  A
                                               ..
                        above                ..
                                           ..
                   oo ymin
                                       oo   B
                                     oo
                       inside       oo        right
                                  oo 
                                oo   
                              D

          And then against the right boundary limit at point C.

        stage 2)                    xmax
                                                  A
                                               ..
                        above                ..
                                           ..
                   .. ymin
                                       ..   B
                                     ..
                       inside       oo        right
                                  oo  C
                                oo   
                              D

          Now we have the line section C..D after two operations.
        Okay, that was the worst case. Lets have a look at another
        line with an identical slope but a different origin.

                                    xmax
                                         A
                                      oo
                        above        oo
                                   oo
                   oo
                               oo    
                    inside   oo      
                           oo                right
                         oo          
                       oo            
                     D

          The same top then right clipping order is performed on this
        new line which gives:

        stage 1)                    xmax
                                         A
                                      ..
                        above        ..
                                B  ..
                   oo
                               oo    
                    inside   oo      
                           oo                right
                         oo          
                       oo            
                     D

          Please notice that the first example needed TWO operations
        whereas this example only requires ONE.

                              SO WHAT ?
                             
          Well, if you perform the right edge clipping operation
        before the top edge then the situation is reversed. The
        first example now needs only ONE operation and the second
        example needs TWO. The inefficiency comes about from not
        selecting the correct boundary edge to clip against.
        So if we can identify the correct edge to use we can avoid
        performing any unnecessary clipping operations. This is
        quite easy once you realise that the point at which two
        region edges meet is the decision point for the top or right
        edge. Simply examine the line's slope from A..D against the
        slope of an imaginary line from K..A

NOTE:   The point K has co-ordinates (xmax,ymax) where the top and right
        boundary lines meet.

                                   xmax
                                                  A
                                           ... oo
                        above           ...  oo
                                     ...   oo
                   Koo ymax
                                       oo
                                     oo
                       inside       oo        right
                                  oo 
                                oo   
                              D


          It could look something like this:

                    (Ay-Ky)      (Ay-Dy)
                IF  >  THEN clip against right
                    (Ax-Kx)      (Ax-Dy)


                    (Ay-Ky)      (Ay-Dy)
                IF  =  THEN clip 45' degree line
                    (Ax-Kx)      (Ax-Dy)


                    (Ay-Ky)      (Ay-Dy)
                IF  <  THEN clip against top
                    (Ax-Kx)      (Ax-Dy)

          Of course the test only really needs to be done once and
        the result used to select the appropriate action.

                                 BUT .....
                                
          The major draw back on this method is that it requires 2
        divisions to perform the test whereas the 2-stage method
        would only use an extra 1 multiply + 1 division in the worst
        case (incorrect edge order) or NONE in the best case.
          At the moment it seems of little interest except for
        experimentation purposes but I'm sure it will find a useful
        application somewhere....


#K5: Divide And Conquer (the CLKs)

          There is an obvious speed-up to the clipping and general
        polygon drawing technique especially if you use an incremental
        approach (to step the X-axis for each line) rather than use
        a Bresenham method. First of all you calculate the slope of
        the line (the increment) BEFORE you do any clipping. Now when
        you want to clip you can simply use a multiply instruction
        for two of the clipping boundaries this saves a costly division.

                      XMIN                            XMAX
                                    ABOVE              
                                                       
y axis          YMAX
 ^                                                     
                                                      
               LEFT            CLIPPING REGION           RIGHT
                                                      
                                                      
               YMIN
                                                      
                                   BELOW              
 
> x axis

NOTE:   the following pseudo-code assumes x2 > x1 and y2 > y1

-----------------------------------------------------------------------------
                e.g.
                        xl = (x2-x1)
                        yl = (y2-y1)

                        xstep = xl / yl         <---- slope reciprocal

                        topclip = y2 - ymax
                        if topclip > 0 then x2=x2 - (topclip*xstep)
                                            y2=ymax

                        botclip = ymin - y1
                        if botclip > 0 then x1=x1 + (botclip*xstep)
                                            y1=ymin
-----------------------------------------------------------------------------

          You can also take the proper slope (yl/xl) and perform the
        left and right boundary clips using that.

NOTE:   the following pseudo-code assumes x2 > x1 and y2 > y1

-----------------------------------------------------------------------------
                e.g.
                        xl = (x2-x1)
                        yl = (y2-y1)

                        ystep = (yl/xl)         <---- slope

                        leftclip = xmin - x1
                        if leftclip > 0 then x1=xmin
                                             y1=y1 + (leftclip*ystep)

                        rightclip = x2 - xmax
                        if rightclip > 0 then x2=xmax
                                              y2=y2 - (rightclip*ystep)
-----------------------------------------------------------------------------

          In the worst clipping case this method would take 2 divides
        and 4 multiplies where the normal similar triangles method
        would take 4 divides and 4 multiples. And remember this method
        automatically calculates the axis step (the X or Y increment)
        so scan converting the line, especially for polygons can be done
        much faster than a Bresenham based one which requires a
        conditional jump instruction within the main loop.


#K6:Bresenham vs. Incremental

          When 'scan-converting' a line or polygon edge (finding the
        X axis co-ordinate for each scan line) you need to interpolate
        between the two end vertices along a straight line to discover
        what pixels you should draw. Many, many moons ago a clever little
        chap called Jack Bresenham described one of the most useful
        algorithms of all time (back in 1965-ish I think). It has been
        so widely used and studied that most programmers can code it
        in their sleep. What makes it a very attractive little algorithm
        is that fact that it can trace out a straight line WITHOUT the
        need for a single division or multiplication. Instead a quick
        test is performed and the nearest axis to the correct line is
        stepped along a pixel at a time. The test is based on the old
        repeated subtraction method to perform division just the
        opposite of repeating addition to perform multiplication. There
        is a hidden trick up it's sleeve, it actually does TWO divisions.
        One for the integer part and one for the fraction part. I will
        not go into detail as this doc is already far too big, but
        see for yourself how the minor step occurs one iteration earlier
        due to the fact of ADDING to the quotient counter rather than
        reloading it (see line marked by ***). This earlier step is
        actually the fractional carry.

                e.g.
                                MAJOR = 100
                                MINOR = 10
                                X = 10
                                Y = 10
                                D = MAJOR - minor
                        again:
                                PLOT (X,Y)
                                D = D - minor
                          ***   IF D <= 0 THEN D=D+MAJOR : Y=Y+1
                                X=X+1
                                IF X < 200 THEN GOTO again

          The problem with the Bresenham style of scan converting is it
        isn't very good for polygons where slopes are smaller than 45
        degrees. For very steep (larger than 45 degree slope) it is
        good because there is only one loop iteration per scan line.
        But for the other slopes many iterations are needed before
        the algorithm advances onto the next scan line. We could be
        tracing many pixels along a horizontal scan line before we
        reached the point where the Y axis changed.

          I believe most people use the incremental method for
        polygon drawing as it requires a constant amount of CPU time
        within the scan-converting loop, usually just 1 ADD instruction,
        whereas the Bresenham way would require about 3 or 5
        instructions per loop. The Bresenham doesn't need a division
        but the incremental method does to calculate the axis stepping
        value. There is a way to perform Bresenham using NO conditional
        jumps but that requires memory accessing (using either the CARRY
        FLAG or the SIGN of the decision variable to act as an index).
        Also you can perform Bressy in 2 or 3 instructions if you stick
        to a 64kb screen mode (like mode 13h) and use 32-bit registers
        (bits 31..16 as the decision and bits 15..0 as the screen offset).
        Together with a 16-bit addressing mode, this can be done
        something like this:

        a 4 instruction Bresenham:

                        MOV     [DI],AL         <--- plot pixel
                        ADD     EDI,ESI         <--- d+minor, DI+minorstep
                        JG      SHORT notyet
                        ADD     EDI,EBX         <--- d+major, DI+majorstep
                notyet:

          I haven't described what the variables are and how it works
        because I'm far too lazy :)

          It is possible to write a Bressy in just 3 instructions
        (well 2 plus 1 to plot the pixel) that doesn't perform the
        conditional jump instruction, but you don't wanna know, do ya ?
        Well, I not gonna tell you :) But here are some hints.
        The Bressy has only TWO states (either a major axis step OR
        a minor axis step). The decision SIGN bit can be used to
        indicate which state (and so which axis) should be taken.
        Okay, enough hints. Here is the darn thing:

                        MOV     [ES:DI],AL      ; plot the pixel
                        SBB     BH,BH           ; n = index = CF
                        SUB     EDI,[BX]        ; d+axis[n], DI+step[n]

NOTE:   This could only works for a 64Kb linear VGA screen mode and
        will probably won't handle the 64Kb wrap correctly (which
        happens if the screen is scrolled).

          I'll leave you to figure it out, you need 4 bytes at
        address [DS:00xx] and 4 bytes at [DS:FFxx] which are the
        update variables for the top 16-bits of EDI and the low
        16-bits (DI) is the screen pixel address.

          In light of the recent discussion about clipping (using the
        slope to clip) I would imagine that the incremental method is
        still the king especially on a dual-pipe Pentium super CPU
        where other instructions can be performed while waiting for the
        division to finish. And with floating-point instructions being
        faster than most integer ones the days of the Bresenham looks
        sadly numbered. But King Bressy has another trick up it's old
        sleeve. It doesn't NOT suffer from the accumulation errors
        which the incremental method does. So, there's still life in
        this old dog yet eh ?


#K7: Binary Sub-Division Clipper

          Unfortunately I can not remember whose algorithm this is
        but I remember reading about somewhere (perhaps I need to
        actually buy a damn graphics books !!). It is a way to avoid
        having to perform multiplications and divisions to find the
        intersection point(s) of a line using nothing more than
        shift, add and subtract instructions. It might be part of
        the Sutherland-Cohen or Hodgman outcode algorithm.

          Say we have a line with a single end vertex outside the
        clipping region. We need to find the point on the line at
        which it meets the boundary limits.

                (x1,y1)     
                        o-  
                          --
                            --
                             --
                outside        --      inside
                                 --
                                   --
                                     --
                                       -o  (x2,y2)

          Given the two end vertices (x1,y1) and (x2,y2) we can
        quickly find the middle point of the line by doing this:

                      (x1+x2)                 (y1+y2)
                xc =           yc = 
                         2                       2

          Now we have the co-ordinates (xc,yc) which are middle
        point which breaks the line into two separate sections
        (x1,y1) to (xc,yc) and (xc,yc) to (x2,y2).

                (x1,y1)     
                        o-  
                          --
                            --
                             --
                outside        *-      inside
                         (xc,yc)  --
                                   --
                                     --
                                       -o  (x2,y2)

          In affect we have subdivided the line into 2 halves.
        In the above diagram we have found a point inside the clipping
        region so we know that the point of intersection is in the
        first half of the line from (x1,y1) to (xc,yc) so we can take
        this as our line and subdivide this too until we finish up ON
        the boundary line. At this point we have found the intersection
        co-ordinate of the other axis.


#K8: Combined Incremental Clipper

          After a little bit of thought and taking a broader outlook
        on the problem of line clipping and drawing, it is possible to
        combine the two tasks and reduce the number of divisions and
        multiplications. Using the incremental method of drawing a
        line together with the slope based edge selection method it
        is possible to perform the clipping tests and all the
        intersection calculations using 4 divides and 2 multiplies
        and this includes calculating the increment value to draw
        the actual line.

          This 4 divide, 2 multiply example is the WORST case where
        BOTH end points need to be clipped to the window region.
        For the normal edge-by-edge approach (top, bottom, left, right)
        it would take 5 divides and 4 multiplies (remember this includes
        a divide to find the slope increment value) in the worst case
        or 3 divides and 2 multiplies in the best case.

          The advantage of this method is that the correct region's
        clipping edge is selected from the start, unlike the 4-stage
        method which can find the intersection point which is still
        beyond the clipping window region (see below T and B).


>X      (x1,y1)          xmin          xmax
                    ***                     
                       ***        above     
v      ymin    T**
Y                             *L*             
                                ***          
                                   ***       
                  left                ***          right
                                         *** 
                                            *R*
                                              ***
                                                 ***
       ymax    B**
                                   below               ***
                                                          ***
                                                              (x2,y2)

-----------------------------------------------------------------------------
 e.g.

    xslope = (y2 - y1) / (x2 - x1)

    yslope = (x2 - x1) / (y2 - y1)      ;; our incremental step for drawing

;** Compare the top-left slope against the line slope, the difference **
;** selects the correct clipping edge (either top or left) **

    IF (xmin - x1) > 0 THEN tslope = (ymin - y1) / (xmin - x1)
                       ELSE tslope = 0

    IF xslope >= tslope THEN y1 = y1 + (xmin - x1) * xslope     ;; left
                             x1 = xmin                          ;; edge

                        ELSE x1 = x1 + (ymin - y1) * yslope     ;; top
                             y1 = ymin                          ;; edge


;** A similar thing is done for the bottom-right slope. The difference **
;** selects the correct clipping edge (either bottom or right) **

    IF (x2 - xmax) > 0 THEN bslope = (y2 - ymax) / (x2 - xmax)
                       ELSE bslope = 0

    IF xslope >= bslope THEN y2 = y2 - (x2 - xmax) * xslope     ;; right
                             x2 = xmax                          ;; edge

                        ELSE x2 = x2 - (y2 - ymax) * yslope     ;; bottom
                             y2 = ymax                          ;; edge

-----------------------------------------------------------------------------

NOTE:     The above code is not a general case algorithm and may
        contain bugs so please use it as reference only to develop
        your own clipper. The above pseudo-code is possibly only
        worth doing for diagonal clipping where a line goes from
        above-left to below-right OR from above-right to below-left
        outside the clipping region.

          Of course this code can be further optimised to only do
        some calculations (like the 'xslope' value) if it actually
        needs to be used

                                THE BAD NEWS
                                ------------
          This method works out slower than the previous DAC method
        (Divide And Conquer) with two more divide instructions.
        It may still be useful for locating the correct edge of the
        clipping region perhaps for polygon clipping.


#K9: Custom Outcode Clipping

          The problem with writing any general code is that it
        usually operates at a far slower pace than some custom,
        special case code. As line and polygon clipping is already
        slow enough any short cut to boost performance is welcome.
        If you stick to the standard outcode method of labelling
        vertices then you can handle difficult (worst case) problems
        in a custom routine which will hopefully run faster.
        The ACCEPT and REJECT cases using the outcode algorithm is
        fine, but the CLIP stage can be improved. I have already
        described some ideas on how to minimise multiplications and
        divisions. The outcodes can be used to select the correct
        clipper sub-case. One obvious solution would be to create
        an 8-bit code from two 4-bit codes, this could then be used
        to index into a jump table to reach the correct routine.
        You could even use this to remove the ACCEPT (logical OR)
        and the REJECT (logical AND) stages. Both of these could be
        built into the jump table.

          This 8-bit jump table could look like this:

 index      outcode1 outcode 2           Action
               
  00 hex        0000 0000               accept entire line
  01            0000 0001               clip vertex 2 against top
  02            0000 0010               clip vertex 2 against bottom
  03            0000 0011                 -- invalid outcode --
  04            0000 0100               clip vertex 2 against left
  ..            .... ....
  11            0001 0001               reject entire line (above window)
  12            0001 0010               clip vertex 1 top, vertex 2 bottom
  13            0001 0011                 -- invalid outcode --
  ..            .... ....
  FF hex        1111 1111                 -- invalid outcode --

          This way it is possible to quickly choose the best custom
        clipping routine for a particular line without having to
        perform lots of tests and conditional jumps.

          It may be worthwhile seeing if this method could be
        extended to polygon clipping ??

#############################################################################
Ŀ
 #L:                     Polygon drawing & clipping                        

#############################################################################

          This has to be one of the biggest hurdles when writing
        3d code for the first (or the 100th) time. Almost all
        books just describe polygons as "a connected series of lines"
        and say that clipped line algorithms must be used to
        scan-convert the polygon edges.

          I will describe CONVEX polygons because they're easy and
        most important of all, FAST ! Some of my first polygon
        drawing code was done on the Amiga, and I was amazed to
        recently discover that the way I devised my first polygon
        filler is still being used today - so I must have got
        something right all almost a decade ago :)
        The method is: Find the topmost vertex of a polygon and
        then scan the right side forwards through the vertex list
        and the left side backwards. 99% of polygons are defined
        in a clockwise order, the other 1% are done in an
        anti-clockwise order just to be different :)

          In this section I will assume that ALL polygons are
        clockwise in order and that anti-clockwise polygons
        are consider as hidden (facing away from the view-plane)

          Imagine a 4 sided polygon with 4 vertices (hmmmm..
        there's a connect here somewhere). The vertices are
        labelled as a, b, c, d. A polygon defined in a clockwise
        order could have a data structure something like :-


     Edge number             Start vertex            End vertex
                      
        0                       a                       b
        1                       b                       c
        2                       c                       d
        3                       d                       a

          So for each of the 4 sides we have a starting vertex
        and an ending vertex. But this vertex list could be defined
        like this instead:-

                a b c d a               <--- vertex list


          Because one polygon side begins where the last ends
        the above list can be used to reduce memory usage.

                Start vertex = Vertexlist[n]
                  End vertex = VertexList[n+1]

        Note how I repeated the 1st vertex at the end to avoid
        doing a wrap-around check (every little helps).

> x                    b
                             / \
                            /   \ |
                        __ /   __\|
                          /|      \
                         / |       \c
                        /          /
v                     a /          /
                        |         /
y                       |        /
                        |     | /
                       /|\    |/__
                      / | \   /
                        |    /
                        |   /
                        |  /
                        | /
                        |/
                        d

          In the above diagram vertex b is the topmost point of
        the polygon. What we want to do is scan the left and the
        right edges of it into 2 co-ordinate lists ready for filling.
        This means that all the left X co-ordinates needs to go
        into one list and all the right X co-ordinates needs to go
        into a 2nd list. We can then draw a series of horizontal lines
        between the left/right edges. One thing of interest to note about
        clockwise polygons is the fact that the edges can quickly
        be sorted into left or right types just by looking at their
        Y lengths (the difference between the start and end Y co-ords).
        A zero Y length indicates a flat top or bottom polygon in
        this case examining the X length will determine which.

                e.g.
                        we have 2 vertices (x1,y1) and (x2,y2)


                        YL = y2 - y1

                        if YL > 0 then Right_Edge_Of_Polygon
                        if YL < 0 then Left_Edge_Of_Polygon

                otherwise ...

                        XL = x2 - x1

                        if XL > 0 then Top_Of_Polygon
                        if XL < 0 then Bottom_Of_Polygon

                else if XL = 0 then ....
                        ignore this vertex as it is has the same
                        X and Y co-ordinates the next vertex.
                        (x1=x2 and y1=y2).

          This is a very useful thing to know as it can make clipping
        much easier and hopefully quicker. For example if a part of
        the right edge is beyond the left clipping limit then we
        know that so is the left edge, so both can be ignored and
        not drawn. The same fact also works with the left edge, if
        that is outside the right clipping limit then it means
        that so is the right edge and again it can be ignored.


#L1:Convex Half-Space Clipping

          Given a convex polygon we know that none of it's interior
        angles can be more than 2*pi (180) which is a straight line.
        There are plenty of definitions of what a CONVEX polygon is
        in any good maths/geometry book. I found a nice one a month
        or two ago which inspired some new tricks when clipping and
        drawing a polygon. It went something like this:

          A convex polygon is the area of the overlapping regions
        of all the half-spaces created by it's edges.

          Put another way, moving round a polygon in a clockwise order
        take a single edge (the line between two vertices). Now imagine
        this edge as being on an infinite line (or hyper-line). The
        hyper-line divides space into two halves, two half-spaces.
        Now for a CONVEX polygon ALL of it's vertices lie on ONE side
        of this hyper-line. This it true for ALL of it's edges.
          If any vertices lie on BOTH sides of a hyper-line then
        the polygon is CONCAVE (and they are much harder to code, so
        I will only stick with CONCAVE ones =)

                e.g.                              1st half-space
                        < a side >

        .................o-----------------o............ an infinite
                        /                   \              plane
                       /                     o
                      /     the polygon's    /
                     /                      /
                    o       interior       /
                    \                     /       2nd half-space
                     \                   /
                      \                 /
                       o_______________o


          The above mathematical description is very useful
        to know because we know that if we moved around the
        polygon in a clockwise direction with the centre area
        of the polygon to our right, then NO edge or vertex can
        be on the right of current edge.

                     left                           right

                                                     
                   a                                 
               ea  top
                 e   a                               
                e     a                              
               e       a           clipping          
              e         a < TOP                     
             e          a         view-screen        
            d            a                           
            d             b                          
             d           b                           
              db  bottom
               d        b                             
                d      b                             
                 cccccb                              


          Imagine the above 5 sided polygon with a,b,c,d,e
        representing each side. Given side a we know it's a
        downwards pointing slope because we can tell by it's
        start and ending Y co-ordinates. This means it is part
        of the right edge of the polygon. As it must be clipped
        against the left boundary edge we have also found the
        top-most clipped Y co-ordinates at the same time.
        If we follow the polygon down to side b, then it too
        needs clipping, against the bottom edge AND the left edge.
        At this stage we can fill the entire polygon without
        having to deal with any other sides because we know
        that all the vertices (and so sides) are on the same
        half-space (side) as the polygon side b plane.
          If side b had not been outside the left edge then we
        would need to check side c and so on. Simply crossing
        the bottom clipping edge is NOT enough to indicate that
        the rest of the polygon is clipped off screen.

                      left                         right
            e.g.
                                                     
                                                     
                top
                                                     
                       ddddddda                       
                      c       a                      
                       c       a                     
                        c        a                    
                        c        a                   
                         c        b                  
           small gap > c      b                   
               cb bottom
                            c  b                     
                             cb                      
                                                     

          In the above diagram side b again crosses the bottom
        clipping edge but does not cross the left edge, which
        means another side could cut across and leave a
        small gap in the bottom left corner (see above).
        If the side c was flat or simply crossed the left edge
        then we would have enough to draw the polygon.

          I have not had chance to research all the possible
        combinations for a 3 of 4 sided polygon, but it may
        be worthwhile seeing if a tokenised table could be built
        to deal with all the possible cases. The outcodes may
        be a very handy way to describe each vertex or maybe
        a left/right flag system could be included as well..
        It would be worth investigating triangles in detail too
        as their interior angles are never bigger than 180 degrees
        so there may be a few more tricks to find...

          If you are having trouble with this then take a single
        side of a polygon and extend it in both directions to
        infinity. We already know that ALL of a vertices must
        lie on OR on one side of this infinite line (the same
        half-space). I believe I 'might' be one of the first
        people to make the connection between the half-space and
        clipping or at least one of the first to describe it in
        a doc !! Or perhaps some other more knowledgeable programmers
        have already discovered this and are keeping quiet.
        Very protective some programmers eh ? Maybe they are so
        reluctant to share because they fear some young whipper-snapper
        coder will come along and write faster code than theirs
        (sad isnt  it ?)


#L2:SUTHERLAND-HODGMAN Algorithm

          This is yet another well known algorithm which I have
        a brief knowledge of. I believe it works by clipping
        the entire polygon against one plane at a time rather than
        against a clipping rectangle or cube (I could be wrong given
        the sparse information I have).

          Basically we walk around the polygon, 1 side at a time
        and create a new vertex for every clipped line (which
        crosses the plane). When we have two new vertices or
        one old and one new vertex we create a new side to join
        them.

NOTE:   It is possible that one or more vertices lie exactly ON the
        clipping plane in which case no new vertices need be created.
        So remember to include the equals sign in your compares !!

                                a
                       o--------------------o          inside
                    f /                      \
                     /    our new polygon     \  b
         ** clipping plane
                   / P                        Q \
                  /                              \
                  o     this will be clipped      o    outside
                   \                             /
                    \                           /
                   e \                         /  c
                      o-----------------------o
                                 d

          In the above diagram a 6 sided polygon (a,b,c,d,e,f)
        is badly drawn. Starting at side a, we keep the entire
        side as both end-point are inside the clipping half-space.
        Now we come to side b, it crosses the clipping-plane
        so we create a new vertex Q which is the intercept
        point on the clipping-plane. Now we ignore all the
        other sides which do not cross back through the
        clipping-plane (c,d and e) until we come to side f.
        This crosses back into the 'inside' so we find the
        intercept point P and create a new vertex. Now we
        connect the vertices Q and P together to make a new
        side so we end up with the following polygon:

                                  a
                       o--------------------o          inside
                    f /                      \
                     /                        \  b
         *--------------------------* clipping plane
                     P      created side      Q

          This new polygon is then tested and clipped
        against the other 3 or 5 clipping-planes. At the
        end we have a one of the following situations:

                1) a totally unclipped polygon  (ACCEPTED)
                2) a partially clipped polygon  (CLIPPED)
                3) a totally clipped polygon    (REJECTED)

          The outcode technique can be extended to 6 planes so
        that a polygon or line can be clipped within a 3d cube
        rather than just a 2d rectangle (4 planes).

          I can remember a series of articles by Jeff Lawson in
        ST WORLD (remember that ?) and he hinted at a faster way
        to clip polygons developed in Canada, but I haven't seen
        or heard anything about it so maybe it was pure hype or
        someone was pulling Mr. Lawson's leg =(


#L3:A small improvement ?

          If we find a side which can be accepted (totally inside
        a clipping-plane) then we can work backwards as well as
        forwards from it. In the above examples we start at
        side a then clipped side b. We could then work backwards
        from side a, clip side f and define a new side between
        P and Q. This means we didn't have to search 3 sides
        (c,d and e).
          But when when no sides are totally outside (only 2
        are intercept) then it would probably work out the
        same with no real saving, just a little more code :(


#L4:Recycling 3-Section Lines

          I did mention elsewhere that it should be easy to reuse
        the edge slopes between two neighbouring polygons. This would
        save having to perform the slope calculations again, it can
        also halve the number of line clipping operations too.
        As drawing polygons is an extension to drawing lines it has
        some similar problems, but also some new ones. For example a
        line might be entirely outside the clipping region and so can
        be rejected but the same is not always true for a polygon edge.
        The line could be one of the polygon's many edges and yet the
        rest of the polygon could be inside the clipping region. So it
        is clear that we can not simply reject lines.

                             Ŀ
                                              A
                                   o----*----o
                  inside          /          \         Outside
                                 /            \
                                /              \
                               o--------*--------o
                                                  B
                             

          In the above diagram we have half of a polygon outside the
        clipping region and half inside. The line segment A..B is outside
        the region so could be rejected but the most of the polygon is
        still inside. If we have another polygon which shared the A..B
        line segment then it could be hidden (back-face culled), be
        completely outside the clipping region or also have part of it
        within the region like the above polygon.

          If we think of a polygon in terms of a finite number of
        horizontal scan lines (like all bitmaps tend to be) and consider
        all the possible line clipping operations in a horizontal
        rectangle type way then it turns out that a line can have
        0 to 5 sections. First think about Y-clipping (above & below
        the clipping region) this can break a line into a maximum of 3
        sections.

                            o                        above
                             \        A
                \
                               \
                                \     B              inside
                                 \
                \
                                   \  C              below
                                    o

          And so does the X-axis boundaries.

                        left         inside          right
                                               
                            A                  
                       o---                    
                           ---                 
                              --*               
                                ---    B       
                                   ---         
                                      ---      
                                         ---   
                                            ---    C
                                               *--
                                                 ---o


          Combining both cases we have 5 possible line sections. This
        is the worse possible case of clipping where the line must be
        clipped against all 4 boundary edges.

             (x1,y1)          LEFT          RIGHT                SECTION
                     A**                                          A  1
                        A**                                       A
       TOP     B**   B  2
                              B**                                  B
                                C**                               C  3
                                   C**                            C
                                      C**                         C
                                         C**                      C
                                            C**                    C
                                              D**                 D  4
                                                 D**              D
       BOTTOM  D**   D
                                                       E**        E  5
                                                          E**     E
                                                              (x2,y2)

          Now consider all the possible polygons which could utilise
        the above line slope as one of it's edges. This turns out to be
        just two, a polygon can be on one side of the line or the other.
        (In the left half-space OR the right half-space).

        e.g.
                        ...00000011111111...    0 = polygon left of line
                        ...00000000111111...    1 = polygon right of line
                        ...00000000001111...
                        ...00000000000011...

          We can make things easier by ignoring the A and E cases
        where a line is above or below our clipping region, so we have
        just 3 possible line sections like this:

                              LEFT          RIGHT                SECTION
                                              
                                              
       TOP     B**   B  1
                              B**                                  B
                                C**                               C  2
                                   C**                            C
                                      C**                         C
                                         C**                      C
                                            C**                    C
                                              D**                 D  3
                                                 D**              D
       BOTTOM  D**   D
                                              
                                              

          The reason why we can discard those two cases is because no
        matter what side a polygon is on the A & E sections it will never
        be seen as we are drawing horizontal scan lines which are
        parallel to the top and bottom clipping region.
        This Y-axis 'banding' may be a good place to start for a
        general polygon clipping and drawing routine. It would reject
        plenty of above and below edges and this would make the rest
        of the code much easier and quicker.

          Now that we have just 3 line sections how can they be reused
        for two connected polygons and how can we clip them ?

          Lets first think about a polygon to the right of the line
        and examine how the line sections are used (taking into
        consideration the B and D clipped sections).

                              LEFT          RIGHT    SECTION   DRAWN
                                              
       TOP     ..ccccccccccccccc   B       left clip
                              ..ccccccccccccccc        B       left clip
                                cccccccccccccc        C        c
                                   ccccccccccc        C        c
                                      cccccccc        C        c
                                         ccccc        C        c
                                            cc        C        c
                                              ..      D
                                                ..    D
       BOTTOM  ..  D
                                              

          Please note: the line section B was replaced with 'left'
        edge of the clipping region and the D line section was
        completely ignored.

          Okay, lets look at the other polygon case, one on the
        left side of the line.

                              LEFT          RIGHT    SECTION   DRAWN
                                              
                                              
       TOP     ..   B
                               ..                      B
                                ccc                   C        c
                                cccccc                C        c
                                ccccccccc             C        c
                                cccccccccccc          C        c
                                cccccccccccccc        C        c
                                cccccccccccccc..       D       right clip
                                cccccccccccccc ..     D       right clip
       BOTTOM     D       right clip
                                              

          Now the situation has reversed concerning the B and D
        line sections. This time B is ignored and D is replaced
        by the right clipping limit.

          There is something which I haven't mentioned yet, you may
        need to flag a line as either going upwards or downwards.
        This vertical direction would be used to determine what side
        a polygon is on (the left or the right). As we have seen in
        the last two diagrams the left (B) and the right (D) line
        sections are affected by the side on which the polygon is.
        I would suggest forcing ALL your edge slopes to be in a
        single direction (upwards or downwards) and use a single
        flag to indicate that the slope has been flipped.


#L5:Recycled Edge Co-ordinates

          The edge recycling can be extended further to include
        texture-space co-ordinates and shading co-ordinates as well.
        Both of these share the same 2 vertices, the same slope,
        the same slope length and hopefully the same perspective
        values. As a number of division are needed for each slope
        (sometimes even each scan line) this can add up to a large
        saving in CPU time.

          An idea I had a while ago was for texture mapping to help
        reduce the number of memory accesses when building up the
        slope value lists. For each slope do just ONE interpolation
        along it instead of the normal texture-space U, V and shading
        values. This one value for each scan line can be thought of
        as a fraction or scale percentage of the entire line with
        half way being equal to 0.5 or 1/2. The scale for the entire
        line would be 1.0 or some other constant value for every
        line.

                e.g.               0%
                                   o
                              50% / \  25%
                            100% o   \
                                      \  50%
                                       \
                                        \  75%
                                         \
                                          o 100%

          In the above diagram we have 2 slopes which could be part
        of a single polygon or parts of two separate polygons. The
        percentage % value indicates how far along the line slope we
        are in relation to the entire line.

          Now when you come to texture map you could take this
        single fraction value and index for the correct coord table.
        If we were using a 64x64 texture bitmap these coord tables
        could look like this:

        e.g.                      top     right  bottom    left
               fraction           edge     edge   edge     edge
                                 
                  0%              (0,0)   (0,0)  (63,63)  (0,63)
                 25%             (16,0)  (0,16)  (48,63)  (0,48)
                 50%             (32,0)  (0,32)  (32,63)  (0,32)
                 75%             (48,0)  (0,48)  (16,63)  (0,16)
                100%             (63,0)  (0,63)   (0,63)  (0,16)

          where the texture bitmap would be:

                           (0,0)   top    (63,0)
                                Ŀ
                                        
                                 bitmap 
                          left           right
                                        
                                
                          (0,63)  bottom  (63,63)

          I'm not sure how useful this would be. It might even be slower
        than scan converting the slope each time due to the slow speed
        of most memory compared to the fast CPU + cache speed. The
        advantage is that these coord table could be non-linear and
        perhaps translate texture space edges in a weird way without too
        much CPU time and maybe even animated for water or lava effects.

          But there is a problem, what happens when you need to clip a
        textured polygon ? Maybe this isn't such a great idea at the
        moment =(


#L6:Z-Cropping Polygons

          This is a very neglected subject in ALL of the books I
        have read. It is basically clipping polygons that intersect
        the Z view-plane (some use the Y coord. as view-plane). I know
        that most people will call it Z-Clipping or View-Plane-Clipping
        but I will call it Z-Cropping because you need to create more
        vertices and it must be down in 3-d, unlike the normal screen
        clipping which happens in 2-d (after projection/perspective).
        I can remember reading an article by Jeff Lawson who said that
        it was best to try and prevent polygons crossing the view-plane
        otherwise you need to create new vertices etc..

                          Okay, enough waffle.

          Like 2-d (X,Y) clipping 3-d Z-Cropping MUST be done on a
        line-by-line (or edge-by-edge) basis. You can NOT simply clip
        each vertex because even though a number of lines might use
        it as an end point the point of intersection is unique for each
        unique line. Also Z-Cropping needs to be performed BEFORE any
        perspective/projection takes place and worst of all you need
        to perform the intersection calculations twice for each line !!
        (once for the X-axis and once for the Y-axis).

          To perform this 3-d Z-cropping we can break it down into two
        2-d clips. We want to eventually find the values of a point
        (xi,yi,zi) which is the point on the projection-plane where the
        line (X1,Y1,Z1) to (X2,Y2,Z2) intersects it. We know that
        The (zi) value will just be the projection-plane Z co-ordinate
        because like most other people keeping it parallel to the X and Y
        axiss makes the maths much easier and quicker. So it's just
        the (xi) and (yi) values that we need to find.

        Lets find the (xi) one first.

                          PLAN VIEW
                                      (X2,Z2)
                                     o
                                    /.
                                   / .
                          (xi,zi) /  .
       projection-plane *
                                /    .        ^
                Z              /    ..         clip this
                ^             o.......        v
                      (X1,Z1)
                >X


          This is identical to a normal 2-d intersection and the
        two formulas to perform this are:

                Pz = Projection Plane Z-co-ordinate

                      (Pz-Z1) * (X2-X1)
                xi =  + X1
                           (Z2 - Z1)

                zi = Pz

          And a similar thing can be done to find the (yi) value.

                        LEFT SIDE VIEW
                                       projection
                                          plane
                                                  (Z1,Y1)
                                                o
                                               /.
                                              / .
                                             /  .
                                            /   .
                                            *    .
                Y                          /    .
                ^                         / <>
                                        o     clip this
           Z<                  (Z2,Y2)

          The formulas to find (yi) are:

                Pz = Projection Plane Z-co-ordinate

                      (Pz-Z1) * (Y2-Y1)
                yi =  + Y1
                           (Z2 - Z1)

                zi = Pz

          So now we have the new 3-d vertex (xi,yi,zi) which lies
        exactly ON the projection-plane. This must be repeated for all
        of the edges of all the polygons which intersection the
        projection-plane. And this means some polygons will have an
        extra vertex (and side) to them, some will have the same number
        and some will have fewer or none at all.

          After this Z-Cropping has taken place you still need to
        project these 3-d vertices onto a 2-d view-screen. All this
        extra work chews up more CPU time so any ways to reduce it is
        a very welcome vistor =)  The 'outcode' method of creating
        bit fields to indicate whether a vertex is beyond the clipping
        region in a number of axiss can be extended from 2-d to 3-d.
        So instead of clipping to a rectangle we are clipping to a
        cube like volume. The outcodes are very good at rejecting or
        accepting polygons and telling us what kind of clipping needs
        to be done.

          The actual Z-Cropping calculations can be done with 1 divide
        and 2 multiplies simply by keeping the (Pz-Z1)/(Z2-Z1) value
        which is the same in both stages.

          The Z-Cropping must be done in 3-d (X,Y,Z) but there are some
        other vital things to remember.

        1) It must be done BEFORE the projection/perspective calculations

        2) every line which shares the same end vertex MUST be Z-cropped
           independently as it has a unique point of intersection on the
           view-plane.

        3) EACH polygon which uses a shared vertex must have it's OWN new
           Z-Cropped vertex (because of the unique point of intersection
           on the Z view-plane). This means a cube could have 10 vertices
           instead of the normal 8, this happens when a single corner
           vertex is on the opposite side of the view-plane to the rest
           of the cube. So 3 faces of the cube will have 5 sided polygons
           instead of the normal 4.

        4) the projection/perspective calculations need to be done on
           these Z-Cropped vertices.

        5) the normal 2-d clipping then needs to be done on these new
           vertices.


#L7:Hidden Surfaces & Drawing

          Today after glancing through some very, very old articles
        about 3-d graphics I made a previously overlooked connection
        between hidden surface rejection (back-face culling) and
        scan converting polygons. I know elsewhere I have stated that

        "Sometimes it is very easy to fall into the low-level trap,
        (not seeing the forest for the trees) this is where I believe a
        more global, group approach can give the best gains."

          Pity that I didn't follow my own advice, until now =)

          Okay, imagine that you have already found the top-most vertex
        of a polygon and now wish to determine if it is anti-clockwise
        (hidden) or not (clockwise). In most cases this test will be
        easy to perform using the X co-ordinate of the vertices.

                        CLOCKWISE                      CLOCKWISE

                          B                          B------------C
                         / \                        /
                        /   \                      /   POLYGON
                       /     \                    /
                      A  POLY \                  /
                               C                A

          In both of the above examples it is clear that polygon is
        clockwise from looking at their A,B,C vertices. Likewise the
        below examples are clockwise too.

                CLOCKWISE               CLOCKWISE         CLOCKWISE

             A-----------B                     B        A----B--------C
                          \                   /|
                           \                 / |
                            \               /  |
                             \             /   |
                              C           A    |
                                               C

          In ALL of the above examples the following test will accept
        A,B,C (clockwise) polygons but would reject C,B,A polygons:

                IF (Ax <= Bx) AND (Cx => Bx) THEN clockwise ...   (visible)
                                             ELSE anti-clockwise... (hidden)

          But if (Ax=Bx) and (Cx=Bx) then we have a problem, the polygon
        is a straight, vertical line it is impossible to know whether
        it is clockwise or anti-clockwise. It is probably best to reject
        this type of polygon rather than using drawing a vertical line.

          We just compare the X co-ordinate of the A, B and C points.
        All of the above examples can be validated with a few compare
        instructions. But there is a trap which I originally fell into
        when writing my first polygon filler.

           CLOCKWISE                    CLOCKWISE

                 --B                    B--
               --  /                    \  --
             --   /                      \   --
           --    /                        \    --
         --     C                          A     --
        A                                          --C

          This time the two vertices on either side of the top-most
        vertex (B) both lie on the SAME side of vertex B, this can not
        be handled by just using compare instructions. You must use the
        slopes of line A..B and C..B to discover which side one is on
        in relation to the other.

              HIDDEN                    HIDDEN

                 --B                    B--
               --  /                    \  --
             --   /                      \   --
           --    /                        \    --
         --     A                          C     --
        C                                          --A

          These same-side cases can be tested for using this check:

                    (By-Ay)       (Cy-Ay)
                IF   <    then clockwise
                    (Ax-Bx)       (Ax-Cx)

        or, you can use:

                IF (By-Ay)*(Ax-Cx)  <  (Cy-Ay)*(Ax-Bx) then clockwise

        or,
                IF (By-Ay)*(Cx-Ax)  >  (Cy-Ay)*(Bx-Ax) then clockwise

          It basically compares one line gradient (slope) against
        the other in a sort of angle-type way.

                                SO WHAT ?
                                ---------
          Well this hidden surface test method uses two slopes of
        each polygon which (here it comes...) can be combined with
        the normal polygon drawing AND the edge recycling (if used)
        to save divisions. You need to handle vertical or horizontal
        slopes separately to avoid any divide-by-zero problems. You
        could even break off into custom polygon code for those slopes
        this would speed up the special cases and possibly clipping
        could be integrated into each case.

          So the slope (gradient) of a line is a vital piece of info.
        to know about. It can be used to draw polygons, locate the
        correct clipping boundary edge and be used to test for hidden
        polygon faces.


#L8:Half-Space Seams & Convex Culling

          As we have already seen convex plane polygons have some very
        useful attributes and very well known characteristics. One
        of the main reasons for choosing convex rather than concave
        polygons is mainly due to the fact that the drawing process
        (scan converting) is far easier for convex ones because no
        matter where you cross section across them they only ever have
        2 edges (usually the left and right). This means that there
        is only a single solid line to draw per scan line, whereas a
        concave can have any number.

                        A CONCAVE POLYGON

                                    o
                             o     / \
                       > /x\   /xxx\ < 2 line spans
                           /   \ /     \
                          /     o       \
                         /               \
                        o-----------------o

          After looking through some of my old scribbles in a dusty
        folder I have only just thought about a new way to cull convex
        polygons which could prove worthwhile. I can remember writing
        it down about 4 or so years ago and then forgetting all about
        it, until now. Originally the note was done without any real
        idea how or if the technique would work. In light of reading
        about the half-space description of a convex polygon another
        piece of the jigsaw has been added.

        1) Remember that a convex polygon has NO interior angle which
           is bigger than 180 degrees.

        2) for each polygon edge ALL of it's vertices must lie in the
           SAME half-space.

          Well the above rules really say the same thing. The important
        thing to note is that 180 degree is a straight line and the
        two half-spaces are also separated by a straight line.

                e.g.                              1st half-space

        .................o-----------------o............ an infinite
                        / p               q \            plane or line
                       /                     o B
                      /     the polygon's    /
                     /                      /
                  A o       interior       /
                    \                     /       2nd half-space
                     \                   /
                      \                 /
                       o_______________o

          If we take the two vertices A and B and move them so that
        angles p and q are at their maximum (180 degrees) we have the
        following:

              A                                 B
        ......o----------o-----------------o---o........ an infinite
               \         p                 q   /         plane or line
                \                             /
                 \          the polygon's    /
                  \                         /
                   \        interior       /
                    \                     /       2nd half-space
                     \                   /
                      \                 /
                       o_______________o

          By choosing any polygon side at random and extending it
        to infinity in both directions we know that ALL of it's
        vertices (and so sides) all lie on one side of it.

                YEAH, BUT WHAT ABOUT THE CLIPPING ?
                -----------------------------------
          Suppose we had a polygon and it was entirely outside the
        clipping region (But we didn't know this yet) and we have
        just 2 of it's vertices that make up a single side (A..B)

                e.g.                                   B
                                    above               o
                                                       / \
                                                      /   \
                                                     /     \
        /\
                                                   /  poly   o
                                  view port       /         /
                                      or         /         /
                                   clipping      o--------o
            left                    region     A                right
                                             
        
                                             
                                    below    
                                             
                                             

          The polygon side A..B can be extended to be a hyper-line
        which divides space into two half-spaces. We can work out
        which half-space the polygon is in by standing on vertex A,
        facing B and looking to our right. This will always give us
        the interior of the polygon otherwise it is not convex !!

                        And now the good bit =)

          If this hyper-line doesn't cross into the clipping region
        then nor does one of it's two half-spaces.

                e.g.                                         .
                                                            . < hyper-line
                                                       B .
                                    above               o
                                                       / \
                                                      /   \
                                                     /     \
        /\
                                                   /  poly   o
                                  view port       /         /
                                      or         /         /
                                   clipping   A .o--------o
            left                    region     .                right
                                              .
        .
                                             .
                                    below   . < hyper-line
                                           . 
                                          .  

          So if the hyper-line doesn't cut through the clipping region
        then we can reject one half-space and if we can do that then
        we can also reject the entire polygon and all of it's vertices
        which lie in that particular half-space.

          In affect we can reject the entire polygon just by checking
        one of it's sides without the need for outcodes or a safety net =)

                                THE BAD NEWS
                                ------------
          But a polygon side does not (and can not) be the full length
        of a hyper-line, so it is possible that the hyper-line might
        cut across the clipping region but the entire polygon is still
        outside it.

                e.g.                                       .
                                                          . < hyper-line
                                                     B .
                                    above             o
                                                     / \
                                                    /   \
                                                   /     \
        /\
                                                 /  poly   o C
                                  view port     /         /
                                      or       /         /
                                   clipping   .o--------o
            left                    region   .  A        D
                                             .
        .
                                           . 
                                    below . < hyper-line
                                         .   
                                        .    

          In the above example the side A..B hyper-line does cross
        the clipping region but the polygon is still outside. In this
        case the side D..A (the closing line of the polygon) could be
        checked


#############################################################################
Ŀ
 #M:                      Trapezoidal Decomposition                        

#############################################################################

          This is another term which I have recently learnt
        and it sounds like a painful booby-trap to me :)
        It is thankfully rather easy to code and understand.
        We take a n-sided polygon and break it down into
        either triangles (3 sided) or trapezoids which are
        4 sided shapes with 2 parallel sides to them, which in
        this case are the top and bottom lines of the shape.
         It's easier to explain with a diagram (except with a
        really slack ASCII one =), so here goes...

                               (x1,y1)

                                /\                      0  scan line
                               /  \                     1
                              /    \                    2
                             /      \   (x2,y2)         3
                            /        |                  4
                  (x5,y5)  /         |                  5
                           \         |                  6
                            \        |                  7
                             \       |                  8
                              \______|                  9
                      (x4,y4)          (x3,y3)


          If we take one ASCII line as one scan line then the
        above polygon can be broken down into 3 parts like this:

                             new  new
                                /\       0
                               /XX\      1
        part 1                /XXXX\     2      a triangle
                             /XXXXXX\    3

                                      new
        part 2              /XXXXXXXX|   4      a trapezoid
                           /XXXXXXXXX|   5

                        new
        part 3             \XXXXXXXXX|   6      a trapezoid
                            \XXXXXXXX|   7
                             \XXXXXXX|   8
                              \XXXXXX|   9
                             new     new

          The points marked 'new' indicate where a new vertex is
        encountered and so requires a new slope to be calculated.
        The bottom 2 'new' point are not used, they simply indicate
        that the bottom of the polygon has been found (the Y length
        of the slope is either 0 or -ve).

*****************************************************************************
NOTE:
        The below pseudo-code is for reference only, it has NOT
        been tested and no doubt does not fully work.
*****************************************************************************

                topper  is the topmost vertex index
                        (in this case is vertex 1)

                sides   is the number of polygon sides
                        (in this case 5 sides)

                X[0], X[1] ... X[n]     = polygon X co-ords
                Y[0], Y[1] ... Y[n]     = polygon Y co-ords

        e.g.
                index1 = topper         <--- left edge index
                index2 = topper         <--- right edge index

                height1 = 0             <--- force new left slope
                height2 = 0             <--- force new right slope

                V = Y[topper]           <--- topmost Y co-ordinate
                                             (the current scan line)
        PolygonLoop:
                WHILE height1 = 0
                                   x1 = X[index1]
                                   index1 - 1
                                   if index1 < 0 then index1 + sides
                                   height1 = Y[index1] - V
                                   if height1 < 0 then goto Done
                                   inc1 = (X[index1] - x1 ) / height1
                WEND

                WHILE height2 = 0
                                   x2 = X[index2]
                                   index2 + 1
                                   if index2 >= sides then index2 - sides
                                   height2 = Y[index2] - V
                                   if height2 < 0 then goto Done
                                   inc2 = (X[index2] - x2 ) / height2
                WEND

                i = height1
                if height2 < i then i = height2   < the MINIMUM height

                height1 - i
                height2 - i

        Trapezoid:
                        Draw_Horz_line (x1,V) to (x2,V)
                        V + 1
                        x1 = x1 + inc1
                        x2 = x2 + inc2
                i - 1
                if i > 0 then goto Trapezoid

                goto PolygonLoop

        Done:

#M1:Problems

          The above code does NOT clip any out of bounds lines.

          It will also lock up if the entire polygon is on the
        same Y line, due to the WHILE and WEND loops. One solution
        is to include a side counter and decrease that for
        each time around the WHILE loops. Or you could put an invalid
        Y co-ordinate marker to cause the height1 and height2 to become
        negative.

          You need to use fixed-point (best) or floating-point
        numbers for the x1, x2, inc1 and inc2 variables as a
        fraction is possible (e.g. 1.5).


#M2:Improvements

          The Trapezoid loop could be replaced with custom code
        for pure rectangles (with purely vertical sides)
        or for trapezoids with only one sloped edge and for
        skewed rectangles where both the inc1 and inc2 values
        are identical.

          Also a Bresenham type line drawing method could be
        used for certain slopes where the Y length is >= to
        the X length. This would remove the divide instruction
        but would require a little more code and introduce
        conditional jumps and more variables which could in
        the end make a slower polygon filler.

          The divide is NOT always needed for calculating the inc1
        and inc2 values (in the case of vertical lines these
        increments will always be zero, because  0/n = 0 !!).

          You may also wish to build a clipping algorithm into
        the polygon drawer itself based on the 'letterbox' method
        described elsewhere in this document. And you might wanna
        have a pure 'no-clipping-needed' polygon drawing routine.


#M3:Orientation & Summits

          Most polygon scan-converting occurs in a top-to-bottom way
        with the two sides (left and right) being scanned out from the
        topmost vertex. But this normally requires a short search
        within the polygon's vertex list to locate this topmost vertex.
        The simplest way to find the summit of an N-sided polygon
        would be to scan all N vertices and record the one with the
        highest Y co-ordinate value (or the lowest depending on your/PC
        Y axis direction).

        e.g.
                topper = 0

                FOR i = 1 to PolygonSides - 1
                        if vertexY[i] < vertexY[topper] then topper = i
                NEXT i

          Now 'topper' is the index of the topmost (lowest Y co-ordinate)
        vertex. For a 4-sided polygon this loop would execute 3 times.

NOTE:     Remember that the Y axis on the PC (and 99% of other machines)
        is inverted with Y=0 at the top of the screen instead of the
        normal Cartesian Y=0 at the bottom of the screen.

          A normal polygon only has 1 or 2 topmost vertices, if it has
        any more than this then some of it's vertices lie on the same
        Y line and so can be skipped as they form a straight, horizontal
        line (and possibly the entire polygon can be rejected as it is
        being viewed along one of it's edges).


                          B      C      D
                e.g.       o-----o-----o
                          /             \
                         /               o E
                      A o

          In the above case vertex C can be skipped and vertex D taken
        as the right topmost vertex, where B is the left topmost vertex.

          So we should only have one of the following 2 polygon tops to
        deal with. Either a pointed or a flat top.

             A POINTED POLYGON          A FLAT TOP POLYGON

        e.g.        o                       o--------o
                   / \                     /          \
                  /   \                   /            \
                 /     o                 /              o
                o                       o

          Going back to the search loop we only update 'topper' if a
        new vertex is found which has a higher Y position on the screen
        (NOTE: a lower Y co-ordinate value on the PC). As we are dealing
        with clockwise only polygons (anti-clockwise ones are hidden)
        and the polygons are flat, non-skewed, convex ones, the vertices
        should always be in a clockwise order which means it is
        impossible to find a higher vertex after a lower one unless it
        is the closing side to the polygon.

        e.g.                      o E
                   B      C      /
                    o-----o     /
                   /       \   /     < NOT a convex polygon !!
                  /         \ /
                 /           o
              A o             D

          So if we are currently at vertex B and examine vertex C then
        it's Y co-ordinate can either be ABOVE, BELOW or LEVEL with
        vertex B's Y co-ordinate. We simply take the sign of By - Ay
        which can of course be done with a CoMPare instruction.

                EXAMPLE 1:         EXAMPLE 2:         EXAMPLE 3:

                                          C             B
                                       __ o             o
                     \                   /|              \
              B o-----o C               / |               \ |
                     /                 /                 __\|
                                    B o                     o C

                LEVEL              ABOVE                BELOW


        In EXAMPLE 1 we take vertex C as our new right-most starting vertex
        (because Cx > Bx) and continue to scan until we find one of the
        following sub-cases.

                1)


                1) The next vertex is to the right of our current one.
                   (keep new X co-ordinate and repeat this)

                2) the next vertex is to the left of our current one.
                   (we have found the




#############################################################################
Ŀ
 #N:                         Group Vertex clipping                         

#############################################################################

          Like most subjects in this rapidly growing document
        clipping too can be gifted with a 'group' approach.
        In the best case it can totally remove ALL need for
        polygon testing and clipping and in the worst case it
        can add a multiply, divide and a few other simple
        instructions and in the intermediate cases it can reduce
        the clipping tests, so there are far more gains than
        losses.

          The basic idea (like most others) is simple. A little
        amount of preparation is required which only needs to
        be done once, probably when the 3d model is created.

          First create either a bounding sphere or a bounding
        rectangle around an object's origin. This is just a
        length which is the radius of the vertex which is
        furthest from the origin. This is very easy to work out
        but requires 3 multiplies and a SQRT (square-root) for
        every vertex which makes up the object. This ONLY needs
        to be done ONCE, unless your vertices move :(

          The below pseudo-code assumes every vertex in an
        object is defined from it's origin (0,0,0).

                e.g.

                        reach = 0
                        for n = 1 to Number_Of_Vertices

                                X = vertex[n].X
                                Y = vertex[n].Y
                                Z = vertex[n].Z

                                radius = SQRT (X*X + Y*Y + Z*Z)

                                if radius > reach then reach = radius
                        next n

          Now the variable 'reach' is the longest 3d vertex
        length from the object's origin. So no matter what
        sequence of rotations is done on these vertices we know
        that none can extend further then the 'reach' value.
        You can think of it as the radius of a sphere which
        encloses all the vertices in it.

          If you don't like the thought of using 3 multiplies
        and a SQRT then try using the longest length of each
        vertex along the X, Y and Z axiss, then times it
        by SQRT(3) = 1.732050808 this radius should then be
        big enough to enclosed the entire vertices. This method
        is guaranteed to enclosed all the vertices but it
        is NOT the true greatest length (like the SQRT method)
        and in many cases it will be bigger than the proper
        length.

                e.g.
                        reach = 0
                        for n = 1 to Number_Of_Vertices
                                X = ABS ( vertex[n].X )
                                Y = ABS ( vertex[n].Y )
                                Z = ABS ( vertex[n].Z )

                                radius = X
                                if Y > radius then radius = Y
                                if Z > radius then radius = Z

                                if radius > reach then reach = radius
                        next n

                        reach = reach * SQRT(3)
                              = reach * 1.732050808

          If we use this 'reach' value as the radius of a 2d
        circle and if we use the object origin's projected 2d screen
        position then we can employ it to check whether any, all
        or none of the object's vertices need to be clipped.
        In the below diagram the top of this bounding circle
        crosses the top clipping edge which indicates that all
        the vertices must be tested & possibly clipped. If the
        entire circle was within the clipping rectangle then
        we would not need to test or clip a single polygon, line
        or vertex !

          e.g.
                        xxxx
                      xx    xx
              left   x        x             right
                    x          x
                   x          x              
                  x    origin  x             
       xx top
                  x     +      x             
                  x    /       x             
                   x  / reach  x             
                   x /        x              
                    x        x               
                     xx    xx                
                       xxxx                  
                                             
        bottom
                                             
                                             
                                             

          At first it may seem difficult to test a circle
        against the clipping rectangle because of the curve, but
        in fact it is similar to checking a square box. The circle
        can be fitted inside a box and we only need to check the
        X and Y extremes of the circle where:

                left    = X - radius
                right   = X + radius
                top     = Y - radius
                bottom  = Y + radius

          Remember we are not interesting in clipping the circle
        we only need to know it any part of it is outside the
        clipping area.
          e.g.
                                        xxxxxxxxxxxxxxxxxxxxxxxx
                                        x                      x
                                       x                     x
                                       x                     x
               xx top
                                       x                     x
                                       x<- reach ->+         x
                                       x                     x
                                       x                     x
                                       x                     x
                                       x                     x
                                       xxxxxxxxxxxxxxxxxxxxxxxx
                                                     
                bottom
                                                     
                                                     
                                                     
                      left                          right

          In the above diagram the bounding box crosses the
        top and right clipping edge. It means that again some
        vertices could possibly need clipping.


#N1:The good news

          This bounding box/circle/sphere is useful in many ways.

        1) it can reject entire objects without the need to
           rotate, project, back-face cull or create outcode for
           each and every vertex (which is REALLY good news =)

        2) using it as a sphere means it can be applied to the
           Z-clipping plane(s) as well.
           (Remember 'reach' is a true 3d radius so this ONE
            length can be used in 2d or 3d clipping)

        3) as a bonus if we create 1 outcode for the bounding
           box/circle/sphere then we can work out what clipping
           tests need to be done and what tests DO NOT (double =)
           (e.g. if the bounding shape only crossed the bottom edge
           then we only need to test and clip that edge on
           EVERY vertex/line/polygon !!)

        4) the true 'reach' length could also be used for collision
           detection purposes (sphere to sphere). Although it will
           not be as correct as a proper polygon-to-polygon test
           it will certainly be much, much quicker.

#N2:The bad news

          Well, there isn't much of it.

        1) some calculation and extra testing is performed ONCE
           per object. The most costly part is that the 'reach'
           radius value which should be scaled up or down depending
           on the object's origin distance from the view-point.

        2) extra set-up calculation is needed, for the SQRT bit.
           This is easy to do even in assembler and it doesn't
           have to be fast so any method can be used. Or you could
           use the previously mentioned longest axis length * SQRT(3)


#############################################################################
Ŀ
 #O:                     Smooth Lines & Anti-Aliasing                      

#############################################################################

          The problem with 99% of the current wave of 3-d game engines
        is the same one which Wolfenstein suffered from, blocky pixels.
        This pixellation occurs because small texture bitmaps are used
        to fill large screen polygons where the scale of each texel
        (textured pixel) is bigger than 1, so a texel is repeated any
        number of times to fill up a 4x4 or 8x8 or AxB sub-polygon area.
        This scale-up problem or 'pixel zoom' is most visible when
        standing point-blank against a wall or 3-d creature model.
        To combat this there are a few solutions, some good, some bad.

        1) use much large texture bitmaps (BAD) this chews up memory and
           the CPU cache is chewed to bits.

        2) use a scale for the projection/perspective calculation so
           that the item (polygon, line or pixel) is kept at a 1:1 zoom
           ratio. This means far bigger textures are needed (perhaps
           640 or 768 lines high) to be able to fill a full screen
           polygon OR very big polygons are broken down into smaller ones.
           This means the maximum scale at the Z-clipping view plane is
           1 pixel any more than this and pixel zoom occurs.

        3) large polygons use the mosaic or bathroom-tile technique to
           repeat the same small texture bitmap again and again to fill
           up the entire area.

        4) interpolation (either bi- or quad-) is used to average out
           the scaled up pixel blocks. Most 3-d cards do this in hardware
           which is good news as the CPU normally has enough to do.

        5) some form of voxel-sprite hybrid method can be used. I believe
           that the Blade Runner game used this technique, although I
           haven't seen or played the game. It should give a far better
           way of creating smooth curves for organic (human) looking
           things and should give very good results for close range
           objects, but for small items in the distance this might be
           time consuming compared to normal texture mapping method.

        6) Voxel based landscapes use smoothing techniques to help iron
           out the sharp corners between map cell corners.


#O1:Smooth & Fast Bresenham

          After reading a short article by M. Abrash about this
        subject which described Xiaolin Wu 's anti-aliasing technique
        an idea came into my vacant head. I think it is possible
        to perform anti-aliasing with ONLY the Bresenham line
        drawing technique and nothing else simply by using the
        error term (which is actually the partial quotient formed
        by DIVIDING the major length by the minor length using
        repeated subtraction !!!). I haven't fully read about Wu's
        algorithm (which I believe uses a divide and has accumulative
        errors problems for very long lines) and I haven't explored
        this Bressy-only idea to any great length so more research
        is vital to discover or dispel this idea.


#O2:Recursive Terrain Mapping

          This is a way to tackle the vast range in environment scaling
        in a sort-of-hierarchical way. To gain any reasonable level of
        realism for an exterior landscape you must be able to view it
        at a huge number of scales from a few inches away up to a number
        of miles away. The very distant and so very small landscape
        details are not really the problem (apart from the CPU having to
        skip bytes in the texture bitmap to scale it down), the real
        problem is the point-blank surfaces and objects which often
        resemble a blocky chess board rather than a highly detailed
        surface. To maintain a high level of quality detail down to a
        very small scale requires a high resolution description in
        the world data and that needs a huge polygon and vertex count.
        For example in an extreme case you may see a large metal water
        tank on the horizon and you may want to walk up close to it
        and see the individual rivets on the seams. In this case do you
        describe each and every rivet as a square polygon or do you
        simply use a pre-drawn metal bitmap with pixel size rivets on it ?
        If you have played DOOM or Wolfenstein then you already know the
        blocky answer :(

          We want to be able to choose the amount of detail that we need
        to render depending on distance so we need a way to introduce
        high resolution detail or to reduce our workload for the mile
        away items on the horizon line. Okay, it seems sensible to
        start with a low-resolution (rough) stage and only increase
        the quality if and when we need to. This way we are not chugging
        through tons of unneeded data like when a very large bitmap is
        scaled down to fill a tiny polygon. The CPU really hates this
        skipping bytes, it much better prefers continuous bytes.

                1) Rough stage (low detail, low resolution)
                2) medium stage (more detail, more resolution)
                3) fine stage (even more detail, high resolution)

          So we start with the first stage and progress only if we need
        that extra detail, but how can we do this without sending the
        polygon & vertex count through the roof ?

          One of the most obvious solutions would be to employ fractals
        or some kind of sub-division method to zoom in on the 'detail'
        in real-time as the landscape or objects are being rendered.
        But there is one big problem, we would have no control over the
        fractals, the high detail created is just the sum of a number of
        low detail parts. And in all honesty we have not created detail
        we have simply smoothed between some low resolution parts.
        So a green and brown texture used to draw a mile away, grass and
        mud hill when viewed from a few inches away would just be a fuzzy
        green and brown mess, we could NOT see individual blades of grass
        or stones in the muddy patches :(
          It seems that we need to go past the single pixel space of
        a bitmap and enter the sub-pixel dimension (spooky eh ? =).

          Right enough waffle, here is my latest hair brain idea:

          What about thinking of a bitmap texture as an array (not very
        ground breaking so far) but instead of thinking of each element
        as a single pixel we think of an element as being a thumbnail of
        another bitmap texture. Or to put it another way we have a
        rough (low detail) array of elements and each element is the
        token of another finer (higher detail) array.

                i.e.    "We have an array of array tokens."

          Going back to the grass and mud example we would have a
        bitmap texture (the rough array) perhaps like this:

                 zoom-> gmgmgmgmgm      g = 1 grass pixel
                        gggmmgmgmm      m = 1 mud pixel
                        ggggmgmmmm
                        gggggggmgm
                        gggggggggg

          Now suppose we zoom in on the top left corner, we have:

                        ggggmmmm Ŀ
                        ggggmmmm  
                        ggggmmmm  
                        gggggggg  > gm...
                        gggggggg               gg...
                        gggggggg               .....
                        gggggggg 

                     BLOCKY (4x4 zoom)          bitmap (1x1)

          We know that each 'g' pixel represents a small area of grass
        and that 'm' is mud so why not use a 'blade of grass' bitmap
        for each 'g' pixel and a 'patch of mud' for each 'm' pixel ?

          This is the basic idea behind "Recursive Terrain Mapping".
        I have used to term 'pixel' where perhaps 'material' or 'token'
        or even 'atom' might have been more descriptive and correct.
        The good thing about this method is that large (high detail)
        array maps can be built up from other array maps just by using
        their token value as the elements in a rougher (lower detail)
        map array. And because it is an array of tokens we can reuse
        the same token any number of times, we could even use the
        token of the array itself (the recursive part of the title).

          There are a couple of items which need to be resolved before
        this method becomes more practical.

        1) because one map is built from an (possibly) infinite number
           of sub-maps (i.e.. itself) this might be rather slow.

        2) a pixel is normally 1 byte in size so only 256 map tokens
           are possible.

        3) the map array address must be calculated from the token.

        In item 1) two maps could be used, one for the actual token
        array map and one for a pure pixel map. We only use the token
        map for large areas (close to the view-point) otherwise the
        pure pixel map is used as normal, this saves having to follow
        all the sub-maps possibly falling into an infinite loop.
        The current map or element scale determines which one is used.
        Also we would never really follow an infinite loop because we
        would stop at a minimum scale value (e.g. 1 pixel).

        item 2) this can be solved by using a word or a dword for
        each array element. This would also remove the need to convert
        a token to address the correct map 3).

          This method is similar to real fractals (Julia & Mandle sets)
        and also fractal compression (IFS) where parts of an image
        (in this case a polygon texture) is built up from sub-images
        or parts of itself. But unlike real fractals this
        self-similarity is predefined within the array maps and using
        the tokens so can be controlled (designed by the graphics artist).

          From a programming point of view this may appear slower than
        the standard one-polygon-per-face method with a little more
        added complexity but remember that a really, really HUGE
        zoom is (perhaps) possible. Just imagine instead of a blocky
        mountain bitmap texture you could keep on magnifying it up to
        see rocks and beyond them to see tiny grains of sand.
        One thing to remember is that to reach this atomic scale you
        need to follow a number of intermediate levels first. The more
        you magnify, the more work is involved to follow the sibling
        bitmaps. This extra work isn't too bad when you consider that
        we are going to be filling a large area so the per-pixel
        workload probably isn't so great but the results hopefully are =)

          From a map designing and starting point of view I would suggest
        first creating the 'atomic' detail level (blades of grass,
        a brick for a wall, a splinter of wood) and then build larger
        maps of them (a clump of grass, a brick wall, a piece of wood)
        and then finally create the large region maps (a huge field of
        grass, a hill side, an entire building side and so on...).
        Now when you wish to design a new game world you can simply use
        a number of the big region maps to quickly slot together a
        highly detailed environment. You can think of this approach as
        being "tiles within tiles". One word of caution, don't be
        tempted into changing a 'small' detail as this would have a
        snowball effect on every large structure which has already used
        it.

          The 'design' contribution comes from being able to build the
        maps from a number of finer detail map blocks, placing grass
        next to mud or mud next to water for example. Just as graphics
        artists can place individual pixels on a bitmap so too can they
        'draw' with the atomic map components to create bigger and
        bigger items.

          The only real downside on this technique is that surfaces
        are still planar, flat without bumps or dips.


#O3:Atomic Lumps & Bumps

          We might be able to magnify a hill side texture to be able
        to see individual rocks or grains of sand but it is still
        flat, level with the rest of the hill. Everything would look
        like it had been run over by a steamroller. What we need to
        do is give them some depth, to make objects stand out from or
        recede into the background, to give the impression of viewing
        solid 3-d items or at least a 3-d face. But by introducing depth
        into the hill for example we would need to define vertices
        or control points which could be used to shape the surface mesh.

          We could introduce Z-depth data for each element in our
        recursive terrain map this way we control and design it's shape
        as the map is magnified. The more the magnification increases,
        the more Z-depth information is needed. It is probably best to
        define 4 depth values (one for each corner) which are relative
        to our parent plane. With each successive sibling (sub-map)
        the magnitude of the Z-depth should be scaled down to relay it's
        smaller scale. At the smallest, atomic scale the Z-depth could
        possibly always be 0.

          But by injecting the Z-depth component some problems occur.

        1) projection/perspective calculations increase.
        2) clipping is more difficult (it's no longer co-planar)
        3) shading becomes more complicated, because the angle has changed

          Perhaps 'Bump Mapping' or a similar technique could be used
        to give the flat maps some appearance of roughness.


#O4:Stop Dithering ?

          This can be one of the simplest ways to help disguise
        blocky ('pixellated') graphics where a single pixel has been
        used to fill a large area, usually where objects are very
        close to the player. Dithering normally means skipping
        every other pixel to give a 50% illusion of a image but it
        can give many more levels by altering the number and spacing
        between pixels (just like a newspaper picture).

          You may think that this technique is too old and has been
        overtaken by proper shading using a look-up table to remap
        pixels to a predetermined (and pre-calculated) level or it
        has been made redundant through the use of interpolation or
        other smoothing techniques, but it can still be useful because
        of it's sheer speed. It allows mixing of two or more items
        without any real overhead in terms of extra calculation.
        I think that even UNREAL used 50% dithering on some of it's
        old, preview screen shots at a screen resolution of 640x400.
        This method is probably only useful for software based
        rendering as modern 3-d hardware cards tend to have bi- or
        quad-linear interpolation to smooth out blocky pixels.

          For normal 320x200 VGA resolutions this technique is not
        very good but for 640x400 the pixels are small enough that
        the viewer can not easily see the dithered pixels. At this
        resolution speed is the main problem and this dithering
        method can save 1000's and 1000's of instructions which
        would be needed for interpolation or smoothing across most
        of the screen. A rough estimation is that around 10 to 30%
        of pixels drawn on the screen would be blocky requiring
        smoothing, this at 640x400 would be 25600 to 76800 pixels.

          Another use for the 50% dither could be to quickly draw
        shadows or to overlay scores and info over a background.
        It could also be used to extent the normal shading look-up
        method especially when you're restricted to just 256 colours.
        I've just played a demo of Monster Trucks 2 and I quickly
        noticed that the horizon-fade-in was not a fade-in, it used
        dithering. I have seen this technique used before on the
        Amiga for a racing game where trees and other objects were
        dithered (or 'screened' ?) as they came into view. Because
        of the Amiga's bitplane method of storing the screens and
        the CPU's modest 8 Mhz clock, it was not possible to re-map
        (shade) each pixel as they are being drawn so a dithering
        method was used. Even a few Command & Conquer style games
        use 50% dithering around the edges of the explored game area
        where the player has yet to go. It's good to know that even
        the oldest techniques still have a place in today's
        super-cray-CPUs.


#############################################################################
Ŀ
 #P:                       Plants, Trees and Forests                       

#############################################################################

#P1:A common theme

          After writing most of this big document I have noticed a
        common theme which is repeated many times throughout. And it
        is "hierarchical structures" or put another way:

                From tiny data acorns,
                        mighty optimised trees grow.

          As 3d programming requires a large amount of effort before
        even the most primitive engine is created with many small
        data handling procedures there doesn't seem to be (at first)
        any general approach to optimising the render pipeline. But
        using trees structures with parents and siblings is an elegant
        solution for just about every aspect of a 3d engine, from clipping
        and object definition to dynamic detail levels the tree appears
        to be king. Even depth sorting and collision detection can
        benefit from a tree approach. It is not just in sorting data or
        string searching that tree structures are incredibly useful,
        giving vast gains with little effort, but depending on how a
        tree is defined it can reduce the considerable workload in
        a large number of areas. Normally an item's position within a
        tree is based upon some spacial attribute (e.g. distance) instead
        of some characteristic (e.g. colour, texture, size, vertices).
        As I have previously mentioned clipping can benefit from a
        tree or a 'forest' approach. The branching or sub-dividing data
        structure of a tree doesn't have to be only used to describe
        every polygon of every object, it can be extended into a
        much bigger hierarchical structure. For example imagine we
        did store every polygon in a single tree, now what happens when
        we want to delete an object and all it's polygons from it ?
        A list of polygons for each object could be defined and this
        could be used to delete nodes from the tree. But what if we
        want to re-use the same object a number of times ?

          It is much better to use a 'forest' structure, i.e.. trees
        within trees. Now instead of a single polygon at each node we
        can simply point to another sub-tree (an object). Of course
        we would also need to keep some of the information from the
        world-tree (the forest) and pass it onto the sub-tree. This
        way we could re-use objects again and again just by pointing
        to the same sub-tree. Now the forest contains the spacial
        map of all objects positions, and the sub-trees contain the
        polygon information themselves. This is a much more sensible
        way to go about it. To remove an object from the forest we
        simply kill the single link to the sub-tree and all it's polygons
        are never visited or rendered. To reverse this and plant a new
        object we can create a new node branch in the forest and point
        that to the object's sub-tree.

          Clipping becomes much faster using this hierarchical method.
        If we can reject the node branch in the forest then we can also
        reject the sub-tree and every one of it's polygons. And taking
        this idea further, if we can reject part of the forest then we
        can also reject all of it's sub-trees and all of their polygons.
        Collision detection can use the spacial coherence of each
        sub-tree in the forest because we only need to check it's
        surrounding neighbouring and not every other object. Even then
        we only really need to check for collision between objects
        which move. E.g. Check the player against the surrounding objects
        and don't bother checking every static wall against every other
        static wall. (of course moving doors and lifts could possibly
        need checking).

          We can also implement an efficient horizon cut-off point when
        rendering the world forest. If an object's position is beyond
        a certain distance from the view point then we can reject the
        entire sub-tree and it's polygons. Even the sub-trees themselves
        could be built using a detail tree instead of just a polygon
        list. This would need to be created in a coarse-to-fine order
        with the smallest detail at the tips of the tree and the bigger
        coarse stuff near the root. Once we get to our horizon cut-off
        point we can stop following the tree down. So the more distant
        the object, the less of the tree we need to follow and the
        fewer the number of polygons that we need to render.

          But this means we lose the ability to order the tree using some
        other selection method (e.g. depth sorting). As far as I know a
        tree can only be used for one purpose with one ordering method.
        A tree created for depth-sorting IS NOT the same as a tree
        built for a detail levelling. The only feasible solution I can
        think of at this time is to built two individual trees and cross
        reference the outcome of both, possibly using a simple flag
        system. For example one tree might describe various detail levels
        and another tree might describe directions for visibility tests.
        Only if a polygon passes BOTH tests will it be rendered, if it
        fails either one then it is simply rejected. As the trees can
        not be combined because their build orders conflict another
        solution could be to take the output from one tree (the items
        which were NOT rejected) and build a second tree from them.
        But this would incur the performance penalty of having to
        sort the unordered output from the first tree, navigating and
        building the second. In this case the flag system should work out
        much faster, even after having to clear the flags in the first
        place. When the last tree is being processed we only need to
        test each item's flag (assuming it passed the last test as well)
        This flag system could be applied to any number of tree "sieves"
        each one would reduce the number of polygons yet further until
        we end up with every polygon, a few or none. The greater the
        number of tree sieve stages the fewer the number of polygons
        (in theory). But you must also remember that with each new
        sieve tree more navigation is required, often tracing paths
        which lead to already rejected items. Until some smart cookie
        comes up with a method to sort items correctly for multiple
        attributes then there is still room for new discovery.

          After recently reading a chapter in a book called Knuth's
        Fundamental Algorithms about trees I was amazed at how long
        ago tree structure had been developed, the book itself was
        dated about 1973 ! Apart from the normal binary tree
        structures it described threaded trees, ring and multi-way
        trees.


#P2:Ring or loop Trees

          These are basically binary (or any other normal kind of)
        tree which uses some of it's sibling links to point back to
        a parent or grand-parent tree node. The most important thing
        to note about these kinds of trees is that they circular,
        infinite paths can be defined from which there is no escape.
        Also they break the parent-to-sibling rule, parent nodes DO NOT
        always point to child nodes - they can point to grand-parent or
        grand..grand-parent etc....
          These structures can be very useful to navigating back 'up'
        the tree towards the root OR even onto a completely different
        branch or tree. Of course normal trees can be extended to allow
        back links (sibling --> parent nodes) so that bi-directional
        tree climbing can be done.


#P3:Threaded Trees

          Put simply, binary trees are empty, dead looking twig-like
        trees and threaded trees look like an Xmas tree with Xmas lights
        from branch to branch. The 'thread' are just links between leaves.
        As the leaves of a tree are normally identical to nodes
        except their sibling links are null (equal to 0) they are
        just going to waste. Usually if a node link equals zero then
        it is treated as a leaf of some kind. A main problem with
        navigating any form of tree is visiting the leaves without
        having to traverse every possible path through the tree. One
        solution is to maintain a separate list of leaves outside of the
        tree structure. Another could be to build a 'leaf-neighbour'
        link into the nodes. These would effectively be sideways links
        to point to the next tip of the tree's branches.
        In the below diagram we have just 3 nodes (A, B and C). Both
        nodes B and C are leaf nodes so their left and right links
        are null.

                e.g.                     A
                                        / \
                                       /   \
                                      /     \
                                     /       \
                                   B          C
                                  / \         / \
                                 /   \       /   \
                               null null   null  null

          This can be described in a table like this:

                      Node      left link       right link
                                   
                        A       node B          node C
                        B       -null-          -null-
                        C       -null-          -null-

          A "threaded" tree uses an extra bit for every link in each
        node structure. This bit indicates whether the link is a true
        link (points to a sibling) or a "thread" (null link). Now any
        null links can be used to point to neighbouring leaves.

                      Node        left link       right link
                                     
                        A       0  node B       0  node C
                        B       1  thread A     1  thread C
                        C       1  thread B     1  thread A

          In the above table we now have one extra bit for each link.
        A '0' bit indicates a normal link to a sibling node. A '1' bit
        denotes a 'thread' (was a null link).

NOTE:   I have chosen to point the leftmost and rightmost nodes back to
        the root node, but they could have been made to point to the
        opposite side of the tree - to wrap around.
                e.g.
                      Node        left link       right link
                                     
                        A       0  node B       0  node C
                        B       1  thread C     1  thread C
                        C       1  thread B     1  thread B

          Given just one leaf we can immediately find the next or the
        previous leaf just by following a thread without having to
        traverse the tree every time.


#P4:Multi-way Trees

          These are just trees which have more than 2 links for each
        node, they can have 3, 4 or any number of links for each node.
        For example oct-tree use 8 links for each node and quad-trees
        use 4 links. Using multi-way trees does mean that far more than
        just 2 links can be used but there are some disadvantages.
        Firstly the node data structures will become increasingly
        bigger with each new link added. Secondly a simply true/false
        condition can not be used to select more than 2 links.


#P5:Side Links & Lop-Sided Trees

          Sometimes you find that you need a variable number of links
        from a node but don't want to waste tons of memory for those
        nodes which only require one or two. This is the situation
        which I found myself in when writing a LZ compression routine
        a number of years ago. The routine needed to find the longest
        matching string in an expanding dictionary, so what I did was
        to use a binary tree but in a lop-sided way. Instead of the
        normal left and right links I used 'side' and 'longer' links.

                        longer links >

                A >P >E
                           
                           v
                           P >L >E
         side links   v
                     R >C >H >E >R >Y
              v       
                      v
                      S >H >E >S
                                  
                                  v
                                  Y

          The above lop-sided binary tree or 'side tree' as I call it
        is very useful for finding variable length strings. Believe
        it or not but that tree describes about 10 English words

           APE, APPLE, ARC, ARCH, ARCHER, ARCHERY, AS, ASH, ASHES, ASHY

          The rules for creating and navigating this type of tree is
        very easy and fast. Compare the first letter with your search
        string's first letter. If it matches then take the 'longer' link
        to your right and advance to the next letter in your search string.
        If it does not match then take the 'side' link down until you
        find one that matches your search letter or a dead end.


#############################################################################
Ŀ
 #Q:           Convex Polyhedra, Planes and Surface-details                

#############################################################################

#Q1:Surface Plane Detail

          Sometimes you wish to draw some fine surface detail on
        objects to give a greater sense of realism. Say for
        example we wanted to draw a racing car with a number or
        logo on the car's door and this number or logo could be
        personalised (perhaps depending on grid position, name etc..).
        The most obvious solution would be to copy the door texture map
        into a buffer and overlay the logo onto using a simple sprite
        routine to draw the non-transparent pixels on the door bitmap.
        Now the car can be drawn normally using this changeable
        texture bitmap. It requires NO more processing during the game
        only once before race time perhaps in the pits area or menu.
          But this does have some limitations, firstly we can't
        modify the bitmap during the game without incurring a large
        amount of data copying and overlaying. If we wanted to draw
        damage or mud on the car door then we could modify the
        bitmap or switch it for one already pre-drawn by a graphics
        artist. This switching of bitmap textures can of course be used
        for animation purposes.

          If we continue the hierarchical mentality a stage further
        then instead of polygons we could describe sub-polygons in
        either a tree or basic table format. In the case of a car
        door number/logo we could draw the entire door normally
        and then draw the logo using more polygons on top. This way
        when the car is in the distance we can just draw the car door
        and stop there, without drawing any of it's surface detail.

          If the car door polygon is hidden or completely clipped then we
        can reject all of it's details too without any further processing.
        This way the door can be thought of as the root and the detail
        as the branches or leaves on the tree. So surface detail on
        objects (or the environment) is based upon visibility and then
        distance. If the root surface is hidden then so is all of it's
        detailing.
          But the problem with this, draw the background then the detail
        method is the old one of overdraw, where pixels are written to
        a number of times which is on 99% of video cards is very slow.
        If a S-BUFFER technique is employed then that would help save
        some processor time by removing the pixel overdraw. Another way
        is to define a detailed polygon and vertex list which avoids the
        overdrawing problem and would replace the simple, one-polygon
        door for an already sub-divided surface.


#Q2:When I'm cleaning windows...

          This was probably the basis for my 'Inlet' rendering method.
        Instead of simply using a polygon to define a plane on which
        all of it's fine detail and sub-polygons lie, why not
        create some fake transparent polygons to classify interior
        groups of polygons. The easiest way to think about this is to
        imagine a house with only one window and that window is a
        fake polygon which completes the exterior surface of the house
        and makes it into a convex object. We also have an interior to
        the house which only has a single room and is a concave shape.
        Now taking the simple cube for the exterior and one cube volume
        for the interior and one for the window then we could define the
        house using just 24 vertices (8 exterior, 8 interior and
        8 for the window volume) and about 22 polygons for the surfaces.
        Now imagine being at the back of the house, not being able to
        see the window at the front. We would not be able to see any
        part of the interior (8 vertices + about 9 polygons) and none
        of the window (8 vertices + 4 polygons). This is over half of
        our polygons and vertices which don't need to be processed.
        Only from a few places at the front of the house at certain angles
        would you be able to see any of the interior. The only connection
        between the interior and the exterior is the window. If we
        can see the window (the 'fake' polygon) then we can see some
        part of the house's interior, and so some of it's polygons.
        So instead of describing surface detail on the polygon plane
        we can describe further polygons or sub-objects using these 'fake'
        (transparent) polygons to encapsulate a complex and possibly
        partly hollow object.

          Another way to think about the 'INLET' method is to describe
        it as a slab or polygon face S-Buffer technique. In my opinion
        it is far superior to the normal S-Buffer method because we
        only really process and clip those polygon faces which can be
        seen from our current view-point and in the current direction,
        we are NOT processing every polygon as is the case with the
        normal S-Buffer technique. The Inlet way of describing both
        opaque (floor, ceilings, doors) and transparent (windows, holes,
        openings) using convex volumes actually guides the engine
        in the correct direction and away from incorrect/hidden ones.


#Q3:Convex Polyhedra & Compass Bubbles

          I have only just made the connection between transparent
        'fake' polygon surfaces and a back-face culling speed up for
        very complex 3d models. This is mostly due to me focusing on the
        problem of rendering buildings, rooms and other 3d structures
        which tend to be the biggest workload for the CPU to handle.
        Now lets turn our attention towards placing inhabitants within
        a 3d world. Not only do they move about, but parts of them
        move in relation to each other (e.g. arms and legs). As the
        polygon count rises due to ever greater complex models so does
        the need to help minimise the number of individual checks for
        each one. A doubling of polygons means a doubling of work
        even though only 50% or less of an object can ever be seen at
        any one time. What we ideally want is some form of fast
        method which would work out what polygon surfaces could be
        seen from the current view point WITHOUT having to check each
        and every one of them.
          Imagine a Rhombi-icosi-dodecahedron (no, I'm NOT going to
        draw an ASCII diagram =) It has 62 faces in total and 80
        vertices and looks like a badly drawn football. The normal
        way to perform back-face culling (hidden surface removal)
        is to rotate and project all 80 vertices and then test
        each one of the 62 faces. We could use the edge connection
        between neighbouring polygons to navigate our way around the
        3d model. The most obvious way is to use a simple link or
        pointer to each connecting polygon for each edge. A four sided
        polygon would require four of these edge links. Given a single
        polygon as a starting point we could then render each one of
        the surrounding polygons by following the edge links. There
        are two problems with this.

          1) tracing across this map of connected polygons is very
        difficult as each polygon can have a number of edges to them
        and so any number of neighbours. Also it is possibly that you
        may find yourself visiting the same polygon two or more times.
        In which case you must record which ones you have already done.

          2) the main idea behind this local edge-connection is that
        we don't need to search to find other polygons which have a
        common edge or similar direction, but what happens when our
        starting point is on the opposite side to what we want ?
        One answer could be to search using the connection links until
        we found the front (facing us) of the object and then proceed
        from that.

          Going back to the title of this little sub-section a very
        complex model with tens or hundreds of faces can be enveloped
        inside a very simple convex 'bubble' object such as the old
        favourite, a cube. We could then use one or more of these
        six faces to direct rendering towards a good starting point
        on the complex object. We would start off with this 'bubble'
        polyhedron and given it's six polygon faces we could quickly
        determine which are visible and which are not (back face culled).
        At most we would end up with a maximum of just 3 faces, now
        instead of drawing these faces we use each one to point to a
        parallel (or near-parallel) face on the complex model. This
        would give a maximum of 3 starting points from where we could
        draw and follow connected polygon faces until we meet a side
        or back facing one.

          So in affect the surrounding 'bubble' has given us a number
        of starting places around a complex model for a number of
        different viewing angles without having to test and reject too
        many faces. You can think of the bubble as being like a 3d
        compass, directing the renderer quickly to a front (or back)
        face given the viewing direction. Or you can think of it as
        being 6 points on a sphere with one at the north pole, one at
        the south and 4 around the equator. Of course there is some
        extra work and storage requirements for the bubble object, with
        more faces and vertices to process, but hopefully this will
        be significantly offset by the saving in rejecting lots of
        hidden polygon faces.

          But you don't really need to create any extra vertices or
        faces to do this 'compass bubble' technique you can use 6
        (or more or less) faces on the complex model and use these
        possible starting points directly. A straight forward list
        might be used which contains the address of these 6 3d compass
        faces. This would not only avoid the extra storage and
        processing requirements but would solve the problem of
        parallax between the surrounding bubble and the contained
        complex model. If the vertices for these compass faces
        were defined together at the start of the complete vertex
        list for the entire model then this would simplify and
        reduce some of the vertex calculations, because once these
        compass vertices had been rotated and projected etc.. then
        we only need to process the remaining ones in the list.


#Q4:Tessellation, Tiles and Blocky Pixels

          This 'compass bubble' idea doesn't have to be restricted
        to just finding various starting points around a 3d model. It
        could possibly be used for landscape and scenery mapping.
        Take the problem of drawing a reasonably realistic looking
        landscape especially one for a quite detailed mountain range
        along it. Most (i.e.. all) 3d engines I have seen tend to have
        hills rather than mountains and even then they're very flat
        hills. Perhaps this is a restriction in the way most scenery
        and terrain is defined, usually with a flat 2d array with
        varying height at each corner vertex. And within each of the
        array cells there is usually one texture/bitmap token which
        will be used to fill the polygon between the vertex corner
        points. Now if you just pull some of these vertices upwards by
        a large amount then the polygon will either:

        1) become very blocky due to the length between vertices becoming
           large, and so the texture/bitmap is scaled up.
           (I reckon about 99% of engines do this, even JEDI KNIGHT !)

        2) or the texture will be repeated many times over like a
           bathroom tiled wall. I understand this as "tessellation"
           but it might have another meaning.

          Which one of the above two solutions is used depends on the
        3d engine. For very, very long walls or floors method 2) the
        tessellation method is used, this does have the advantage of
        keeping textures all to the same scale so the viewer can more
        easily recognise distant or close-up items just by the amount
        of pixel-zoom which occurs. But this method does introduce
        more instructions within the texture-mapping routine because
        it must wrap around at the texture-space edges. This can be
        quickly done using a simple (and fast) AND instruction so long
        as the texture dimension is a power of 2 (32,64,128,256 etc..)
        It also means that you don't have to store the texture-space
        co-ordinates with each polygon vertex, you 'could' use the
        differences in their world co-ordinates. e.g. if a wall was
        1000 pixels long and a texture was only 32 pixel wide then you
        need to repeat the texture 31.25 times. This of course needs
        more calculation but allows faces to grow or shrink without
        stretching or squashing the texture.

          Method 1) works out the fastest because it avoids having to
        perform the wrap-around logical AND instruction in the texture
        mapping routine (as long as the vertex texture-space co-ords
        do not exceed the texture dimensions, i.e.. with a 64 pixel wide
        texture you can NOT map from 32 to 96). The down side to this is
        that amount of pixel-zoom across polygons can vary depending
        the magnitude of scaling between the polygon edge lengths and
        the texture bitmap dimensions. After playing a JEDI-KNIGHT demo
        I could see at the end that the huge cargo ship which you must
        jump onto is a small bitmap scaled up to cover a vast area.

          It is possible to write an engine which allows both kinds of
        texture-mapping and mark polygons with a bit flag to indicate
        which kind of mapping routine should be used.


#Q5:'Checkerboard' or Grid Based Textures

          There is another kind but it would require far more work than
        the tessellation method, but could allow a far greater variety
        in filling large polygons without the need to break them up into
        many smaller ones. Instead of repeating the same texture once
        an edge has been crossed why not use another texture ?
        This would require a map or array of texture tokens to be stored
        and that the texture-filler routine would need to detect when
        a neighbouring texture needs to be fetched from the token map.
        So instead of drawing a bathroom like wall with the same tile
        used again and again, we have the ability to have any number
        of tiles in any order along the wall. We could have one texture
        for the left side of the polygon, one for the centre and one
        for the right side.
          There are some limitations and problems with this:
        a) the textures will need to be of an identical size so that
           each neighbouring texture lines up (most likely square)
        b) the texture-filling routine will be much slower
        c) extra storage is required for the token array map
        d) all the textures on the polygon still lie on the same plane.
           So even though you could have grass on one edge and rock on
           the other they would both be flat unlike if more vertices
           (and more polygons) were used.

          Another way to think about this method is to imagine the
        polygon as a flat wall and the chequer-board as various
        pictures hung along the wall's length.


#Q6:One Big Texture, Many Mappings

          Depending on how the texture bitmaps are stored (usually in a
        256-byte-per-line format) it is possible to greatly reduce the
        number of small textures in a crafty and easy to do way.
        Imagine we need to draw a rocky field landscape with mud, grass,
        gravel and some stone or rock path. Five or more simple texture
        bitmaps could be drawn by a graphics artist for each type of
        terrain. Now we design and render a rough field using these
        texture bitmaps to cover a number of polygons. The result is
        reasonably, except where textures of different kinds meet, e.g.
        where mud meets grass or grass meets stone. It looks like a
        chess-board and the viewer can easily see where one texture
        meets another (he or she can see the seams in the landscape).
        To reduce this the graphic artist could draw more textures
        which can be used to blend one terrain type into another
        (e.g. 50% grass and 50% mud). The seams are still there but
        the viewer doesn't notice them as much.
          The problem of using 'blending' texture bitmaps to smooth
        out the edges between two terrain type is it quickly increases
        the amount of memory used. If we had 64 textures then we
        would need about 8192 textures to smooth from each one to the
        other 63. As you can see this is an extreme case and most
        texture bitmaps only need to be smooth between one or two
        others and NOT every other one.

          Most textures these days range in size of 32x32 up to a
        maximum of 256x256 and most being about 64x64 in size. There
        is a problem facing designers and programmers. Should they
        use big 256x256 texture bitmaps to cover large areas quickly
        in one go or should they break the area into a smaller parts
        and use a size of 64x64 or less ? Personally I think the
        smaller the texture, the better as they tend to cache very
        well in the CPU with less memory reads and also free up more
        memory for different textures. As almost all textures need to
        be stored in a 256-per-byte-line format and most textures are
        smaller than 256 pixels in height and width, we can cheat
        and create a huge 4096 textures from just FOUR 64x64 textures.
        We know that each line of a texture is 256 bytes apart from
        the previous one so we can easily store 4 textures in the
        following way:

                        0 ................. 255

                        aaaaa bbbbb                     < 1st line
                        aaaaa bbbbb                     < 2nd line
                        aaaaa bbbbb                     < 3rd line

                        ccccc ddddd             where a,b,c,d are the
                        ccccc ddddd             texture bitmap pixels.
                        ccccc ddddd

          In a 256x256 block of memory we could store 16 of these
        64x64 texture bitmaps without wasting a single byte of memory.
        Each 64x64 texture bitmap can be drawn separately and only
        stored together like this by the rendering program in memory.
        It's loader would just interleave each 64 pixel line as each
        texture bitmap is read from a disk file. So the textures do
        not need to be drawn or stored in any particular order.

          Right enough waffle, here is the crafty trick.

          Make the graphic artist draw the 64x64 textures on a huge
        256x256 bitmap (go on, nail 'em to the chair). All the
        textures DO NOT have to be 64x64 pixels in size, some can be
        8x8, some 16x64, some 256x48 or whatever.... So long as there
        are NO gaps between each rectangular texture. After the
        graphic artist has stopped complaining about "not being able
        to see the edges between neighbouring textures" tell 'em
        "Yeah, that's the whole idea pal !"

          Think of the below diagram as being a collection of small
        texture bitmaps on a large 256x256 bitmap.

                0 .................................... 255

                +-------+--------+----+------------------+
                |       |        |    |                  |
                | grass |  mud   |    |   long slab      |
                |       |        |    |                  |
                +-------+--------+----+----------+-------+
                |       |        |    |          |       |
                | rock  |  water |    |          |  tall |
                |       |        |    +----------+ thing |
                |       |        |    |          |       |
                |       |        |    |          |       |
                +-------+--------+----+----------+-------+

          You should notice that the bitmaps do not have to be all
        the same size as long as there are no gaps between them.
        Using the 4 textures (1 for grass, mud, rock and water) we can
        also blend between grass + mud or mud + water simply by
        starting somewhere on this 256x256 bitmap, NOT on the texture
        boundaries. We could start half way across the grass and end
        up half way into the mud or we could begin 1/5th into the mud
        and end up 1/5th (or any other amount) into the water.

          We have blended neighbouring textures together WITHOUT having
        to create a single new texture !!!! So instead of wrapping
        around in the same texture bitmap we allow the mapper to
        cross into the neighbouring one.

          Of course some care and pre-planning is required before the
        graphics are drawn but this should help the graphic artists as
        much as hinder them because they can see the joins between
        the small terrain texture when they drawn them. This will
        allow them to smoothly blend from one to another simply by
        treating the 256x256 bitmap as one giant picture. This huge
        texture can be used in it's entirety for filling large areas
        with a pond or rocks at it's centre or can be used as normal
        and small parts of it used to fill small blended polygons.

          Actually it might not be a good idea to place textures
        directly next to other textures (e.g. grass next to water)
        because if you use just the grass to tessellate a large
        area then the smoothed edges (between grass and water which
        the artist drew) will break up the illusion of a continuous
        area of grass. The old isolated and flat-drawn texture bitmaps
        would give a much better illusion of a seamless area because
        their left and right (and top and bottom) edge have roughly
        the same amount of colour and shade, i.e.. one side doesn't fade
        into water and the other side fade into stone.
        But all is not lost, remember these gaps between textures ?
        Well, why not introduce gaps to separate the 'flat' continuous
        textures and then get the artist to draw some smoothing
        graphical bits in these gaps. This way we can still use the
        individual textures to tessellate large areas and we can
        also use some/all of these new gap graphics for blending.
        (nice eh ?)


#Q7:'Horizon' Z clipping

          Most of the 3d performance boost comes from various types
        of clipping. Whether its back-face culling (hidden surface
        removal), object rejection, Z-buffering or Span-buffering
        they all have the same goal, to reduce the amount of
        polygons, lines or pixels which need to be drawn on the
        screen. The ideal situation is only having to draw each
        pixel once and only once, never to overdraw anything.
        Whether you intentionally use them or not, 3d object models
        contain some amount of hierarchy (the models are built from
        polygons, the polygons from lines and the lines from pixels).
        As objects move into the distance some part or all of them
        will be reduced to the size of single pixels. In the classic
        example of a aircraft runway with white line markings on a
        mostly black tarmac there needs to be a cut-off distance for
        each. If we continued to drawn both then at some point
        both would become single pixels one black and one white and
        every so often the runway would appear to flash white then
        black. It is clear that the white line markings should not
        be drawn - they should be clipped if beyond a certain
        distance from the view point. And the black tarmac would too
        be clipped at some further distance because of it's larger
        size.
          The distance clipping is normally performed using just the
        Z component of a polygon (instead of the proper distance
        SQRT(XX+YY+ZZ) which this is SLOW). So each polygon needs to
        have a 'horizon' or distance-cut-off point beyond which it
        is not drawn even though it is visible.
          Most games use a number of polygon models each for varying
        amount of detail to them. Four seems to be a favourite
        number. The closer to the 3d model the greater the number of
        polygons and detail. The further away the simpler and more
        crude the model. Instead of using the cop-out method of
        multiple models I will try to explain some ideas. Some will
        be practical and some not so, depending on how the models
        are defined and rendered.

          One of the most obvious ways to render a 3d model/object
        is to go through the polygon list and reject those beyond
        the horizon cut-off point. But this would require another
        test (and perhaps some calculation) for each polygon face.

        e.g.
                for i = 1 to Number_Of_Polygons
                        if Polygon[i].Z  > Polygon[i].Horizon then reject
                                else render( Polygon[i] )
                next i

          Note how the above loop takes the polygons in no
        particular order, just the way they are defined in the
        polygon list. Within the loop each polygon has it's Z
        value compared against it's Horizon (or Z-cut off) point.
        If it is beyond this limit it is not drawn, otherwise it is.

          Suppose we order the polygon list in decreasing order
        of their 'Horizon' field with furthest cut-off distance
        first (the biggest polygon) and the closest cut-off distance
        last (the smallest polygon). We know that every polygon
        after 'n' will have a closer cut-off point and so will
        disappear sooner so if polygon 'n' is beyond the cut-off
        point then so will ALL the following ones. Because the list
        of polygons are sorted this way we can immediately stop if
        we encounter a polygon which is beyond the Z cut-off limit.

        e.g.
                for i = 1 to Number_Of_Polygons
                        if Polygon[i].Z > Polygon[i].Horizon then stop
                        render( Polygon[i] )
                next i

          In the worst case every polygon's Z will be less than
        the cut-off distance so 'N' checks are being performed for
        nothing. You could store a depth field with the object
        model and use this together with the relative distance
        of the object to quickly reject or accept the entire
        model without the need to perform any horizon checks.
        As we are basically searching for the first cut-off polygon
        in the sorted list then we could employ a binary-search
        or some other hashing/look-up technique, this way the
        number of non cut-off polygons can quickly be found
        and a straight loop without checks can be performed.

          But one of the main problems with simply losing polygons
        that 'fall' over the horizon cut-off point is that objects
        may appear to suddenly have holes in them when a small
        part of the model is rejected but the surrounding larger
        ones are not. As this pruning is done on mostly small, far
        away objects you might get away with Swiss cheese :)


#Q8:Dynamic Details & Model Simplification

          Another way to simplify models (which I haven't tried yet
        or really thought about to any great extent) is to build
        the object model like a sculpture and build many detail
        levels into a single model. This would require more polygons
        but perhaps no more vertices. To see what I mean imagine a
        solid square box of stone this will be our coarsest model
        (of course it doesn't have to be square) with only six faces
        its a pretty fast object to render. This is fine for the most
        distant model as it would appear to be a few pixels in size.
        You can think of this as the beginning of a sculpture with
        no detail just the basic outline. Now chisel away a corner
        or two and you start to have a more detailed model with
        more faces and more vertices. Continue this process removing
        corners and sub-dividing faces and you eventually end up
        with the most detailed model.
          You could think of this as another form of hierarchy with
        the most coarse model being the root and the more detailed
        being the leaves. If a polygon face is close enough then
        use it's sibling sub-faces. This genealogical rendering
        continues until we reach either the horizon cut-off point
        or the leaves (finest detail) of the model.

                        PROBLEMS, PROBLEMS .....

          There is a HUGE problem with this egg-within-an-egg idea;
        that of parallax. The sub-faces directly under a coarser
        face depends on the viewing angle and angles of rotation.
        So moving the object model from side to side will make the
        sub-faces seem to slide underneath a parent face.

          Personally I am not convinced by this idea (yet) it still
        needs much more work. In the end its probably far easier to
        create multiple detail models instead rather than trying to
        clump it all together in a single data structure. The only
        advantage from having an 'all-in-one' model is the ability
        to select any number of detail levels for a smooth coarse-to-
        fine transition. Using a number of individual detail models
        means you only have a few levels of details to choose between,
        the more detail levels, the greater the number of models that
        you need.


#Q9:MIP Faces & Component Models

          As with most programming problems the surface detail one can
        be eased a great deal by throwing lots of memory at it.
        Going back to the racing car door and it's surface detail we
        can improve matters by defining two or more door models. The
        overall distance to the car would determine which door model to
        use, the most detailed one for close-ups and the most basic
        one for long range views. By having more than one 2d/3d model
        for a component would take up far more memory it's sensible
        to try and reuse them as frequently as possible. This would be
        like building a large object from a number of sub-objects (the
        components) and we would select a reasonable version of each
        sub-object for a certain distance & detail range. An advantage
        of this cloned part approach is that we could modify one single
        model and change the entire game world or at least every item
        which uses the same component.

          But having a variable detail level for a polygon face means
        a variable number of sub-polygon faces which is much slower
        than a straight forward texture bitmap approach. Due to the
        increase in polygon count and not forgetting vertices and
        rotation/perspective calculations it first appears to be a
        bad idea with changeable bitmap textures looking like the best
        method. Just remember that these bitmaps are just 2-d planes
        and suffer from pixellation when viewed from short distances.

          The good thing about using sub-polygons or 'component models'
        is that our old friend 'the tree' can be used. We also have
        much more control over the detail levels and we need far less
        memory than using MIP-mapping techniques (multiple copies of the
        same bitmap texture at different scales) or simply using a
        very high resolution bitmap to avoid pixellation. Just like
        the bitmap approach the component models can be reused again
        and again to build up very large models from a few components.
        This method might be best suited for landscape rendering where
        the player can get very close to hills, rocks or the ground.
        Once the 3-d component models have been designed (and perhaps
        optimised) it would be very easy and quick to build up a large
        environment or object without having to design each and every
        tree on the landscape or every bolt on a robot.

          Another possible method could be to employ both techniques,
        normal bitmap textures for distant items and proper polygons
        for close-up ones. This leads to the problem of creating these
        detail models and associated bitmaps. One obvious solution
        would be to define the highest detail 2d/3d models first and
        then render them on a 2d screen like any other 3d object. Then
        this 2d rendering can be taken directly to be it's bitmap.
        When programming the map/game editing utility it is probably
        best to restrict the designer to placing the low detail bitmaps
        which fill the large areas. This way huge worlds can be created
        quickly without having to design thousands of detailed
        component models, each of which require a 2d bitmap.

          The problem with all these MIP-mapping and multi-detail model
        techniques is that they really need a smooth transition between
        two scales otherwise the model will appear to suddenly change
        and shatter the illusion of realism. By using horizon fading
        (black or white fog) this sudden jump can be visually disguised.


#Q10:Primative Component Models

          When most people think of and define polyhedral object models
        they think in terms of vertices and polygons/faces, but there
        is another higher level way to build up complex environments
        and models, that of primitives. A primitive is just a basic,
        building block solid object component such as a cube, pyramid
        and so on. These are often used in CAD design packages to help
        speed up an otherwise lengthy design process. You don't have
        to stick with sharp, planar components you can use spheres,
        circles, cylinders or even more complex solids. I think the
        Freespace system used in games like Castle Master and it's
        grandparents used this method in designing their levels and
        objects. Even newer games like Estatica uses primitives in the
        form of ellipsoids and spheres. And I think most people can
        remember seeing a DOC-like demo with rotating objects made up
        entirely from balls (helicopters, peoples and national flags
        were all favourites).

          The advantage from using primitives is that their shape,
        vertex and face counts are already know and so can be optimised
        and pre-processed in ways in which a general polyhedral shape
        could not be. Also symmetry can be used to greatly reduce
        rotations to their minimum. For example a cube only requires
        a single vertex (X,Y,Z) to be defined and then all of it's other
        7 corner vertices can be quickly created from negating and/or
        swapping these X,Y,Z values about.

          The bad points (lame pun) is that they can require more
        custom code (not too bad, is it ?) and tend to make objects look
        like building blocks stuck together. Also complex models may
        require tens of these primitive solids instead of a single,
        more flexible mesh. This can lead to more faces being rendered
        then is absolutely necessary, you may end up with primitive
        faces which are inside other solids and so shouldn't really need
        to be defined or rendered. In short you are forced to draw each
        part of each primitive even though some of it might be completely
        wasted.



#############################################################################
Ŀ
 #R:                     Projections and Corrections                       

#############################################################################

          The problem with the monitor screen is that it is flat,
        just a 2d bitmap on which 3d objects have to be drawn.
        It is at this stage where one dimension is lost, discarded
        forever. All the preceding transformations do not lose any
        information (apart from precision errors) so to a great
        extent they can be reliably undone and their calculations
        reversed, but this is not the case with the perspective
        (projection) 3d-to-2d stage because we would need to
        create a dimension from nothing.

          The perspective stage is normally done with a projection
        of some kind. The most simple is to divide the X and Y
        co-ordinates by the Z, but this is incorrect. The basic idea
        behind the simulated perspective is that the further away
        things are the smaller they should be. Using just the Z
        co-ordinate as the distance from the view point is only ever
        correct when X=0 and Y=0, otherwise the square-root of
        (X" + Y" + Z") should be used. This calculation is very
        slow because 3x multiplies and 1x square-root needs to be
        done PER VERTEX !! using 2 divisions is a reasonable cheat.

          There are some subtle characteristics in the normal
        projection formulas which can cause some viewing errors and
        prevent any optimisations which 'might' be possible from
        combining the rotation and projection stages. If a 3d object
        model is projected with it's centre origin at (0,0) then
        the distance errors are hardly noticeable but move the
        object to the edge of the view-port/screen and it begins
        to sheer in one or two directions. Another error can be
        seen if an object is rotated around the view point while
        keeping a constant radius. Again near the edges of the
        view-port/screen distortion occurs, the object appears to
        grow in size because it's Z distance has decreased and it's
        X and/or Y has increased. This is why the square-root
        method gives the correct result whereas the divide-by-Z
        does not. The greater the resolution of the view-screen
        in terms of pixels, the greater the amount of this distortion.
        You may want to adjust the Z co-ordinate using a small
        amount of the X and Y co-ordinates to give a closer
        approximation to the true square-root or you could simply
        push the object slightly further away depending on it's
        angle to the (0,0) origin on the view-screen. So as an
        object gets closer to one of the screen edges you move it
        slightly into the distance BEFORE projecting it's vertices.

          Okay you might say, why not simply project the object
        on the (0,0) origin and THEN translate it to the correct
        view-port/screen position ? Well this would help minimise
        sheering/distance errors but the parallax would be incorrect.
        Try holding a box directly in front of your eyes and then
        move it to the left or right. The sides of the object
        appear to shrink or grow because the front corner vertices
        seem to move faster than the back ones (i.e.. parallax).
        You can think of this another way (which may or may not be
        correct), imagine that object has rotated slightly.
        Hold an object directly in front of your eyes and twist it
        to the right a little, now move it right a foot or so.
        You should hopefully see that this is almost (if not
        entirely) identical to the proper square-root distancing.
        Because we are rotating and projecting around the object's
        (0,0,0) origin when it is close to the view-screen edges
        the sheering and size distortion should be minimise a
        great deal (if not completely removed).

          There is some extra calculation involved to work out
        the amount of rotation which is needed. The amount of
        rotation depends on the angle between the view-port/eye
        (0,0) origin and the object's central origin. One way to
        do this it take the correct distance of JUST the object's
        origin (relative to the view-point) together with it's
        angle from the view-screen (0,0) origin and use these to
        rotate and project all the object's vertices.

                                     X = 0
                e.g.                        . .
                                          .    object
                                          .  o   .
                                            /  .
                  Z     / view-plane
                  ^                       /             (the screen)
                                      a / r
                                       /
                  > X             /         PLAN VIEW

                                      eye

          In the above diagram the object's origin is marked by 'o'
        the object vertices are marked by '.' and 'a' is the angle
        between the object's-origin and the X=0 plane. The 'r' is
        the true length of the object's-origin to the eye-point
        (from 'o' to the 'eye').
        This diagram only shows the X-Z plane it should be done for
        the Y-Z plane as well. so the true 3d distance is found and
        the 2 angluar adjustments.


#R1:The Angle Grinder

          Here is a little algorithm which I use to calculate the
        angle between two points using the X and Y axis lengths:

                IF x <> 0 THEN angle = ATN(ABS(y)/x)*180/PI
                          ELSE angle = 0
                IF x < 0 THEN angle = angle + 180
                IF y < 0 THEN angle = 360 - angle

          It works for all 360 in a fairly compact way. If you use
        some other resolution for a complete 360 circle then just
        replace 360 with your resolution and 180 with 1/2 your
        angle resolution.
        For example if you use 1024 for one complete circle then use:

                degrees = 1024
                half = degrees / 2

                IF x <> 0 THEN angle = ATN(ABS(y)/x) * half/PI
                          ELSE angle = 0
                IF x < 0 THEN angle = angle + half
                IF y < 0 THEN angle = degrees - angle

          Of course the "half/PI" value can be replaced with a
        constant or pre-calculated value. This would remove a divide
        instruction.

NOTE:
          The angles are converted from DEGREES into RADIANS for
        the ATN function. There are 2*PI radians in a circle or
        360 degrees.

          So we end up with a divide and a multiply, but the real
        problem is the ATN (Arc TaNgent) function which is difficult
        to do in 80x86 (I not even sure that there are any floating-
        point instructions which perform it, I could be wrong).
        After pausing to take a quick look at the old Spectrum
        ROM book the correct polynomial method looks way too long and
        far too slow, so I suggest using a LUT (look-up table).
        After a little bit of experimentation I found that basing it
        around 45 arcs works reasonably well and using the shortest
        length divided by the longest length can be used to index
        into an correction table, something like this:

  ;* First create an adjustment table *

                DIM adjust[45]

                FOR a = 0 to 45
                        n = ( SIN(a*PI/180) * 45 / COS(a*PI/180) )
                        adjust[n] = a - n
                NEXT a

  ;* Now here is the angle-finding code *

                angle = 0
        turn90:
                IF x < 0 OR y < 0 THEN
                                        SWAP x,y
                                        y = 0 - y
                                        angle = angle + 90
                                        GOTO turn90

                IF x = 0 THEN angle = angle + 90 : RETURN
                IF y = 0 THEN RETURN

                IF y > x THEN
                                n = 45 * x / y
                                angle = angle + 90 - n - adjust[n]
                         ELSE
                                n = 45 * y / x
                                angle = angle + n + adjust[n]
                RETURN

          It's far from perfect, but it works (sort of). It can
        be improved slightly by building two look-up tables
        (one for y>x and one for x>y). You could also detect 45
        angles simply by comparing the x and y lengths.


#R2:Round the Bend

          The difficulty in writing a ATN (Arc Tangent) or ARCSIN
        or ARCCOS function (the last two are slower) is that we must
        find an angle based upon an X,Y position on a circle. We need
        to find the reverse of a SIN (sine) or COS (cosine) function,
        that is the angle. There is no easy, quick way to do this.
        I haven't found any descriptions or algorithms which perform
        these functions which is surprising considering how useful they
        are for direction finding, anti-rotations and so on...


#R3:Hint, Hint, Intel

          What I don't understand is why chip makers don't create
        floating-point instructions to performs some of the most
        used formulas in maths. Some functions like these would be
        a god send.

                a = FANGLE ( x, y )

                l = FMAG2D ( x, y )

                l = FMAG3d ( x, y, z )

          Where FANGLE returns the angle from the two operand lengths
        and FMAG2D returns the magnitude (SQRT of X*X + Y*Y) and
        FMAG3d returns the magnitude of SQRT (X*X + Y*Y + Z*Z).
        You can easily find the minimum values for the FMAG2D and FMAG3d
        functions just by finding the largest ABSolute length.

                e.g.
                        major = ABS(x)
                        minor = ABS(y)
                        IF major < minor THEN SWAP major, minor

        Now major is the minimum value of SQRT(X*X + Y*Y). You can
        also find the maximum value by:

                2D length                       3d length

                major*SQRT(2)           or      major*SQRT(3)


#R4:Faster Perspective/Projection

          As the 3-d vertices must be converted into 2-d ones
        there is usually the need to perform a division and a
        multiplication together. Say we had two calculations like
        the ones below.

                               X                       Y
                X' = xratio *        Y' = yratio * 
                               Z                       Z

          The 'xratio' and 'yratio' values are used to modify the
        angle of the projection and change the field-of-vision.
        Most people use a value of 128, 256 or 512 for these
        variables because they can be done using a very fast shift
        instruction, so by removing an multiply.

          This should look familiar to most people as a form of
        these calculations are mainly used for the 3-d to 2-d
        conversion.

          But we have 2x multiplies and 2x divides which are very
        slow compared to additions or subtractions. One way to help
        speed these up is to use a table of 1/n values, so instead
        of performing a division you perform a multiplication.

                e.g.

                        a = b * table[c]

                where each element in table[n] = 1/n (the reciprocal),
                so we are doing the same as:-

                                 1                            b
                        a = b *      which equals:   a =  
                                 c                            c

          Going back to the projection/perspective formulas, if the
        xratio equals the yratio then we can avoid the second
        division by reusing the result of the first.

                        NOTE: only IF xratio = yratio

                e.g.
                                  xratio      yratio
                        scalar =  = 
                                     Z           Z

                X' = scalar *  X        Y' = scalar * Y

          So this turns out to be 1 division and 2 multiplies, but
        you may need to use fixed-point maths to keep the precision
        of 'scalar' to a modest level.


#R5:Combining Rotations & Projection

          In the general render-pipe-line the projection/perspective
        calculations usually follow some rotations, either matrix or
        straight forward 3-stage X, Y then Z axis rotations. As you
        should already know the X and Y co-ordinates need to be
        magnified up in the projection part before being divided by
        the Z co-ordinate. These days everyone has a Pentium or at least
        a fast 486 slug, so floating-point instructions are finally
        worth using rather than integer ones. This means that using
        fractions and combining operations now doesn't mean losing
        tons of precision. So operations or formulas can be combined
        without too many problems.

          Take a simple rotation around the Z axis (pointing into the
        screen) followed by a basic projection.

        Z ROTATION:
                        x' = x * cos(a) - y * sin(a)
                        y' = x * sin(a) + y * cos(a)
                        z' = z

          the above cos(a) and sin(a) values can be placed in a matrix.
        This helps when dealing with lots of vertices. In this case it
        could look like this:

                        x' = x * m[11] - y * m[21]
                        y' = x * m[12] + y * m[22]
                        z' = z
        where:
                m[11] = cos(a)                  m[21] = sin(a)
                m[12] = sin(a)                  m[22] = cos(a)

          Here is the basic projection stage.

        PROJECTION:
                             x' * Xratio
                        h =  + Xcentre
                                 z

                             y' * Yratio
                        v =  + Ycentre
                                 z

          where:
                Xcentre, Ycentre        are the centre co-ordinates of screen
                Xratio, Yratio          are the field of vision magnifiers

          they usually have the values something like these:

                Xcentre = 160
                Ycentre = 100
                 Xratio = 500
                 Yratio = 500

          Right enough waffle, here is the good bit =)

          When the rotation matrix is being built simply combine the
        Xratio and Yratio values into it.

        e.g.
                m[11] = cos(a)*Xratio           m[21] = sin(a)
                m[12] = sin(a)*Yratio           m[22] = cos(a)

          now the rotation is,

                        x' = x * m[11] - y * m[21]
                        y' = x * m[12] + y * m[22]
                        z' = z

          and the projection is,

                              x'
                        h =  + Xcentre
                              z

                              y'
                        v =  + Ycentre
                              z

          So we have removed 2 multiply instructions for each vertex.
        Well actually we have moved them into the matrix set up code.
        This means if we rotation and project N vertices we can save
        2 * (N-1) multiply instructions, not bad eh ?


#############################################################################
Ŀ
 #S:              Unfolding Polyhedra & Mapping Adjacent Faces            

#############################################################################

          In a couple of previous sections I have described methods
        which follow neighbouring polygon faces to exploit the
        locality of surfaces, shared edges and vertices etc..
        but there some problems which need to be tackled in order to
        make these methods feasible. The main problems are:

        1) following these neighbouring faces.
           There are as many neighbours for each face as there are edges.

        2) It is possible to visit the same face twice
           Because every polygon is connected to AT LEAST 3 others
           (3 sides = 3 neighbours) it is possible to find your way
           back to the starting polygon in many, many ways.

        3) neighbouring faces can be at any angle to the current one.
           So there is no easy way to find the polygon face above
           (or in any direction to) the current one.

        point 1) there are two likely strategies for tracing the
        neighbouring (Mapping Adjacent Faces). One way it to create
        two elements for every polygon edge where these two elements
        point to the two neighbouring polygons which share the edge.
        Another way which I have used throughout this document is to
        create N links for the N sides of each polygon. So for a
        5 sided polygon there would be 5 links. Each link is just a
        pointer to the neighbouring polygon.
        Creating these links is a very simple matter of searching for
        two polygons which share the same 2 vertices but in reverse
        order. So one polygon would use 2 vertices A..B and the other
        would use B..A to describe ONE edge.

        point 2) as there are many links (because the polyhreda is a
        closed surface of joined faces) there is no start or end and
        no single direction to trace out these neighbouring faces.
        You can think of this as a multi-directional circular tree.

        point 3) it would be incredibly useful if there was a way to
        move around the object quickly in a certain direction.
        If there was we could possibly reject large numbers of polygons
        when we encounter a clipping edge.
        e.g. if the current polygon is clipped against the right screen
        edge then we can reject ALL those polygons to the right of it,
        and likewise with the other screen/clipping edges.


#S1:Unfolding

          If it wasn't for the 3rd dimension of the 3d models which
        connects one side along the back to the other, then the
        links would not need be circular. If the model was 2d then
        we would have leaves to the tree structure where the outer
        polygons have no neighbours. Because at the end of the day the
        3d model will be projected onto a 2d bitmap screen you could
        think of the entire 3d model being squashed flat onto a plane.
        This is what the projection actually does, it removes one
        dimension to create a flat group of co-planar polygons.
        We only see (and draw) the polygons on one side of this plane
        because the others are rejected by the back-face culling.
        If all these polygons remained rectangular with no overlapping
        then finding the polygons in a particular direction would be
        very easy, just step across this 2d array map. But this is
        never the case.
          I believe that only convex polyhedra can be folded flat
        this way with no overlapping of polygon faces. Concave objects
        can not be made from a single piece of paper or card, where
        convex can (I think).
          By thinking of a 3-d model as being a 2-d one with 2 sides
        (of which 1 is rejected) then it should be possible to trace
        around the edge of the polyhedral object to discover those
        polygon faces which are on the visible side. That way any
        faces inside this front/back boundary can be accepted and
        those outside it will can be rejected without the need to
        apply back-face culling to every face.

NOTE:   This scanning of the front/back boundary polygons is no doubt
        only valid for true convex polyhedral object models (those
        without lumps or dips in their surface skins).


#S2:Neighbours and Trees

          Programs and CPU's are efficient at handling sequential
        data (one after the other), but they are lousy with multi-
        direction data structures. We can define fancy binary
        or multi-way trees and jump tables which branch off into
        many directions from one single point although there is
        no easy way to simultaneously follow more than one branch.
        To visit all the nodes/junctions on just a binary tree
        requires a temporary linear buffer (i.e.. a stack) so we can
        back track and follow the second route after following the
        first to it's conclusion (a leaf).
          What's this got to do with 3d models ? Well, a circular
        tree (or "ring" tree) can be used to model a 3d object by
        taking the tree nodes as being the polygon edges we could
        define our old friend the cube using the following tree for
        it's six faces:

                                        1 ------
                                     /  |  \     \
                                  /     |     \   \
                                6 ----- 2 ---- 5   \
                                 \  \   |   / /    |
                                  \   \ | /  /     /
                                   \    3   /     /
                                     \  |  /     /
                                      \ | /     /
                                        4 ------

          The above (lousy) ASCII diagram shows how each of the six
        faces are connected to it's four neighbouring faces.
        Please note that the connecting lines are BI-DIRECTIONAL so
        face 1 is joined to 4 and face 4 is joined back to 1.
        The biggest problem with the above structure is knowing
        which links you have already visited and when you have reached
        the end.

          Another way to represent the cube is choose one starting
        face and then squash it flat. If we repeat this for all the
        faces then we have the following holy shapes :)

          The top-most square is the starting face.

                Ŀ     Ŀ     Ŀ     Ŀ     Ŀ     Ŀ
                A     B     C     D     E     F
              Ŀ Ŀ Ŀ Ŀ Ŀ Ŀ
              FBE FCE FDE FAE ABC CBA
                   
                B     D     A     B     F     E
                Ĵ     Ĵ     Ĵ     Ĵ     Ĵ     Ĵ
                B     A     B     C     D     D
                                         

          We could use a 2d table to represent the cube like this:

                      Face      Up    Right   Down    Left
                                       
                        A       D       E       B       F
                        B       A       E       C       F
                        C       B       E       D       F
                        D       C       E       A       F
                        E       D       C       B       A
                        F       D       A       B       C

          For the moment I can't think of any really practical
        way to define general polyhedral based objects using
        either binary or multi-way trees. And it might be a lost
        cause to believe a solution exsists because tree based
        structures are best utilised for navigating a SINGLE path
        through pre-sorted data. They tend to be really awful for
        visiting every location as recursion (real or fake) is
        needed to follow every possible path. And visiting every
        path (in some order) is what we need for 3d model
        rendering. Finding one, single face isn't enough and if
        we repeat the navigation for every face then the tree
        structure is actually creating more work instead of saving
        it. Tasks such as string-searching, locating a particular
        item in a sorted list both benefit from using a tree, but
        sadly I think face rendering doesn't (apart from BSP trees).


#S3: 3d models, 2d belts

          As I have previously mentioned linear (sequential)
        data structures are best suited for programming purposes
        because they usually have a beginning and an end. All of
        the 3d models that we wish to render will tend to be closed
        ones with no beginning or end. Even 'open' objects like
        a cup can be represented by a continuous surface made up
        from connected polygons or 'mesh' as I believe most people
        like to call it. Think of a lump of clay, the exterior
        surface of the clay is our polygon mesh. Now deform it
        into the shape of a cup. I think if you take any convex
        polyhedron and reverse deform it back into a clay lump
        then you always end up with a spherical shaped mesh lump.
        This general, globe-like lump could be the basis for all
        3d models (maybe).
          Now we need to find a suitable way to describe this
        ball shaped lump and if possible do it in a mostly linear
        way so a straight forward list could be used. At this point
        I will break with tradition and use a regular dodecahedron
        instead of our overly employed cube. It has 12 faces, 20
        vertices and 30 edges (each face has 5 edges). If you
        looked square on at this dodecahedron then you would see
        5 faces with 3 at the top and 2 at the bottom.

                                   J
                e.g.         _____________
                            /  |       |  \     <--- Cool back-face culled
                           / A |   B   | C \         object (who need SVGA =)
                          /   /\       /\   |
                          |  /  \     /  \  |
                          | /     \ /      \|
                           \   E   |   F   /
                            \      |      /
                             \_____|_____/

                                   K

          The above diagram (okay, stop laughing) shows 5 of it's 12
        faces with the other 7 faces hidden from view. Unlike a cube
        we can not use left/right/up/down direction to navigate a
        path across it's surface polygons. For example starting at
        face B what is the next face on the right, is it C or F ?
        One idea which I had today is to cross-section an object
        into a number of 'belts' using a series of parallel cuts
        through it. A 'belt' is a sequence of polygon faces which
        follow an imaginary plane as closely as possible. In the
        above diagram the A,B,C (and the hidden) D,E faces would
        be classified as a single belt. It's data structure is
        nothing more complicated than a circular list which is a
        wrap-around linear list.

                e.g.
                        <<Ŀ
                        v                              <--- A 'belt'
                        A > B > C > D > E 

          This parallel dismembering of the 3d object model
        continues with the next belt of faces. We must also repeat
        this for the top and bottom layers. At the end we have the
        following belts listed in vertical order.

               Belt     Faces
                    
                1       J
                2       A B C D E
                3       E F G H I
                4       K

          NOTE: the faces in the object only appear ONCE in this
                list of belts. This means we never need to worry
                about revisiting the same polygon face.

SO WHAT ??????
          At the moment I am not really sure how useful this is.
        It could possibly be good for back-face culling or trivial
        polygon rejection. One strategy for using these belts might
        be to test the visibility of the first face in the list and
        if that is visible then continue with through the list until
        we find a back-face culled one. At this point start again
        at the beginning of the list and step backwards through it
        until we encounter another invisible face. Now hopefully
        between these two completion points we have correctly
        rejected many faces without the need for visibility testing.
        i.e.. We have followed and drawn each face from the front of
        the belt in both directions stopping at each side and NOT
        bothering to process the back faces.
          This method is perhaps only useful for 3d object models
        which have a high number of polygons. Primitive things like
        a cube, pyramid and the like are probably not worth doing.

#############################################################################
Ŀ
 #T:                         Our 3d world is flat                          

#############################################################################

          Most of the 3d problems concerning rendering can be quickly
        approximated to and thought of in terms of 2d, after all this
        is what the view-screen bitmap is. The subject of lighting,
        shading and polygon filling may appear to be pure 3d ones but
        can be thought of in terms of filling horizontal or vertical
        lines on the 2d screen bitmap. If we take the X and Y co-ords
        as being the view-screen co-ordinates then the lighting/shading
        value together with the Z co-ordinate can be thought of as one
        parameter which changes over the length of a single line span.
        This parameter at it's most simple would be constant (no
        shading) and at it's most complex it would change at every pixel
        along the line span, possibly once for the red, green and blue
        of each pixel as in the case of coloured RGB lighting.
        Basic shading would take the form of linear stepping along the
        line span and advanced shading would perform some form of
        radial/circular shading across the polygon face, this is because
        lighting a flat polygon can be thought of as a plane
        intersecting a solid sphere (the radiating light). The distance
        from the light source affects the shading so the further away
        the plane (flat polygon) is, the less light should fall on it.
        Perhaps the maths world of conic sections may prove useful in
        this area as that deals with planes intersecting cones to
        produce ellipses, circles and all other types of curves.


#T1:Normal Shading

          I believe most people programming 3d stuff using vector maths
        to perform hidden-surface removal (back face culling) and
        various shading techniques. Using a vector for each light
        source and the normal-vector for each polygon it is possible
        to calculate the amount of shading required. I haven't looked
        into this area too much because I have only recently managed
        to get my sticky-mitts on a few scrap of info. I think you need
        to store normal-vectors (or is it unit-vectors ?) for either
        each polygon face or each vertex (which is impossible isn't it
        how can a point have a normal vector ? I thought you needed
        a plane ? Possibly using the surrounding 3 polygon faces
        which share the vertex).


#T2:Pointless Shading ?

          One way I have thought about how to do shading is to find
        the distance from each light-source (X,Y,Z) to each vertex
        (X,Y,Z) this would mean a N sided polygon would have N
        shading parameters (one for each vertex). Then as the polygon
        is drawn the shading parameter is interpolated between them.

                    V1                            V2
                      oo
                      .                   ....
                       .            ......
                       .       .....             B
                        . .....
                        A

          In the above 2d diagram we have two vertices V1 and V2
        which define a line and we have two light-sources A and B.
        We could take the distance from A to each vertex V1 and V2
        and then do the same for light-source B. At the end we
        should have two lighting totals (one for each vertex).
        Now we can interpolate between them along the line to give
        a rough approximation to the light level at each pixel.

          Of course this is not absolutely correct, you should really
        perform the lighting/distance calculation PER PIXEL as it
        is possible to get overlapping regions in the middle of
        a line span where the lighting amount should peak before
        decreasing as it moves towards each end vertex. One way to
        handle this could be to detect if one vertex exceeds a
        light-source's illumination range (so at some point along
        the line it stops being lit by this light-source). This
        would mean you should really create a quasi-vertex on the
        line/plane and interpolate in two steps. If there is another
        light-source which partly illuminates the line/plane
        (again with one vertex within it's illumination range) then
        we would need to create yet another quasi-vertex and
        interpolate between it. As you can see this would make more
        and more work depending on how many partially light sections
        there are.

          Like most other things in this document I haven't tried this
        method yet so I can't comment on how good (or bad) it looks.
        The proper vector method would no doubt give a much better
        and more realistic results but I think this method (cheat)
        would be faster. But calculating the true distance between
        two 3d points requires 3 multiplies and 1 square-root which are
        too slow. So I suggest using the longest axis length this
        would remove the 3 multiplies and square-root and replace them
        with the following code:

                (Lx,Ly,Lz)      = light source co-ords.
                (Vx,Vy,VZ)      = Vertex co-ords

                X = ABS (Vx - Lx)
                Y = ABS (Vy - Ly)
                Z = ABS (Vz - Lz)

                D = X
                IF Y > D THEN D = Y
                IF Z > D THEN D = Z

        Now:
                D = longest absolute axis length.

          So if we have V number of vertices and L number of
        light-sources then we need to do V*L calculations.

GOOD NEWS:
          The advantage of this method is that you don't need to
        store the normal-vectors or do any of the multiplication and
        it also returns the distance. This distance can be used to
        simulate fog effects like horizon cut-off.

BAD NEWS:
          The lighting is NOT directional, it is kind of spherical.
        It does not take into account the direction of the light or the
        direction of the polygon (plane). It will even light vertices
        which should be hidden by other things because we are really
        lighting points (the vertices) rather than planes.
        It takes time to process L (light sources) times V (vertices).
        It does not handle multiple light-sources correctly where
        regions along a line/plane are lit by two or more overlapping
        illumination zones.


#T3:Regional Light-Sources

          Checking every light source against every vertex would be
        far too slow to be use-able so we need some way to speed it up.
        For a very large level with rooms, walls and doors only a
        few light-sources will be in range (supply enough light to
        reach the polygon's vertices). Also if you close a door then
        the light source behind it should be hidden or partially
        stopped so you could only see the light through the gap.

          What we need is some form of regional restriction to the
        light sources we check. Only the local and TRACEABLE lights
        should be used. When I say "traceable" I mean light-sources
        from which a direct line can be traced out to a vertex/face.
        This is not the same as visibility because a light behind
        your view-point can not be visible but will still lights
        the scene in front of you. Also lights around corners will
        still illuminate the walls around them. There is also the
        problem of shadowing when a light is on one side of a wall
        and so it can not illuminate the other side (unless it is
        a transparent wall in which case it is a window).

          On the face of it (lame pun) the problem seems very
        difficult and complex. We need to block out some lights and
        only consider those within a certain distance and at
        certain angles. Going back to the INLET rendering technique
        with it's convex volumes and transparent face links it does
        offer some solutions to these problems. For a start the
        regional part is mostly taken care of by the rendering method
        itself because we only follow inlets (doors, windows) that
        fall in our view-point's line-of-sight. So only the local
        regions in the environment parts are used and rendered.
        The light sources can be defined within each of these inlet
        volumes (the convex sub-rooms or sub-areas). Now if an
        inlet volume is rejected then so too can it's lighting
        and shading requirements on the accepted vertices. We could
        use the inlet links (the window or door faces) to halt
        all light source which are external to the current volume.
        (i.e.. if we close the door then the light-source beyond the
        door is rejected and ignored). This effectively allows
        curtain like effects to be done. A door or wall could open
        and illuminate a darken room or visa versa.
          But there is a problem with this rendering-rejection. Just
        because a neighbouring inlet room volume can not be seen
        from the current view-point does not mean it's light-sources
        should be ignored.

                e.g.
                     ______________________
                    /    \                |
                   /      \X    room 2    |
                  / room 3 \______________|
                           /              \
                     L    /   room 1   ^   \
                         /                 \
                                  view point

          In the above diagram we have 3 rooms, we are standing in
        room 1 and looking into room 2 through an inlet-link.
        We would reject room 3 because inlet-link 'X' is considered
        invisible and so is ignored. But suppose that there is a
        light-source 'L' it would illuminate part of room 2 through
        the inlet-link 'X'. As we have rejected room 2 the 'L'
        light-source would also be rejected which is wrong.
        Now if we turn our view-point so that inlet-link 'X' becomes
        visible then suddenly the light-source would be used.
        Even though the light-source has not moved or changed in
        brightness it has suddenly switched on.
          So we need to follow rooms that are INVISIBLE but have
        light-sources which are TRACEABLE. The traceablity of a
        light-source in this inlet method would need to take into
        account any closed inlets such as closed doors or blackened
        windows or wall etc..
          A neat bonus with using the inlet method is that we know
        where local light shines through (the inlets themselves) and
        could dim any light passing through them to create smoked glass
        or a LCD like fade effects.


#T4:Last Orders ?

          One of the most obvious ways to perform shading is to process
        an entire polygon at a time for each polygon in the scene. But
        we only need to calculate the shading parameters for polygons
        which are visible AND only those which are not entirely clipped.
        So a typical renderer would do the shading/lighting stage as
        one of the final stages in the rendering pipe-line. We take
        the output of the back-face culling and polygon clipper and
        use these items to perform the lighting effects on. This
        should help minimise the amount of work which the shading
        algorithms have to do.
          If we work out the shading on a vertex basis then this
        post-visibility and post-clip method should work okay. We
        could calculate the lighting amount for the clipped vertex
        points OR for the unclipped vertices and then clip these
        lighting amounts as we clip the polygon. So the decision is
        whether to light to pre-clipped vertices (this would allow
        up to three polygons to share the same value) or to use the
        post-clipped vertices. I think the first option would work
        out faster as most of a scene tends to contain far more
        unclipped vertices than clipped ones, especially if fairly
        small polygons are used to build up the scene.


#T5:Here's One I lit earlier

          But all this real-time lighting calculation takes time
        and no matter how fast the algorithm is that performs it
        it will still take a fair amount of time. So we do what all
        good video-games do, we CHEAT !! Rather than start of with
        a list of fully illuminated polygons, a list of light-sources
        and process them all, we can pre-calculate as much of the
        static lighting as possible at the level-editor stage. This
        would give us far less to do when rendering. We examine the
        shading values stored with each vertex and interpolate
        between them as we fill each polygon. This does mean a little
        more storage (perhaps one number per vertex) but it also
        means a lot less processing.
          So we are left with the task of shading each polygon pixel
        as we scan-convert it onto the screen bitmap. This often
        requires a pixel look-up to shade a pixel and a few ADD's.
        But even here there is another cheat, and perhaps one of the
        most lazy :) After playing the MDK demo a couple of times I
        get the feeling of NO-SHADING on the polygons which make up
        the levels and creatures. I could be wrong but they don't
        seem to change their lighting level even when firing your
        2d-bitmap gun sprite point-blank at a wall (go on, try it).
        This would explain why the game run fairly smoothly at a
        high resolution (even though it has a large blank border to
        further reduce the amount of CPU workload).
          Games like QUAKE, QUAKE2 and (I think) UNREAL all handle
        lighting in various ways. Firstly there is the static
        shading which is probably done in the level-editor. Secondly
        there is the impact lighting where a flickering torch burns
        on a wall lighting up the surrounding area. And thirdly we have
        the dynamic, travelling lights (blaster trails which
        illuminate the surrounding corridor as they move).
        Actually the second and third cases are the same, except one
        moves. They both illuminate a very local area around them.
        This is a good strategy because most of the lighting and
        fancy shading can be done by the level-editor removing most
        of the CPU workload from the game engine. I hazard a guess
        that they use the vertex parameter method I previously
        mentioned and interpolate the light level across each polygon
        as they are drawn. When a 'dynamic' light source is needed
        we can just modify these vertex-levels for a short amount
        of time until the rocket explodes or the burning torch dies
        out etc... and then their normal level returns.


#T6:Multiple Light-Sources

          This is a 'simple' case of summing up all the light
        which falls on a vertex or polygon. We take each of the
        light-sources and add it's lighting contribution to it's
        target subject. Possibly even doing three of these totals
        for the R,G and B lighting (this could be how UNREAL does it
        but having not seen the game running I can't guess too much =)
          Having more than one light-source which can fall on a
        vertex or polygon does mean extra work but it doesn't have to
        be done every render-cycle. Take the example of a room with
        two light-bulbs in which both illuminate the same wall.
        All the correct lighting amounts could be pre-calculated
        by the level-editor and each vertex assigned a lighting total.
        This total is interpolated across the polygon to give an okay
        approximation. But this means the lighting is static.
        Suppose we wanted to turn off one of the light bulbs then we
        would need to recalculate everything again wouldn't we ?
        And what about blinking lights or pulsating laser beams
        or some other flashy effect ?


#T7:Static Kinship Lighting Tables

          As we don't mind a little more data to store and have
        plenty of RAM to spare especially when you consider most
        PC's have 16 meg or more then instead of calculating the
        distance of vertices from each light source and all other
        problems connected with it, we can build relationship tables
        for each vertex and their shared light-sources. We know
        that each vertex (or polygon) can only be illuminated by
        a certain (and hopefully small) number of light-sources
        and we know that the distances between light and vertex
        will remain constant (remember this is STATIC lighting).
        For each vertex we need to sum up the total amount of
        light which it receives, also these light-sources can
        vary the amount of light that they emit (we can turn them
        on/off or fade them in a groovy way). These variable
        brightness and static lighting effects can be performed with
        little more than a few lookups and a series of adds.
          For each light-source we can define a simple table where
        one entry describes it's brightness level.
        For R,G,B lighting (with a separate level for the red, green
        and blue components) it would require three such entries.
        We can assign a unique token value to each of these
        light-source definition or "lamps", this way we can specify
        which lamp (or lamps) affect a particular vertex or polygon.
        The lamp-token is nothing more than a straight forward index
        or address-pointer. It is used to allow many target vertices
        to all share the same lamp (light-source definition).
        Suppose we have six vertices and one lamp:

                e.g.     B_____________C
                         /             \
                        /               \
                       /                 \
                    A /                   \D
                      \             L     |
                       \           .      |
                        \_________________|
                        F                  E

          In the above diagram we have a six sided shape with six
        vertices (A...F) and a single light-source 'L'.
        Examining just one vertex we need to indicate what
        illumination it receives. This can be done with a "lamp-token"
        list. It just describes which light-sources affects a
        particular vertex. There would be a separate lamp-token list
        for each vertex. In the above diagram this means six lists.

PLEASE NOTE:
          I said "which light-sources affects a particular vertex"
        this means that for each vertex we only list the lamp-tokens
        that can affect it. We only include a lamp-token in the list
        if any light from the source can possibly strike the vertex
        otherwise we do not because either the light is hidden by
        some obstruction or is too far away.

          The 'KIN' table is basically a table of lamp-token lists
        of varying lengths (depending on how many light-sources
        are traceable to each vertex). Each list element is made up
        from just 2 parameters, one is the lamp token this represents
        which light-source should be used and can be implemented
        as either an address pointer or look-up index. The other
        is the strength of the light-source which can be used
        to calculate the amount of illumination which manages
        to arrive at the vertex (due to atmospheric dust, fog
        and so on...). It is also a good idea to have a count or
        a special list terminator code so we can tell when we
        have reached the end of each lamp-token list.
          To put it simply, we have a list of lamp-tokens and
        strengths for each vertex. The strength modifies the lamp's
        brightness level for distance (fog etc..). It is really
        just a scaling amount used to divide the brightness.
        If lamp L had a range of 100 then a "KIN" table could
        look like this:

                e.g.                        KIN table
                         Vertex      Count    Lamp    Strength
                               
                           A            1       L       57%
                           B            1       L       50%
                           C            1       L       57%
                           D            1       L       73%
                           E            1       L       78%
                           F            1       L       68%

          Where each 'Strength' value is calculated from the lamp's
        reach and the vertex's distance from the lamp. I didn't
        use a distance field because doing it this way removes
        some calculation which is important when you consider that
        this needs to be done for every vertex. As vertices are
        defined further and further away from the light, so their
        strength decreases until it is zero. Once it is zero it is
        deemed to be out of range and does NOT contribute anything
        to the vertex and so is NOT entered in a KIN table's list
        and does not appear in the vertex's lamp-token list.
        A level-editor would need to store each light's range
        and work out this strength factor when a level is saved, but
        a game engine would probably only need the strength values.

        The 'lamp' table could look something like this:

                 Lamp            Brightness
                         
                   L               100%

        and for R,G,B lighting like this:

                                     Brightness
                 Lamp           RED     GREEN   BLUE
                         
                   L            100%    100%      0%

          The above lamp definition would describe a yellow light.

          Defining the light-sources using this tokenised method
        means that we can control an entire room's (or even entire
        level's) lighting just by modifying it's brightness in the
        lamp table definition. By changing a value up and down we
        could produce some pulsating or flashing lighting effects.

          The reason why a "Strength" parameter was included in the
        KIN table is because it allows us to scale a lamp's
        brightness for distance more quickly, rather than having
        to calculate the distance from the light-source every time.
        As the light-sources do not move and neither do the vertices
        it's distance value does not change so can be pre-calculated
        by either the level-editor or the loader. I think the best
        option is in the level-editor as this allows weird effects
        to be designed into levels to make 'em more interesting.

          Now let's suppose we added two more lights to our six-sided
        shape (labelled J and K) and both these emit very little
        light (candles for example). So vertices close to them
        would be illuminated but more distant ones would not because
        their illumination range has been exceeded.

                e.g.     B_____________C
                         /             \
                        /               \
                       /  J              \
                    A /  .                \D
                      \             L   K |
                       \           .   .  |
                        \_________________|
                        F                  E

          Now the KIN table could look something like this:

        e.g.                               KIN table
                 Vertex      Count    Lamp Strength    Lamp Strength
                         
                   A            2       L     57%       J     50%
                   B            1       L     50%
                   C            1       L     57%
                   D            2       L     73%       K     30%
                   E            2       L     78%       K     60%
                   F            1       L     68%

          Because our two very dim light-sources (J and K) only emit
        a very small amount of light they can only illuminate close
        vertices (in the above example A,D and E) so only these
        are within their very short range and will recieve any light.


#T8:Problems

          In the last example three vertices received the light from
        two lamps and the other three from only one lamp. After
        totalling up all the different illumination amounts from
        the lamps it is possible that the maximum lighting limit
        is exceeded (when many lamps are at full brightness and
        very close or have a vast range). So perhaps an upper-limit
        check is needed on the illumination total before it is used
        or the "Strength" field could be fudged to prevent this.
          Another problem is that even with using look-up tables
        this totalling up for each vertex can take time. Remember
        that we might have a list of lamps for each vertex not just
        one to look-up. The more lights which can strike a vertex
        the more work will be involved. My advice is to restrict
        the range and number of light-sources to a reasonable
        amount and don't allow a mile away light to illuminate
        hundreds of vertices.


#T9:Here comes the sun..

          On the subject of vastly distant light sources it is
        possible to create a moving sun effect with a little
        pre-planning. Having a stationary sun is boring, one which
        drifts around a scene is far more interesting (and something
        which I haven't witnessed in any game engine YET !).
        The problem is that we want to sun to move or at least give
        the impression of movement across the sky and this means
        we can't use our previous static lighting techniques.
        (Doesn't it ?) If the sun moved then ALL the vertex distances
        would need to be calculated and so too would the amount
        of illumination striking them.
          Now what is movement in terms of computer animation ?
        Just a series of frames used one after the other to give
        the illusion of  movement. If you think of these frames as
        being static images then the following cheat should soon
        spring to mind.
          We can define a series of infinity distant light sources
        which are placed in a semi-elliptical manner around the
        scene just like how the sun would arc across the sky.
        You can think of this string of lamps as being snap-shots
        of the sun at various intervals throughout the day.
        Now to give the sun the appearance of movement we just
        switch one light off and the next one on to give a chasing
        lights effect and yippee !! we have a moving sun using static
        lamps. All we have to do is build the correct lamp-token
        list for each vertex which the sun can possibly strike
        in the same manner as all the other light-sources.
        Then to move the sun we just modify the brightness of
        these orbiting lamps to give the impression of movement.
        We don't have to use a great number of lamps to define
        the arc we can fade one light out and the other one in to
        give the illusion of a smooth transition. i.e. for a light
        source between two lamps you could make each one 50%
        bright, easy eh ?


#T10:Delta Illumination

          Unless you are planning to create a Disco level creator
        with every single light-source flashing in a funky way then
        a vast amount of vertices will receive a near constant
        amount of light because the light-sources remain steady.
        And even with blinking lights or ones which can be switched
        on or off these will not change state very often. So a delta
        method can be employed. Keep the lighting total for each
        vertex and only ever recalculate the total if any of the
        lamp's brightnesss change. One way would be to include a
        flag in the lamp table to indicate when it's brightness has
        changed, but this would still mean testing every lamp in
        each vertex list so it would probably be faster to just
        perform the totalling in the first place.
          Another way could be to modify each vertex total whenever
        a brightness changed (if it turns off then subtract the
        amount and if it turns on then add the amount). This would
        require additional storage to record the list of vertices
        which each lamp affects. And it means that every time a
        light's brightness changes we need to modify all the
        vertex totals.


#T11:Texture Light mapping

          The normal way to shade a polygon (textured or solid
        colour) is to interpolate between 2,3 or 4 values across
        it's surface to quickly calculate the shading/lighting
        amount for each pixel. Depending on the amount of work
        the interpolation take up this is usually the quickest
        (and most CPU friendly) way to fill shaded polygons.
          Another way which I originally looked at when writing
        my very first texture mapping routines is a pixel based
        shading technique which I believe is called "Light mapping"
        (I could be wrong). The basic idea behind it is to use
        another bitmap (2d array) for the lighting level at each
        pixel position. In many respects it is identical to
        texture mapping except each pixel/element is used as a
        shading/brightness level rather than a screen pixel.

          A normal texture-mapper would plot a pixel like this:

                e.g.
                        pixel = bitmap[u,v]
                        plot (x,y), pixel

          But this would just plot pixel from our source bitmap
        on the screen. The simplest form of shading would take
        each pixel and use a look-up table to find the correct
        shaded pixel.

                e.g.
                        pixel = bitmap[u,v]
                        plot (x,y), shadingtable[shade, pixel]

          If a light-map array has the same dimension as a the
        source bitmap then we use each element in the light-map
        to be our shading index value.

                e.g.
                        pixel = bitmap[u,v]
                        shade = lightmap[u,v]
                        plot (x,y), shadingtable[shade, pixel]

          The above code can be performed in about 5 instructions.
        Of course you still need to step the (u,v) and (x,y) co-ords
        for the correct texture mapping.


#T12:2d screen filters

          I'm not sure how useful or worthwhile this method could be
        but I'll describe it anyway because it might inspire something....

          There is another way which 'might' be useful when drawing
        shaded polygons and other lighting effects (lens flaring and
        other dazzling stuff). Instead of shading each pixel as we
        draw it on a 2d bitmap, why not build two 2d bitmaps with one
        for the pixel and one for the shade. So we are drawing the
        shade as if they were real pixels except in a separate buffer.
        Now we can shade the entire screen bitmap against the entire
        shade bitmap in a single loop or two.

          e.g.
                for y = 0 to screenheight-1
                        for x = 0 to screenwidth-1
                                pixel = screenmap[x,y]
                                shade = shademap[x,y]
                                plot (x,y), shadingtable[shade, pixel]
                        next x
                next y

          What is the point of this method ? Surely it would cache
        into the CPU more badly than a normal shade-as-you-plot
        technique. Well, yes. It also requires more storage, an extra
        memory write and an extra memory read, so doesn't look good.
        But this method does allow some post-filling shade tricks to
        be performed on the shade-map array such as lens flaring, fog,
        rain or edge-fade outs near the screen edges.

          Personally I feel that this method does not really justify
        the amount of extra CPU work for the few extra effects which
        it gives. Most of these effects can be achieved using some
        2d-sprite techniques afterwards. In the case of lens-flaring
        a "shaded-bob" sprite can be blasted onto the screen far
        more quickly than writing-then-reading the entire shade-map
        array in memory.


#############################################################################
Ŀ
 #U:                           Distant Horizons                            

#############################################################################

          Like most programming tasks drawing an exterior landscape
        or an interior environment is a problem of finding a balance
        between detail and speed. This is much more so when dealing
        with 3-d objects and realistic looking terrain. It's a simple
        matter of the more items you render, the more processing time
        you need. Because almost every 3-d scene is drawn on a flat 2-d
        bitmap which only has a very small, finite number of pixels
        it means items beyond a certain distance will be reduced to
        a single or less. This problem is normally handled by applying
        a form of clipping which discards things beyond a certain
        range. But this can cause the odd 'pop-up' or 'fade-in' object to
        appear out of thin air. This is where parts of the scenery, items
        or creatures appear from no where. Take a look at Terminator:
        Future Shock or Skynet to see what I mean. Sometimes laser bullets
        suddenly appear without warning because the gun turret or HK is
        beyond the Z-clipping threshold. It seems that ALL objects and
        explosion beyond a pre-set range are held in limbo until the player
        comes into range.
          To help hide the pop-up problem many games use fade-in techniques
        to slowly introduce items to the player rather than surprise
        them with the suddenly appearance of something. The old classic DOOM
        used a distance Z based fade-in method so that the horizon cut-off
        point is disguised. It also helps the player judge distances in
        a far more effective way. The technique of fading items to black
        as they move into the distance is called "Black Fog" and behaves
        in a similar way to mist or fog. In Hexen on some levels they used
        "White Fog" to give the impression of mist, but the ideal is the
        same. And flight simulators used blue or grey as their horizon
        colours just like the way the real atmosphere appears.
          The main dilemma for programmers is where to draw the horizon
        cut-off point. Place it too far away and the game engine crawls
        to a sluggish pace, but place it too near and the game might race
        along but the object pop-up makes it too difficult to play.


#U1:International Interpolation

          By far one of THE most useful techniques for programmers is
        interpolation. It's a fairly recent phrase and most coders have
        been using it for years before they knew what it was called.
        The idea is simple, take two pieces of data (two known values)
        and then interpolate between them to calculate the value at ANY
        point in the interval. One of the easiest to understand examples of
        this is linear-interpolation used for drawing lines or calculating
        the intersection of a line against a screen edge.
          The 'voxel landscape' technique uses interpolation to smooth
        between the 'voxels' (the corner vertices of the map grid).
        Polygon drawing routines also use this method to scan-convert
        each side using linear-interpolation between 2 corner vertices.
        You don't have to used a straight-line 'linear' method you
        can use curves, splines and the like, but of course the more
        complex the interpolation the slower it will be.
          One of the many good advantages to interpolation is the fact
        that with a minute number of data values it is possible to create
        an infinite number of values simply by interpolating more
        between the data points. This is great from a CPU point of view
        as only a very, very few memory reads are required and then the
        CPU can generate the pseudo-data using an algorithm. It is also
        good from a storage view because only the limits and possibly
        a parameter or two is required to describe a curve or line.


#U2:MIP-Terrain-Maps

          Again this technique can be thought of in term of our
        old friend the 'hierarchical data structure'. The C.A.N.
        method (Coarse Area Nets) could be described as a collection
        of root cells and the covered map cells it's siblings.
        This 'might' be a good way to render landscapes or other
        such environments which need a very distant horizon cut off.
        The terrain map could use very coarse cells for the distant
        mountain range that is miles from your view-point and smaller,
        fine detail cells for closer items.
        This way all the items reduced to a single pixel or less could
        be filtered out in favour of large, more important structures.
        The renderer would need to adjust it's working map scale as
        the landscape is drawn. You can think of this as a kind of
        terrain MIP-Mapping, possibly using multiple maps or data trees.
          But there are problems with this method; storage space and
        the extra processing needed to select the appropriate map for
        the current scale. If the rendering of the landscape occurs in
        a predictable way (e.g. view-point --> horizon) then the
        selection process for the correct scale might be reduced to
        using a counter or even reduced to pre-processed/hard coded
        instructions or data tables.


#U3:Realtime Creation

          If the horizon is extended to a more realistic distant from
        the view point then the scenery rendering must be even more
        efficient than it would normally need to be. The great increase
        in workload is mainly due to the larger number of items
        (hills, rocks, creatures, trees etc..) which need to be handled.
        Every exterior landscape I have seen tended to look very barren
        with a few trees here and there to break up the wide open spaces.
        This is because exterior items are not very geometric looking
        like the inside of buildings are. Trees have transparent gaps
        between leaves and branches, also their silhouettes have a very
        random, irregular shape to them. This means drawing trees, bushes
        and hedges often requires a pixel-based sprite routine to
        overlay them onto the background.
          To create a very dense forest would require a vast number of
        trees to cover just a small area of ground. On top of the task of
        drawing these mis-shaped objects is the task of rotating and
        projecting (not to mention sorting) them. If the extra storage
        is not a problem, then the extra processing is.
          One idea could be to generate parts of the scenery as it is
        being rendered based on distance and terrain type. For example a
        distant hill might require a few 'forest' bitmap sprites to
        give the impression of a far away, dense wood, but a close up
        forest might need to have a few hundred trees and randomly placed
        rocks on the forest floor. So given a starting cell, terrain type
        and level of detail it should be feasible to create a highly
        complex looking environment using interpolation for the floor
        with a pseudo-random number generator to drop plants/trees every
        Nth pixel or so on...


#U4:Volume Blinds

          I have already highlighted a problem with rendering exterior
        scenery when I mentioned the forest example. The main bottleneck
        is the overlaying of all those trees, bushes and hedges over
        the background. With the background (grass, water, rock etc..)
        it is possible to use a S-BUFFER (span buffer) technique to
        avoid overdrawing pixels or polygons, but there is no quick
        way to speed up overlaying multiple layers of sprites. Each layer
        must be drawn and then possibly overdrawn by closer layers.
        This is also the case when drawing those five-mile-away items
        which are reduced to a few pixels. At this point most of the
        very small items would be immediately rejected. This would help
        reduce the number of items that need to be processed but the
        forest would slowly become less and less dense as entire trees
        were reject in order to reduce their number.

          An idea that I have had, it is to cheat when drawing items
        like trees, hedges, bushes and other such sprite-like objects.
        If the landscape items themselves are reduced to a pixel or less
        in size then so are the transparent gaps between leaves. Also
        once objects are beyond a certain distance the parts of the
        background which could be seen through the gaps become more
        difficult to see, so could be anything.

          As a solid sprite/texture is much faster to draw than a
        partly transparent one with holes in it, then why not ignore the
        gaps beyond a certain distance. This way a tree would become a
        solid looking polygon and it's silhouette used to mask out any
        background pixels. It's similar to making a glass window opaque
        beyond a certain range stopping the interior scene inside from
        being seen. In the example of a dense forest an entire block of
        many trees can be quickly replaced with a solid cube covered in
        a forest-like texture. To help disguise the straight edges of
        the opaque cube volume you could draw narrow leaf sprites along
        the edges.

          This feather-edging could be used to simulate long grass,
        water or any other type of terrain which doesn't have a solid
        edge to it. We have used a mostly solid polygon with a fluffy
        surround to fool the player into believing that a complex, multi-
        layer scene has been rendered.

          In affect we have pulled down the blinds on a complex, distant
        scene with multiple layers of objects to make it into a far
        simpler, opaque 3-d model like a cube. But by ignoring the
        transparent parts of an object we hide everything behind it
        which could be bad if it is an enemy solider or tank. But then
        again if something nasty is IN the forest then it would appear
        darker and camouflaged by the trees and branches.


#U5:Flat Arial Maps

          Rather than actually draw individual trees, rocks and proper
        3-d buildings there is another technique which is favoured by
        flight-sim programmers. In these games/simulations the need for
        a very distant horizon is extremely important far more than
        true detail. The cheat is very simple and FAST !!!, use some
        Arial photograph-like textures to draw the scenery. This way we
        have a semi-nice looking landscape for screen shots with
        thousands of highly detailed objects on the ground.

        "Wow ! You can even seen the road markings on the streets !"

        So basically all the complex, processor hungry tasks of rendering
        thousands of buildings, trees, grass, river and static items
        can be replaced with a pre-drawn 2d bitmap. Take a look at
        Flight Unlimited and other flight-sims to see what I mean.
          This does mean those FLAT items on the ground are not true
        3-d and have no parallax or changeable view point. Also these
        Arial bitmaps are usually large in size compared to normal
        32x32 or 64x64 pixel bitmaps. This means they chew up a lot
        more memory and probably will cache very badly into the CPU but
        as a huge area is being filled (perhaps only a dozen or less
        polygons for the entire screen) then processor time is saved
        from elsewhere, i.e.. from not having to render hundreds of
        small structures.
          The huge saving in processing time makes this attractive
        to us speed-freaks. Combined with MIP-Mapping and other such
        distance based techniques this is good way to boost performance
        without all the hard work =)  I suggest using these Arial maps
        for the most distant, near-horizon parts of the scenery where
        most 3-d models would just be pixels or blobs. Or possibly for
        the ground behind trees to create the impression of a dense
        forest.


#U6:Sprites & Crosses

          I can't believe I got this far without describing this method.
        Anyone who has played Wolfenstein, Doom, Heretic, System Shock
        etc... etc... will know this method. Basically instead of a
        true 3-d model a flat 2-d bitmap sprite is drawn. The item is
        usually pre-drawn in 8 or more directions and the one closest
        to the desired direction is chosen and scaled onto the screen.
        Usually the 2-d sprite is scaled using the Z-distance from the
        view point and remains parallel to the view-plane. This does
        mean that items sometimes skate along and always face towards
        you even though you may be looking down on them.
          This is a quick method for rendering complex models without
        the need for back-face culling, polygon scan-converting,
        texture mapping or shading as all these can be done when the
        item is pre-drawn by a graphics artist. But the amount of
        memory needed for all the animation frames for each direction
        can quickly add up into many megs. My own opinion on using
        2-d sprites is that they should only be used for non-descript
        items or garnish effects like explosions, rocks, sea splashes
        and so on.
          Even some of the military flight simulators use this flat
        2-d sprite technique for trees and explosions, but instead of
        using a single bitmap always parallel to the view-plane they
        use two or more intersecting sprites to form a cross or star
        shaped structure. This does give a much greater sense of
        realism because they can be rotated and scaled just like other
        textured polygons. Unfortunately you can still see how these
        items are constructed.


#U7:Mips & Bits

        It is nice to have a distant horizon so  more of the background
        can be seen, this gives the player more time to react to oncoming
        hazards such as enemy tanks, cliffs or incoming missiles etc..
        But the problem of simply pushing the horizon cut-off point is
        much more widespread than a large increase in visible terrain and
        number of items to be processed. There is the ugly problem of
        flashing pixels caused by the linear scaling of bitmaps. This is
        where small details are skipped, then shown as the item's scale
        changes. Techniques such as MIP-mapping can be useful to reduce
        this flashing pixel problem. As models and parts of the terrain
        move into the distance they become much smaller and so more and
        more pixels are skipped over to approximate the new perspective
        size. With MIP-mapping a smaller 'averaged' bitmap is chosen
        instead of scaling a large one down. This is good in some ways:

        1) the CPU is reading a smaller bitmap, so it will cache much
           better as a smaller number of pixels (bytes) need to be used.
           And more importantly far less pixels are skipped, the CPU
           cache is VERY, VERY bad at reading randomly accessed fragments
           of memory it perhaps sequential blocks.

        2) the horrid flashing artefacts are reduced because pixels are
           pre-combined instead of using a single pixel every Nth one.

        3) the averaging actually increases realism because you can think
           of it as a form of blurring or de-focusing just like real
           photography.

        But the bad points are:

        1) more memory is needed to store the extra MIP bitmaps

        2) more processing is required to select the correct MIP bitmap

        3) some detail is lost due to the pixel averaging.

          All this MIP-mapping is fine for solid bitmap textures but
        what about overlaid textures like fences, grills, bars ? How can
        you average a transparent pixel with a opaque one ? Should it
        be forced to transparent or opaque ?

          The other problem with fence like textures is the old one of
        flashing artefacts when it is scaled. This is where parts of the
        fence either turn solid (because the transparent pixels are skipped)
        or they turn transparent so big holes appear. So one moment a
        fence is normal then as it moves away it might become solid and
        then totally transparent at a certain distance.

          Here are a few ideas to help disguise this problem:

        1) Don't use very fine fence or grill textures, instead use a
           much larger giant bar-code method.
                i.e.. use a wood fence instead of a fine wire mesh fence.

        2) use custom CPU routines to draw the fences. This would be faster
           than allowing a general bitmap to be overlaid as the transparent
           pixels are not encoded into instructions, but the flexibility
           is lost.

        3) instead of drawing the background and then the fence, try simply
           shading the background to 50% or 25% normal brightness.
           This is easy to do using the INLET rendering method, just set
           the master brightness level to 50% or scale the shading values
           before drawing the polygon.

        4) don't allow transparent textures. I know it's very lame, but
           it would help speed things up quite a bit.

        5) ignore the transparent gaps in the textures when they go
           beyond a certain distance. This could mean trees and bushes
           becoming solid polygons thereby hiding part of the background.


#U8:Squashed Horizons

          Most (i.e.. all) 3-d engines use a Cartesian based co-ordinate
        system to define objects and Earth-like terrain. This means that
        the origin surface is defined as a flat, infinite plane usually
        Y=0 (or Z=0 depending on your X,Y,Z system). But the Earth is almost
        a sphere so in fact spherical co-ordinates should really be used.
        This would make wrap-around navigation of the planet/world
        very simple but is much more difficult than a flat, plane based
        Cartesian system to implement translations.

          Thinking of the Earth as a solid sphere means it has the
        following characteristics:

        1) The finite surface wraps around.

        2) There is no edge to the surface.

        3) It is impossible to see the entire surface in one go.

        4) Objects located on this spherical surface will appear to
           rotate over the horizon and disappear.

          Using a flat plane based map does means movement, gravity,
        distance and line-of-sight calculations are much simpler because
        a straight line can be used instead of working out the path
        across a sphere. But it does cause a few problems:

        1) The surface does not wrap, it should be infinite but
           there is usually a memory or co-ordinate limit.

        2) There is an edge, due to the range of the co-ordinates used.
           Again this is usually determined by memory space.

        3) From certain locations all of the objects CAN be seen
           (i.e.. standing at one edge and looking across the map).

        4) All objects appear to travel in a straight line and do not
           rotate like on a sphere, they only change in size.

          The wrap-around problem can be easily done using either a
        limit check or using a power of 2 for the world size with a
        logical AND operation to produce the same wrap effect quickly.
        A lot of games programmers and designers use a restrictive
        form of map where impassable obstacles are placed around the
        play-area to stop the player wondering off into the sun set or
        worse wondering through memory and possibly crashing.
        Mountains are the favourite form of this 'feature' used in
        games like Jedi Knight and Terminator Future shock. Others use
        giant walls or sides of buildings to stop people escaping.
        The problem with this method is that it sort of defeats one of
        the main advantages of 3-d games; freedom of movement.
        This is a reason why so many inside building environments have
        been used instead of exterior, go-anywhere ones. Also because
        buildings and even huge complexes are much smaller than an entire
        world they are usually quicker to render with plenty of dead-end
        walls to prevent the whole level from being seen in one go.

          From the flight-simulators I have seen they appear to use
        4 or more tricks to help disguise the plane based world which
        they use for terrain and buildings.

        1) use 'magic horizon' objects.
           This is where objects and terrain suddenly appear from
           thin air.

        2) use black-fog or white-mist.
           Objects and terrain are faded into the background/horizon
           colour which is usually black, white or sky blue.
           DOOM used black-fog and HEXEN used white on certain levels
           to give the impression of mist.

        3) use a 'cut-off' or black curtain.
           This is like the black-fog method except NO fading is done.
           Items are simply clipped to a horizon-plane parallel to the
           view-plane. Terminator Future Shock does this badly !!
           It means parts of items are cut off parallel to the screen.

        4) use 'horizon squashing'.
           Usually the Y axis co-ordinates are scaled down and the object
           is pushed down below the horizon. This gives a fake impression
           of a true horizon where objects look like they have fallen
           off the edge of the world. This squashing of a single axis
           makes it look like objects or the landscape are rotating away
           from the view-point due to the curvature of the Earth.
           It would be more correct to rotate them down below the ground
           level.

          The 'squashing' trick can be done faster than a proper
        rotation and usually the matrix or the perspective calculation
        can be fudged to perform this single axis scaling. I haven't
        tried this trick yet, but I reckon because the object/terrain
        will be far away (so very small) most players won't be able to
        tell the difference, unless structure are very, very tall.


#U9:Moving the Earth

          As far as I know NO 3-d engines have ever used spherical
        co-ordinates for their world maps. I believe some use polar or
        spherical based co-ordinates for objects, but not for the terrain
        itself. As the Earth is such a large sphere (about 12800 Km dia)
        it appears to be flat at very close range. Even at 20,000 feet
        the ground still looks very flat, but in truth it is not.
        A late friend of mine pointed out one problem with using a
        flat plane for the ground; that of corners. He created a demo
        sometime in 1990/1991 where a large rectangle was used as the
        ground, then moved over it and then rotated his view angle.
        Sensible enough eh ? But of course at certain angles the
        corners of the ground rectangle could be seen. At the time I
        hadn't thought about this much but now the solution is really
        quite simple. The ground DOES NOT move but the items on it DO.
        You don't really need to define a rectangle you can use a
        a straight line across the screen to represent the horizon.
        This horizon line only needs two Y co-ordinates to be calculated
        (one for each end) these are found from the altitude, angle
        to the ground and side-to-side tilt angle.


#U10:Silouettes

          This is a very simple and realistic effect which can be used
        to gain some extra speed when drawing the most distant items.
        When combined with the fade-into-the-background technique this
        can save plenty of valuable processor time. The method works like
        this, when a polygon exceeds a certain distance and the fading
        has begun the normal texture-mapping with shading is replaced
        with a flat, solid polygon filling routine. This means only the
        outline of an object is seen and not any of it's surface detail.


#U11:Field of Vision Slices

          With a distant horizon comes a huge amount of landscape
        data which must be processed and the further the horizon the
        greater the amount of data. If the landscape is divided into
        a grid with object links from each cell then this can help
        speed up some of the work. If the entire cell can be rejected
        (behind the view point or beyond our field-of-view (FOV) then
        so too can all of the objects in it. As you move away from the
        view point more and more of the landscape can be seen because
        the scale of each cell is getting smaller (it's further away).
        Even the most, basic simple test can take time when applied to
        each and every map cell. It would be nice to avoid having to
        do most of them if possible.

          I'm sure that most of you have seen roto-zoomers in demos
        before where the entire screen is filled with a bitmap which
        rotates around one point just like a steering wheel. The effect
        is very easy to code and could look like this:

                        Xstep = COS(angle)
                        Ystep = SIN(angle)

                FOR y = 0 to height-1
                        h = y * Ystep
                        v = y * Xstep

                        FOR x = 0 to width-1
                                plot (x,y),bitmap(h,v)
                                h = h + Xstep
                                v = v + Ystep
                        NEXT x

                NEXT y

          Basically it steps across the bitmap by incrementing the
        (h,v) co-ordinates using the Xstep and Ystep values. These
        are just the X and Y increments for the desired direction.

          Well this technique could be applied to a grid based
        landscape map with the view point being the centre of rotation
        (the origin) and each pixel being a single map cell. Starting
        at the view point a slice across the map parallel to the
        view plane (usually Z) could be scanned and each cell's objects
        could be drawn or placed in a depth buffer (for a back-to-front
        rendering). So we scan the map at right angles to our viewing
        direction. You should remember that each map slice will get
        longer with more cells needed at both ends as we move into the
        distance. The map is scanned in an isosceles triangle like way
        with the view point at the peak of the triangle and it's two
        equal sides marking out our field-of-vision.

          This method is good because we are only dealing with the
        visible parts of the map (possibly only a 90 degrees segment)
        and so those map cells behind the view point are never processed
        which saves a lot of time. There is another way in which the
        map slices can help rendering. Because we are only scanning
        map cells in our field-of-vision this makes them visible, so
        some of the clipping stages can be ignored. Possibly only the
        outer boundary cells will need to be checked and clipped. Those
        map cells between the ends of a slice can be drawn without too
        much work and that can't be bad news =)


#############################################################################
Ŀ
 #V:                           Tips And Tricks                             

#############################################################################

          In this section I will describe some short tricks
        which may help gain a few CLK-cycles here and there.

        1) re-used polygon edges & slopes
           just as a polyhedron can be made from reused vertices
           so can the edges (even clipped ones - keep the top and
           bottom clipping lengths and determine left or right
           polygon sides).

        2) to table or not to table ?
           It seems that 80x86 and all other new CPUs don't
           like accessing memory which is strange considering
           the pathetic number of registers most have. My advice
           is to keep tables to a reasonable length and
           "blitz" use them (do ALL the indexing into the table
           in one go so that CPU cache doesn't have to be
           refilled.) and for 2d tables (arrays) organise the
           most likely data horizontally so element (x+1,y)
           directly follows (x,y) as this way the CPU will cache
           this kind of data in more quickly.

        3) avoid reading the video card at all cost.
           Show me a video card which is as fast as the main CPU
           memory and I will stop complaining, until then send
           hate mail to IBM and all PC hardware developers ;)

        4) don't be fooled by conditional jumps, they are evil ):[
           I have heard about fancy new CPUs with branch-prediction
           stuff which can fail causing performance hic-cups.

        5) reuse the same texture to fill all the polygons before
           drawing a new one. This will help maximum the cache
           benefits, but this method is NOT really practical in
           most cases unless you only use 1 texture :(

        6) use a dithering method to help smooth out blocky
           texture fills so you can get away with small textures.
           Try MIP-MAPPING techniques (use smaller textures for
           very distant objects) this will cache in better because
           the CPU isn't skipping as many bytes to scale down the
           texture (wasting cache space).

        7) texture SOFTWARE caches 'could' be handy especially
           for 90, 180 or 270 texture scanning which the CPU
           really hates. (Don't believe the Intel 1 CLK memory
           timings they be lies..)

        8) use 'fog' or short corridors this will help reduce the
           amount of CPU workload that an infinite horizon would
           cause. In real life you never see an infinite horizon
           because (a) the Earth is curved so distant objects will
           appear to pop up (b) dust and other atmospheric stuff
           gets in the way.

        9) use 'horizon' maps. This is another one of my untested
           ideas. For each window or doorway define an 'horizon'
           texture bitmap token. Now at render time if the door
           or window is beyond a certain distance then simply fill
           it with the horizon bitmap instead of rendering the
           pixel high objects which should be seen three miles away.

        10) keep data accesses to a WORD or DWORD boundary.
            Mis-aligned data chews up valuable CPU ticks.

        11) restrict the view angles to 2 axiss.
            This removes a lot of multiples or you could use
            spherical or polar co-ordinates instead.

        12) use MIP-MAPPING (multiple copies of a texture at
            different sizes) or better still use surface detail
            links, so that mile away objects have the basic
            polygon shape and close up ones have bar-codes and
            other texture detail fancy bits.

        13) anti-aliasing - smooth out these blocky or stair
            case lines. This is best used for overlaying sprites
            (scores, ammo, weapons) so that chunky pixels don't
            appear to be that chunky.

        14) use dark environments. This means that most walls
            and surfaces can be ignored and drawn as a solid
            black polygon (sly eh ?)

        15) this is THE golden rule, never read from a disk or CD
            when in the middle of a level. It really sux when the
            game suddenly halts while the disk or CD spins up to
            speed - not only does this break the illusion of the
            game but thrown it to the ground and stamps on the
            pieces.

        16) Don't shade your polygons ! I think (I could be wrong)
            that MDK didn't perform any real-time shading in their
            texture-mapper, so this removes 1 instruction (1 memory
            access) PER-PIXEL. When dealing with SVGA video modes
            which begin at 640x480 (307,200 pixels) this saving can
            be VERY large indeed. Even Monster Trucks 2 don't bother
            with shading their polygons either, they used dithering.


#V1:Need more MHZ ?

          Texture mapping with shading can chew through even the
        fastest of today's CPU's. If we use a resolution of
        640x480 at a SLOW vertical frequency of 60 Hz then to perform
        a silky smooth engine we need to draw and shade 18,432,000
        pixels per second. A primitive texture mapper would need to
        do these operation:

                a) Fetch a pixel from the bitmap texture
                   (1 memory read)

                b) index the pixel using a shade look-up table
                   (1 memory read)

                c) write the pixel to the screen
                   (1 memory write)

          Not including the CPU instructions to perform the above
        code a total of 36,864,000 reads and 1,843,200 writes need to
        be done thats 55,296,000 memory accesses !! Remember this
        does NOT include all the other engine code, data processing
        and possible pixel overdraw or overlaid scores etc..
        Now shall we try a resolution of 1024x768 or higher ?
        Nah, thought not (heh heh).
          At the end of the day PC's are still extremely S-L-O-W
        on the video accessing side of things. Your super Pentium
        beast might be ticking on at 266 Mhz but the memory is
        probably only operating at 1/3rd of this speed (if you are
        lucky) but the video card is normally much slower because
        the CPU is fighting the video card to access the same
        memory. Thankfully this bottleneck is slowly, so very slowly
        being tackled with better video card developments, but it
        still is one of the worst things about the old PC (and I do
        mean old).


#V2:Crashing the Cache

          Almost every modern CPU uses burst reads and burst writes
        along with caches to grab small linear blocks of memory.
        This is good for linear data structures like lists, tables
        and programs as all these tend to be mostly sequential. But
        for things such as texture mapping and accessing 2d arrays
        (i.e.. bitmaps) it really sux. The main problem is that
        texture mapping often only needs a single byte from every
        Nth byte in memory whereas modern CPU like to read 16, 32 or
        more bytes at each address into it's cache.


#V3:Moral of the story

          If you can, CHEAT !! and cheat often as 99% of players
        don't really care if your texture-mapper using the
        mathematically correct formulas or a quick 'n' dirty
        approximation, so long as it runs smoothly and is playable
        then a lot of errors will be overlooked. Take a look at
        Jedi Knight or Tomb Raider, not exactly the perfect texture
        mappers are they ? Players will often overlook graphical
        cheats if the game remains playable.

#############################################################################
Ŀ
 #W:                     Gallons Into Pint Pots                            

#############################################################################

          If you absolutely need to keep reading the level because
        it won't all fit into memory in one go then try some of the
        following tips.

        a) blame your data structures, did you really need all
           those data fields and a dword for a single bit flag ?

        b) tokenise. Often this can actually help speed up certain
           tasks and applied to levels with lifts, doors and so on
           can allow the recycling of things without having to
           re-process all the states and logic. (e.g. blinking lights)

        c) design your levels so that lifts or transporters can be
           used to illustrate to the player why the game halts there.
           If the machine suddenly stop for a few seconds then players
           might think it has crashed and hits reset just as your
           games loads from their hard-drive... blammo....

        d) depending on the available memory at load time try:
           1) using a lower sample rate when sounds are loaded
           2) halve the resolution of your textures as you load 'em
           Both of these are really easy to implement and can boost
           performance on slower machines too !

        e) compression. This should be used with a large pinch of
           salt as the time taken to decompress may be slower than
           actually performing the load from disk.

        f) allow the user to install often loaded stuff onto their
           hard-drive from the CD. I know many new CD's are 32x
           speed or something silly, but they still tend to be much
           slower than a hard-drive. My CD drive IS faster but it
           spends a second or so spinning up to speed before data can
           be read - this is a real pain for lots of little transfers.

        g) don't have too many files open at once. Use a single file
           if possible instead of switching between many file handles.
           Group all the levels, graphics and other data into a few
           library files and simply seek within these rather than
           keep opening and closing files.

        h) remove disk caches ? These little memory chewers store up
           disk writes and then pounce a few seconds later. They
           can often be useful when reading (opening files, reading
           the directory or FAT tables) but for very large files the
           cache is mostly flushed which doesn't help much. In a lot
           of ways your program can cache more efficiently than DOS
           or Windows etc.. because YOU know the likely order in
           which the data will be accessed.

#############################################################################
Ŀ
  #Y:                  Terminology & Incorrect Phrases                     

#############################################################################

          Here is a brief list of 'jargon' words which I used in this
        document. Please forgive any errors in the naming of concepts,
        algorithms or terminology. I would say about 95% of the ideas
        and explanations in this file have been written without
        seeing any form of render descriptions, techniques or in-depth
        details about the described methods, so hopefully most of this
        stuff will be new, correct or easy to understand. Where ever
        possible I tried to avoid techno-babble or maths jargon but
        when I did use it to try and explain things in every day terms
        or real world things (trees, plants, planets, webs etc..)

LEVEL or MAP:

        This is the current region of the game world or universe
        which is current being played through by the player. This can
        be the inside of a building, an open air park or the bottom
        of the ocean. It's basically the environment currently being
        drawn and explored.

OBJECT or MODEL:

        I think the term model is the most correct one. It is one,
        single, self-contained 3d item such as a chair, door, building
        or creature which are used to furnish the 3d games environment.
        This name also applies to monsters/creatures.

LINEAR:

        Anything which is straight like a ruler, a continuous line
        with no curve or bend to it. I have used this to describe
        sequential processes or data structures as well. as they tend
        to happen in an A,B,C ... Z manner.
        This list method is almost always the best possible way
        for any CPU to process things.

LINKED-LIST:

        A very, very useful method to connect two separated regions
        of memory by using an address or 'pointer' to indicate
        where the next or previous region of memory is. Its like
        following a route by using road signs. Each sign points
        to the next stage in the journey. So a sign could be called
        a 'link' like that in a chain. It simply tells you where
        another item is located in memory.
        There are many different uses for linked-lists or "chains"
        as some people call them, these include circular lists,
        sorting, fast insertion or deletion and so on... and not
        forgetting binary, multi-way or ringed trees. The great
        advantages of using linked-lists or links is that items
        do NOT have to be stored in a sequential order, the last
        item can be located in memory before the first or separated
        by megabytes of memory.

        In this document I have used 3 distinct types of linked-lists
        these are:

(1-d) LINKED-LIST:

          These allow 1 axis of travel and are true lists. This name
        is used to describe 2-way linked-lists which are still only 1-d
        (i.e. you can traverse forwards or backwards, but still it's
        just ONE axis).
        They allow movement along a line in a linear, list-like way.

2-d LINKED-ARRAYS:

          These are the next step up from 1-d, they allow travel in
        2-dimensions (forwards, backwards AND left, right). They
        typically require 4 links for a node (2 for each axis).
        These allow movement along a rectangle in a 2d-map way.

3-d LINKED-WEBS:

          These have 3 axiss of travel and can be used to navigate
        through a 3-dimensional space. They normally need 6 links
        for each node (2 for each of the 3 axiss).
        These allow movement in a cube-like way, we can go up/down
        as well. as north, south, east and west.

RENDER:

        The process of drawing the graphical items which can be
        seen from a particular view-point and angle. It's just a fancy
        word for "drawing the scene".

RENDERER or ENGINE:

        This is the collection of code which draws all the graphics
        and performs things like back-face culling, clipping,
        shading and texture-mapping etc.. It can be thought of as a
        group of drawing routines or as a complex interactive graphics
        system or whatever....

TOKENS:

        This is a way to describe an item by giving it a number or
        code which can be used to identify it. Rather than redefining
        all of an item's data structure we can simply reuse it's
        token or code-number. I have used tokens in two ways, to save
        memory (avoiding having to repeat the same data again) and to
        direct separated items back to the same destination.

CREATURES, MONSTERS & BEINGS:

        These mean all the same thing, the non-player entities in a
        game. They move, kill and interactive with the player and
        background.

TEXTURES & BITMAPS:

        A texture is basically a rectangular bitmap which is used to
        fill a polygon with pixels or "texels" as people like to call
        'em these days (textured-pixels, I guess =).

TEXELS:

          This is an abbreviation of "textured-pixels" i.e.. a collection
        of pixels which are taken from a texture bitmap.

SURFACES &, FACES:

        Yep, they are almost identical. But a face is normally a single
        polygon used to built an object and a surface is all the
        connected polygon faces that are used to describe a solid object
        or landscape terrain (hills and valleys for example). I think
        some people call the surface of an object/model a "skin"
        because it is pulled over the vertex skeleton I guess.
                e.g.    a cube has 6 faces, but 1 surface or skin

        I have sometimes interchanged the words "face" and "polygon"
        at times, but they are used to mean the same thing.

SIDES:

        The term 'side' has been used to mean two things.
        1) a single, straight edge of a polygon (e.g. square = 4 sides)
        2) part of the object/model which can be seen (front/back side)

POLYGONS:

        I have only used convex polygons in ALL the examples as they
        are the fastest to draw and have special properties. Also
        I use non-skewed (plane) polygons where ALL of it's vertices
        lie on a flat plane.
PLANE:

        A flat, infinite surface without start or end. Like a mirror
        or the cover of a book it does not curve so no part of the
        plane can be hidden behind any other part of it. Also it
        can be tilted at any angle not just vertically or horizontally.

POLYHEDRA:

        This is a collection of flat 2d polygons which have been
        glued together to represent a 2d object or 'model' as I
        think it's correctly called. Examples of Polyhedra are
        cubes, boxes, pyramids.

VOLUMES:

        I have used this to mean the inside 3-d area within a
        Polyhedra of some kind (cube, pyramid, dodecahedron etc..)
        The volume of a cup is the interior area defined by the
        exterior faces. Also I have used this term to denote the
        interior space of a room, corridor or level. In this case
        the exterior space is totally ignored (null-space) because
        it can never been seen or ventured into.

HORIZON:

        A very distant point or boundary at which objects are not
        drawn any more as they are considered as being too far away
        and too small to be seen. In most cases this means Z-Clipping.

VIEW-PLANE or VIEW-SCREEN:

        This is the 2d area on your monitor on which 3d objects are
        drawn and filled. Anything behind this is considered hidden
        (because you can only see in one direction at a time).
        Between the view-plane and the horizon every part of the
        scene is considered and possibly drawn.

SCENE:

        This is part of the games environment (world/universe) which
        can be seen from the current view-point in the current
        direction.

TESSELATION:

        This is (might be) filling a polygon with a texture/bitmap a
        number of times like a drawing a wall using just one brick
        by repeating it in both directions. Like the tiles on a
        bathroom wall for example.

CLIP:

        To remove some, all or no part of an item. Normally used to only
        draw the parts of a polygon or bitmap which appears within
        our view-screen's boundary. Any part above, below, left or right
        of this boundary is clipped and not used.

CULL:

        Normally used to describe back-face culling this means to
        reject or clip an entire item such as an 3d model or polygon.
        In the case of back-face culling the direction of a face
        is tested against the viewing direction and if it is opposite
        then the polygon/face is totally ignored and not drawn.

GRID:

        Just like a piece of lined graph paper an area (or 'space') is
        divided into small sub-areas and each sub-area is bound by
        the surrounding sides. The parallel horizontal and vertical sides
        of a grid are defined at a regular interval (i.e.. every Nth pixel)
        each sub-area or 'cell' in a grid is like a brick in a wall, it
        has the identical size and orientation as all of it's neighbours.

CELL or ELEMENT:

        This is the smallest part of a grid, net or mesh and can be
        thought of as being a brick in a wall or a single piece of a
        jigsaw.

NETS:

        This is a grid which is overlaid over a surface or collection
        of randomly placed items so that some form of locality in
        their relative position can be exploited. So a 'net' is like
        the grid reference lines in an atlas or road map. Just like
        in the case of a fishing net items within a single square can
        be handling more easily than trying to deal with the entire
        catch in one go.

MESH:

        Like a Grid except the vertices (where two sides meet) can be
        or have been moved. This is like taking a piece of mesh fencing
        and distorting it by squashing or stretching parts of it. The
        most important thing to remember is that vertices and so the
        sides (and neighbouring squares) do NOT line up into a
        straight line as they do with a grid or net. This means each
        point where two sides meet (a vertex) must be defined and
        stored separately. Where a grid has equally spaced divisions
        a mesh does not. The cells in a mesh do NOT have a regular
        size or shape to them.

PIXELLATION:

        This is the ugly blocky pixels problem that appears on greatly
        magnified items. For example when a 32x10 bitmap is used to
        fill a 320x200 screen the result is a grid of 10x10 pixel blocks
        and this doesn't look very realistic. The problem is caused
        when a small item is magnified to fill a large area. A much
        nicer solution would employ a maximum magnification of 1:1 so
        that pixels are only ever drawn once but this would chew up
        tons of memory and be much, much slower.

INTERPOLATION:

        The method by which any number of values between 2 or more
        known data points are calculated. In the simplest form this can
        be 'linear interpolation' where the various intercept points
        along a straight line is calculated given it's two end
        co-ordinates. Polygons, Lines, Voxel maps, Texture mapping and
        Splines are all examples of interpolation but the idea is the
        same, values in the interval between known data values are
        generated/calculated, this can be to ANY resolution (infinite).

BEZIER CURVES, ARCS & SPLINES:

        These are ways to describe and draw non-linear (curved) lines.
        The Bezier curves normally use 4 'control points' which define
        the overall shape of the curve. An arc has normally 3 controls
        and a Spline can have any number. Also an arc has a regular
        shape to it usually part of a large circle or ellipse.


#############################################################################
Ŀ
 #Z:                            Final words                                

#############################################################################

#Z0:The Crystal Fool

          Here are some predictions about the kind of abilities
        which the next generation of 3-d engine might have and some
        of the common sense rules which unfortunately some new games
        still ignore.

        1) curved polygons.
          No more breeze block people or creatures. Instead of simply
        boosting the polygon count like most engines do these days
        perhaps Spline or Voxel based rendering methods can be used.
        This could allow smooth, organic looking items to be modelled
        with a modest number of control points using only a fraction
        of today's vertex counts. I think Blade Runner and Estactica
        were some of the first games to tackle the block-head problem.
          This curve interpolation would allow very large models to
        remain smooth looking when viewed from very close range.

        2) dynamic game worlds.
          Flexibility in the game engine allowing trees, walls, even
        buildings themselves to be demolished or created. The very
        static, traditional BSP type mapping and other similar methods
        really need to be greatly overhauled with far more REAL-TIME
        processing and structural-manipulation done by the CPU during
        play rather than before hand.
          This would require some new, fast techniques to be developed,
        so plenty of room for talented binary inventors here =)

        3) jelly scenery.
          Items such as trees or other flimsy objects behave and
        respond to impacts or environmental forces, such as wind, tides
        or other non-player creatures. Things such as weather, natural
        or artificial events should be possible using 'local knowledge'
        of the player's current surroundings.

        4) better details.
          The level of detailing will hopefully increase in line with
        level size rather than simply producing vast, empty rooms
        for the player to run through.

        5) more interaction.
          Yeah, more of this within the levels instead of the ancient
        "lets put a switch every 3 miles" method of game design.
        We have all played in high-tec environments but all seem to
        be reduced to pressing buttons, collecting keys or jumping
        across vast canyons. If an object is drawn on the screen then
        why can't I interact with it, pick it up and use it ?

        6) greater freedom.
          Most games tend to take you by the hand and guide you through
        the level. The game designers have forced us into a narrow
        and linear way of playing. Which is good from a programming
        point of view as it means there are only a few possible routes
        and sequences in which things can be done. But from an
        adventure point it usually sux. There should always be an
        alternative way of completing a task, using a different object
        or by taking another route.

          Hopefully you can see that there is still a vast amount of
        new techniques which can be introduced to the novelty eager
        players out there. Don't get bogged down by counting polygons
        or creating a photo-realistic renderer as most players won't
        notice these things only other programmers will. The player
        is usually far more impressed by new stuff, new toys to have
        fun with and new ways to interact with the level.
          There is such a rich and already well known resource for
        future 3-d game ideas. It's the REAL-WORLD !! So take a good
        look around, see what looks like fun or better still, dangerous
        and try to present it to the player in an easy to understand
        manner. It is very easy to just look at other games for ideas
        but most of the time you will be cloning a clone, so look
        at science, biology and old sci-fi films. I have seen some
        state-of-the-art demo effects in 30-50 year old sci-fi film
        titles !!! Things like motion blurring, text blends and
        plasma-like bobs can be found in the opening title for the
        classic "The Day Of The Triffids".

          There is only one rule for games programming:

          "If it is still fun for the programmer to play after months
        of development, then it is usually fun for the player too".

          I have witnessed plenty of games done by 9-to-5 programmers
        who just wanted to meet the deadlines and get paid. Their sole
        interest in the game was to finish it and get it out of their
        sight. Sadly most companies tend to favour these individuals
        as they are often like the managers themselves, but their
        'video games' talent is often lacking the enthusiasm which
        turns an average game into a really playable game.
          I think writing video games is more a question of 'what if'
        rather than one of 'daily schedules'. The whole process is
        the total opposite to that which the 'serious, professional'
        programmers work by. Their products have a very clear design
        spec and the plan doesn't really change a great deal, also
        each new product is often just an upgraded and embellished
        version of the previous one. Video games have NO clear goal
        in mind, the basic outline, story and map designs can be
        drawn up at the beginning but usually major and I mean major
        changes occur forcing pages of code to be tweaked or totally
        scrapped in the name of playability. Each game should at least
        attempt to break new ground, to present something novel
        which the player has seen before. There can sometimes be
        a lot of 'play it by ear' design and programming which help
        to shape a game beyond the predictable clone status. This
        gives many managers ulcers as they are unable to control the
        'talent' of their employees, but why should the programmers
        be the only ones to sweat blood and tears ?


#Z1:So Long, Fare-well..

          One of the most interesting things about programming 3d
        it that there is still so much yet to be done before
        the all time ultimate, mega-optimum method is found. Many
        of the well established algorithms and techniques are useful
        in themselves and can often be applied to other things
        but there are still many holes yet to be plugged. Like
        the Sutherland-Cohen line clipping using outcodes, under
        certain situations it can not reject or accept certain
        slopes which must be clipped and re-tested, so there is
        room for improvement here. Even things like the Bresenham
        line drawing algorithm which on the face of it may appear
        to be the ultimate scan converting method can in fact be
        improved using a "run-length slice" method something which
        is almost identical to an optimisation that I had worked
        out 4 years before I knew what it was called (except mine
        doesn't require a division, heh heh). I think even the
        God-like Mr. Bresenham had figured this out as well.

        Sometimes "You have boldy followed where someone else has
        gone before...."

          So okay, you might not be a pioneer in the field but
        perhaps your fresh, new approach might yield a few more
        tricks here and there. Sometimes after looking at a piece
        of code for too long you can start to get 'snow blind' and
        miss a trick here or here, so take a break or better still
        ask a fellow coder to take a pew or two they might suggest
        an obvious trick that you overlooked. If you think you have
        found the ultimate algorithm then take a long look at some
        of your old 'optimised' code. This will usually make you
        say "Yuck ! What the hell was I doing back then ? If I knew
        then what I know now...." yep, the moral of the story is..

                Today's optimisation is tomorrow's slug...

          This is too true, just look at the various CLK-timings of
        8086 CPU's compared to many of today's "faster" CPU's and
        note how some instructions have actually got slower !
        And on this happy note I will say .....

                                                "That's All Folks !"

                                                                the end.


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Please note: 

        I do NOT plan to do any major corrections in the future.
        Just running this through a spell checker took a number of
        hours and after attempting to convert it into HMTL documents
        (twice) I gave up, coz those types of documents didn't seem
        to like TAB (09) characters ???? After converting ALL the
        TABs into SPACEs  my HMTL editor (which really sucks)
        decided to remove ALL the spaces when saving to disk without
        telling me... ARRRGGgggggGRGGGGHHHHH.....

        Just getting this DOS document into the spell-check was a
        bitch, I used the horrid MSWORKS and it has more bugs than
        a tramps mattress. 

        So after too many hours that I wish to admit, I have given up.
        So, folks, if you see a mistake, correct it, save it and
        keep quiet.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!



                               Have a nice day.
