ZealOS/Adam/Gr/GrDC.HC
2020-02-15 14:01:48 -06:00

434 lines
11 KiB
HolyC
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#help_index "Graphics/Math/3D Transformation"
#help_file "::/Doc/Transform"
#define GR_SCALE (1<<32)
public U0 Mat4x4MulXYZ(I64 *r,I64 *_x,I64 *_y,I64 *_z)
{//Rotate 3D point using 4x4 matrix. Uses $LK,"fixed-point",A="FI:::/Demo/Lectures/FixedPoint.HC"$.
I64 x1,y1,z1,xx=*_x,yy=*_y,zz=*_z;
x1=(r[0*4+0]*xx+r[0*4+1]*yy+r[0*4+2]*zz+r[0*4+3])>>32;
y1=(r[1*4+0]*xx+r[1*4+1]*yy+r[1*4+2]*zz+r[1*4+3])>>32;
z1=(r[2*4+0]*xx+r[2*4+1]*yy+r[2*4+2]*zz+r[2*4+3])>>32;
*_x=x1;*_y=y1;*_z=z1;
}
public U0 DCTransform(CDC *dc,I64 *_x,I64 *_y,I64 *_z)
{//This is the dft dc->transform() callback.
//Uses $LK,"fixed-point",A="FI:::/Demo/Lectures/FixedPoint.HC"$.
Mat4x4MulXYZ(dc->r,_x,_y,_z);
*_x+=dc->x;
*_y+=dc->y;
*_z+=dc->z;
}
public I64 *Mat4x4IdentEqu(I64 *r)
{//Set matrix to identity. Uses $LK,"fixed-point",A="FI:::/Demo/Lectures/FixedPoint.HC"$.
MemSet(r,0,sizeof(I64)*16);
r[0*4+0].i32[1]=1;
r[1*4+1].i32[1]=1;
r[2*4+2].i32[1]=1;
r[3*4+3].i32[1]=1;
return r;
}
public I64 *Mat4x4IdentNew(CTask *mem_task=NULL)
{//MAlloc an identity matrix. Uses $LK,"fixed-point",A="FI:::/Demo/Lectures/FixedPoint.HC"$.
return Mat4x4IdentEqu(MAlloc(sizeof(I64)*16,mem_task));
}
public I64 Mat4x4NormSqr65536(I64 *r)
{//Norm Squared of r.
//(1.0/Sqrt(3))*65536=37837.22
return SqrI64((r[0*4+0]*37838+r[0*4+1]*37838+r[0*4+2]*37838)>>32)+
SqrI64((r[1*4+0]*37837+r[1*4+1]*37837+r[1*4+2]*37837)>>32)+
SqrI64((r[2*4+0]*37837+r[2*4+1]*37837+r[2*4+2]*37837)>>32);
}
public U0 DCMat4x4Set(CDC *dc=NULL,I64 *r)
{//Set device context's rot matrix. Will be $LK,"Free",A="MN:Free"$d() in $LK,"DCDel",A="MN:DCDel"$().Uses $LK,"fixed-point",A="FI:::/Demo/Lectures/FixedPoint.HC"$.
//The main purpose is to set matrix norm for thick scaling.
//NULL as dc means gr.dc
if (!dc) dc=gr.dc;
dc->r=r;
dc->r_norm=Sqrt(Mat4x4NormSqr65536(r))*65536; //scaled 32 bits
}
#help_index "Graphics/Mesh"
public U0 DCLighting(CDC *dc,
CD3I32 *p1,CD3I32 *p2,CD3I32 *p3,CColorROPU32 color)
{//This is the dft dc->lighting() callback.
CD3I32 v1,v2;
I64 i,vn_x,vn_y,vn_z;
F64 d;
v1.x=p1->x-p2->x;
v1.y=p1->y-p2->y;
v1.z=p1->z-p2->z;
v2.x=p3->x-p2->x;
v2.y=p3->y-p2->y;
v2.z=p3->z-p2->z;
//V1 and V2 are vects along two sides
//of the tri joined at p2.
vn_x=v1.y*v2.z-v1.z*v2.y;
vn_y=v1.z*v2.x-v1.x*v2.z;
vn_z=v1.x*v2.y-v1.y*v2.x;
if (d=Sqrt(SqrI64(vn_x)+SqrI64(vn_y)+SqrI64(vn_z)))
d=1<<16/d;
vn_x*=d;
vn_y*=d;
vn_z*=d;
//Vn is the cross product of V1 and V3
//which means it is perpendicular.It
//is the normal vect to the surface.
//It has been scaled to length 65536.
//Light source has been scaled to length 65536.
i=(vn_x*dc->ls.x+vn_y*dc->ls.y+vn_z*dc->ls.z)>>16;
//The dot product of the light source
//vect and the surface normal
//gives an illumination number.
//65536*65536>>16=65536
//TempleOS will generate a random U16
//and compare to dither_probability_u16 and
//will pick from two colors.
//Probability dithering does not work with thick>1 at this time.
if (color.c0.rop&ROPBF_TWO_SIDED) {
color.c0.rop&=~ROPBF_TWO_SIDED;
i=AbsI64(i)<<1;
} else
i+=65536;
if (color.c0.rop&ROPBF_HALF_RANGE_COLOR) {
color.c0.rop&=~ROPBF_HALF_RANGE_COLOR;
i>>=1;
if (color>=8) {
color-=8;
i+=65536;
}
}
if (i<65536) {
dc->color=ROPF_PROBABILITY_DITHER+color<<16+BLACK;
dc->dither_probability_u16=i;
} else {
dc->color=ROPF_PROBABILITY_DITHER+(color^8)<<16+color;
dc->dither_probability_u16=i-65536;
}
}
#help_index "Graphics/Device Contexts"
public U0 DCFill(CDC *dc=NULL,CColorROPU32 val=TRANSPARENT)
{//Fill entire device context with color.
if (!dc) dc=gr.dc;
MemSet(dc->body,val,dc->width_internal*dc->height);
}
public U0 DCClear(CDC *dc=NULL)
{//Set entire device context image body to 0 (BLACK).
if (!dc) dc=gr.dc;
DCFill(dc,0);
}
public U0 DCRst(CDC *dc)
{//Reset $LK,"CDC",A="MN:CDC"$ structure members but not image body, itself.
dc->color=BLACK;
dc->color2=BLACK;
dc->bkcolor=BLACK;
dc->collision_cnt=0;
dc->thick=1;
dc->ls.x=37837; //1<<16/Sqrt(3)
dc->ls.y=37837;
dc->ls.z=37837;
dc->x=0;
dc->y=0;
dc->z=0;
dc->transform=&DCTransform;
dc->lighting =&DCLighting;
Mat4x4IdentEqu(dc->r);
dc->r_norm=GR_SCALE;
dc->flags&=~(DCF_SYMMETRY|DCF_TRANSFORMATION|DCF_JUST_MIRROR);
MemCpy(dc->palette,gr_palette_std,sizeof(CBGR48)*COLORS_NUM);
}
public U0 DCExtentsInit(CDC *dc=NULL)
{//Init markers for extent of next newly drawn graphics.
//NULL means gr.dc
//See $LK,"::/Demo/Graphics/Extents.HC"$
//You should clear the record flag yourself
if (!dc) dc=gr.dc;
dc->flags|=DCF_RECORD_EXTENTS;
dc->min_x=I64_MAX;
dc->max_x=I64_MIN;
dc->min_y=I64_MAX;
dc->max_y=I64_MIN;
}
public CDC *DCAlias(CDC *dc=NULL,CTask *task=NULL)
{//Create alias of dc, so can change pen, color, etc.
//NULL means gr.dc
CDC *res;
if (!dc) dc=gr.dc;
if (!task) task=Fs;
if (dc->dc_signature!=DCS_SIGNATURE_VAL)
throw('Graphics');
res=MAlloc(sizeof(CDC),task);
MemCpy(res,dc,sizeof(CDC));
res->win_task=res->mem_task=task;
res->r=MAlloc(16*sizeof(I64),task);
DCRst(res);
res->flags|=DCF_ALIAS;
res->alias=dc;
return res;
}
public CDC *DCNew(I64 width,I64 height,CTask *task=NULL,Bool null_bitmap=FALSE)
{//Create new width x height device context.
//Internally only allows widths which are divisible by 8.
//Don't forget these $MA-X+PU,"sizeof(CDC)",LM="Find(\"sizeof(CDC)\",\"/*\");View;"$.
CDC *res;
if (!task) task=Fs;
res=CAlloc(sizeof(CDC),task);
res->win_task=task;
res->mem_task=task;
res->width=width;
res->width_internal=(width+7)&~7;
res->height=height;
if (null_bitmap)
res->flags|=DCF_DONT_DRAW;
else
res->body=CAlloc(res->width_internal*res->height,task);
res->r=MAlloc(16*sizeof(I64),task);
DCRst(res);
res->dc_signature=DCS_SIGNATURE_VAL;
return res;
}
public U0 DCDel(CDC *dc)
{//Free dc, image body, rot mat and depth buf.
if (!dc) return;
if (dc->dc_signature!=DCS_SIGNATURE_VAL)
throw('Graphics');
dc->dc_signature=0;
Free(dc->r);
if (!(dc->flags & DCF_ALIAS))
Free(dc->body);
Free(dc->depth_buf);
Free(dc);
}
public I64 DCSize(CDC *dc)
{//Mem size of header, image body and depth buffer.
if (dc)
return MSize2(dc)+MSize2(dc->body)+MSize2(dc->depth_buf);
else
return 0;
}
public I32 *DCDepthBufRst(CDC *dc)
{//Reset device context depth buf to far away.
if (dc->depth_buf)
MemSetU32(dc->depth_buf,I32_MAX,dc->width_internal*dc->height);
return dc->depth_buf;
}
public I32 *DCDepthBufAlloc(CDC *dc)
{//Alloc a 32-bit depth buffer for device context.
Free(dc->depth_buf);
dc->depth_buf=MAlloc(dc->width_internal*dc->height*sizeof(I32),dc->mem_task);
return DCDepthBufRst(dc);
}
public CDC *DCCopy(CDC *dc,CTask *task=NULL)
{//Alloc copy of dc, including image body, rot mat and depth buf.
CDC *res;
if (!dc) return NULL;
if (dc->dc_signature!=DCS_SIGNATURE_VAL)
throw('Graphics');
res=MAllocIdent(dc,task);
DCMat4x4Set(res,Mat4x4New(dc->r,task));
res->mem_task=task;
res->body=MAllocIdent(dc->body,task);
res->depth_buf=MAllocIdent(dc->depth_buf,task);
return res;
}
public U0 DCMono(CDC *dc,
I64 quest=TRANSPARENT,I64 true_color=0,I64 false_color=COLOR_MONO)
{//Set entire device context to one of two colors.
I64 i;
U8 *dst;
dst=dc->body;
i=dc->width_internal*dc->height;
while (i--)
if (*dst==quest)
*dst++=true_color;
else
*dst++=false_color;
}
public I64 DCColorChg(CDC *dc,I64 src_color,I64 dst_color=TRANSPARENT)
{//Find and replace src color with dst in device context.
I64 i,res=0;
U8 *dst;
dst=dc->body;
i=dc->width_internal*dc->height;
while (i--)
if (*dst==src_color) {
*dst++=dst_color;
res++;
} else
dst++;
return res;
}
public U8 *DCSave(CDC *dc,I64 *_size=NULL,I64 dcsf_flags=DCSF_COMPRESSED)
{//Stores device context to mem, perhaps, with compression.
U8 *res,*ptr,*body;
CArcCompress *arc;
I64 body_size=dc->width_internal*dc->height,total_size,flags;
CBGR48 palette[COLORS_NUM];
if (dcsf_flags&DCSF_COMPRESSED) {
arc=CompressBuf(dc->body,body_size);
body_size=arc->compressed_size;
body=arc;
} else {
arc=NULL;
body=dc->body;
}
total_size=offset(CDC.end)-offset(CDC.start)+body_size;
if (dcsf_flags&DCSF_COMPRESSED)
flags=DCF_COMPRESSED;
else
flags=0;
if (dcsf_flags&DCSF_PALETTE_GET)
GrPaletteGet(palette);
else
MemCpy(palette,&dc->palette,COLORS_NUM*sizeof(CBGR48));
if (MemCmp(palette,gr_palette_std,COLORS_NUM*sizeof(CBGR48))) {
flags|=DCF_PALETTE;
total_size+=COLORS_NUM*sizeof(CBGR48);
}
ptr=res=MAlloc(total_size);
#assert !offset(CDC.start)
MemCpy(ptr,&dc->start,offset(CDC.end)-offset(CDC.start));
ptr(CDC *)->flags=flags;
ptr+=offset(CDC.end)-offset(CDC.start);
#assert offset(CDC.end)==offset(CDC.palette)
if (flags&DCF_PALETTE) {
MemCpy(ptr,palette,COLORS_NUM*sizeof(CBGR48));
ptr+=COLORS_NUM*sizeof(CBGR48);
}
MemCpy(ptr,body,body_size);
ptr+=body_size;
Free(arc);
if (_size) *_size=total_size;
return res;
}
public CDC *DCLoad(U8 *src,I64 *_size=NULL,CTask *task=NULL)
{//Loads device context from mem.
CDC *res;
U8 *ptr=src;
CArcCompress *arc;
I64 body_size;
if (!task) task=Fs;
res=CAlloc(sizeof(CDC),task);
res->win_task=task;
res->mem_task=task;
MemCpy(&res->start,ptr,offset(CDC.end)-offset(CDC.start));
ptr+=offset(CDC.end)-offset(CDC.start);
if (res->flags&DCF_PALETTE) {
MemCpy(&res->palette,ptr,COLORS_NUM*sizeof(CBGR48));
ptr+=COLORS_NUM*sizeof(CBGR48);
} else
MemCpy(&res->palette,gr_palette_std,COLORS_NUM*sizeof(CBGR48));
body_size=res->width_internal*res->height;
if (res->flags&DCF_COMPRESSED) {
res->flags&=~DCF_COMPRESSED;
arc=ptr;
res->body=ExpandBuf(arc,task);
ptr+=arc->compressed_size;
} else {
res->body=MAlloc(body_size,task);
MemCpy(res->body,ptr,body_size);
ptr+=body_size;
}
res->thick=1;
res->r=Mat4x4IdentNew(task);
res->r_norm.u32[1]=1;
res->dc_signature=DCS_SIGNATURE_VAL;
if (_size) *_size=ptr-src;
return res;
}
#help_index "Graphics/GR Files"
#help_file "::/Doc/GRFiles"
#help_index "Graphics/Device Contexts;Graphics/GR Files"
#define GR_FILE_MAX (offset(CDC.end)-offset(CDC.start)+\
COLORS_NUM*sizeof(CBGR48)+sizeof(CArcCtrl)+GR_WIDTH*GR_HEIGHT)
public I64 GRWrite(U8 *filename,CDC *dc,I64 dcsf_flags=DCSF_COMPRESSED)
{//TempleOS GR File.
I64 size;
U8 *st=ExtDft(filename,"GR"),
*src=DCSave(dc,&size,dcsf_flags);
FileWrite(st,src,size);
Free(st);
Free(src);
return size;
}
public CDC *GRRead(U8 *filename,CTask *task=NULL)
{//TempleOS GR File.
CDC *dc=NULL;
U8 *st=ExtDft(filename,"GR"),
*src=FileRead(st);
if (src)
dc=DCLoad(src,,task);
Free(src);
Free(st);
return dc;
}
#help_index "Graphics/Sprite;Graphics/GR Files;DolDoc/Output;StdOut/DolDoc"
public U0 DocGR(CDoc *doc=NULL,U8 *filename)
{//Put a GR file into a document as asprite.
CDC *dc=GRRead(filename);
CSprite *elems=DC2Sprite(dc);
DocSprite(doc,elems);
Free(elems);
DCDel(dc);
}
#help_index "Graphics/Device Contexts;Graphics/Scrn"
public CDC *DCScrnCapture(Bool include_zoom=TRUE,CTask *task=NULL)
{//Capture scrn to a device context.
CDC *dc;
U8 *dst;
Refresh(0,FALSE);
if (include_zoom)
dc=DCCopy(gr.scrn_image,task);
else
dc=DCCopy(gr.dc1,task);
dc->flags&=~DCF_SCRN_BITMAP;
dst=MAlloc(dc->width_internal*dc->height,task);
//Pick background color that never occurs. COLOR_INVALID
GrBitMap4ToBitMap8(dst,dc->body,
(dc->width_internal*dc->height)>>1,COLOR_INVALID);
Free(dc->body);
dc->body=dst;
return dc;
}