view dmline.c @ 160:67d2cba58a87

Add fontconv tool.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 06 Oct 2012 07:29:26 +0300
parents 92cc5e1fa180
children 79dac918c81e
line wrap: on
line source

/*
 * DMLib
 * -- Arbitrary line drawing functions
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2011 Tecnic Software productions (TNSP)
 */
#include "dmlib.h"


/* Clip line coordinates. Return value:
 * = 0  : No clipping needed.
 * > 0  : Clipped. Line partially inside the clipping area.
 * < 0  : Line completely outside the clipping area.
 */
#define dmClipBits(Q, x, y)	\
    do {			\
        Q = 0;			\
        if (x < clipX0) Q |= 1;	\
        else			\
        if (x > clipX1) Q |= 2;	\
        if (y < clipY0) Q |= 4;	\
        else			\
        if (y > clipY1) Q |= 8;	\
    } while (0)

#define xA (*x0)
#define xB (*x1)
#define yA (*y0)
#define yB (*y1)

int dmClipLineCoords(int *x0, int *y0, int *x1, int *y1, SDL_Surface *screen)
{
    const int clipX0 = screen->clip_rect.x,
              clipY0 = screen->clip_rect.y;
    const int clipX1 = clipX0 + screen->clip_rect.w - 1,
              clipY1 = clipY0 + screen->clip_rect.h - 1;

    int cA, cB;

    dmClipBits(cA, xA, yA);
    dmClipBits(cB, xB, yB);

    if (cA & cB)
        return -1;              /* the line segment is outside */

    if ((cA | cB) == 0)         /* the line segment is inside of the clipping rectangle */
        return 0;

#if 1
    // Cohen-Sutherland clipping method
    do
    {
        const int c = cA ? cA : cB;
        int x, y;
        
        if (c & 1)
        {
            y = yA + ((clipX0 - xA)*(yB - yA)) / (xB - xA);
            x = clipX0;
        }
        else
        if (c & 2)
        {
            y = yA + ((clipX1 - xA)*(yB - yA)) / (xB - xA);
            x = clipX1;
        }
        else
        if (c & 4)
        {
            x = xA + ((clipY0 - yA)*(xB - xA)) / (yB - yA);
            y = clipY0;
        }
        else
        if (c & 8)
        {
            x = xA + ((clipY1 - yA)*(xB - xA)) / (yB - yA);
            y = clipY1;
        }

        if (c == cA)
        {
            xA = x;
            yA = y;
            dmClipBits(cA, xA, yA);
        }
        else
        {
            xB = x;
            yB = y;
            dmClipBits(cB, xB, yB);
        }
        
    } while (cA | cB);
#else
    // Buyu-Skala clipping method
    const int dx = xB - xA;
    const int dy = yB - yA;
    float k, m;
    int z;

    switch (cA + cB)
    {
        case 1:
            if (cA == 1)
            {
                xA = clipX0;
                yA = (clipX0 - xB) * dy / dx + yB;
            }
            else
            {
                xB = clipX0;
                yB = (clipX0 - xA) * dy / dx + yA;
            }
            break;

        case 3:
            k = dy / dx;
            yA = (clipX0 - xA) * k + yA;
            xA = clipX0;
            yB = (clipX1 - xB) * k + yB;
            xB = clipX1;
            break;

        case 5:
            k = dy / dx;
            z = (clipX0 - xA) * k + yA;
            if (z < clipY0)
            {
                switch (cA)
                {
                    case 0:
                        xB = xB + (clipY0 - yB) / k;
                        yB = clipY0;
                        break;
                    case 5:
                        xA = xA + (clipY0 - yA) / k;
                        yA = clipY0;
                        break;

                    default:
                        return -1;  /* the line segment is outside */
                }
            }
            else
            {
                switch (cA)
                {
                    case 0:
                        xB = clipX0;
                        yB = z;
                        break;
                    case 1:
                        xB = xB + (clipY0 - yB) / k;
                        yB = clipY0;
                        xA = clipX0;
                        yA = z;
                        break;
                    case 4:
                        xA = xA + (clipY0 - yA) / k;
                        yA = clipY0;
                        xB = clipX0;
                        yB = z;
                        break;
                    case 5:
                        xA = clipX0;
                        yA = z;
                        break;
                }
            }
            break;

        case 7:
            switch (cA)
            {
                case 1:
                    k = dy / dx;
                    yA = (clipX0 - xB) * k + yB;
                    if (yA < clipY0)
                        return -1;  /* the line segment is outside */
                    xA = clipX0;
                    yB = (clipX1 - clipX0) * k + yA;
                    if (yB < clipY0)
                    {
                        xB = (clipY0 - yB) / k + clipX1;
                        yB = clipY0;
                    }
                    else
                        xB = clipX1;
                    break;

                    /* similarly for cases cA == 2, 5, 6 */
            }
        case 15:
            switch (cA)
            {
            case 5:
                if (dy * (clipX1 - clipX0) < dx * (clipY1 - clipY0))
                {
                    k = dy / dx;
                    yA = (clipX0 - xB) * k + yB;
                    if (yA > clipY1)
                        return -1;  /* the line segment is outside */
                    yB = (clipX1 - clipX0) * k + yA;
                    if (yB < clipY0)
                        return -1;  /* the line segment is outside */
                    if (yA < clipY0)
                    {
                        xA = (clipY0 - yA) / k + clipX0;
                        yA = clipY0;
                        xB = clipX1;
                    }
                    else
                    {
                        xA = clipX0;
                        if (yB > clipY1)
                        {
                            xB = (clipY1 - yB) / k + clipX1;
                            yB = clipY1;
                        }
                        else
                            xB = clipX1;
                    }
                }
                else
                {
                    m = dx / dy;
                    xA = (clipY0 - yB) * m + xB;
                    if (xA > clipX1)
                        return -1;  /* the line segment is outside */
                    xB = (clipY1 - clipY0) * m + xA;
                    if (xB < clipX0)
                        return -1;  /* the line segment is outside */
                    if (xA < clipX0)
                    {
                        yA = (clipX0 - xA) / m + clipY0;
                        xA = clipX0;
                        yB = clipY1;
                    }
                    else
                    {
                        yA = clipY0;
                        if (xB > clipX1)
                        {
                            yB = (clipX1 - xB) / m + clipY1;
                            xB = clipX1;
                        }
                        else
                            yB = clipY1;
                    }
                }

                /* similarly for cases cA == 6, 9, 10 */
            }

            /* cases 2, 4, 8 are similar as case 1, cases 6, 9, 10 are similar as case 5 */
            /* cases 11, 13, 14 are similar as case 7, case 12 is similar case 3 */
    }                           /* of case cA + cB */
#endif

    return 1;
}



