l1paint.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 575 行 · 第 1/2 页

C
575
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "gdefn.h"
#if !defined( _DEFAULT_WINDOWS )
#include <malloc.h>
#include "stkavail.h"

#define TUNING          6


/*  Use PASCAL pragma to define our convention for
    calling the ScanLeft and ScanRight routines.    */

#define SCAN_FUNC pascal

#if defined ( __386__ )
    #pragma aux pascal "*" parm caller [es edi] [eax] [ebx] [ecx] [edx] [esi] value [bx];
#else
    #pragma aux pascal "*" parm caller [es di] [ax] [bx] [cx] [dx] [si] value [bx];
#endif


struct frame {
    short         direction;
    short         left;
    short         right;
    short         ypos;
};


static char     CheckIfOut( short, short, short );
static short    PaintLeft( short, short, short, short );
static short    PaintRight( short, short, short, short );
static short    ScanLeft( short, short, short, short );
static short    ScanRight( short, short, short, short );
static short    AddEntry( short, short, short, short, unsigned, unsigned *, struct frame * );
static char     NotValidFrame( unsigned, unsigned *, struct frame * );
static char     StackCompare( struct frame *, unsigned * );


// Visit code is used to get around a bug in the floodfill algorithm.
// If filling with a non-solid pattern, it is not always possible to
// tell if an area has already been filled, leading to infinite loops.
// For WPAINT, (which uses worldm.lib or worldl.lib) the visit routines
// keep track of what points we have visited.

#if defined( __MEDIUM__ ) || defined( __LARGE__ )
extern int      _flood_is_visited( short, short );
extern void     _flood_visit( short, short, short );
#else
#define _flood_visit( x, y, len )
#endif

#endif


#if defined( _DEFAULT_WINDOWS )
static short _L0Paint( short stop_color, short x, short y )
/*=========================================================
  This function does the filling. */
{
    WORD                fill_style;
    WPI_PRES            dc;
    HBITMAP             bm;
    HBRUSH              brush;
    HBRUSH              old_brush;
    HRGN                temprgn;
    WPI_COLOUR          color;
    short               rc;
    WPI_RECT            clip_rect, temp_rect;
    WPI_INST            inst;
    short               t;
    short               clipy1, clipy2;
  #if defined( __OS2__ )
    WPI_RECT            wrect;
    short               height;
  #endif

    // Map our way of filling to Window API's
    if( stop_color == -1 ) {
        fill_style = FLOODFILLSURFACE;
        stop_color = _getpixel( x, y );
    } else {
        fill_style = FLOODFILLBORDER;
    }

    //Setup before filling
    dc = _Mem_dc;

    // Do the clippings
    temprgn = _ClipRgn;
    clipy1 = _wpi_cvth_y( _CurrState->clip_def.ymin, _GetPresHeight() );
    clipy2 = _wpi_cvth_y( _CurrState->clip_def.ymax + 1, _GetPresHeight() );
    _wpi_setintwrectvalues( &clip_rect,
                           _CurrState->clip_def.xmin,
                           clipy1,
                           _CurrState->clip_def.xmax + 1,
                           clipy2 );
    temp_rect = clip_rect;
    _ClipRgn = _wpi_createrectrgn( dc, &clip_rect );
    _wpi_getclipbox( dc, &clip_rect);
    _wpi_selectcliprgn( dc, _ClipRgn );
    _wpi_deletecliprgn( dc, temprgn );

// Setup
    color = _Col2RGB( _CurrColor );

// Check for fillmask
    if( _HaveMask == 0 ) {
        brush = _wpi_createsolidbrush( color );
    } else {
        /* if a mask is defined, convert it to bitmap */
        bm = _Mask2Bitmap( dc, &_FillMask );
        brush = _wpi_createpatternbrush( bm );
    }

    old_brush = _wpi_selectbrush( dc, brush );

// Do the floodfill
    y = _wpi_cvth_y( y, _GetPresHeight() );
    rc = _wpi_extfloodfill( dc, x, y, _Col2RGB( stop_color ), fill_style );


// Cleanup
    if( _HaveMask != 0 ) {
        _wpi_deletebitmap( bm );
    }

    _wpi_getoldbrush( dc, old_brush );
    _wpi_deletebrush( brush );

    temprgn = _ClipRgn;
    _ClipRgn = _wpi_createrectrgn( dc, &clip_rect );
    _wpi_selectcliprgn( dc, _ClipRgn );
    _wpi_deletecliprgn( dc, temprgn );

// Update the entire Clipping area
  #if defined( __OS2__ )
    GetClientRect( _CurrWin, &wrect );
    height = _wpi_getheightrect( wrect );
    t = _GetPresHeight() - height - _BitBlt_Coord.ycoord;
  #else
    t = _BitBlt_Coord.ycoord;
  #endif
    inst = _GetInst();
    _wpi_offsetrect( inst, &temp_rect,
                     -_BitBlt_Coord.xcoord,
                     -t );
    _wpi_invalidaterect( _CurrWin, &temp_rect, 0 );
    return ( rc );
}
#endif


