Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_zb_buffer 5 #define tools_zb_buffer 6 7 #include <cfloat> //DBL_MAX 8 9 #include "polygon" 10 11 namespace tools { 12 namespace zb { 13 14 // ZPos, ZZ defined in point. 15 16 class buffer { 17 18 typedef double ZReal; 19 static ZReal ZREAL_HUGE() {return DBL_MAX;} 20 21 public: 22 typedef unsigned int ZPixel; 23 //NOTE : with X11, bits_per_pixel can't be > 32. 24 protected: 25 26 class writer { 27 public: 28 virtual void write(ZPos,ZPos,ZZ) = 0; 29 public: 30 writer(ZPixel a_pixel):m_pixel(a_pixel){} 31 virtual ~writer(){} 32 public: 33 writer(const writer& a_from):m_pixel(a_from.m_pixel){} 34 writer& operator=(const writer& a_from){ 35 m_pixel = a_from.m_pixel; 36 return *this; 37 } 38 public: 39 ZPixel m_pixel; 40 }; 41 42 void _write_point(ZPos a_x,ZPos a_y,ZZ a_z,ZPixel a_pixel) { 43 if((a_x<m_begX) || (a_x>m_endX)) return; 44 if((a_y<m_begY) || (a_y>m_endY)) return; 45 46 ZReal zpoint = (ZReal)a_z; 47 unsigned long offset = a_y * m_zbw + a_x; 48 ZReal* zbuff = m_zbuffer + offset; 49 50 if(m_depth_test) {if(zpoint<*zbuff) return;} 51 52 ZPixel* zimage = m_zimage + offset; 53 54 *zbuff = zpoint; 55 blend(*zimage,a_pixel); 56 } 57 void write_point(ZPos a_x,ZPos a_y,ZZ a_z,unsigned int a_size,ZPixel a_pixel) { 58 if(a_size>=1) { //see zb_action::npix(). 59 ZPos x,y; 60 for(int i=-int(a_size);i<=int(a_size);i++) { 61 x = a_x + i; 62 for(int j=-int(a_size);j<=int(a_size);j++) { 63 y = a_y + j; 64 _write_point(x,y,a_z,a_pixel); 65 } 66 } 67 } else { 68 _write_point(a_x,a_y,a_z,a_pixel); 69 } 70 } 71 72 public: 73 buffer() 74 :m_depth_test(true) 75 ,m_blend(false) 76 ,m_zbuffer(0) 77 //,m_zmin(0),m_zmax(0) 78 ,m_zimage(0) 79 ,m_zbw(0),m_zbh(0) 80 ,m_begX(0),m_begY(0),m_endX(0),m_endY(0) 81 ,m_scan_pixel(0L) 82 ,m_planeAC(0),m_planeBC(0),m_planeDC(0) 83 //,m_zboundPrec(10) 84 {} 85 virtual ~buffer(){ 86 cmem_free(m_zbuffer); 87 cmem_free(m_zimage); 88 m_zbw = 0; 89 m_zbh = 0; 90 m_polygon.clear(); 91 } 92 protected: 93 buffer(const buffer& a_from) 94 :m_depth_test(a_from.m_depth_test) 95 ,m_blend(a_from.m_blend) 96 {} 97 buffer& operator=(const buffer& a_from){ 98 m_depth_test = a_from.m_depth_test; 99 m_blend = a_from.m_blend; 100 return *this; 101 } 102 public: 103 void set_depth_test(bool a_on) {m_depth_test = a_on;} 104 //bool depth_test() const {return m_depth_test;} 105 106 void set_blend(bool a_value) {m_blend = a_value;} 107 108 bool change_size(unsigned int a_width,unsigned int a_height){ 109 if(!a_width||!a_height) return false; 110 111 if(m_zbuffer && (m_zbw==a_width) && (m_zbh==a_height) ) return true; 112 113 if(m_zbuffer){ 114 cmem_free(m_zbuffer); 115 cmem_free(m_zimage); 116 } 117 118 //printf ("debug:ZBufferChangeSize:%d %d\n",a_width,a_height); 119 m_zbw = a_width; 120 m_zbh = a_height; 121 m_zbuffer = cmem_alloc<ZReal>(m_zbw*m_zbh); 122 if(!m_zbuffer){ 123 m_zbw = 0; 124 m_zbh = 0; 125 return false; 126 } 127 128 m_zimage = cmem_alloc<ZPixel>(m_zbw*m_zbh); 129 if(!m_zimage){ 130 cmem_free(m_zbuffer); 131 m_zbw = 0; 132 m_zbh = 0; 133 return false; 134 } 135 136 set_clip_region(0,0,m_zbw,m_zbh); 137 m_polygon.clear(); 138 return true; 139 } 140 141 ZPixel* get_color_buffer(unsigned int& a_width,unsigned int& a_height) const { 142 a_width = m_zbw; 143 a_height = m_zbh; 144 return m_zimage; 145 } 146 147 void clear_color_buffer(ZPixel a_pixel) { 148 // Erase acoording clip region. 149 ZPos row,col; 150 for(row=m_begY;row<=m_endY;row++){ 151 ZPixel* zimage = m_zimage + row * m_zbw + m_begX; 152 for(col=m_begX;col<=m_endX;col++,zimage++) *zimage = a_pixel; 153 } 154 } 155 156 void clear_depth_buffer() { 157 // Erase acoording clip region. 158 ZPos row,col; 159 //printf("debug:ZBufferClearDepthBuffer: %g.\n",a_depth); 160 161 for(row=m_begY;row<=m_endY;row++) { 162 ZReal* zbuff = m_zbuffer + row * m_zbw + m_begX; 163 for(col=m_begX;col<=m_endX;col++,zbuff++){ 164 *zbuff = - ZREAL_HUGE(); 165 } 166 } 167 } 168 169 ZPixel* zimage() {return m_zimage;} 170 171 bool get_clipped_pixel(ZPos a_x,ZPos a_y,ZPixel& a_pixel) const { 172 if((a_x<m_begX) || (a_x>m_endX)) {a_pixel = 0;return false;} 173 if((a_y<m_begY) || (a_y>m_endY)) {a_pixel = 0;return false;} 174 a_pixel = *(m_zimage + a_y * m_zbw + a_x); 175 return true; 176 } 177 178 public: 179 void set_clip_region(ZPos a_x,ZPos a_y,unsigned int a_width,unsigned int a_height){ 180 // if a_width or a_height is zero, clip region is empty. 181 182 m_begX = a_x; 183 m_begY = a_y; 184 m_endX = a_x + a_width - 1; 185 m_endY = a_y + a_height - 1; 186 187 if(m_begX<0) m_begX = 0; 188 if(m_begY<0) m_begY = 0; 189 if(m_endX>ZPos(m_zbw-1)) m_endX = m_zbw-1; 190 if(m_endY>ZPos(m_zbh-1)) m_endY = m_zbh-1; 191 } 192 193 void draw_point(const point& a_p,ZPixel a_pixel,unsigned int a_size){ 194 write_point(a_p.x,a_p.y,a_p.z,a_size,a_pixel); 195 } 196 197 void draw_line(const point& a_beg,const point& a_end,ZPixel a_pixel,unsigned int a_size){ 198 WriteLine(a_beg,a_end,a_size,a_pixel); 199 } 200 201 void draw_lines(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){ 202 for(int count=1;count<a_number;count++) { 203 WriteLine(a_list[count-1],a_list[count],a_size,a_pixel); 204 } 205 } 206 207 void draw_segments(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){ 208 int segment_number = a_number/2; 209 for(int count=0;count<segment_number;count++) { 210 WriteLine(a_list[2*count],a_list[2*count+1],a_size,a_pixel); 211 } 212 } 213 void draw_markers(int a_number,const point* a_list,ZPixel a_pixel,unsigned int a_size){ 214 for(int count=0;count<a_number;count++){ 215 const point& p = a_list[count]; 216 write_point(p.x,p.y,p.z,a_size,a_pixel); 217 } 218 } 219 220 void draw_polygon(int a_number,const point* a_list, 221 ZZ a_A,ZZ a_B,ZZ a_C,ZZ a_D, 222 //ZZ a_zmin,ZZ a_zmax, 223 ZPixel a_pixel){ 224 // Assume a_list is closed. 225 if(a_number<3) return; 226 if(a_C==0) return; //polygone seen from edge 227 //if(m_zboundPrec<0) m_zboundPrec = 0; 228 229 m_scan_pixel = a_pixel; 230 m_planeAC = a_A/a_C; 231 m_planeBC = a_B/a_C; 232 m_planeDC = a_D/a_C; 233 234 //if this polygon A is quite perpandicular to screen and close 235 //to an other B than |dz| then some pixel of A could overwrite 236 //pixel of B. Your have then to give a lower m_zboundPrec 237 238 //ZZ dz = m_zboundPrec * (a_zmax - a_zmin)/100.; 239 //m_zmin = (ZReal)(a_zmin - dz); 240 //m_zmax = (ZReal)(a_zmax + dz); 241 242 m_polygon.scan(a_number,a_list,0,WriteScanLine,this); 243 244 } 245 246 typedef unsigned char uchar; 247 static void rgba2pix(float a_r,float a_g,float a_b,float a_a,ZPixel& a_pix) { 248 uchar* _px = (uchar*)&a_pix; 249 *_px = (uchar)(255.0F * a_r);_px++; 250 *_px = (uchar)(255.0F * a_g);_px++; 251 *_px = (uchar)(255.0F * a_b);_px++; 252 *_px = (uchar)(255.0F * a_a);_px++; 253 } 254 static void pix2rgba(const ZPixel& a_pix,float& a_r,float& a_g,float& a_b,float& a_a) { 255 uchar* _px = (uchar*)&a_pix; 256 a_r = (*_px)/255.0f;_px++; 257 a_g = (*_px)/255.0f;_px++; 258 a_b = (*_px)/255.0f;_px++; 259 a_a = (*_px)/255.0f;_px++; 260 } 261 protected: 262 void scan_write_point_1(ZPos a_x,ZPos a_y,ZZ a_z,ZPos /*a_beg*/,unsigned int a_size,ZPixel a_pixel) { 263 write_point(a_x,a_y,a_z,a_size,a_pixel); 264 } 265 void scan_write_point_2(ZPos a_x,ZPos a_y,ZZ a_z,ZPos /*a_beg*/,unsigned int a_size,ZPixel a_pixel) { 266 write_point(a_y,a_x,a_z,a_size,a_pixel); 267 } 268 void scan_write_point_3(ZPos a_x,ZPos a_y,ZZ a_z,ZPos a_beg,unsigned int a_size,ZPixel a_pixel) { 269 write_point(a_x,2*a_beg-a_y,a_z,a_size,a_pixel); 270 } 271 void scan_write_point_4(ZPos a_x,ZPos a_y,ZZ a_z,ZPos a_beg,unsigned int a_size,ZPixel a_pixel) { 272 write_point(2*a_beg-a_y,a_x,a_z,a_size,a_pixel); 273 } 274 275 void blend(ZPixel& a_pix,const ZPixel& a_new) { 276 if(!m_blend) { 277 a_pix = a_new; 278 return; 279 } 280 float _or,_og,_ob,_oa; 281 pix2rgba(a_pix,_or,_og,_ob,_oa); 282 float nr,ng,nb,na; 283 pix2rgba(a_new,nr,ng,nb,na); 284 if((0.0f<=na)&&(na<1.0f)) { 285 // same as glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA): 286 float one_minus_na = 1.0f-na; 287 float pr = nr*na+_or*one_minus_na; 288 float pg = ng*na+_og*one_minus_na; 289 float pb = nb*na+_ob*one_minus_na; 290 float pa = 1; 291 rgba2pix(pr,pg,pb,pa,a_pix); 292 } else { 293 a_pix = a_new; 294 } 295 } 296 297 static void WriteScanLine(void* a_tag,int a_beg,int a_end,int a_y){ 298 buffer& a_buffer = *((buffer*)a_tag); 299 300 if((a_y<a_buffer.m_begY) || (a_y>a_buffer.m_endY)) return; 301 if(a_end<=a_beg) return; 302 303 if(a_beg>a_buffer.m_endX) return; 304 if(a_end<a_buffer.m_begX) return; 305 306 // border clip : 307 int beg = mx(a_beg,(int)a_buffer.m_begX); 308 int end = mn(a_end,(int)a_buffer.m_endX); 309 310 unsigned long offset = a_y * a_buffer.m_zbw + beg; 311 ZReal* zbuff = a_buffer.m_zbuffer + offset; 312 ZPixel* zimage = a_buffer.m_zimage + offset; 313 314 ZReal zpoint; 315 for(int x=beg;x<=end;x++){ 316 zpoint = 317 (ZReal)(- a_buffer.m_planeDC 318 - a_buffer.m_planeAC * x 319 - a_buffer.m_planeBC * a_y); 320 if(a_buffer.m_depth_test) { 321 if((zpoint>=(*zbuff)) 322 // &&(zpoint>=a_buffer.m_zmin) //for plane quite perpandicular to screen. 323 // &&(zpoint<=a_buffer.m_zmax) 324 ){ 325 *zbuff = zpoint; 326 a_buffer.blend(*zimage,a_buffer.m_scan_pixel); 327 } 328 } else { 329 *zbuff = zpoint; 330 a_buffer.blend(*zimage,a_buffer.m_scan_pixel); 331 } 332 zbuff ++; 333 zimage ++; 334 } 335 } 336 337 typedef void(buffer::*scan_write_point_func)(ZPos,ZPos,ZZ,ZPos,unsigned int,ZPixel); 338 void ScanLine(ZPos a_x,ZPos a_y,ZZ a_z, 339 ZPos a_dx,ZPos a_dy,ZZ a_dz, 340 unsigned int a_size,ZPixel a_pixel, 341 scan_write_point_func a_func){ 342 // Mid point algorithm 343 // assume 0<dx 0<=dy<=dx 344 345 ZPos end = a_x + a_dx; 346 ZPos beg = a_y; 347 ZZ incz = a_dz/(ZZ)a_dx; 348 if(a_dy==0) { 349 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel); 350 while(a_x<end){ 351 a_x++; 352 a_z += incz; 353 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel); 354 } 355 } else if(a_dy==a_dx) { 356 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel); 357 while(a_x<end){ 358 a_x++; 359 a_y++; 360 a_z += incz; 361 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel); 362 } 363 } else { 364 ZPos d = 2 * a_dy - a_dx; 365 ZPos incrE = 2 * a_dy; 366 ZPos incrNE = 2 * ( a_dy - a_dx); 367 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel); 368 while(a_x<end){ 369 if(d<=0){ 370 d += incrE; 371 a_x++; 372 }else{ 373 d += incrNE; 374 a_x++; 375 a_y++; 376 } 377 a_z += incz; 378 (this->*a_func)(a_x,a_y,a_z,beg,a_size,a_pixel); 379 } 380 } 381 } 382 383 void WriteLine(const point& a_beg, 384 const point& a_end, 385 unsigned int a_size,ZPixel a_pixel){ 386 ZPos dx = a_end.x - a_beg.x; 387 ZPos dy = a_end.y - a_beg.y; 388 ZZ dz = a_end.z - a_beg.z; 389 390 // 6 2 391 // 5 1 392 // 7 3 393 // 8 4 394 395 if( (dx==0) && (dy==0) ) { 396 write_point(a_beg.x,a_beg.y,a_beg.z,a_size,a_pixel); 397 write_point(a_end.x,a_end.y,a_end.z,a_size,a_pixel); 398 399 } else if(dx==0) { 400 if(dy>0) 401 ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy, dx, dz, a_size,a_pixel,&buffer::scan_write_point_2); 402 else 403 ScanLine ( a_end.y, a_end.x,a_end.z,-dy, dx,-dz, a_size,a_pixel,&buffer::scan_write_point_2); 404 405 } else if(dx>0) { 406 if((0<=dy) && (dy<=dx)) /*1*/ 407 ScanLine ( a_beg.x, a_beg.y,a_beg.z, dx, dy, dz, a_size,a_pixel,&buffer::scan_write_point_1); 408 else if(dx<dy) /*2*/ 409 ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy, dx, dz, a_size,a_pixel,&buffer::scan_write_point_2); 410 else if((-dx<=dy) && (dy<0) ) /*3*/ 411 ScanLine ( a_beg.x, a_beg.y,a_beg.z, dx,-dy, dz, a_size,a_pixel,&buffer::scan_write_point_3); 412 else if(dy<-dx) /*4*/ 413 ScanLine ( a_end.y, a_end.x,a_end.z,-dy, dx,-dz, a_size,a_pixel,&buffer::scan_write_point_4); 414 415 } else { //dx<0 416 if((0<=dy) && (dy<=-dx)) /*5*/ 417 ScanLine ( a_end.x, a_end.y,a_end.z,-dx, dy,-dz, a_size,a_pixel,&buffer::scan_write_point_3); 418 else if(-dx<dy) /*6*/ 419 ScanLine ( a_beg.y, a_beg.x,a_beg.z, dy,-dx, dz, a_size,a_pixel,&buffer::scan_write_point_4); 420 else if((dx<=dy) && (dy<0) ) /*7*/ 421 ScanLine ( a_end.x, a_end.y,a_end.z,-dx,-dy,-dz, a_size,a_pixel,&buffer::scan_write_point_1); 422 else if(dy<dx) /*8*/ 423 ScanLine ( a_end.y, a_end.x,a_end.z,-dy,-dx,-dz, a_size,a_pixel,&buffer::scan_write_point_2); 424 } 425 426 } 427 428 429 protected: 430 bool m_depth_test; 431 bool m_blend; 432 ZReal* m_zbuffer; 433 //ZReal m_zmin,m_zmax; 434 435 ZPixel* m_zimage; 436 437 unsigned int m_zbw,m_zbh; 438 ZPos m_begX,m_begY; 439 ZPos m_endX,m_endY; //could be <0 440 441 ZPixel m_scan_pixel; 442 ZZ m_planeAC; 443 ZZ m_planeBC; 444 ZZ m_planeDC; 445 //int m_zboundPrec; 446 polygon m_polygon; 447 }; 448 449 }} 450 451 #endif