// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_zb_buffer #define tools_zb_buffer #include //DBL_MAX #include "polygon" namespace tools { namespace zb { // ZPos, ZZ defined in point. class buffer { typedef double ZReal; static ZReal ZREAL_HUGE() {return DBL_MAX;} public: typedef unsigned int ZPixel; //NOTE : with X11, bits_per_pixel can't be > 32. protected: class writer { public: virtual void write(ZPos,ZPos,ZZ) = 0; public: writer(ZPixel a_pixel):m_pixel(a_pixel){} virtual ~writer(){} public: writer(const writer& a_from):m_pixel(a_from.m_pixel){} writer& operator=(const writer& a_from){ m_pixel = a_from.m_pixel; return *this; } public: ZPixel m_pixel; }; class point_writer : public virtual writer { public: virtual void write(ZPos a_x,ZPos a_y,ZZ a_z) { if(m_size>1) { ZPos x,y; for(int i=-int(m_size);i<=int(m_size);i++) { x = a_x + i; for(int j=-int(m_size);j<=int(m_size);j++) { y = a_y + j; _write(x,y,a_z); } } } else { _write(a_x,a_y,a_z); } } public: point_writer(ZPixel a_pixel,buffer& a_buffer,unsigned int a_size) :writer(a_pixel) ,m_buffer(a_buffer) ,m_size(a_size) {} virtual ~point_writer(){} public: point_writer(const point_writer& a_from) :writer(a_from) ,m_buffer(a_from.m_buffer) ,m_size(a_from.m_size) {} point_writer& operator=(const point_writer& a_from){ writer::operator=(a_from); m_size = a_from.m_size; return *this; } protected: void _write(ZPos a_x,ZPos a_y,ZZ a_z) { if((a_xm_buffer.m_endX)) return; if((a_ym_buffer.m_endY)) return; ZReal zpoint = (ZReal)a_z; unsigned long offset = a_y * m_buffer.m_zbw + a_x; ZReal* zbuff = m_buffer.m_zbuffer + offset; if(m_buffer.m_depth_test) {if(zpoint<*zbuff) return;} ZPixel* zimage = m_buffer.m_zimage + offset; /* transparency : ZPixel old_pix = *zimage; // need the alpha of m_pixel ! */ *zbuff = zpoint; *zimage = m_pixel; } protected: buffer& m_buffer; unsigned int m_size; }; /* class edge_point_writer : public virtual writer { public: virtual void write(ZPos a_x,ZPos a_y,ZZ) { if((a_xm_buffer.m_endX)) return; if((a_ym_buffer.m_endY)) return; // Computing must be the same as in WriteScanLine routine. ZReal zpoint = (ZReal)(- m_buffer.m_planeDC - m_buffer.m_planeAC * a_x - m_buffer.m_planeBC * a_y); // for edge plane quite perpandicular to screen //if((zpointm_buffer.m_zmax)) return; unsigned long offset = a_y * m_buffer.m_zbw + a_x; ZReal* zbuff = m_buffer.m_zbuffer + offset; if(m_buffer.m_depth_test) {if(zpoint<*zbuff) return;} ZPixel* zimage = m_buffer.m_zimage + offset; *zbuff = zpoint; *zimage = m_pixel; } public: edge_point_writer(ZPixel a_pixel,buffer& a_buffer) :writer(a_pixel) ,m_buffer(a_buffer) {} virtual ~edge_point_writer(){} public: edge_point_writer(const edge_point_writer& a_from) :writer(a_from) ,m_buffer(a_from.m_buffer) {} edge_point_writer& operator=(const edge_point_writer& a_from){ writer::operator=(a_from); return *this; } protected: buffer& m_buffer; }; */ public: buffer() :m_depth_test(true) ,m_zbuffer(0) //,m_zmin(0),m_zmax(0) ,m_zimage(0) ,m_zbw(0),m_zbh(0) ,m_begX(0),m_begY(0),m_endX(0),m_endY(0) ,m_scan_pixel(0L) ,m_planeAC(0),m_planeBC(0),m_planeDC(0) //,m_zboundPrec(10) {} virtual ~buffer(){ cmem_free(m_zbuffer); cmem_free(m_zimage); m_zbw = 0; m_zbh = 0; m_polygon.clear(); } protected: buffer(const buffer& a_from) :m_depth_test(a_from.m_depth_test) {} buffer& operator=(const buffer& a_from){ m_depth_test = a_from.m_depth_test; return *this; } public: void set_depth_test(bool a_on) {m_depth_test = a_on;} //bool depth_test() const {return m_depth_test;} bool change_size(unsigned int a_width,unsigned int a_height){ if(!a_width||!a_height) return false; if(m_zbuffer && (m_zbw==a_width) && (m_zbh==a_height) ) return true; if(m_zbuffer){ cmem_free(m_zbuffer); cmem_free(m_zimage); } //printf ("debug:ZBufferChangeSize:%d %d\n",a_width,a_height); m_zbw = a_width; m_zbh = a_height; m_zbuffer = cmem_alloc(m_zbw*m_zbh); if(!m_zbuffer){ m_zbw = 0; m_zbh = 0; return false; } m_zimage = cmem_alloc(m_zbw*m_zbh); if(!m_zimage){ cmem_free(m_zbuffer); m_zbw = 0; m_zbh = 0; return false; } // Init buffer done by further call to ZBufferErase. /* unsigned int size = m_zbw * m_zbh; ZReal* zbuffer = m_zbuffer; ZPixel* zimage = m_zimage; for(unsigned int count=0;countm_endX)) return false; if((a_ym_endY)) return false; a_pixel = *(m_zimage + a_y * m_zbw + a_x); return true; } public: void set_clip_region(ZPos a_x,ZPos a_y, unsigned int a_width,unsigned int a_height){ // if a_width or a_height is zero, clip region is empty. m_begX = a_x; m_begY = a_y; m_endX = a_x + a_width - 1; m_endY = a_y + a_height - 1; if(m_begX<0) m_begX = 0; if(m_begY<0) m_begY = 0; if(m_endX>ZPos(m_zbw-1)) m_endX = m_zbw-1; if(m_endY>ZPos(m_zbh-1)) m_endY = m_zbh-1; } void draw_point(const point& a_p,ZPixel a_pixel,unsigned int a_size){ point_writer pw(a_pixel,*this,a_size); pw.write(a_p.x,a_p.y,a_p.z); } void draw_line(const point& a_beg,const point& a_end,ZPixel a_pixel,unsigned int a_size){ point_writer pw(a_pixel,*this,a_size); WriteLine(a_beg,a_end,pw); } void draw_lines(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){ point_writer pw(a_pixel,*this,a_size); for(int count=1;counta_buffer.m_endY)) return; if(a_end<=a_beg) return; if(a_beg>a_buffer.m_endX) return; if(a_end=(*zbuff)) // &&(zpoint>=a_buffer.m_zmin) //for plane quite perpandicular to screen. // &&(zpoint<=a_buffer.m_zmax) ){ *zbuff = zpoint; *zimage = a_buffer.m_scan_pixel; } } else { *zbuff = zpoint; *zimage = a_buffer.m_scan_pixel; } zbuff ++; zimage ++; } } static void WriteLine(const point& a_beg, const point& a_end, writer& a_writer){ ZPos dx = a_end.x - a_beg.x; ZPos dy = a_end.y - a_beg.y; ZZ dz = a_end.z - a_beg.z; // 6 2 // 5 1 // 7 3 // 8 4 scan_writer_1 sw1(a_writer); scan_writer_2 sw2(a_writer); scan_writer_3 sw3(a_writer); scan_writer_4 sw4(a_writer); if( (dx==0) && (dy==0) ) { a_writer.write(a_beg.x,a_beg.y,a_beg.z); a_writer.write(a_end.x,a_end.y,a_end.z); } else if(dx==0) { if(dy>0) ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy, dx, dz,sw2); else ScanLine ( a_end.y, a_end.x,a_end.z,-dy, dx,-dz,sw2); } else if(dx>0) { if((0<=dy) && (dy<=dx)) /*1*/ ScanLine ( a_beg.x, a_beg.y,a_beg.z, dx, dy, dz,sw1); else if(dx