short _L1Paint( short stop_color, short x, short y )
/*==================================================

    Paint a region on the screen starting at the point (x,y). If the
    stop_color is -1, then painting continues as long as the color of
    the neighbouring pixels is the same as the color of the starting pixel.
    Otherwise, stop_color defines the boundary of the fill region. Returns
    TRUE if paint is successful. Otherwise, returns FALSE and will try
    to paint as much as possible. This function obtains its dynamic
    memory off the stack.   */

{
#if defined( _DEFAULT_WINDOWS )
    short               rc;
#else
    unsigned            max_frames;             /* maximum # of frames      */
    unsigned            stack_count;            /* # of non-active frames   */
    short               left_edge;          /* left pixel of active frame   */
    short               right_edge;         /* right pixel of active frame  */
    short               direction;          /* direction of active frame    */
    short               left_scan;          /* temp. left while scanning    */
    short               right_scan;         /* temp. right while scanning   */
    short               cutoff;             /* stopping pixel in scanning   */
    short               success;                    /* flag for success     */
    char                border_flag;                /* 0 - until; 1 - while */
    struct frame *      stack;                      /* ptr to list of frames*/
#endif

    if( _L1OutCode( x, y ) ) {              /* starting point is outside    */
        _ErrorStatus = _GRINVALIDPARAMETER;
        return( FALSE );                    /* so do nothing                */
    }

#if defined( _DEFAULT_WINDOWS )
    rc = _L0Paint( stop_color, x, y );
    _RefreshWindow();
    return ( rc );
#else
    /*  Calculate the number of frames which can be held on the stack.
        Note : stack[0] always contains the active frame.   */

    max_frames = ( _stackavail() - 0x100 ) / sizeof( struct frame );
    if( max_frames >= 2 ) {                     /* need at least 2 frames   */
        stack = __alloca( _RoundUp( sizeof( struct frame ) * max_frames ) );
    } else {
        _ErrorStatus = _GRINSUFFICIENTMEMORY;
        return( FALSE );                    /* not enough memory so quit    */
    }
    max_frames -= 1;                    /* stack[0] is the active frame     */

    if( stop_color == -1 ) {
        stop_color = _L1GetDot( x, y );     /* get color of starting pixel  */
        if( stop_color == _CurrColor ) {
            if( _HaveMask == 0 ) {                  /* solid fill and pixel */
                _ErrorStatus = _GRINVALIDPARAMETER; /* already in the       */
                return( FALSE );                    /* current color        */
            }
        }
        border_flag = 1;                /* paint inside while same color    */
    } else {
        stop_color &= _CurrState->vc.numcolors - 1;
        if( stop_color == _L1GetDot( x, y ) ) {     /* on border of region */
            _ErrorStatus = _GRINVALIDPARAMETER;
            return( FALSE );
        }
        border_flag = 0;        /* paint inside until border encountered    */
    }
    /* Fill first line starting at (x,y)    */

    _StartDevice();
    left_edge = PaintLeft( x, y, stop_color, border_flag );
    right_edge = PaintRight( x, y, stop_color, border_flag );
    stack[0].ypos = y - 1;                          /* Process the frame    */
    stack[0].right = right_edge;                    /* going down first.    */
    stack[0].left = left_edge;
    stack[0].direction = -1;
    stack_count = 1;                                    /* 1 active frame   */
    stack[1].ypos = y;                                  /* save the frame   */
    stack[1].right = right_edge;                        /* going up         */
    stack[1].left = left_edge;
    stack[1].direction = 1;
    success = 0;                                /* assume success at first  */
    for( ;; ) {                                 /* process all the frames   */
        do {                                /* process frame row per row    */
            direction = stack[0].direction;         /* load active frame    */
            left_edge = stack[0].left;              /* ( frame may change ) */
            right_edge = stack[0].right;
            y = stack[0].ypos;
            if( CheckIfOut( left_edge, right_edge, y ) ) {
                break;                      /* frame is outside viewport    */
            }
            /* Start scanning. Scan left as much as possible.   */
            left_scan = PaintLeft( left_edge, y, stop_color, border_flag );
            right_scan = left_edge;
            left_edge = left_scan;
            /* Check for a hole to the left */
            if( left_scan <= right_scan - 2 ) {
                success += AddEntry( y, right_scan - 2, left_scan, -direction,
                                     max_frames, &stack_count, stack );
            }
            /* Now scan right until we reach the right edge */
            /* and skip holes if any.   */
            cutoff = right_scan;
            if( right_scan < right_edge || right_scan >= left_scan ) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?