// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_sg_render_zb #define tools_sg_render_zb #include "manager_zb" #include "render_action" #include "primitive_visitor" #include "../glprims" #include "../zb/buffer" #include "../lina/plane" #include "../mathf" #include "../hls" #include "../colorfs" #include "../lina/vec2f" #include "../lina/vec3d" //ZZ=double #include "../lina/geom2" #ifdef _MSC_VER // disable the warning about the usage of "this" in the constructor. #pragma warning(disable:4355) #endif namespace tools { namespace sg { class render_zb : public render_action { public: virtual void draw_vertex_array(gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs){ m_pv.add_primitive(a_mode,a_floatn,a_xyzs); } virtual void draw_vertex_array_xy(gl::mode_t a_mode,size_t a_floatn,const float* a_xys){ m_pv.add_primitive_xy(a_mode,a_floatn,a_xys); } virtual void draw_vertex_color_array(gl::mode_t a_mode,size_t a_floatn, const float* a_xyzs,const float* a_rgbas){ m_pv.add_primitive(a_mode,a_floatn,a_xyzs,a_rgbas); } virtual void draw_vertex_normal_array(gl::mode_t a_mode,size_t a_floatn, const float* a_xyzs,const float* /*a_nms*/){ m_pv.add_primitive(a_mode,a_floatn,a_xyzs); } virtual void draw_vertex_color_normal_array(gl::mode_t a_mode,size_t a_floatn, const float* a_xyzs,const float* a_rgbas,const float* /*a_nms*/){ // We expect a_nms of size : 3*(a_floatn/3) // (then one normal per 3D point). m_pv.add_primitive(a_mode,a_floatn,a_xyzs,a_rgbas); } virtual void clear_color(float a_r,float a_g,float a_b,float a_a){ zb::buffer::ZPixel px = get_pix(colorf(a_r,a_g,a_b,a_a)); m_zb.clear_color_buffer(px); } virtual void color4f(float a_r,float a_g,float a_b,float a_a){ m_rgba.set_value(a_r,a_g,a_b,a_a); } virtual void line_width(float a_v){m_line_width = a_v;} virtual void point_size(float a_v) {m_point_size = a_v;} virtual void set_polygon_offset(bool a_v) {m_POLYGON_OFFSET_FILL = a_v;} virtual void normal(float a_x,float a_y,float a_z) { m_normal.set_value(a_x,a_y,a_z); } virtual void set_winding(winding_type a_v) { m_ccw = (a_v==winding_ccw?true:false); } virtual void set_depth_test(bool a_on) {m_DEPTH_TEST = a_on;} virtual void set_cull_face(bool a_on) {m_CULL_FACE = a_on;} virtual void set_point_smooth(bool a_on) {m_POINT_SMOOTH = a_on;} virtual void set_line_smooth(bool a_on) {m_LINE_SMOOTH = a_on;} virtual void load_proj_matrix(const mat4f& a_mtx) { m_proj = a_mtx; if(!m_proj.invert(m_proj_1)){} } virtual void load_model_matrix(const mat4f& a_mtx) {m_model = a_mtx;} virtual unsigned int max_lights() {return 1000;} virtual void enable_light(unsigned int, float a_dx,float a_dy,float a_dz, float a_r,float a_g,float a_b,float a_a){ m_light_color.set_value(a_r,a_g,a_b,a_a); m_light_direction.set_value(a_dx,a_dy,a_dz); m_light_on = true; } virtual void set_lighting(bool a_on) {m_light_on = a_on;} virtual void restore_state(unsigned int /*a_ret_num_light*/) { m_proj = m_state.m_proj; m_model = m_state.m_model; if(!m_proj.invert(m_proj_1)){} m_rgba = m_state.m_color; m_ccw = (m_state.m_winding==winding_ccw?true:false); m_POLYGON_OFFSET_FILL = m_state.m_GL_POLYGON_OFFSET_FILL; m_CULL_FACE = m_state.m_GL_CULL_FACE; m_POINT_SMOOTH = m_state.m_GL_POINT_SMOOTH; m_LINE_SMOOTH = m_state.m_GL_LINE_SMOOTH; m_line_width = m_state.m_line_width; m_point_size = m_state.m_point_size; m_light_on = m_state.m_GL_LIGHTING; m_DEPTH_TEST = m_state.m_GL_DEPTH_TEST; /* if(m_state.m_GL_TEXTURE_2D) ::glEnable(GL_TEXTURE_2D); else ::glDisable(GL_TEXTURE_2D); // The "return of separator" state had ret_num_light. // The restored state has m_light. // We have to glDisable lights with index in [m_light,ret_num_light-1] for(unsigned int index=m_state.m_light;index poly; poly.push_back(t1); poly.push_back(t2); poly.push_back(t3); poly.push_back(t4); poly.push_back(t1); {float r,g,b,tx,ty; vec3f p; vec2f t; unsigned char* pos = img.buffer(); for(unsigned int row=0;row cmap_t; public: //const cmap_t& colormap() const {return m_cmap;} //cmap_t& colormap() {return m_cmap;} zb::buffer::ZPixel add_color(float a_r,float a_g,float a_b,float a_a){ return add_color(colorf(a_r,a_g,a_b,a_a)); } zb::buffer::ZPixel add_color(float a_r,float a_g,float a_b){ return add_color(a_r,a_g,a_b,1); } zb::buffer::ZPixel add_color(const colorf& a_col){ //::printf("debug : render_zb::add_color : %g %g %g %g : %d\n", // a_col.r(),a_col.g(),a_col.b(),a_col.a(),m_cmap.size()); zb::buffer::ZPixel pix = (zb::buffer::ZPixel)m_cmap.size(); m_cmap[a_col] = pix; return pix; } zb::buffer::ZPixel get_pix(const colorf& a_rgba) { cmap_t::const_iterator it = m_cmap.find(a_rgba); if(it!=m_cmap.end()) return (*it).second; return add_color(a_rgba); } typedef std::map rcmap_t; const rcmap_t& rcolormap() const {return m_rcmap;} rcmap_t& rcolormap() {return m_rcmap;} protected: void gen_rcmap() { m_rcmap.clear(); cmap_t::const_iterator it; for(it=m_cmap.begin();it!=m_cmap.end();++it){ m_rcmap[(*it).second] = (*it).first; } } public: //typedef wps::VCol VCol; typedef float VCol; static bool get_rgb(void* a_tag,unsigned int a_col,unsigned int a_row,VCol& a_r,VCol& a_g,VCol& a_b){ //used with wps. render_zb* rzb = (render_zb*)a_tag; zb::buffer::ZPixel pix; if(!rzb->zbuffer().get_clipped_pixel(a_col,rzb->wh()-1-a_row,pix)){ rzb->out() << "get_rgb : can't get zbuffer pixel" << std::endl; a_r = 1; a_g = 0; a_b = 0; return false; } if(rzb->rcolormap().empty()) rzb->gen_rcmap(); {rcmap_t::const_iterator it = rzb->rcolormap().find(pix); if(it==rzb->rcolormap().end()) { rzb->out() << "can't find pixel " << pix << " in cmap (sz " << rzb->rcolormap().size() << ")." << std::endl; a_r = 1; a_g = 0; a_b = 0; return false; } a_r = (*it).second.r(); a_g = (*it).second.g(); a_b = (*it).second.b();} return true; } unsigned char* get_rgbas(size_t& a_sz) { if(!m_ww || !m_wh) {a_sz = 0;return 0;} a_sz = 4 * m_ww * m_wh; typedef unsigned char uchar; uchar* rgbas = new uchar[a_sz]; if(!rgbas) {a_sz = 0;return 0;} uchar* pos = rgbas; VCol r,g,b; VCol a = 1; for(unsigned int row=0;row int a_p.y = fround(a_y); //float -> int a_p.z = (zb::ZZ)a_z; //float -> double } unsigned int npix(float a_size) { //a_size must be >1 // 0 -> 0 // 1 -> 0 // 2 -> 1 3x3 // 3 -> 1 3x3 // 4 -> 2 5x5 // 5 -> 2 5x5 // 6 -> 3 7x7 unsigned int num = (unsigned int)a_size; unsigned int num_2 = num/2; if(2*num_2==num) {num++;num_2 = num/2;} return num_2; } bool _add_point(float a_x,float a_y,float a_z,const colorf& a_color){ m_rzb.m_zb.set_depth_test(m_rzb.m_DEPTH_TEST); m_rzb.m_vp_mtx.mul_3f(a_x,a_y,a_z); a_z *= -1; zb::point p; zinit(p,a_x,a_y,a_z); zb::buffer::ZPixel px = m_rzb.get_pix(a_color); m_rzb.m_zb.draw_point(p,px,npix(m_rzb.m_point_size)); return true; } bool _add_triangle(float a_p1x,float a_p1y,float a_p1z,float a_p1w, float a_p2x,float a_p2y,float a_p2z,float a_p2w, float a_p3x,float a_p3y,float a_p3z,float a_p3w, const colorf& a_color){ float p1x = a_p1x;float p1y = a_p1y;float p1z = a_p1z;//float p1w = a_p1w; float p2x = a_p2x;float p2y = a_p2y;float p2z = a_p2z;//float p2w = a_p2w; float p3x = a_p3x;float p3y = a_p3y;float p3z = a_p3z;//float p3w = a_p3w; m_rzb.m_vp_mtx.mul_3f(p1x,p1y,p1z); m_rzb.m_vp_mtx.mul_3f(p2x,p2y,p2z); m_rzb.m_vp_mtx.mul_3f(p3x,p3y,p3z); p1z *= -1; p2z *= -1; p3z *= -1; if(m_rzb.m_POLYGON_OFFSET_FILL){ // zs are in [-1,1] float epsil = 1e-5f; //float epsil = 1e-4f; p1z -= epsil; p2z -= epsil; p3z -= epsil; } typedef zb::ZZ ZZ; //double plane pn( vec3(p1x,p1y,p1z), vec3(p2x,p2y,p2z), vec3(p3x,p3y,p3z) ); if(!pn.is_valid()) return true; // norm[0]*x+norm[1]*y+norm[2]*z = dist // A*x+B*y+C*z+D = 0 ZZ C = pn.normal()[2]; if(m_rzb.m_CULL_FACE){ // check back facing or by the edge : if(m_rzb.m_ccw) { if(C<=0) return true; } else { if(C>=0) return true; } } ZZ A = pn.normal()[0]; ZZ B = pn.normal()[1]; ZZ D = -pn.distance_from_origin(); //ZZ zmn = mn(mn(p1z,p2z),p3z); //ZZ zmx = mx(mx(p1z,p2z),p3z); zb::point list[3]; zinit(list[0],p1x,p1y,p1z); zinit(list[1],p2x,p2y,p2z); zinit(list[2],p3x,p3y,p3z); m_rzb.m_zb.set_depth_test(m_rzb.m_DEPTH_TEST); if(m_rzb.m_light_on) { float _p1x = a_p1x;float _p1y = a_p1y;float _p1z = a_p1z;float _p1w = a_p1w; float _p2x = a_p2x;float _p2y = a_p2y;float _p2z = a_p2z;float _p2w = a_p2w; float _p3x = a_p3x;float _p3y = a_p3y;float _p3z = a_p3z;float _p3w = a_p3w; _p1x *= _p1w;_p1y *= _p1w;_p1z *= _p1w; _p2x *= _p2w;_p2y *= _p2w;_p2z *= _p2w; _p3x *= _p3w;_p3y *= _p3w;_p3z *= _p3w; m_rzb.m_proj_1.mul_4f(_p1x,_p1y,_p1z,_p1w); m_rzb.m_proj_1.mul_4f(_p2x,_p2y,_p2z,_p2w); m_rzb.m_proj_1.mul_4f(_p3x,_p3y,_p3z,_p3w); plane _pn( vec3(_p1x,_p1y,_p1z), vec3(_p2x,_p2y,_p2z), vec3(_p3x,_p3y,_p3z) ); if(_pn.is_valid()) { vec3f npn(float(_pn.normal().x()), float(_pn.normal().y()), float(_pn.normal().z())); vec3f d = m_rzb.m_light_direction; float dx = m_rzb.m_light_direction.x(); float dy = m_rzb.m_light_direction.y(); float dz = m_rzb.m_light_direction.z(); m_rzb.m_model.mul_3f(dx,dy,dz); d.set_value(dx,dy,dz); if(d.normalize()) { float dot = npn.dot(d); if((-1<=dot)&&(dot<=0)) { dot *= -1; // colorf c // (a_color.r()*dot,a_color.g()*dot,a_color.b()*dot,a_color.a()); float h,l,s; rgb_to_hls(a_color.r(),a_color.g(),a_color.b(),h,l,s); l *= dot; float r,g,b; hls_to_rgb(h,l,s,r,g,b); colorf c(r,g,b,a_color.a()); m_rzb.m_zb.draw_polygon(3,list,A,B,C,D,m_rzb.get_pix(c)); //m_rzb.m_zb.draw_polygon(3,list,A,B,C,D,m_rzb.get_pix(a_color)); } } } } else { m_rzb.m_zb.draw_polygon(3,list,A,B,C,D,m_rzb.get_pix(a_color)); } return true; } protected: render_zb& m_rzb; }; protected: manager_zb& m_mgr; mat4f m_vp_mtx; zb::buffer m_zb; primvis m_pv; mat4f m_proj_1; //OPTIMIZE : used if m_light_on true. cmap_t m_cmap; rcmap_t m_rcmap; colorf m_light_color; vec3f m_light_direction; vec3f m_normal; // to be restored in restore_state() : mat4f m_proj; mat4f m_model; colorf m_rgba; bool m_ccw; bool m_POLYGON_OFFSET_FILL; bool m_CULL_FACE; bool m_POINT_SMOOTH; bool m_LINE_SMOOTH; float m_line_width; float m_point_size; bool m_light_on; bool m_DEPTH_TEST; }; }} #endif