
#help_index "Graphics/Bitmaps;Graphics/Screen"
public GrBitMap *gr_screen_image; //This is read only
#help_index "Graphics/Bitmaps"
public GrBitMap *grbase; //This is updated every refresh
GrBitMap *gr_scaled_base;
U2 *gr_textbase_cache;
void GrClear2(GrBitMap *base)
{
switch (base->type) {
case BMT_COLOR4:
MemSet(base->body,0,(base->width_internal*base->height)>>1);
break;
case BMT_COLOR4_U1:
MemSet(base->body,0,base->width_internal*base->height);
break;
case BMT_MONO:
MemSet(base->body,0,(base->width_internal*base->height)>>3);
break;
}
if (base->mask)
GrClear2(base->mask);
}
public void GrClear(GrBitMap *base=NULL)
{
if (!base)
GrClear2(Gs->grbase);
else
GrClear2(base);
}
#help_index "Graphics/Char;Char"
public void FillWinText(TssStruct *tss,U8 d)
{
I8 x,y;
if (!tss) tss=Fs;
I8 t= tss->win_top>0
? tss->win_top : 0,
b= tss->win_bottom<TEXT_ROWS
? tss->win_bottom : TEXT_ROWS-1,
l= tss->win_left>0
? tss->win_left : 0,
r= tss->win_right<TEXT_COLS
? tss->win_right : TEXT_COLS-1;
U4 *ptr;
for (y=t;y<=b;y++) {
ptr=textbase><(U1 *)+(y*TEXT_COLS+l)*4;
for (x=l;x<=r;x++)
*ptr++=d;
}
}
public void ClearWinText(TssStruct *tss=NULL)
{
if (!tss) tss=Fs;
FillWinText(tss,tss->text_attr<<8);
}
public void SetWinBkColor(TssStruct *tss,U8 c)
{
if (!tss) tss=Fs;
tss->text_attr=tss->text_attr&0x0F | c<<4;
FillWinText(tss,c<<12);
}
#help_index "Graphics/Screen"
I4 gr_table[1024];
public I4 gr_rainbow_10[10]=
{
BLACK,BROWN,RED,LTRED,YELLOW,
GREEN,BLUE,PURPLE,LTGRAY,WHITE
};
LoadList("ST_RAINBOW_10",
"BLACK\0BROWN\0RED\0LTRED\0YELLOW\0"
"GREEN\0BLUE\0PURPLE\0LTGRAY\0WHITE\0");
#define GR_NUM_PEN_BRUSHES 64
GrBitMap *gr_pen_brushes[GR_NUM_PEN_BRUSHES];
#define GR_MAX_SCREEN_SCALE 8
U1 *gr_screen_scale_tables[GR_MAX_SCREEN_SCALE+1];
I8 gr_screen_scale=1,grsx=0,grsy=0;
//When zoomed, this keeps the mouse centered.
public BoolI1 gr_continuous_scroll=FALSE;
#define GR_REFRESH_LOG_CNT 16
U8 gr_refresh_time_stamps[GR_REFRESH_LOG_CNT],gr_refresh_ts_ptr=0;
void GrSetupTable(GrBitMap *hidden)
{
GrBitMap *b;
I8 i,j,k,l,m,x,y,rr;
U1 *dst;
for (i=-16;i<16;i++) {
for (j=-16;j<16;j++) {
k=(i>=0 ? i:32+i)<<5+(j>=0 ? j:32+j);
gr_table[k]=(i*hidden->width_internal+j)>>3;
}
}
for (i=0;i<GR_NUM_PEN_BRUSHES;i++) {
k=i+1;
j=(i+7)&~7;
b=GrNew(BMT_MONO,i,i);
// b=GrNew(BMT_MONO,j,i);
gr_pen_brushes[i]=b;
b->color=WHITE;
rr=k*k;
for (y=1;y<k;y++)
for (x=1;x<k;x++)
if (SqrI8(y*2-k)+SqrI8(x*2-k)<rr)
GrPlot0(b,x-1,y-1);
}
if (text_mode) {
MemSet(0xB8000,0,TEXT_ROWS*TEXT_COLS*2);
MemSet(gr_textbase_cache,0,TEXT_ROWS*TEXT_COLS*2);
} else {
OutP(VGA_SC_INDEX,VGA_MAP_MASK);
OutP(VGA_SC_DATA,0x0F);
MemSet(0xA0000,0,GR_HEIGHT*GR_WIDTH>>3);
MemSet(gr_screen_image->body,0,GR_WIDTH*GR_HEIGHT>>1);
}
for (i=1;i<=GR_MAX_SCREEN_SCALE;i++) {
dst=gr_screen_scale_tables[i]=MAlloc(256*i);
for (j=0;j<256;j++) {
m=0;
for (k=0;k<8;k++) {
if (Bt(&j,k)) {
for (l=0;l<i;l++)
Bts(&m,l+k*i);
}
}
for (l=0;l<i;l++)
dst[j+l*256]=m.u1[l];
}
}
for (i=0;i<GR_REFRESH_LOG_CNT;i++)
gr_refresh_time_stamps[i]=GetTimeStamp;
}
void GrInitCPU(CPUCachedStruct *c)
{ //Gets called from $LK,"GrInitCPU","FF:::/LT/OSMain/Cmd.CPZ,GrInitCPU"$
c->grbase=GrNew(BMT_COLOR4,GR_WIDTH,GR_HEIGHT);
c->grbase->flags|=BMF_SCREEN_BITMAP;
c->grbase->mask=GrNew(BMT_MONO,GR_WIDTH,GR_HEIGHT);
c->grbase->mask->flags|=BMF_SCREEN_BITMAP;
c->grbase->mask->color=WHITE;
GrClear2(c->grbase);
}
void GrInitGraphics()
{
textbase=MAlloc(GR_WIDTH/FONT_WIDTH*(GR_HEIGHT/FONT_HEIGHT)<<2);
gr_textbase_cache=MAlloc(TEXT_ROWS*TEXT_COLS*2);
grbase=GrNew(BMT_COLOR4,GR_WIDTH+128,GR_HEIGHT+32);
grbase->left_margin=64;
grbase->right_margin=GR_WIDTH+grbase->left_margin;
grbase->top_margin=16;
grbase->bottom_margin=GR_HEIGHT+grbase->top_margin;
grbase->flags|=BMF_SCREEN_BITMAP;
gr_screen_image=GrNew(BMT_COLOR4,GR_WIDTH,GR_HEIGHT);
gr_scaled_base=GrNew(BMT_COLOR4,GR_WIDTH,GR_HEIGHT);
gr_scaled_base->flags|=BMF_SCREEN_BITMAP;
GrInitCPU(Gs);
GrSetupTable(grbase);
}
U8 gr_win_updates=0;
void GrUpdateWins()
{
I8 i;
TssStruct *tss,*tss1;
GrBitMap *base;
refresh_ode_time=0;
try {
for (i=0;i<mp_cnt;i++) {
if (i)
tss=cpu_cached[i].seth_tss;
else
tss=Fs;
tss1=tss;
do {
if (!ValidateTss(tss))
break;
sys_task_being_screen_updated=tss;
UpdateOdes(tss);
if (!ValidateTss(tss))
break;
if (Bt(&tss->display_flags,DISPLAYf_SHOW)) {
if (!Bt(&tss->display_flags,DISPLAYf_NO_BORDER))
DrawTaskBorder(tss);
ClearWinText(tss);
if (tss->update_win)
tss->update_win(tss);
if (tss->draw_it) {
base=GrAlias(grbase,tss);
tss->draw_it(tss,base);
GrDel(base);
}
if (!ValidateTss(tss))
break;
DrawCtrls(tss);
}
if (!ValidateTss(tss))
break;
tss=tss->next_tss;
} while (tss!=tss1);
}
} catch
Debugger;
last_refresh_ode_time=refresh_ode_time;
sys_task_being_screen_updated=NULL;
gr_refresh_time_stamps[gr_refresh_ts_ptr++&(GR_REFRESH_LOG_CNT-1)]=GetTimeStamp;
win_actual_refresh=(GR_REFRESH_LOG_CNT-1)*time_stamp_freq/
(gr_refresh_time_stamps[(gr_refresh_ts_ptr-1)&(GR_REFRESH_LOG_CNT-1)]-
gr_refresh_time_stamps[gr_refresh_ts_ptr&(GR_REFRESH_LOG_CNT-1)]);
gr_win_updates++;
}
void GrMergePersistentLayers()
{
U8 reg *mask_ptr,reg *m_dst,reg *m_src;
U8 i,reg j,row,reg col,plane,
d0=Gs->grbase->width_internal>>6,
d1=(grbase->width_internal*grbase->top_margin)>>6;
for (i=0;i<mp_cnt;i++) {
m_src=cpu_cached[i].grbase->body;
m_dst=grbase->body;
for (plane=1;plane<0x10;plane<<=1) {
mask_ptr=cpu_cached[i].grbase->mask->body;
m_dst+=d1;
for (row=0;row<Gs->grbase->height;row++) {
m_dst++;
for (col=0;col<d0;col++) {
if (j=*mask_ptr)
*m_dst=*m_dst&~j|*m_src&j;
m_dst++;
mask_ptr++;
m_src++;
}
m_dst++;
}
m_dst+=d1;
}
}
}
void GrFixScale()
{
gr_screen_scale=LimitI8(gr_screen_scale,1,GR_MAX_SCREEN_SCALE);
if (gr_screen_scale==1) {
grsx=0;
grsy=0;
} else {
grsx=LimitI8(grsx,0,GR_WIDTH-GR_WIDTH/gr_screen_scale)&~7;
grsy=LimitI8(grsy,0,GR_HEIGHT-GR_HEIGHT/gr_screen_scale);
}
}
public void GrScaleZoom(double scale)
{
BoolI1 old_preempt=Preempt(OFF);
double s=gr_screen_scale;
gr_screen_scale=gr_screen_scale*scale;
GrFixScale;
s/=gr_screen_scale;
ipx_scale*=s;
ipy_scale*=s;
ipz_scale*=s;
ipx_offset=ipx-(ipx-ipx_offset)*s;
ipy_offset=ipy-(ipy-ipy_offset)*s;
ipz_offset=ipz-(ipz-ipz_offset)*s;
grsx=ipx-gr_scaled_base->width >>1/gr_screen_scale;
grsy=ipy-gr_scaled_base->height>>1/gr_screen_scale;
GrFixScale;
Preempt(old_preempt);
}
public void GrZoomIn()
{
GrScaleZoom(2.0);
}
public void GrZoomOut()
{
GrScaleZoom(0.5);
}
void CtrlAltZ(U8 sc)
{
if (sc&SCF_SHIFT)
GrZoomOut;
else
GrZoomIn;
}
SetCtrlAltLetterRoutine('Z',&CtrlAltZ,"Sys/Zoom In or Out");
void GrScaleImage()
{
GrFixScale;
I8 plane,row,col,k,l,
d1=(grbase->width_internal*grbase->top_margin)>>3,
d2=gr_scaled_base->width>>3/gr_screen_scale,
d4=gr_scaled_base->width_internal>>3,
d5=d4-d2*gr_screen_scale,
d3=gr_scaled_base->height/gr_screen_scale,
d6=(gr_scaled_base->height-d3)*grbase->width_internal>>3,
d7=gr_scaled_base->height%gr_screen_scale*d4;
U1 *src,*src2,*dst,*src3,*map=gr_screen_scale_tables[gr_screen_scale];
src=grbase->body+grsx>>3+grsy*grbase->width_internal>>3;
dst=gr_scaled_base->body;
for (plane=1;plane<0x10;plane<<=1) {
src+=d1;
for (row=0;row<d3;row++) {
src+=64>>3;
for (k=1;k<=gr_screen_scale;k++) {
src2=src;
for (col=0;col<d2;col++) {
src3=&map[*src2++];
for (l=1;l<=gr_screen_scale;l++) {
*dst++=*src3;
src3+=256;
}
}
for (l=0;l<d5;l++)
*dst++=0;
}
src+=d4+64>>3;
}
for (l=0;l<d7;l++)
*dst++=0;
src+=d1+d6;
}
}
void GrUpdateBackgroundOfText()
{
U8 d1=grbase->width_internal>>3,
d2=(grbase->width_internal*grbase->height-FONT_HEIGHT*grbase->width)>>3,
d4=(grbase->width_internal*FONT_HEIGHT-Gs->grbase->width)>>3,
d7=1-(grbase->width_internal*grbase->height<<2)>>3;
U8 row,col;
U4 *src,cur_ch;
U1 *dst;
BoolI1 blink_flag=Blink;
src=textbase;
dst=grbase->body+(grbase->width_internal*grbase->top_margin+grbase->left_margin)>>3;
for (row=0;row<TEXT_ROWS;row++) {
for (col=0;col<TEXT_COLS;col++) {
cur_ch=*src++;
if (cur_ch & (LTFLT_SELECTED | LTFLT_INVERT | LTFLT_BLINK)) {
if (cur_ch & LTFLT_SELECTED)
cur_ch.u1[1]=cur_ch.u1[1]^0xFF;
if (cur_ch & LTFLT_INVERT)
cur_ch.u1[1]=cur_ch.u1[1]<<4+cur_ch.u1[1]>>4;
if (cur_ch & LTFLT_BLINK)
if (blink_flag)
cur_ch.u1[1]= cur_ch.u1[1]<<4+ cur_ch.u1[1]>>4;
}
GrPlotBackground(cur_ch.u1[1],&dst,d1,d2);
dst+=d7;
}
dst+=d4;
}
}
$AN,"ExtScanCodes","ExtScanCodes"$
// Bits 0-7 ASCII (Screen Code)
// Bits 8-11 Foreground color
// Bits 12-15 Background color
// Bits 16-20 Signed X position shift value
// Bits 21-25 Signed Y position shift value
// Bit 28 Blink
// Bit 29 Inverted (Swap foreground and background)
// Bit 30 Selected (XOR colors with FF)
// Bit 31 Underline
void GrUpdateForegroundOfText()
{
U4 *src;
U8 u,cur_ch,row,col,plane,ch_line,i,
d1=grbase->width_internal>>3,
d2=(grbase->width_internal*grbase->height-FONT_HEIGHT*grbase->width)>>3,
d4=(grbase->width_internal*FONT_HEIGHT-Gs->grbase->width)>>3;
U2 *dst2;
U1 *dst,*font_ptr,*font_ptr2,saved_font_line;
BoolI1 blink_flag=Blink,skip_space;
font_ptr=&grfont[FONT_WIDTH*FONT_HEIGHT>>3*CH_SPACE];
skip_space=TRUE;
for (row=0;row<FONT_HEIGHT;row++)
if (font_ptr[row]) {
skip_space=FALSE;
break;
}
src=textbase;
dst=grbase->body+(grbase->width_internal*grbase->top_margin+grbase->left_margin)>>3;
for (row=0;row<TEXT_ROWS;row++) {
for (col=0;col<TEXT_COLS;col++) {
cur_ch=*src++;
if (cur_ch & (LTFLT_UNDERLINE | LTFLT_SELECTED | LTFLT_INVERT | LTFLT_BLINK)) {
if (cur_ch & LTFLT_SELECTED)
cur_ch.u1[1]=cur_ch.u1[1]^0xFF;
if (cur_ch & LTFLT_INVERT)
cur_ch.u1[1]=cur_ch.u1[1]<<4+cur_ch.u1[1]>>4;
if (cur_ch & LTFLT_BLINK)
if (blink_flag)
cur_ch.u1[1]= cur_ch.u1[1]<<4+cur_ch.u1[1]>>4;
} else
if (!cur_ch.u1[0] || skip_space && cur_ch.u1[0]==CH_SPACE)
goto skip_char;
font_ptr=&grfont[FONT_WIDTH*FONT_HEIGHT>>3*cur_ch.u1[0]];
if (cur_ch & LTFLT_UNDERLINE) {
saved_font_line=font_ptr[7];
font_ptr[7]=0xFF;
}
i=cur_ch.u2[1]&0x3FF;
dst2=dst+gr_table[i];
if (i) {
i&=7;
for (plane=0x01;plane!=0x10;plane<<=1) {
font_ptr2=font_ptr;
if (cur_ch.u1[1] & plane) {
for (ch_line=0;ch_line<FONT_HEIGHT;ch_line++) {
u=*font_ptr2++<<i;
*dst2|=u.u2[0] | u.u2[1];
dst2><(U1 *)+=d1;
}
} else {
for (ch_line=0;ch_line<FONT_HEIGHT;ch_line++) {
u=*font_ptr2++<<i;
*dst2&=~(u.u2[0] | u.u2[1]);
dst2><(U1 *)+=d1;
}
}
dst2><(U1 *)+=d2;
}
} else
GrPlotChar(font_ptr,cur_ch.u1[1],&dst2,d1,d2);
if (cur_ch & LTFLT_UNDERLINE)
font_ptr[7]=saved_font_line;
skip_char:
dst++;
}
dst+=d4;
}
}
void GrUpdateTextModeText()
{
U4 *src=textbase;
U8 cur_ch,i,d0=TEXT_COLS*TEXT_ROWS;
U2 *dst=0xB8000,*dst2=gr_textbase_cache;
BoolI1 blink_flag=Blink;
if (LBtr(&sys_semas[SYS_SEMA_FLUSH_VGA_IMAGE],0)) {
for (i=0;i<d0;i++) {
cur_ch=*src++;
if (cur_ch & LTFLT_SELECTED)
cur_ch.u1[1]=cur_ch.u1[1]^0xFF;
if (cur_ch & LTFLT_INVERT)
cur_ch.u1[1]=cur_ch.u1[1]<<4+cur_ch.u1[1]>>4;
if (cur_ch & LTFLT_BLINK)
if (blink_flag)
cur_ch.u1[1]= cur_ch.u1[1]<<4+ cur_ch.u1[1]>>4;
cur_ch&=0x7FFF;
*dst++=*dst2++=cur_ch;
}
} else {
for (i=0;i<d0;i++) {
cur_ch=*src++;
if (cur_ch & LTFLT_SELECTED)
cur_ch.u1[1]=cur_ch.u1[1]^0xFF;
if (cur_ch & LTFLT_INVERT)
cur_ch.u1[1]=cur_ch.u1[1]<<4+cur_ch.u1[1]>>4;
if (cur_ch & LTFLT_BLINK)
if (blink_flag)
cur_ch.u1[1]= cur_ch.u1[1]<<4+ cur_ch.u1[1]>>4;
cur_ch&=0x7FFF;
if (*dst2!=cur_ch)
*dst++=*dst2++=cur_ch;
else {
dst++;
dst2++;
}
}
}
}
void GrUpdateVGAGraphics()
{
U8 row,plane,d0,d1,
d2=gr_scaled_base->width_internal>>6;
U4 *src,*dst,*dst2;
//Update Graphic Card
if (gr_screen_scale==1) {
src=grbase->body;
d1=(grbase->width_internal*grbase->top_margin)>>5,
d0=64>>5;
} else {
GrScaleImage;
src=gr_scaled_base->body;
d1=0;
d0=0;
}
dst2=gr_screen_image->body;
if (LBtr(&sys_semas[SYS_SEMA_FLUSH_VGA_IMAGE],0)) {
for (plane=1;plane<0x10;plane<<=1) {
OutP(VGA_SC_INDEX,VGA_MAP_MASK);
OutP(VGA_SC_DATA,plane);
dst=0xA0000;
src+=d1;
for (row=0;row<gr_scaled_base->height;row++) {
src+=d0;
GrUpdateLineU8FlushCache(&dst,&src,d2,&dst2);
src+=d0;
}
src+=d1;
}
} else {
for (plane=1;plane<0x10;plane<<=1) {
OutP(VGA_SC_INDEX,VGA_MAP_MASK);
OutP(VGA_SC_DATA,plane);
dst=0xA0000;
src+=d1;
for (row=0;row<gr_scaled_base->height;row++) {
src+=d0;
GrUpdateLineU8(&dst,&src,d2,&dst2);
src+=d0;
}
src+=d1;
}
}
}
void GrUpdateScreen()
{
GrBitMap *base;
BoolI1 old_preempt=Preempt(ON);
if (text_mode)
GrUpdateWins;
else {
GrUpdateBackgroundOfText;
GrUpdateForegroundOfText;
GrUpdateWins;
GrMergePersistentLayers;
}
base=GrAlias(grbase,Fs);
base->flags|=BMF_ON_TOP;
CallExtNum(EXT_FINAL_SCREEN_UPDATE,base);
GrDel(base);
if (text_mode)
GrUpdateTextModeText;
else
GrUpdateVGAGraphics;
Preempt(old_preempt);
}
#help_index "Graphics"
Graphics to Screen