root/src/add-ons/accelerants/3dfx/3dfx_draw.cpp
/*
        Copyright 2010 Haiku, Inc.  All rights reserved.
        Distributed under the terms of the MIT license.

        Authors:
        Gerald Zajac
*/


#include "accelerant.h"
#include "3dfx.h"


// Constants for the DST_FORMAT register based upon the color depth.

static const uint32 fmtColorDepth[] = {
        0x10000,                // 1 byte/pixel
        0x30000,                // 2 bytes/pixel
        0x50000,                // 3 bytes/pixel (not used)
        0x50000                 // 4 bytes/pixel
};


void
TDFX_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, 
        uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
        uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];

        TDFX_WaitForFifo(3);
        OUTREG32(DST_FORMAT, fmt);
        OUTREG32(COLOR_BACK, color);
        OUTREG32(COLOR_FORE, color);

        while (count--) {
                int x = list->left;
                int y = list->top;
                int w = list->right - x + 1;
                int h = list->bottom - y + 1;

                TDFX_WaitForFifo(3);
                OUTREG32(DST_SIZE, w | (h << 16));
                OUTREG32(DST_XY,   x | (y << 16));
                OUTREG32(CMD_2D, RECTANGLE_FILL | CMD_2D_GO | (ROP_COPY << 24));

                list++;
        }
}


void
TDFX_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
        uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];

        TDFX_WaitForFifo(3);
        OUTREG32(DST_FORMAT, fmt);
        OUTREG32(COLOR_BACK, color);
        OUTREG32(COLOR_FORE, color);

        while (count--) {
                int y = *list++;
                int x = *list++;
                int w = *list++ - x + 1;

                if (w <= 0)
                        continue;       // discard span with zero or negative width

                TDFX_WaitForFifo(3);
                OUTREG32(DST_SIZE, w | (1 << 16));
                OUTREG32(DST_XY,   x | (y << 16));
                OUTREG32(CMD_2D, RECTANGLE_FILL | CMD_2D_GO | (ROP_COPY << 24));
        }
}


void
TDFX_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
        uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];

        TDFX_WaitForFifo(1);
        OUTREG32(DST_FORMAT, fmt);

        while (count--) {
                int x = list->left;
                int y = list->top;
                int w = list->right - x + 1;
                int h = list->bottom - y + 1;

                TDFX_WaitForFifo(3);
                OUTREG32(DST_SIZE, w | (h << 16));
                OUTREG32(DST_XY,   x | (y << 16));
                OUTREG32(CMD_2D, RECTANGLE_FILL | CMD_2D_GO | (ROP_INVERT << 24));

                list++;
        }
}


void
TDFX_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
        uint32 fmt = mode.bytesPerRow | fmtColorDepth[mode.bytesPerPixel - 1];

        TDFX_WaitForFifo(2);
        OUTREG32(DST_FORMAT, fmt);
        OUTREG32(SRC_FORMAT, fmt);

        while (count--) {
                int src_x = list->src_left;
                int src_y = list->src_top;
                int dest_x = list->dest_left;
                int dest_y = list->dest_top;
                int width = list->width;
                int height = list->height;

                uint32 cmd = SCRN_TO_SCRN_BLIT | CMD_2D_GO | (ROP_COPY << 24);

                if (src_x <= dest_x) {
                        cmd |= X_RIGHT_TO_LEFT;
                        src_x += width;
                        dest_x += width;
                }

                if (src_y <= dest_y) {
                        cmd |= Y_BOTTOM_TO_TOP;
                        src_y += height;
                        dest_y += height;
                }

                TDFX_WaitForFifo(4);
                OUTREG32(SRC_XY, src_x | (src_y << 16));
                OUTREG32(DST_SIZE, (width + 1) | ((height + 1) << 16));
                OUTREG32(DST_XY, dest_x | (dest_y << 16));
                OUTREG32(CMD_2D, cmd);

                list++;
        }
}