wij
2025-01-01 07:48:32 UTC
Reply
Permalinkthe so called 'graphics' can be a file descriptor.
================ q_mand2.cpp
/* Copyright is licensed by GNU LGPL, see file COPYING. by I.J.Wang 2024
Draw image of Mandelbrot set (can zoom-in, one thread, slower)
Build: make q_mand2
*/
#include <Wy.stdio.h>
#include <Wy.complex.h>
#include <CSCall/Face.h>
#include <CSCall/Array2D.h>
using namespace Wy;
//--------- Drawing --------
typedef Face::RGB32_Pixel Pixel;
constexpr Pixel White=Face::RGB32_White;
constexpr Pixel Black=Face::RGB32_Black;
const char GrSvr[]="../face/face"; // see ../face/README
typedef long double MandFType;
constexpr int MaxItrNum=255;
// [Ret] Conversion table from itrnum to Pixel
Array<Pixel> itrnum_pixel() {
Array<Pixel> tab;
for(int n=0; n<=MaxItrNum; ++n) {
// transform $itrnum to approximate temperature color
Pixel pix(Black);
pix[2]= (n&7)<<5;
pix[1]= ((n>>3)&7)<<5;
pix[0]= ((n>>6)&3)<<6;
tab << pix;
}
return tab;
};
const Array<Pixel> ctab( itrnum_pixel() );
constexpr unsigned int Dim=800;
MandFType dist_pd=(4.0/(Dim-1)); // mand distance per dot distance
MandFType mand_lft=-3.0;
MandFType mand_top=2.0;
Array2D<Pixel> mand_img(Dim,Dim);
// [Syn] Draw Mand. image in line range [lbgn,lend)
//
void draw_mand(const Hdr2D<Pixel>& hdr, int lbgn, int lend) {
for(int y=lbgn; y<lend; ++y) {
for(int x=0; x<static_cast<int>(hdr.width()); ++x) {
const Complex<MandFType> c( x*dist_pd +mand_lft, mand_top -y*dist_pd );
const MandFType MaxValue=2.0*abs(c);
Complex<MandFType> z;
int itrnum;
for(itrnum=0; itrnum<MaxItrNum; ++itrnum) {
z=(z*z)+c;
if(abs(z)>MaxValue) {
break;
}
};
hdr.write_point(x,y,ctab[itrnum]);
};
};
};
//--------------- Process mouse events
FifoFile frd,fwr;
class StrmRcvr : public Face::Receiver {
int m_px,m_py;
public:
StrmRcvr() : Face::Receiver() {};
StrmRcvr(RdBuf& strm) : Face::Receiver(strm) {};
Errno cb_headpkt(const char*) override { return Ok; };
Errno cb_MO(Wy::WeeStr mtype, int x, int y, unsigned int butt) override {
Errno r;
if(mtype=="press") {
if(butt&Face::LeftButton) {
m_px=x;
m_py=y;
}
} else if(mtype=="release") {
if(butt&Face::LeftButton) {
int dx,dy; // process the zoom-in box
if(x>=m_px) {
dx=x-m_px;
} else {
dx=m_px;
m_px=x;
x=dx;
dx-=m_px;
}
if(y>=m_py) {
dy=y-m_py;
} else {
dy=m_py;
m_py=y;
y=dy;
dy-=m_py;
}
if((dx<10)||(dy<10)) {
return Ok; // not to zoom-in
}
MandFType mand_rit= mand_lft+x*dist_pd;
MandFType mand_btm= mand_top-y*dist_pd;
mand_lft+= m_px*dist_pd;
mand_top-= m_py*dist_pd;
if(dx>=dy) {
dist_pd= (mand_rit-mand_lft)/Dim;
} else {
dist_pd= (mand_top-mand_btm)/Dim;
}
if(dx>10) {
draw_mand(mand_img.header(),0,mand_img.height()-1);
if((r=Face::put_image(fwr, mand_img.header()))!=Ok) {
WY_THROW(r);
}
}
}
} else {
}
return Ok;
};
Wy::Errno cb_error(Wy::Errno err, int id) override {
cerr << "q_mand2: " << Wy::wrd(err) << ", id=" << id << WY_ENDL;
return err;
};
};
int main(int argc, char *argv[]) try {
Errno r;
ProcessID cpid;
draw_mand(mand_img.header(),0,mand_img.height()-1);
if((r=popen(GrSvr,cpid,frd,fwr))!=Ok) {
WY_THROW(r);
}
if((r=Face::put_image(fwr, mand_img._data(),Dim,Dim))!=Ok) {
WY_THROW(r);
}
RdBuf strm(frd);
StrmRcvr rcvr(strm);
if((r=rcvr.pkt_dispatch())!=Ok) {
WY_THROW(r);
}
WaitStat wstt;
if((r=waitpid(cpid,&wstt,0))!=Ok) {
WY_THROW(r);
}
cout << "Child exit " << wstt.exit_status() << WY_ENDL;
cout << "OK" WY_ENDL;
return 0;
}
catch(const Errno& e) {
cerr << wrd(e) << WY_ENDL;
return -1; // e.c_errno();
}
catch(...) {
cerr << "main() caught(...)" WY_ENDL;
throw;
};
=================== end of q_mand2.cpp
We open 'graphics' with a pathname GrSvr (whatever) and get a file descriptor (fwr
and frd can be the same file descriptor if supported):
if((r=popen(GrSvr,cpid,frd,fwr))!=Ok) {
WY_THROW(r);
}
Then, we write (image or 'command') data to the file descriptor:
if((r=Face::put_image(fwr, mand_img._data(),Dim,Dim))!=Ok) {
WY_THROW(r);
}
(ByteFlow is actually a file descriptor, it is a base class of regular file,
fifo file, socket file character file...)
Perhaps, this is a 'GUI device', so we read GUI events:
RdBuf strm(frd);
StrmRcvr rcvr(strm);
if((r=rcvr.pkt_dispatch())!=Ok) {
WY_THROW(r);
}
Perfect fit! Any idea that 'graphics' be a file descriptor?