Panda3D

meshDrawer.cxx

00001 // Filename: meshDrawer.cxx
00002 // Created by:  treeform (19dec08)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "meshDrawer.h"
00016 
00017 #include "geomVertexFormat.h"
00018 #include "geomVertexArrayFormat.h"
00019 #include "geomVertexData.h"
00020 #include "geomVertexWriter.h"
00021 #include "geomVertexRewriter.h"
00022 #include "camera.h"
00023 #include "boundingSphere.h"
00024 #include "geomTristrips.h"
00025 #include "geomTriangles.h"
00026 #include "geom.h"
00027 #include "geomNode.h"
00028 #include "pnmPainter.h"
00029 #include "pnmBrush.h"
00030 #include "lvecBase4.h"
00031 #include "lvector3.h"
00032 #include "pandaNode.h"
00033 
00034 TypeHandle MeshDrawer::_type_handle;
00035 
00036 float randFloat() {
00037   return ((float) rand() / (float) 0x7fffffff);
00038 }
00039 
00040 ////////////////////////////////////////////////////////////////////
00041 //     Function: MeshDrawer::generator
00042 //       Access: Private
00043 //  Description: Creates a system with a given budget.
00044 ////////////////////////////////////////////////////////////////////
00045 void MeshDrawer::generator(int budget) {
00046   // create enough triangles for budget:
00047   _vdata = new GeomVertexData(_root.get_name(), GeomVertexFormat::get_v3n3c4t2(), Geom::UH_static);//UH_dynamic);
00048   GeomVertexWriter *tvertex = new GeomVertexWriter(_vdata, "vertex");
00049   GeomVertexWriter *tnormal = new GeomVertexWriter(_vdata, "normal");
00050   GeomVertexWriter *tuv = new GeomVertexWriter(_vdata, "texcoord");
00051   GeomVertexWriter *tcolor = new GeomVertexWriter(_vdata, "color");
00052   _prim = new GeomTriangles(Geom::UH_static);
00053 
00054   // iterate and fill _up a geom with random data so that it will
00055   // not be optimized out by panda3d system
00056   for(int i = 0; i < budget; i++) {
00057     for( int vert = 0; vert < 3; vert++) {
00058       LVector3f vec3 = LVector3f(randFloat()+1000,randFloat(),randFloat())*.001;
00059       LVector4f vec4 = LVector4f(1,1,1,randFloat());
00060       LVector2f vec2 = LVector2f(0,randFloat());
00061       tvertex->add_data3f(vec3);
00062       tcolor->add_data4f(vec4);
00063       tuv->add_data2f(vec2);
00064       tnormal->add_data3f(vec3);
00065     }
00066     _prim->add_vertices(i * 3, i * 3 + 1, i * 3 + 2);
00067   }
00068   // create our node and attach it to this node path
00069   _prim->close_primitive();
00070   _geom = new Geom(_vdata);
00071   _geom->add_primitive(_prim);
00072   _geomnode = new GeomNode("__MeshDrawer_GeomNode");
00073   _geomnode->add_geom(_geom);
00074   _root.attach_new_node(_geomnode);
00075   _last_clear_index = budget;
00076 
00077   delete tvertex;
00078   delete tnormal;
00079   delete tuv;
00080   delete tcolor;
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: MeshDrawer::begin
00085 //       Access: Published
00086 //  Description: Pass the current camera node and the root node.
00087 //               Passing the camera is required to generate
00088 //               bill boards that face it.
00089 ////////////////////////////////////////////////////////////////////
00090 void MeshDrawer::begin(NodePath camera, NodePath render) {
00091   // sanity check
00092   assert(render.get_error_type() == NodePath::ET_ok);
00093   assert(camera.get_error_type() == NodePath::ET_ok);
00094 
00095   // remember our arguments
00096   _camera = camera;
00097   _render = render;
00098 
00099   // compute some help vectors
00100   _eyePos = camera.get_pos();
00101   _up = _render.get_relative_vector(camera, LVector3f(0, 0, 1));
00102   _right = _render.get_relative_vector(camera, LVector3f(1, 0, 0));
00103   _b1 = - _right - _up;
00104   _b2 =   _right - _up;
00105   _b3 =   _right + _up;
00106   _b4 = - _right + _up;
00107 
00108   // recreate our rewriters
00109   if (_vertex != NULL) delete _vertex;
00110   if (_normal != NULL) delete _normal;
00111   if (_uv != NULL)     delete _uv;
00112   if (_color != NULL)  delete _color;
00113   _vertex = new GeomVertexRewriter(_vdata, "vertex");
00114   _uv = new GeomVertexRewriter(_vdata, "texcoord");
00115   _normal = new GeomVertexRewriter(_vdata, "normal");
00116   _color = new GeomVertexRewriter(_vdata, "color");
00117   _dprim = _prim->decompose();
00118 
00119   // reseta our clearning indexes
00120   _start_clear_index = 0;
00121   _end_clear_index = _budget;
00122   _clear_index = _start_clear_index;
00123 
00124 }
00125 
00126 ////////////////////////////////////////////////////////////////////
00127 //     Function: MeshDrawer::end
00128 //       Access: Published
00129 //  Description: Finish the drawing and clearing off the remaining
00130 //               vertexes.  
00131 ////////////////////////////////////////////////////////////////////
00132 void MeshDrawer::end() {
00133 
00134   // clear the unused triangles at the end of the buffer
00135   for(int i = _clear_index ; i < _last_clear_index; i ++ ) {
00136     _vertex->add_data3f(0,0,0);
00137     _vertex->add_data3f(0,0,0);
00138     _vertex->add_data3f(0,0,0);
00139   }
00140   // dont clear more then you have too
00141   _last_clear_index = _clear_index;
00142 
00143   // delete the re writers
00144   delete _vertex; _vertex = NULL;
00145   delete _uv;     _uv     = NULL;
00146   delete _normal; _normal = NULL;
00147   delete _color;  _color  = NULL;
00148 
00149 }
00150 
00151 ////////////////////////////////////////////////////////////////////
00152 //     Function: MeshDrawer::particle
00153 //       Access: Published
00154 //  Description: Draws a particle that is sort of like a bill board
00155 //               but has an extra rotation component.
00156 //               Frame contains u,v,u-size,v-size quadruple.
00157 ////////////////////////////////////////////////////////////////////
00158 void MeshDrawer::particle(LVector3f pos, LVector4f frame, float size, 
00159   LVector4f color, float rotation) {
00160 
00161   rotation = rotation / 57.29578;
00162 
00163   LVector3f v1 = pos + _b1*size*sin(rotation) + _b2*size*cos(rotation);
00164   LVector3f v2 = pos + _b2*size*sin(rotation) + _b3*size*cos(rotation);
00165   LVector3f v3 = pos + _b3*size*sin(rotation) + _b4*size*cos(rotation);
00166   LVector3f v4 = pos + _b4*size*sin(rotation) + _b1*size*cos(rotation);
00167 
00168   float u = frame.get_x();
00169   float v = frame.get_y();
00170   float us = frame.get_z();
00171   float vs = frame.get_w();
00172 
00173   tri(
00174     v1, color, LVector2f(u,v),
00175     v2, color, LVector2f(u+us,v),
00176     v3, color, LVector2f(u+us,v+vs));
00177   tri(
00178     v3, color, LVector2f(u+us,v+vs),
00179     v4, color, LVector2f(u,v+vs),
00180     v1, color, LVector2f(u,v));
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: MeshDrawer::blended_particle
00185 //       Access: Published
00186 //  Description: Works just like particle but accepts 2 frames and
00187 //               a blend (from 0 to 1) component between them
00188 //               Frame contains u,v,u-size,v-size quadruple.
00189 ////////////////////////////////////////////////////////////////////
00190 void MeshDrawer::blended_particle(LVector3f pos, LVector4f frame1, 
00191   LVector4f frame2, float blend, float size, LVector4f color, float rotation) {
00192 
00193   float original_w = color.get_w();
00194   color.set_w((1.f-blend)*original_w);
00195   particle(pos,frame1,size,color,rotation);
00196   color.set_w(blend*original_w);
00197   particle(pos,frame2,size,color,rotation);
00198 
00199 }
00200 
00201 ////////////////////////////////////////////////////////////////////
00202 //     Function: MeshDrawer::billboard
00203 //       Access: Published
00204 //  Description: Draws a billboard - particle with no rotation.
00205 //               Billboards always face the camera.
00206 //               Frame contains u,v,u-size,v-size quadruple.
00207 ////////////////////////////////////////////////////////////////////
00208 void MeshDrawer::billboard(LVector3f pos, LVector4f frame, float size, 
00209   LVector4f _color) {
00210 
00211   LVector3f v1 = pos + _b1*size;
00212   LVector3f v2 = pos + _b2*size;
00213   LVector3f v3 = pos + _b3*size;
00214   LVector3f v4 = pos + _b4*size;
00215 
00216   float u = frame.get_x();
00217   float v = frame.get_y();
00218   float us = frame.get_z();
00219   float vs = frame.get_w();
00220   
00221   tri(
00222     v1, _color, LVector2f(u,v),
00223     v2, _color, LVector2f(u+us,v),
00224     v3, _color, LVector2f(u+us,v+vs));
00225   tri(
00226     v3, _color, LVector2f(u+us,v+vs),
00227     v4, _color, LVector2f(u,v+vs),
00228     v1, _color, LVector2f(u,v));
00229 }
00230 
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: MeshDrawer::segment
00234 //       Access: Published
00235 //  Description: Draws a segment a line with a thickness. That has
00236 //               billboarding effect.
00237 //               Frame contains u,v,u-size,v-size quadruple.
00238 ////////////////////////////////////////////////////////////////////
00239 void MeshDrawer::segment(LVector3f start, LVector3f stop, LVector4f frame,
00240                          float thickness, LVector4f color) {
00241   link_segment(start, frame, thickness, color);
00242   link_segment(stop, frame, thickness, color);
00243   link_segment_end(frame, color);
00244 }
00245 ////////////////////////////////////////////////////////////////////
00246 //     Function: MeshDrawer::cross_segment
00247 //       Access: Published
00248 //  Description: Draws a segment a line with a thickness.  This
00249 //               segment does not use the bill boarding behavior
00250 //               and instead draws 2 planes in a cross.
00251 //               Stars at start and ends at stop.
00252 //               Frame contains u,v,u-size,v-size quadruple.
00253 ////////////////////////////////////////////////////////////////////
00254 void MeshDrawer::cross_segment(LVector3f start, LVector3f stop, LVector4f frame,
00255                                float thickness, LVector4f color) {
00256   
00257   float u = frame.get_x();
00258   float v = frame.get_y();
00259   float us = frame.get_z();
00260   float vs = frame.get_w();
00261 
00262   LVector3f v1 = start - _up*thickness;
00263   LVector3f v2 = stop - _up*thickness;
00264   LVector3f v3 = stop + _up*thickness;
00265   LVector3f v4 = start + _up*thickness;
00266 
00267   tri(v1, color, LVector2f(u,v),
00268       v2, color, LVector2f(u+us,v),
00269       v3, color, LVector2f(u+us,v+vs));
00270   tri(v3, color, LVector2f(u+us,v+vs),
00271       v4, color, LVector2f(u,v+vs),
00272       v1, color, LVector2f(u,v));
00273 
00274   v1 = start - _right*thickness;
00275   v2 = stop - _right*thickness;
00276   v3 = stop + _right*thickness;
00277   v4 = start + _right*thickness;
00278 
00279   tri(v1, color, LVector2f(u,v),
00280       v2, color, LVector2f(u+us,v),
00281       v3, color, LVector2f(u+us,v+vs));
00282   tri(v3, color, LVector2f(u+us,v+vs),
00283       v4, color, LVector2f(u,v+vs),
00284       v1, color, LVector2f(u,v));
00285 
00286 }
00287 
00288 
00289 
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: MeshDrawer::uneven_segment
00293 //       Access: Published
00294 //  Description: Draws a segment a line with different thickness
00295 //               and color on both sides.
00296 //               Stars at start and ends at stop.
00297 //               Frame contains u,v,u-size,v-size quadruple.
00298 ////////////////////////////////////////////////////////////////////
00299 void MeshDrawer::uneven_segment(LVector3f start, LVector3f stop,
00300   LVector4f frame, float thickness_start, LVector4f color_start,
00301   float thickness_stop, LVector4f color_stop) {
00302 
00303   float u = frame.get_x();
00304   float v = frame.get_y();
00305   float us = frame.get_z();
00306   float vs = frame.get_w();
00307   
00308   LVector3f v1 = start - _up*thickness_start;
00309   LVector3f v2 = stop - _up*thickness_stop;
00310   LVector3f v3 = stop + _up*thickness_stop;
00311   LVector3f v4 = start + _up*thickness_start;
00312   
00313   tri(v1, color_start, LVector2f(u,v),
00314       v2, color_stop, LVector2f(u+us,v),
00315       v3, color_stop, LVector2f(u+us,v+vs));
00316   tri(v3, color_stop, LVector2f(u+us,v+vs),
00317       v4, color_start, LVector2f(u,v+vs),
00318       v1, color_start, LVector2f(u,v));
00319   
00320   v1 = start - _right*thickness_start;
00321   v2 = stop - _right*thickness_stop;
00322   v3 = stop + _right*thickness_stop;
00323   v4 = start + _right*thickness_start;
00324   
00325   tri(v1, color_start, LVector2f(u,v),
00326       v2, color_stop, LVector2f(u+us,v),
00327       v3, color_stop, LVector2f(u+us,v+vs));
00328   tri(v3, color_stop, LVector2f(u+us,v+vs),
00329       v4, color_start, LVector2f(u,v+vs),
00330       v1, color_start, LVector2f(u,v));
00331 }
00332 
00333 ////////////////////////////////////////////////////////////////////
00334 //     Function: MeshDrawer::explosion
00335 //       Access: Published
00336 //  Description: Draws number of particles in a sphere like emitter.
00337 //               Frame contains u,v,u-size,v-size quadruple.
00338 ////////////////////////////////////////////////////////////////////
00339 void MeshDrawer::explosion(
00340   LVector3f pos, LVector4f frame, float size, LVector4f _color,
00341   int seed, int number, float distance) {
00342   srand(seed);
00343   LVector3f relative_pos;
00344   for(int i = 0; i < number; i++) {
00345     relative_pos = LVector3f(randFloat()-.5f,randFloat()-.5f,randFloat()-.5f);
00346     relative_pos.normalize();
00347     relative_pos *= randFloat()*distance;
00348     particle(relative_pos+pos,frame,size,_color,randFloat()*360.0f);
00349   }
00350 }
00351 
00352 ////////////////////////////////////////////////////////////////////
00353 //     Function: MeshDrawer::stream
00354 //       Access: Published
00355 //  Description: Draws a number of particles in a big line with a
00356 //               shift dictated by the offset.
00357 //               Frame contains u,v,u-size,v-size quadruple.
00358 ////////////////////////////////////////////////////////////////////
00359 void MeshDrawer::stream(LVector3f start, LVector3f stop, LVector4f frame, float size, LVector4f _color,
00360         int number, float offset) {
00361 
00362   offset = offset-floor(offset);
00363   LVector3f relative_pos = stop;
00364   LVector3f vec = stop - start;
00365   float distance = vec.length();
00366   for(int i = 0; i < number; i++) {
00367     relative_pos = stop + vec * ((i-offset)*(distance/float(number)));
00368     billboard(relative_pos,frame,size,_color);
00369   }
00370 }
00371 
00372 
00373 
00374 ////////////////////////////////////////////////////////////////////
00375 //     Function: MeshDrawer::geometry
00376 //       Access: Published
00377 //  Description: Draws the geometry that is inside this node path into
00378 //               the MeshDrawer object.  This performs a similar
00379 //               functions as RigidBodyCombiner but for very
00380 //               dynamic situations that share the same texture
00381 //               like physcal chunks of explosions.  
00382 //               It can be a little slow 
00383 ////////////////////////////////////////////////////////////////////
00384 void MeshDrawer::geometry(NodePath draw_node) {
00385   assert(_render.get_error_type() == NodePath::ET_ok);
00386 
00387   LVector4f color = LVector4f(1,1,1,1);
00388   LVector3f vec[3];
00389   LVector2f uv[3];
00390 
00391   // process node
00392   NodePathCollection geom_collection = draw_node.find_all_matches("**/+GeomNode");
00393   for(int i=0; i < geom_collection.get_num_paths(); i++ ) {
00394     NodePath current_node_path = geom_collection.get_path(i);
00395     PT(GeomNode) geomNode = DCAST(GeomNode, current_node_path.node());
00396 
00397     // process geom node
00398     for(int j=0; j<geomNode->get_num_geoms(); j++) {
00399       CPT(Geom) geom = geomNode->get_geom(j);
00400       CPT(GeomVertexData) v_data = geom->get_vertex_data();
00401       GeomVertexReader *prim_vertex_reader = new GeomVertexReader(v_data, "vertex");
00402       GeomVertexReader *prim_uv_reader = new GeomVertexReader(v_data, "texcoord");
00403       for(int k=0; k <geom->get_num_primitives(); k++) {
00404         CPT(GeomPrimitive) prim1 = geom->get_primitive(k);
00405         CPT(GeomPrimitive) _prim  = prim1->decompose();
00406 
00407         // process primitive
00408         for(int p=0; p < _prim->get_num_primitives();p++) {
00409           int s = _prim->get_primitive_start(p);
00410           int e = _prim->get_primitive_end(p);
00411           int indx_over = 0;
00412 
00413           // process polygon
00414           for(int idx=s; idx<e; idx++) {
00415             int vidx = _prim->get_vertex(idx);
00416             prim_vertex_reader->set_row(vidx);
00417             prim_uv_reader->set_row(vidx);
00418             vec[indx_over] = _render.get_relative_point(
00419               current_node_path,prim_vertex_reader->get_data3f());
00420             uv[indx_over] = prim_uv_reader->get_data2f();
00421             indx_over++;
00422             if (indx_over > 2) break;
00423           }
00424 
00425           // draw polygon
00426           tri(vec[0],color,uv[0],
00427             vec[1],color,uv[1],
00428             vec[2],color,uv[2]);
00429         }
00430         // if we are over budget just quit
00431         if( _clear_index > _end_clear_index) return;
00432       }
00433       // delete our reders
00434       delete prim_vertex_reader;
00435       delete prim_uv_reader;
00436     }
00437   }
00438 }
00439 
00440 
00441 
00442 ////////////////////////////////////////////////////////////////////
00443 //     Function: MeshDrawer::link_segment
00444 //       Access: Published
00445 //  Description: Stars or continues linked segment.
00446 //               Control position, frame, thickness and color with
00447 //               parameters.
00448 //               Frame contains u,v,u-size,v-size quadruple.
00449 ////////////////////////////////////////////////////////////////////
00450 void MeshDrawer::link_segment(LVector3f pos, LVector4f frame,
00451         float thickness, LVector4f color) {
00452   assert(_render.get_error_type() == NodePath::ET_ok);
00453   assert(_camera.get_error_type() == NodePath::ET_ok);
00454     /*
00455      * X
00456      * ---X
00457      * ===0---X
00458      * ===0===0---X
00459      * ===0===0===O---X
00460      * ===0===0===0===End
00461      *
00462      * first call marks position X
00463      * second call moves position and promises to draw segment
00464      * it can't draw it yet because next segment might bend it
00465      * third call finally draws segment
00466      * and the chain continues till
00467      * link_segment_end to flush the linking segments is called.
00468      */
00469 
00470     // mark 1st position
00471     if(_at_start==0) {
00472         _last_pos = pos;
00473         _last_thickness = thickness;
00474         _last_color = color;
00475         _at_start=1;
00476         return;
00477     }
00478 
00479     LVector3f start = _last_pos;
00480     LVector3f stop = pos;
00481 
00482   LVector3f cam_start3d = _camera.get_relative_point(_render, start);
00483   LPoint2f cam_start2d = LVector2f();
00484   LVector3f cam_stop3d = _camera.get_relative_point(_render, stop);
00485   LPoint2f cam_stop2d = LVector2f();
00486 
00487   PT(Camera) camera = DCAST(Camera, _camera.node());
00488   PT(Lens) lens = camera->get_lens();
00489 
00490   bool start_good = lens->project(cam_start3d, cam_start2d);
00491   bool stop_good = lens->project(cam_stop3d, cam_stop2d);
00492   //if start_good and stop_good:
00493 
00494   LVector2f dif =  cam_stop2d - cam_start2d;
00495   float rotation = atan2(dif.get_x(),dif.get_y());
00496 
00497   LVector3f now_v1 = start + _b1*(float)(thickness*sin(rotation)) + _b2*(float)(thickness*cos(rotation));
00498   LVector3f now_v4 = start + _b4*(float)(thickness*sin(rotation)) + _b1*(float)(thickness*cos(rotation));
00499   LVector3f now_v2 = stop + _b2*(float)(thickness*sin(rotation)) + _b3*(float)(thickness*cos(rotation));
00500   LVector3f now_v3 = stop + _b3*(float)(thickness*sin(rotation)) + _b4*(float)(thickness*cos(rotation));
00501 
00502   // mark the segment we going to draw
00503   // we need to draw it when we know what the next segment looks like
00504   // because it can bend it a little
00505   if(_at_start==1) {
00506         _last_v1 = now_v1;
00507         _last_v2 = now_v2;
00508         _last_v3 = now_v3;
00509         _last_v4 = now_v4;
00510         _at_start = 2;
00511         return;
00512   }
00513 
00514   // draw the last segment a little bent
00515   LVector3f v1 = _last_v1;
00516   LVector3f v2 = (_last_v2+now_v1)/2.0f;
00517   LVector3f v3 = (_last_v3+now_v4)/2.0f;
00518   LVector3f v4 = _last_v4;
00519 
00520   // compute this frame
00521   float u = frame.get_x();
00522   float v = frame.get_y();
00523   float us = frame.get_z();
00524   float vs = frame.get_w();
00525 
00526   tri(v1, _last_color, LVector2f(u,v),
00527     v2, color, LVector2f(u+us,v),
00528     v3, color, LVector2f(u+us,v+vs));
00529   tri(v3, color, LVector2f(u+us,v+vs),
00530     v4, _last_color, LVector2f(u,v+vs),
00531     v1, _last_color, LVector2f(u,v));
00532 
00533   // save this segment
00534   _last_v1 = v2;
00535   _last_v2 = now_v2;
00536   _last_v3 = now_v3;
00537   _last_v4 = v3;
00538 
00539   // make this position
00540   _last_pos = pos;
00541   _last_thickness = thickness;
00542   _last_color = color;
00543 }
00544 
00545 ////////////////////////////////////////////////////////////////////
00546 //     Function: MeshDrawer::link_segment_end
00547 //       Access: Published
00548 //  Description: Finish drawing linked segments, needs at least
00549 //               two calls to link_segment before it can end
00550 //               the linked segment.
00551 //               Frame contains u,v,u-size,v-size quadruple.
00552 ////////////////////////////////////////////////////////////////////
00553 void MeshDrawer::link_segment_end(LVector4f frame, LVector4f color)
00554 {
00555   float u = frame.get_x();
00556   float v = frame.get_y();
00557   float us = frame.get_z();
00558   float vs = frame.get_w();
00559 
00560   tri(_last_v1, _last_color, LVector2f(u,v),
00561       _last_v2, color, LVector2f(u+us,v),
00562       _last_v3, color, LVector2f(u+us,v+vs));
00563   tri(_last_v3, color, LVector2f(u+us,v+vs),
00564       _last_v4, _last_color, LVector2f(u,v+vs),
00565       _last_v1, _last_color, LVector2f(u,v));
00566 
00567   _at_start = 0;
00568 }
 All Classes Functions Variables Enumerations