Warning, /include/Geant4/tools/zb/buffer is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_zb_buffer
0005 #define tools_zb_buffer
0006
0007 #include <cfloat> //DBL_MAX
0008
0009 #include "polygon"
0010
0011 namespace tools {
0012 namespace zb {
0013
0014 // ZPos, ZZ defined in point.
0015
0016 class buffer {
0017
0018 typedef double ZReal;
0019 static ZReal ZREAL_HUGE() {return DBL_MAX;}
0020
0021 public:
0022 typedef unsigned int ZPixel;
0023 //NOTE : with X11, bits_per_pixel can't be > 32.
0024 protected:
0025
0026 class writer {
0027 public:
0028 virtual void write(ZPos,ZPos,ZZ) = 0;
0029 public:
0030 writer(ZPixel a_pixel):m_pixel(a_pixel){}
0031 virtual ~writer(){}
0032 public:
0033 writer(const writer& a_from):m_pixel(a_from.m_pixel){}
0034 writer& operator=(const writer& a_from){
0035 m_pixel = a_from.m_pixel;
0036 return *this;
0037 }
0038 public:
0039 ZPixel m_pixel;
0040 };
0041
0042 void _write_point(ZPos a_x,ZPos a_y,ZZ a_z,ZPixel a_pixel) {
0043 if((a_x<m_begX) || (a_x>m_endX)) return;
0044 if((a_y<m_begY) || (a_y>m_endY)) return;
0045
0046 ZReal zpoint = (ZReal)a_z;
0047 unsigned long offset = a_y * m_zbw + a_x;
0048 ZReal* zbuff = m_zbuffer + offset;
0049
0050 if(m_depth_test) {if(zpoint<*zbuff) return;}
0051
0052 ZPixel* zimage = m_zimage + offset;
0053
0054 *zbuff = zpoint;
0055 blend(*zimage,a_pixel);
0056 }
0057 void write_point(ZPos a_x,ZPos a_y,ZZ a_z,unsigned int a_size,ZPixel a_pixel) {
0058 if(a_size>=1) { //see zb_action::npix().
0059 ZPos x,y;
0060 for(int i=-int(a_size);i<=int(a_size);i++) {
0061 x = a_x + i;
0062 for(int j=-int(a_size);j<=int(a_size);j++) {
0063 y = a_y + j;
0064 _write_point(x,y,a_z,a_pixel);
0065 }
0066 }
0067 } else {
0068 _write_point(a_x,a_y,a_z,a_pixel);
0069 }
0070 }
0071
0072 public:
0073 buffer()
0074 :m_depth_test(true)
0075 ,m_blend(false)
0076 ,m_zbuffer(0)
0077 //,m_zmin(0),m_zmax(0)
0078 ,m_zimage(0)
0079 ,m_zbw(0),m_zbh(0)
0080 ,m_begX(0),m_begY(0),m_endX(0),m_endY(0)
0081 ,m_scan_pixel(0L)
0082 ,m_planeAC(0),m_planeBC(0),m_planeDC(0)
0083 //,m_zboundPrec(10)
0084 {}
0085 virtual ~buffer(){
0086 cmem_free(m_zbuffer);
0087 cmem_free(m_zimage);
0088 m_zbw = 0;
0089 m_zbh = 0;
0090 m_polygon.clear();
0091 }
0092 protected:
0093 buffer(const buffer& a_from)
0094 :m_depth_test(a_from.m_depth_test)
0095 ,m_blend(a_from.m_blend)
0096 {}
0097 buffer& operator=(const buffer& a_from){
0098 m_depth_test = a_from.m_depth_test;
0099 m_blend = a_from.m_blend;
0100 return *this;
0101 }
0102 public:
0103 void set_depth_test(bool a_on) {m_depth_test = a_on;}
0104 //bool depth_test() const {return m_depth_test;}
0105
0106 void set_blend(bool a_value) {m_blend = a_value;}
0107
0108 bool change_size(unsigned int a_width,unsigned int a_height){
0109 if(!a_width||!a_height) return false;
0110
0111 if(m_zbuffer && (m_zbw==a_width) && (m_zbh==a_height) ) return true;
0112
0113 if(m_zbuffer){
0114 cmem_free(m_zbuffer);
0115 cmem_free(m_zimage);
0116 }
0117
0118 //printf ("debug:ZBufferChangeSize:%d %d\n",a_width,a_height);
0119 m_zbw = a_width;
0120 m_zbh = a_height;
0121 m_zbuffer = cmem_alloc<ZReal>(m_zbw*m_zbh);
0122 if(!m_zbuffer){
0123 m_zbw = 0;
0124 m_zbh = 0;
0125 return false;
0126 }
0127
0128 m_zimage = cmem_alloc<ZPixel>(m_zbw*m_zbh);
0129 if(!m_zimage){
0130 cmem_free(m_zbuffer);
0131 m_zbw = 0;
0132 m_zbh = 0;
0133 return false;
0134 }
0135
0136 set_clip_region(0,0,m_zbw,m_zbh);
0137 m_polygon.clear();
0138 return true;
0139 }
0140
0141 ZPixel* get_color_buffer(unsigned int& a_width,unsigned int& a_height) const {
0142 a_width = m_zbw;
0143 a_height = m_zbh;
0144 return m_zimage;
0145 }
0146
0147 void clear_color_buffer(ZPixel a_pixel) {
0148 // Erase acoording clip region.
0149 ZPos row,col;
0150 for(row=m_begY;row<=m_endY;row++){
0151 ZPixel* zimage = m_zimage + row * m_zbw + m_begX;
0152 for(col=m_begX;col<=m_endX;col++,zimage++) *zimage = a_pixel;
0153 }
0154 }
0155
0156 void clear_depth_buffer() {
0157 // Erase acoording clip region.
0158 ZPos row,col;
0159 //printf("debug:ZBufferClearDepthBuffer: %g.\n",a_depth);
0160
0161 for(row=m_begY;row<=m_endY;row++) {
0162 ZReal* zbuff = m_zbuffer + row * m_zbw + m_begX;
0163 for(col=m_begX;col<=m_endX;col++,zbuff++){
0164 *zbuff = - ZREAL_HUGE();
0165 }
0166 }
0167 }
0168
0169 ZPixel* zimage() {return m_zimage;}
0170
0171 bool get_clipped_pixel(ZPos a_x,ZPos a_y,ZPixel& a_pixel) const {
0172 if((a_x<m_begX) || (a_x>m_endX)) {a_pixel = 0;return false;}
0173 if((a_y<m_begY) || (a_y>m_endY)) {a_pixel = 0;return false;}
0174 a_pixel = *(m_zimage + a_y * m_zbw + a_x);
0175 return true;
0176 }
0177
0178 public:
0179 void set_clip_region(ZPos a_x,ZPos a_y,unsigned int a_width,unsigned int a_height){
0180 // if a_width or a_height is zero, clip region is empty.
0181
0182 m_begX = a_x;
0183 m_begY = a_y;
0184 m_endX = a_x + a_width - 1;
0185 m_endY = a_y + a_height - 1;
0186
0187 if(m_begX<0) m_begX = 0;
0188 if(m_begY<0) m_begY = 0;
0189 if(m_endX>ZPos(m_zbw-1)) m_endX = m_zbw-1;
0190 if(m_endY>ZPos(m_zbh-1)) m_endY = m_zbh-1;
0191 }
0192
0193 void draw_point(const point& a_p,ZPixel a_pixel,unsigned int a_size){
0194 write_point(a_p.x,a_p.y,a_p.z,a_size,a_pixel);
0195 }
0196
0197 void draw_line(const point& a_beg,const point& a_end,ZPixel a_pixel,unsigned int a_size){
0198 WriteLine(a_beg,a_end,a_size,a_pixel);
0199 }
0200
0201 void draw_lines(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){
0202 for(int count=1;count<a_number;count++) {
0203 WriteLine(a_list[count-1],a_list[count],a_size,a_pixel);
0204 }
0205 }
0206
0207 void draw_segments(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){
0208 int segment_number = a_number/2;
0209 for(int count=0;count<segment_number;count++) {
0210 WriteLine(a_list[2*count],a_list[2*count+1],a_size,a_pixel);
0211 }
0212 }
0213 void draw_markers(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){
0214 for(int count=0;count<a_number;count++){
0215 const point& p = a_list[count];
0216 write_point(p.x,p.y,p.z,a_size,a_pixel);
0217 }
0218 }
0219
0220 void draw_polygon(int a_number,const point* a_list,
0221 ZZ a_A,ZZ a_B,ZZ a_C,ZZ a_D,
0222 //ZZ a_zmin,ZZ a_zmax,
0223 ZPixel a_pixel){
0224 // Assume a_list is closed.
0225 if(a_number<3) return;
0226 if(a_C==0) return; //polygone seen from edge
0227 //if(m_zboundPrec<0) m_zboundPrec = 0;
0228
0229 m_scan_pixel = a_pixel;
0230 m_planeAC = a_A/a_C;
0231 m_planeBC = a_B/a_C;
0232 m_planeDC = a_D/a_C;
0233
0234 //if this polygon A is quite perpandicular to screen and close
0235 //to an other B than |dz| then some pixel of A could overwrite
0236 //pixel of B. Your have then to give a lower m_zboundPrec
0237
0238 //ZZ dz = m_zboundPrec * (a_zmax - a_zmin)/100.;
0239 //m_zmin = (ZReal)(a_zmin - dz);
0240 //m_zmax = (ZReal)(a_zmax + dz);
0241
0242 m_polygon.scan(a_number,a_list,0,WriteScanLine,this);
0243
0244 }
0245
0246 typedef unsigned char uchar;
0247 static void rgba2pix(float a_r,float a_g,float a_b,float a_a,ZPixel& a_pix) {
0248 uchar* _px = (uchar*)&a_pix;
0249 *_px = (uchar)(255.0F * a_r);_px++;
0250 *_px = (uchar)(255.0F * a_g);_px++;
0251 *_px = (uchar)(255.0F * a_b);_px++;
0252 *_px = (uchar)(255.0F * a_a);_px++;
0253 }
0254 static void pix2rgba(const ZPixel& a_pix,float& a_r,float& a_g,float& a_b,float& a_a) {
0255 uchar* _px = (uchar*)&a_pix;
0256 a_r = (*_px)/255.0f;_px++;
0257 a_g = (*_px)/255.0f;_px++;
0258 a_b = (*_px)/255.0f;_px++;
0259 a_a = (*_px)/255.0f;_px++;
0260 }
0261 protected:
0262 void scan_write_point_1(ZPos a_x,ZPos a_y,ZZ a_z,ZPos /*a_beg*/,unsigned int a_size,ZPixel a_pixel) {
0263 write_point(a_x,a_y,a_z,a_size,a_pixel);
0264 }
0265 void scan_write_point_2(ZPos a_x,ZPos a_y,ZZ a_z,ZPos /*a_beg*/,unsigned int a_size,ZPixel a_pixel) {
0266 write_point(a_y,a_x,a_z,a_size,a_pixel);
0267 }
0268 void scan_write_point_3(ZPos a_x,ZPos a_y,ZZ a_z,ZPos a_beg,unsigned int a_size,ZPixel a_pixel) {
0269 write_point(a_x,2*a_beg-a_y,a_z,a_size,a_pixel);
0270 }
0271 void scan_write_point_4(ZPos a_x,ZPos a_y,ZZ a_z,ZPos a_beg,unsigned int a_size,ZPixel a_pixel) {
0272 write_point(2*a_beg-a_y,a_x,a_z,a_size,a_pixel);
0273 }
0274
0275 void blend(ZPixel& a_pix,const ZPixel& a_new) {
0276 if(!m_blend) {
0277 a_pix = a_new;
0278 return;
0279 }
0280 float _or,_og,_ob,_oa;
0281 pix2rgba(a_pix,_or,_og,_ob,_oa);
0282 float nr,ng,nb,na;
0283 pix2rgba(a_new,nr,ng,nb,na);
0284 if((0.0f<=na)&&(na<1.0f)) {
0285 // same as glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA):
0286 float one_minus_na = 1.0f-na;
0287 float pr = nr*na+_or*one_minus_na;
0288 float pg = ng*na+_og*one_minus_na;
0289 float pb = nb*na+_ob*one_minus_na;
0290 float pa = 1;
0291 rgba2pix(pr,pg,pb,pa,a_pix);
0292 } else {
0293 a_pix = a_new;
0294 }
0295 }
0296
0297 static void WriteScanLine(void* a_tag,int a_beg,int a_end,int a_y){
0298 buffer& a_buffer = *((buffer*)a_tag);
0299
0300 if((a_y<a_buffer.m_begY) || (a_y>a_buffer.m_endY)) return;
0301 if(a_end<=a_beg) return;
0302
0303 if(a_beg>a_buffer.m_endX) return;
0304 if(a_end<a_buffer.m_begX) return;
0305
0306 // border clip :
0307 int beg = mx(a_beg,(int)a_buffer.m_begX);
0308 int end = mn(a_end,(int)a_buffer.m_endX);
0309
0310 unsigned long offset = a_y * a_buffer.m_zbw + beg;
0311 ZReal* zbuff = a_buffer.m_zbuffer + offset;
0312 ZPixel* zimage = a_buffer.m_zimage + offset;
0313
0314 ZReal zpoint;
0315 for(int x=beg;x<=end;x++){
0316 zpoint =
0317 (ZReal)(- a_buffer.m_planeDC
0318 - a_buffer.m_planeAC * x
0319 - a_buffer.m_planeBC * a_y);
0320 if(a_buffer.m_depth_test) {
0321 if((zpoint>=(*zbuff))
0322 // &&(zpoint>=a_buffer.m_zmin) //for plane quite perpandicular to screen.
0323 // &&(zpoint<=a_buffer.m_zmax)
0324 ){
0325 *zbuff = zpoint;
0326 a_buffer.blend(*zimage,a_buffer.m_scan_pixel);
0327 }
0328 } else {
0329 *zbuff = zpoint;
0330 a_buffer.blend(*zimage,a_buffer.m_scan_pixel);
0331 }
0332 zbuff ++;
0333 zimage ++;
0334 }
0335 }
0336
0337 typedef void(buffer::*scan_write_point_func)(ZPos,ZPos,ZZ,ZPos,unsigned int,ZPixel);
0338 void ScanLine(ZPos a_x,ZPos a_y,ZZ a_z,
0339 ZPos a_dx,ZPos a_dy,ZZ a_dz,
0340 unsigned int a_size,ZPixel a_pixel,
0341 scan_write_point_func a_func){
0342 // Mid point algorithm
0343 // assume 0<dx 0<=dy<=dx
0344
0345 ZPos end = a_x + a_dx;
0346 ZPos beg = a_y;
0347 ZZ incz = a_dz/(ZZ)a_dx;
0348 if(a_dy==0) {
0349 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel);
0350 while(a_x<end){
0351 a_x++;
0352 a_z += incz;
0353 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel);
0354 }
0355 } else if(a_dy==a_dx) {
0356 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel);
0357 while(a_x<end){
0358 a_x++;
0359 a_y++;
0360 a_z += incz;
0361 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel);
0362 }
0363 } else {
0364 ZPos d = 2 * a_dy - a_dx;
0365 ZPos incrE = 2 * a_dy;
0366 ZPos incrNE = 2 * ( a_dy - a_dx);
0367 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel);
0368 while(a_x<end){
0369 if(d<=0){
0370 d += incrE;
0371 a_x++;
0372 }else{
0373 d += incrNE;
0374 a_x++;
0375 a_y++;
0376 }
0377 a_z += incz;
0378 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel);
0379 }
0380 }
0381 }
0382
0383 void WriteLine(const point& a_beg,
0384 const point& a_end,
0385 unsigned int a_size,ZPixel a_pixel){
0386 ZPos dx = a_end.x - a_beg.x;
0387 ZPos dy = a_end.y - a_beg.y;
0388 ZZ dz = a_end.z - a_beg.z;
0389
0390 // 6 2
0391 // 5 1
0392 // 7 3
0393 // 8 4
0394
0395 if( (dx==0) && (dy==0) ) {
0396 write_point(a_beg.x,a_beg.y,a_beg.z,a_size,a_pixel);
0397 write_point(a_end.x,a_end.y,a_end.z,a_size,a_pixel);
0398
0399 } else if(dx==0) {
0400 if(dy>0)
0401 ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy, dx, dz, a_size,a_pixel,&buffer::scan_write_point_2);
0402 else
0403 ScanLine ( a_end.y, a_end.x,a_end.z,-dy, dx,-dz, a_size,a_pixel,&buffer::scan_write_point_2);
0404
0405 } else if(dx>0) {
0406 if((0<=dy) && (dy<=dx)) /*1*/
0407 ScanLine ( a_beg.x, a_beg.y,a_beg.z, dx, dy, dz, a_size,a_pixel,&buffer::scan_write_point_1);
0408 else if(dx<dy) /*2*/
0409 ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy, dx, dz, a_size,a_pixel,&buffer::scan_write_point_2);
0410 else if((-dx<=dy) && (dy<0) ) /*3*/
0411 ScanLine ( a_beg.x, a_beg.y,a_beg.z, dx,-dy, dz, a_size,a_pixel,&buffer::scan_write_point_3);
0412 else if(dy<-dx) /*4*/
0413 ScanLine ( a_end.y, a_end.x,a_end.z,-dy, dx,-dz, a_size,a_pixel,&buffer::scan_write_point_4);
0414
0415 } else { //dx<0
0416 if((0<=dy) && (dy<=-dx)) /*5*/
0417 ScanLine ( a_end.x, a_end.y,a_end.z,-dx, dy,-dz, a_size,a_pixel,&buffer::scan_write_point_3);
0418 else if(-dx<dy) /*6*/
0419 ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy,-dx, dz, a_size,a_pixel,&buffer::scan_write_point_4);
0420 else if((dx<=dy) && (dy<0) ) /*7*/
0421 ScanLine ( a_end.x, a_end.y,a_end.z,-dx,-dy,-dz, a_size,a_pixel,&buffer::scan_write_point_1);
0422 else if(dy<dx) /*8*/
0423 ScanLine ( a_end.y, a_end.x,a_end.z,-dy,-dx,-dz, a_size,a_pixel,&buffer::scan_write_point_2);
0424 }
0425
0426 }
0427
0428
0429 protected:
0430 bool m_depth_test;
0431 bool m_blend;
0432 ZReal* m_zbuffer;
0433 //ZReal m_zmin,m_zmax;
0434
0435 ZPixel* m_zimage;
0436
0437 unsigned int m_zbw,m_zbh;
0438 ZPos m_begX,m_begY;
0439 ZPos m_endX,m_endY; //could be <0
0440
0441 ZPixel m_scan_pixel;
0442 ZZ m_planeAC;
0443 ZZ m_planeBC;
0444 ZZ m_planeDC;
0445 //int m_zboundPrec;
0446 polygon m_polygon;
0447 };
0448
0449 }}
0450
0451 #endif