#include "dmlinefunc.h"

static const DMDrawLineFunc dmDrawLineTable[DMD_NMODES][DMD_NBITDEPTHS] =
{
    /* DMD_NONE          */ { dmDrawLine8              , dmDrawLine32 },
    /* DMD_TRANSPARENT   */ { dmDrawLine8Transparent   , dmDrawLine32Transparent },
    /* DMD_SATURATE      */ { dmDrawLine8Saturate      , dmDrawLine32Saturate },
#if 0
    /* DMD_NONE + AA     */ { NULL, NULL },
    /* DMD_TRANSP + AA   */ { NULL, NULL },
    /* DMD_SATURATE + AA */ { dmDrawLine8AASaturate    , dmDrawLine32AASaturate },
#endif
};

static const int ndmDrawLineTable = sizeof(dmDrawLineTable) / sizeof(dmDrawLineTable[0]);


DMDrawLineFunc dmGetDrawLineFunc(SDL_PixelFormat *dst, int mode)
{
    int index;
    if (dst == NULL || mode < 0 || mode >= ndmDrawLineTable)
        return NULL;

    if ((index = dmBitsPerPixel2Index(dst->BitsPerPixel)) < 0)
        return NULL;
    
    return dmDrawLineTable[mode][index];
}


int dmDrawLineAny(SDL_Surface *screen, int x0, int y0, int x1, int y1, const Uint32 col, int mode)
{
    DMDrawLineFunc bfunc = dmGetDrawLineFunc(screen->format, mode);

    if (bfunc == NULL)
        return -15;

    return bfunc(screen, x0, y0, x1, y1, col);
}