Panda3D
|
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 }