📄 drawutil.c
字号:
#include "DrawUtil.h"
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
void MakeHueRGBTable(void);
static void MakeNoise1d(void);
static void MakeNoise2d(void);
static void MakeNoise3d(void);
//-------------------------------------------------------
static ulong lastRandomNumber = 0xA2A9; // that's a prime
void DrawUtil_Randomize( void )
{
ulong cnt;
cnt = clock();
cnt &= 0xFF;
while(cnt--)
{
lastRandomNumber = lastRandomNumber*65539+3;
lastRandomNumber = lastRandomNumber*1009 +7;
}
}
ulong REGCALL DrawUtil_Rand( ulong max )
{
ulong a;
lastRandomNumber = a = lastRandomNumber*65539+3;
return (a>>16)%max;
}
//-------------------------------------------------------
float DrawUtil_SinTable[TABLE_SIZE];
float DrawUtil_CosTable[TABLE_SIZE];
ubyte DrawUtil_ByteSinTable[256];
ubyte DrawUtil_ByteCosTable[256];
static bool DidUtilInit = false;
void DrawUtil_Init(void)
{
int i;
double radVal;
if ( DidUtilInit )
return;
float_SinglePrecision();
float_RoundToZero();
for (i = 0; i < TABLE_SIZE; i ++)
{
radVal = i * (TWOPI / TABLE_SIZE );
DrawUtil_SinTable[i] = fSin(radVal);
DrawUtil_CosTable[i] = fCos(radVal);
}
for (i = 0; i < 256; i ++)
{
radVal = i * (TWOPI / 256.0);
DrawUtil_ByteSinTable[i] = (int) (127.5 * (sin(radVal) + 1.0));
DrawUtil_ByteCosTable[i] = (int) (127.5 * (cos(radVal) + 1.0));
}
MakeHueRGBTable();
MakeNoise1d();
MakeNoise2d();
MakeNoise3d();
DidUtilInit = true;
}
//-------------------------------------------------------
ubyte HueRGBTable[768];
void MakeHueRGBTable(void)
{
int hue;
for(hue=0;hue<256;hue++)
{
int h,H,r,g,b;
H = (hue * 360)>>8;
h = 180 - (H % 60)*3;
switch( (H % 360)/60 )
{
case 0: r = 180; g = 180 - h;b = 0; break;
case 1: r = h; g = 180; b = 0; break;
case 2: r = 0; g = 180; b = 180 - h; break;
case 3: r = 0; g = h; b = 180; break;
case 4: r = 180 - h;g = 0; b = 180; break;
case 5: r = 180; g = 0; b = h; break;
}
HueRGBTable[hue*3 ] = r;
HueRGBTable[hue*3+1] = g;
HueRGBTable[hue*3+2] = b;
}
}
void DrawUtil_HueRGBFast(int H,uword *r,uword *g,uword *b)
{
H = (H & 0xFF) * 3;
*r = HueRGBTable[H ];
*g = HueRGBTable[H+1];
*b = HueRGBTable[H+2];
}
void DrawUtil_HueRGBSlow(int H,uword *pr,uword *pg,uword *pb)
{
int h;
h = 255 - (H & 0xFF);
switch( (H % (256*6))>>8 )
{
case 0: *pr = 255; *pg = 255 - h;*pb = 0; break;
case 1: *pr = h; *pg = 255; *pb = 0; break;
case 2: *pr = 0; *pg = 255; *pb = 255 - h; break;
case 3: *pr = 0; *pg = h; *pb = 255; break;
case 4: *pr = 255 - h; *pg = 0; *pb = 255; break;
case 5: *pr = 255; *pg = 0; *pb = h; break;
}
}
//------------------------------------------------------------------------
uword DrawUtil_MakePixel(int Mode,uword r,uword g,uword b)
{
switch(Mode)
{
case DRIVER_MODE_555:
return ((r>>3)<<10) | ((g>>3)<<5) | ((b>>3));
case DRIVER_MODE_565:
return ((r>>3)<<11) | ((g>>2)<<5) | ((b>>3));
default:
return 0;
}
}
void DrawUtil_DrawLine(Driver_Window * W,int x1,int y1,int x2,int y2,uword pixel)
{
int dx,dy,m16;
uword * pBuf;
uint Stride;
if ( ! DrawUtil_ClipSegI(W,&x1,&y1,&x2,&y2) )
return; //totally clipped away
assert( min(x1,x2) >= 0 );
assert( max(x1,x2) < (int)W->Width );
assert( min(y1,y2) >= 0 );
assert( max(y1,y2) < (int)W->Height );
pBuf = (uword *)W->Buffer;
Stride = W->Stride >>1;
if ( x2 < x1 )
{
swapints(x1,x2);
swapints(y1,y2);
}
dx = x2 - x1;
dy = y2 - y1;
if ( ABS(dx) > ABS(dy) )
{
int x,y16;
assert( dx > 0 );
m16 = (dy << 16)/dx;
y16 = (y1 << 16);
for(x=x1;x<=x2;x++)
{
pBuf[ x + (y16>>16)*Stride ] = pixel;
y16 += m16;
}
}
else
{
int y,x16;
assert( dy > 0 );
m16 = (dx << 16)/dy;
x16 = (x1 << 16);
for(y=y1;y<=y2;y++)
{
pBuf[ (x16>>16) + y*Stride ] = pixel;
x16 += m16;
}
}
}
/*
or = ((*ptr)>>10)<<3;
og = (((*ptr)>>5)&0x1F)<<3;
ob = ((*ptr)&0x1F)<<3;
r = (a16 * r + (65536 - a16) * or)>>16;
g = (a16 * g + (65536 - a16) * og)>>16;
b = (a16 * b + (65536 - a16) * ob)>>16;
assert( r <= 255 && g <= 255 && b <= 255 );
*ptr = ((r>>3)<<10) | ((g>>3)<<5) | ((b>>3));
*/
void INLINE blendpel555(uword *ptr,uint a16,uword r,uword g,uword b)
{
uword or,og,ob;
or = (*ptr)>>10;
og = ((*ptr)>>5)&0x1F;
ob = (*ptr)&0x1F;
r = (a16 * r + (65536 - a16) * or)>>16;
g = (a16 * g + (65536 - a16) * og)>>16;
b = (a16 * b + (65536 - a16) * ob)>>16;
assert( r <= 31 && g <= 31 && b <= 31 );
*ptr = (r<<10) | (g<<5) | b;
}
void INLINE blendpel565(uword *ptr,uint a16,uword r,uword g,uword b)
{
uword or,og,ob;
or = (*ptr)>>11;
og = ((*ptr)>>5)&0x3F;
ob = (*ptr)&0x1F;
r = (a16 * r + (65536 - a16) * or)>>16;
g = (a16 * g + (65536 - a16) * og)>>16;
b = (a16 * b + (65536 - a16) * ob)>>16;
assert( r <= 31 && g <= 63 && b <= 31 );
*ptr = (r<<11) | (g<<5) | b;
}
void shiftdowncolors(Driver_Window * W,uword *r,uword *g,uword *b)
{
switch(W->Mode)
{
case DRIVER_MODE_555:
*r >>= 3;
*g >>= 3;
*b >>= 3;
break;
case DRIVER_MODE_565:
*r >>= 3;
*g >>= 2;
*b >>= 3;
break;
}
}
void DrawUtil_DrawLineV(Driver_Window * W,const Vec2d *cv1,const Vec2d *cv2,uword r,uword g,uword b)
{
int m16;
uword * pBuf;
uint Stride;
Vec2d v1,v2;
v1 = *cv1;
v2 = *cv2;
if ( ! DrawUtil_ClipSegV(W,&v1,&v2) )
return; //totally clipped away
assert( min(v1.x,v2.x) >= 0 );
assert( max(v1.x,v2.x) < (int)W->Width );
assert( min(v1.y,v2.y) >= 0 );
assert( max(v1.y,v2.y) < (int)W->Height );
pBuf = (uword *)W->Buffer;
Stride = W->Stride >>1;
shiftdowncolors(W,&r,&g,&b);
// @@ could do horizontal anti-aliasing at the start & finish too
if ( ABS(v2.x - v1.x) > ABS(v2.y - v1.y) ) // mostly horizontal
{
int x,y16;
int ix1,ix2;
if ( v2.x < v1.x )
{
swapf(v1.x,v2.x);
swapf(v1.y,v2.y);
}
if ( v1.y >= (W->Height-1) ) v1.y--;
if ( v2.y >= (W->Height-1) ) v2.y--;
y16 = ftoi(v1.y * 65536.0f);
ix1 = ftoi(v1.x);
ix2 = ftoi(v2.x);
if ( ix1 == ix2 ) m16 = 0;
else m16 = ftoi(((v2.y - v1.y) * 65536.0f))/(ix2 - ix1);
switch(W->Mode)
{
case DRIVER_MODE_555:
for(x=ix1;x<=ix2;x++)
{
uint frac;
uword *ptr;
frac = y16 & 0xFFFF;
ptr = pBuf + x + (y16>>16)*Stride;
blendpel555(ptr,0xFFFF - frac,r,g,b);
blendpel555(ptr+Stride, frac,r,g,b);
y16 += m16;
}
break;
case DRIVER_MODE_565:
for(x=ix1;x<=ix2;x++)
{
uint frac;
uword *ptr;
frac = y16 & 0xFFFF;
ptr = pBuf + x + (y16>>16)*Stride;
blendpel565(ptr,0xFFFF - frac,r,g,b);
blendpel565(ptr+Stride, frac,r,g,b);
y16 += m16;
}
break;
}
}
else // mostly vertical
{
int y,x16;
int iy1,iy2;
if ( v2.y < v1.y )
{
swapf(v1.y,v2.y);
swapf(v1.x,v2.x);
}
if ( v1.x >= (W->Width-1) ) v1.x--;
if ( v2.x >= (W->Width-1) ) v2.x--;
x16 = ftoi(v1.x * 65536.0f);
iy1 = ftoi(v1.y);
iy2 = ftoi(v2.y);
if ( iy1 == iy2 ) m16 = 0;
else m16 = ftoi(((v2.x - v1.x) * 65536.0f))/(iy2 - iy1);
switch(W->Mode)
{
case DRIVER_MODE_555:
for(y=iy1;y<=iy2;y++)
{
uint frac;
uword *ptr;
frac = x16 & 0xFFFF;
ptr = pBuf + y*Stride + (x16>>16);
blendpel555(ptr ,0xFFFF - frac,r,g,b);
blendpel555(ptr+1, frac,r,g,b);
x16 += m16;
}
break;
case DRIVER_MODE_565:
for(y=iy1;y<=iy2;y++)
{
uint frac;
uword *ptr;
frac = x16 & 0xFFFF;
ptr = pBuf + y*Stride + (x16>>16);
blendpel565(ptr ,0xFFFF - frac,r,g,b);
blendpel565(ptr+1, frac,r,g,b);
x16 += m16;
}
break;
}
}
}
void DrawUtil_DrawLineAA(Driver_Window * W,int x1,int y1,int x2,int y2,uword r,uword g,uword b)
{
int dx,dy,m16;
uword * pBuf;
uint Stride;
if ( ! DrawUtil_ClipSegI(W,&x1,&y1,&x2,&y2) )
return; //totally clipped away
assert( min(x1,x2) >= 0 );
assert( max(x1,x2) < (int)W->Width );
assert( min(y1,y2) >= 0 );
assert( max(y1,y2) < (int)W->Height );
pBuf = (uword *)W->Buffer;
Stride = W->Stride >>1;
dx = x2 - x1;
dy = y2 - y1;
shiftdowncolors(W,&r,&g,&b);
if ( ABS(dx) > ABS(dy) ) // mostly horizontal
{
int x,y16;
if ( dx == 0 ) return;
if ( x2 < x1 )
{
swapints(x1,x2);
swapints(y1,y2);
}
if ( y1 == (int)(W->Height-1) ) y1--;
if ( y2 == (int)(W->Height-1) ) y2--;
dx = x2 - x1;
dy = y2 - y1;
m16 = (dy<<16)/dx;
y16 = (y1 << 16);
switch(W->Mode)
{
case DRIVER_MODE_555:
for(x=x1;x<=x2;x++)
{
uint frac;
uword *ptr;
frac = y16 & 0xFFFF;
ptr = pBuf + x + (y16>>16)*Stride;
blendpel555(ptr,0xFFFF - frac,r,g,b);
blendpel555(ptr+Stride, frac,r,g,b);
y16 += m16;
}
break;
case DRIVER_MODE_565:
for(x=x1;x<=x2;x++)
{
uint frac;
uword *ptr;
frac = y16 & 0xFFFF;
ptr = pBuf + x + (y16>>16)*Stride;
blendpel565(ptr,0xFFFF - frac,r,g,b);
blendpel565(ptr+Stride, frac,r,g,b);
y16 += m16;
}
break;
}
}
else // mostly vertical
{
int y,x16;
if ( dy == 0 ) return;
if ( y2 < y1 )
{
swapints(x1,x2);
swapints(y1,y2);
}
if ( x1 == (int)(W->Width-1) ) x1--;
if ( x2 == (int)(W->Width-1) ) x2--;
dx = x2 - x1;
dy = y2 - y1;
m16 = (dx<<16)/dy;
x16 = (x1 << 16);
switch(W->Mode)
{
case DRIVER_MODE_555:
for(y=y1;y<=y2;y++)
{
uint frac;
uword *ptr;
frac = x16 & 0xFFFF;
ptr = pBuf + y*Stride + (x16>>16);
blendpel555(ptr ,0xFFFF - frac,r,g,b);
blendpel555(ptr+1, frac,r,g,b);
x16 += m16;
}
break;
case DRIVER_MODE_565:
for(y=y1;y<=y2;y++)
{
uint frac;
uword *ptr;
frac = x16 & 0xFFFF;
ptr = pBuf + y*Stride + (x16>>16);
blendpel565(ptr ,0xFFFF - frac,r,g,b);
blendpel565(ptr+1, frac,r,g,b);
x16 += m16;
}
break;
}
}
}
bool DrawUtil_ClipPoint(const Driver_Window * pWindow,float *px,float *py)
{
bool clipped = false;
if ( *px < 1.0f )
{
*px = 0.5f;
clipped = true;
}
else if ( *px > (pWindow->Width-2) )
{
*px = pWindow->Width-1.5f;
clipped = true;
}
if ( *py < 1.0f )
{
*py = 0.5f;
clipped = true;
}
else if ( *py > (pWindow->Height-2) )
{
*py = pWindow->Height-1.5f;
clipped = true;
}
return clipped;
}
bool DrawUtil_ClipSegI(const Driver_Window * W,int *px1,int *py1,int *px2,int *py2)
{
float x1,y1,x2,y2,m;
x1 = *px1; y1 = *py1;
x2 = *px2; y2 = *py2;
if ( x1 > x2 )
{
swapf(x1,x2);
swapf(y1,y2);
}
m = (y2 - y1)/(x2 - x1);
if ( x1 < 0.0f )
{
// clip against the left
if ( x2 <= 0.0f )
return false;
y1 += m * ABS(x1);
x1 = 0.0f;
}
if ( x2 >= W->Width-1 )
{
// clip right
if ( x1 >= W->Width-1 )
return false;
y2 -= m * (x2 - (W->Width-1));
x2 = W->Width-1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -