📄 genfunc.c
字号:
/*
** $Id: genfunc.c,v 1.12 2004/04/19 06:04:57 snig Exp $
**
** genfunc.c: Native Low Level Graphics Engine 's commone file
**
** Copyright (C) 2003 Feynman Software
** Copyright (C) 2000 Song Lixin
**
** Create by Song Lixin, 2000/10/18
*/
/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "minigui.h"
#include "gal.h"
#include "native.h"
//==================================================================================================
//general functions
//
static void drawrow(PSD psd, int x1, int x2, int y);
static void drawcol(PSD psd, int x,int y1,int y2);
static inline void setpixel(PSD psd, int x, int y, int c);
static void setcirclepixels(PSD psd, int x, int y, int sx, int sy, int c);
static void setcirclepixels(PSD psd, int x, int y, int sx, int sy, int c);
static inline int muldiv64(int m1, int m2, int d);
/* initialize memory device with passed parms*/
void native_gen_initmemgc
(PSD mempsd,int w,int h,int planes,int bpp,int linelen, int size,void *addr) {
mempsd->xres = w;
mempsd->yres = h;
mempsd->xvirtres = w;
mempsd->yvirtres = h;
mempsd->planes = planes;
mempsd->bpp = bpp;
mempsd->linelen = linelen;
mempsd->size = size;
mempsd->addr = addr;
}
/* allocate a memory screen device*/
PSD native_gen_allocatememgc(PSD psd)
{
PSD mempsd;
mempsd = malloc(sizeof(SCREENDEVICE));
if (!mempsd)
return NULL;
/* copy passed device get initial values*/
*mempsd = *psd;
/* initialize*/
mempsd->flags |= PSF_MEMORY;
mempsd->flags &= ~PSF_SCREEN;
mempsd->addr = NULL;
return mempsd;
}
void native_gen_freememgc(PSD mempsd)
{
/* note: mempsd->addr must be freed elsewhere*/
free(mempsd);
}
void native_gen_fillrect(PSD psd,int x, int y, int w, int h, gal_pixel c)
{
#if 1
while (h--)
psd->DrawHLine(psd, x, y++, w, c);
#else
while (w--)
psd->DrawVLine(psd, x++, y , h, c);
#endif
}
int native_gen_clippoint(PSD psd, int x ,int y)
{
if(psd->doclip) {
if ((x >= psd->clipminx) && (x < psd->clipmaxx) &&
(y >= psd->clipminy) && (y < psd->clipmaxy))
return CLIP_VISIBLE;
} else {
if ((x >= 0) && (x < psd->xres) && (y >= 0) && (y < psd->yres))
return CLIP_VISIBLE;
}
return CLIP_INVISIBLE;
}
int native_gen_cliphline(PSD psd,int * px,int * py, int * pw)
{
if (psd->doclip) {
if ( (*px >= psd->clipmaxx) || (*py >= psd->clipmaxy) ||
(*px + *pw - 1 < psd->clipminx) || (*py < psd->clipminy) )
return CLIP_INVISIBLE;
if ( (*px >= psd->clipminx) && (*py >= psd->clipminy) &&
(*px + *pw -1 < psd->clipmaxx) && (*py < psd->clipmaxy) )
return CLIP_VISIBLE;
if (*px < psd->clipminx) {
*pw -= psd->clipminx - *px;
*px = psd->clipminx;
}
if (*px + *pw - 1 >= psd->clipmaxx)
*pw = psd->clipmaxx - *px;
} else {
if ( (*px >= psd->xres) || (*py >= psd->yres) || (*px + *pw - 1 < 0) || (*py < 0) )
return CLIP_INVISIBLE;
if ( (*px >= 0) && (*py >= 0) && (*px + *pw -1 < psd->xres) && (*py < psd->yres) )
return CLIP_VISIBLE;
if (*px < 0) {
*pw += *px;
*px = 0;
}
if (*px + *pw - 1 >= psd->xres)
*pw = psd->xres - *px;
}
if (*pw <= 0)
return CLIP_INVISIBLE;
return CLIP_PARTIAL;
}
int native_gen_clipvline(PSD psd,int * px,int * py, int *ph)
{
if (psd->doclip) {
if ( (*px >= psd->clipmaxx) || (*py >= psd->clipmaxy) ||
(*px < psd->clipminx) || (*py + *ph - 1 < psd->clipminy) )
return CLIP_INVISIBLE;
if ( (*px >= psd->clipminx) && (*py >= psd->clipminy) &&
(*px < psd->clipmaxx) && (*py + *ph - 1 < psd->clipmaxy) )
return CLIP_VISIBLE;
if (*py < psd->clipminy) {
*ph -= psd->clipminy - *py;
*py = psd->clipminy;
}
if (*py + *ph - 1 >= psd->clipmaxy)
*ph = psd->clipmaxy - *py;
} else {
if ( (*py >= psd->yres) || (*px >= psd->xres) || (*py + *ph - 1 < 0) || (*px < 0) )
return CLIP_INVISIBLE;
if ( (*py >= 0) && (*px >= 0) && (*py + *ph -1 < psd->yres) && (*px < psd->xres) )
return CLIP_VISIBLE;
if (*py < 0) {
*ph += *py;
*py = 0;
}
if (*py + *ph - 1 >= psd->yres)
*ph = psd->yres - *py;
}
if (*ph <= 0)
return CLIP_INVISIBLE;
return CLIP_PARTIAL;
}
int native_gen_clipline (PSD psd,int * px1,int * py1, int * px2,int *py2)
{
int w,h;
int r1;
int clip_first;
int clip_last;
if(*px1 == *px2) {
if (*py1 == *py2)
return native_gen_clippoint (psd,*px1,*px2);
if (*py1 > *py2) {
h = *py1 - *py2 + 1;
r1 = native_gen_clipvline (psd, px1, py2, &h);
if (r1 == CLIP_PARTIAL)
*py1 = *py2 + h - 1;
return r1;
} else {
h = *py2 - *py1 + 1;
r1 = native_gen_clipvline (psd, px1, py1, &h);
if (r1 == CLIP_PARTIAL)
*py2 = *py1 + h - 1;
return r1;
}
}
if(*py1 == *py2) {
if (*px1 > *px2) {
w = *px1 - *px2 + 1;
r1 = native_gen_clipvline (psd, px2, py1, &w);
if (r1 == CLIP_PARTIAL)
*px1 = *px2 + w - 1;
return r1;
} else {
w = *px2 - *px1 + 1;
r1 = native_gen_clipvline (psd, px2, py2, &w);
if (r1 == CLIP_PARTIAL)
*px2 = *px1 + w - 1;
return r1;
}
}
return cs_clipline(psd,px1,py1,px2,py2,&clip_first,&clip_last);
}
/*
* You should give a normalized rect. that is
*pw > 0
*ph > 0
*
* returned value:
* CLIP_VISIBLE The whole rectangle is visible
* CLIP_INVISIBLE The whole rectangle is invisible
* CLIP_PARTIAL The rectangle may be partially visible
*
* if returned CLIP_PARTIAL,the parameter is modified to hold the part
* that is in the clip region.
*/
int native_gen_clipbox (PSD psd,int * px,int * py, int * pw,int *ph)
{
if (*pw == 1)
return native_gen_clipvline(psd, px, py, ph);
if (*ph == 1)
return native_gen_cliphline(psd, px, py, pw);
if (psd->doclip) {
if ( (*px >= psd->clipmaxx) || (*py >= psd->clipmaxy) ||
(*px + *pw - 1 < psd->clipminx) || (*py + *ph - 1 < psd->clipminy) )
return CLIP_INVISIBLE;
if ( (*px >= psd->clipminx) && (*py >= psd->clipminy) &&
(*px + *pw -1 < psd->clipmaxx) && (*py + *ph - 1 < psd->clipmaxy) )
return CLIP_VISIBLE;
if (*px < psd->clipminx) {
*pw -= psd->clipminx - *px;
*px = psd->clipminx;
}
if (*py < psd->clipminy) {
*ph -= psd->clipminy - *py;
*py = psd->clipminy;
}
if (*px + *pw - 1 >= psd->clipmaxx)
*pw = psd->clipmaxx - *px;
if (*py + *ph - 1 >= psd->clipmaxy)
*ph = psd->clipmaxy - *py;
} else {
if ( (*px >= psd->xres) || (*py >= psd->yres) ||
(*px + *pw - 1 < 0) || (*py +*ph - 1 < 0) )
return CLIP_INVISIBLE;
if ( (*px >= 0) && (*py >= 0) && (*px + *pw -1 < psd->xres)
&& (*py + *ph - 1 < psd->yres) )
return CLIP_VISIBLE;
if (*px < 0) {
*pw += *px;
*px = 0;
}
if (*px + *pw - 1 >= psd->xres)
*pw = psd->xres - *px;
if (*py < 0) {
*ph += *py;
*py = 0;
}
if (*py + *ph - 1 >= psd->yres)
*ph = psd->yres - *py;
}
if (*pw <= 0 || *ph <= 0)
return CLIP_INVISIBLE;
return CLIP_PARTIAL;
}
//==================================================================================================
// help functions
/*
* Calculate size and linelen of memory gc.
* If bpp or planes is 0, use passed psd's bpp/planes.
* Note: linelen is calculated to be DWORD aligned for speed
* for bpp <= 8. Linelen is converted to bytelen for bpp > 8.
*/
int native_gen_calcmemgcalloc(PSD psd, unsigned int width, unsigned int height, int planes,
int bpp, int *psize, int *plinelen)
{
int bytelen, linelen;
if(!planes)
planes = psd->planes;
if (!bpp)
bpp = psd->bpp;
/*
* use bpp and planes to create size and linelen.
* linelen is in bytes for bpp 1, 2, 4, 8, and pixels for bpp 16,24,32.
*/
if(planes == 1) {
switch(bpp) {
case 1:
case 2:
case 4:
case 8:
bytelen = linelen = (width+3) & ~3;
break;
case 16:
linelen = width;
bytelen = width * 2;
break;
case 24:
linelen = width;
bytelen = width * 3;
break;
case 32:
linelen = width;
bytelen = width * 4;
break;
default:
return 0;
}
} else if(planes == 4) {
/* FIXME assumes VGA 4 planes 4bpp*/
/* we use 4bpp linear for memdc format*/
bytelen = linelen = (width+3) & ~3;
} else {
*psize = *plinelen = 0;
return 0;
}
*plinelen = linelen;
*psize = bytelen * height;
return 1;
}
void native_gen_rect(PSD psd , int l, int t, int r, int b)
{
drawrow(psd, l, r, t);
drawrow(psd, l, r, b);
drawcol(psd, l, t, b);
drawcol(psd, r, t, b);
}
/*
* Draw an arbitrary line using the current clipping region and foreground color
* If bDrawLastPoint is FALSE, draw up to but not including point x2, y2.
*
* This routine is the only routine that adjusts coordinates for supporting
* two different types of upper levels, those that draw the last point
* in a line, and those that draw up to the last point. All other local
* routines draw the last point. This gives this routine a bit more overhead,
* but keeps overall complexity down.
*/
void native_gen_line(PSD psd, int x1, int y1, int x2, int y2, BOOL bDrawLastPoint)
{
int xdelta; /* width of rectangle around line */
int ydelta; /* height of rectangle around line */
int xinc; /* increment for moving x coordinate */
int yinc; /* increment for moving y coordinate */
int rem; /* current remainder */
int temp;
/* See if the line is horizontal or vertical. If so, then call
* special routines.
*/
if (y1 == y2) {
/*
* Adjust coordinates if not drawing last point. Tricky.
*/
if(!bDrawLastPoint) {
if (x1 > x2) {
temp = x1;
x1 = x2 + 1;
x2 = temp;
} else
--x2;
}
/* call faster line drawing routine*/
drawrow(psd, x1, x2, y1);
return;
}
if (x1 == x2) {
/*
* Adjust coordinates if not drawing last point. Tricky.
*/
if(!bDrawLastPoint) {
if (y1 > y2) {
temp = y1;
y1 = y2 + 1;
y2 = temp;
} else
--y2;
}
/* call faster line drawing routine*/
drawcol(psd, x1, y1, y2);
return;
}
/* The line may be partially obscured. Do the draw line algorithm
* checking each point against the clipping regions.
*/
xdelta = x2 - x1;
ydelta = y2 - y1;
if (xdelta < 0) xdelta = -xdelta;
if (ydelta < 0) ydelta = -ydelta;
xinc = (x2 > x1) ? 1 : -1;
yinc = (y2 > y1) ? 1 : -1;
if (psd->ClipPoint(psd, x1, y1))
psd->DrawPixel(psd, x1, y1, psd->gr_foreground);
if (xdelta >= ydelta) {
rem = xdelta / 2;
for(;;) {
if(!bDrawLastPoint && x1 == x2)
break;
x1 += xinc;
rem += ydelta;
if (rem >= xdelta) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -