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 + -
显示快捷键?