Panda3D
 All Classes Functions Variables Enumerations
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 PN_stdfloat randFloat() {
00037   return ((PN_stdfloat) rand() / (PN_stdfloat) 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       LVector3 vec3 = LVector3(randFloat()+1000,randFloat(),randFloat())*.001;
00059       LVector4 vec4 = LVector4(1,1,1,randFloat());
00060       LVector2 vec2 = LVector2(0,randFloat());
00061       tvertex->add_data3(vec3);
00062       tcolor->add_data4(vec4);
00063       tuv->add_data2(vec2);
00064       tnormal->add_data3(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, LVector3(0, 0, 1));
00102   _right = _render.get_relative_vector(camera, LVector3(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_data3(0,0,0);
00137     _vertex->add_data3(0,0,0);
00138     _vertex->add_data3(0,0,0);
00139   }
00140   // don't 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(const LVector3 &pos, const LVector4 &frame, PN_stdfloat size, 
00159   const LVector4 &color, PN_stdfloat rotation) {
00160 
00161   rotation = rotation / 57.29578;
00162 
00163   LVector3 v1 = pos + _b1*size*sin(rotation) + _b2*size*cos(rotation);
00164   LVector3 v2 = pos + _b2*size*sin(rotation) + _b3*size*cos(rotation);
00165   LVector3 v3 = pos + _b3*size*sin(rotation) + _b4*size*cos(rotation);
00166   LVector3 v4 = pos + _b4*size*sin(rotation) + _b1*size*cos(rotation);
00167 
00168   PN_stdfloat u = frame.get_x();
00169   PN_stdfloat v = frame.get_y();
00170   PN_stdfloat us = frame.get_z();
00171   PN_stdfloat vs = frame.get_w();
00172 
00173   tri(
00174     v1, color, LVector2(u,v),
00175     v2, color, LVector2(u+us,v),
00176     v3, color, LVector2(u+us,v+vs));
00177   tri(
00178     v3, color, LVector2(u+us,v+vs),
00179     v4, color, LVector2(u,v+vs),
00180     v1, color, LVector2(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(const LVector3 &pos, const LVector4 &frame1, 
00191   const LVector4 &frame2, PN_stdfloat blend, PN_stdfloat size, const LVector4 &color, PN_stdfloat rotation) {
00192 
00193   LVector4 c2 = color;
00194   PN_stdfloat original_w = c2.get_w();
00195   c2.set_w((1.f-blend)*original_w);
00196   particle(pos,frame1,size,c2,rotation);
00197   c2.set_w(blend*original_w);
00198   particle(pos,frame2,size,c2,rotation);
00199 
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: MeshDrawer::billboard
00204 //       Access: Published
00205 //  Description: Draws a billboard - particle with no rotation.
00206 //               Billboards always face the camera.
00207 //               Frame contains u,v,u-size,v-size quadruple.
00208 ////////////////////////////////////////////////////////////////////
00209 void MeshDrawer::billboard(const LVector3 &pos, const LVector4 &frame, PN_stdfloat size, 
00210   const LVector4 &_color) {
00211 
00212   LVector3 v1 = pos + _b1*size;
00213   LVector3 v2 = pos + _b2*size;
00214   LVector3 v3 = pos + _b3*size;
00215   LVector3 v4 = pos + _b4*size;
00216 
00217   PN_stdfloat u = frame.get_x();
00218   PN_stdfloat v = frame.get_y();
00219   PN_stdfloat us = frame.get_z();
00220   PN_stdfloat vs = frame.get_w();
00221   
00222   tri(
00223     v1, _color, LVector2(u,v),
00224     v2, _color, LVector2(u+us,v),
00225     v3, _color, LVector2(u+us,v+vs));
00226   tri(
00227     v3, _color, LVector2(u+us,v+vs),
00228     v4, _color, LVector2(u,v+vs),
00229     v1, _color, LVector2(u,v));
00230 }
00231 
00232 
00233 ////////////////////////////////////////////////////////////////////
00234 //     Function: MeshDrawer::segment
00235 //       Access: Published
00236 //  Description: Draws a segment a line with a thickness. That has
00237 //               billboarding effect.
00238 //               Frame contains u,v,u-size,v-size quadruple.
00239 ////////////////////////////////////////////////////////////////////
00240 void MeshDrawer::segment(const LVector3 &start, const LVector3 &stop, const LVector4 &frame,
00241                          PN_stdfloat thickness, const LVector4 &color) {
00242   link_segment(start, frame, thickness, color);
00243   link_segment(stop, frame, thickness, color);
00244   link_segment_end(frame, color);
00245 }
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: MeshDrawer::cross_segment
00248 //       Access: Published
00249 //  Description: Draws a segment a line with a thickness.  This
00250 //               segment does not use the bill boarding behavior
00251 //               and instead draws 2 planes in a cross.
00252 //               Stars at start and ends at stop.
00253 //               Frame contains u,v,u-size,v-size quadruple.
00254 ////////////////////////////////////////////////////////////////////
00255 void MeshDrawer::cross_segment(const LVector3 &start, const LVector3 &stop, const LVector4 &frame,
00256                                PN_stdfloat thickness, const LVector4 &color) {
00257   
00258   PN_stdfloat u = frame.get_x();
00259   PN_stdfloat v = frame.get_y();
00260   PN_stdfloat us = frame.get_z();
00261   PN_stdfloat vs = frame.get_w();
00262 
00263   LVector3 v1 = start - _up*thickness;
00264   LVector3 v2 = stop - _up*thickness;
00265   LVector3 v3 = stop + _up*thickness;
00266   LVector3 v4 = start + _up*thickness;
00267 
00268   tri(v1, color, LVector2(u,v),
00269       v2, color, LVector2(u+us,v),
00270       v3, color, LVector2(u+us,v+vs));
00271   tri(v3, color, LVector2(u+us,v+vs),
00272       v4, color, LVector2(u,v+vs),
00273       v1, color, LVector2(u,v));
00274 
00275   v1 = start - _right*thickness;
00276   v2 = stop - _right*thickness;
00277   v3 = stop + _right*thickness;
00278   v4 = start + _right*thickness;
00279 
00280   tri(v1, color, LVector2(u,v),
00281       v2, color, LVector2(u+us,v),
00282       v3, color, LVector2(u+us,v+vs));
00283   tri(v3, color, LVector2(u+us,v+vs),
00284       v4, color, LVector2(u,v+vs),
00285       v1, color, LVector2(u,v));
00286 
00287 }
00288 
00289 
00290 
00291 
00292 ////////////////////////////////////////////////////////////////////
00293 //     Function: MeshDrawer::uneven_segment
00294 //       Access: Published
00295 //  Description: Draws a segment a line with different thickness
00296 //               and color on both sides.
00297 //               Stars at start and ends at stop.
00298 //               Frame contains u,v,u-size,v-size quadruple.
00299 ////////////////////////////////////////////////////////////////////
00300 void MeshDrawer::uneven_segment(const LVector3 &start, const LVector3 &stop,
00301   const LVector4 &frame, PN_stdfloat thickness_start, const LVector4 &color_start,
00302   PN_stdfloat thickness_stop, const LVector4 &color_stop) {
00303 
00304   PN_stdfloat u = frame.get_x();
00305   PN_stdfloat v = frame.get_y();
00306   PN_stdfloat us = frame.get_z();
00307   PN_stdfloat vs = frame.get_w();
00308   
00309   LVector3 v1 = start - _up*thickness_start;
00310   LVector3 v2 = stop - _up*thickness_stop;
00311   LVector3 v3 = stop + _up*thickness_stop;
00312   LVector3 v4 = start + _up*thickness_start;
00313   
00314   tri(v1, color_start, LVector2(u,v),
00315       v2, color_stop, LVector2(u+us,v),
00316       v3, color_stop, LVector2(u+us,v+vs));
00317   tri(v3, color_stop, LVector2(u+us,v+vs),
00318       v4, color_start, LVector2(u,v+vs),
00319       v1, color_start, LVector2(u,v));
00320   
00321   v1 = start - _right*thickness_start;
00322   v2 = stop - _right*thickness_stop;
00323   v3 = stop + _right*thickness_stop;
00324   v4 = start + _right*thickness_start;
00325   
00326   tri(v1, color_start, LVector2(u,v),
00327       v2, color_stop, LVector2(u+us,v),
00328       v3, color_stop, LVector2(u+us,v+vs));
00329   tri(v3, color_stop, LVector2(u+us,v+vs),
00330       v4, color_start, LVector2(u,v+vs),
00331       v1, color_start, LVector2(u,v));
00332 }
00333 
00334 ////////////////////////////////////////////////////////////////////
00335 //     Function: MeshDrawer::explosion
00336 //       Access: Published
00337 //  Description: Draws number of particles in a sphere like emitter.
00338 //               Frame contains u,v,u-size,v-size quadruple.
00339 ////////////////////////////////////////////////////////////////////
00340 void MeshDrawer::explosion(
00341   const LVector3 &pos, const LVector4 &frame, PN_stdfloat size, const LVector4 &_color,
00342   int seed, int number, PN_stdfloat distance) {
00343   srand(seed);
00344   LVector3 relative_pos;
00345   for(int i = 0; i < number; i++) {
00346     relative_pos = LVector3(randFloat()-.5f,randFloat()-.5f,randFloat()-.5f);
00347     relative_pos.normalize();
00348     relative_pos *= randFloat()*distance;
00349     particle(relative_pos+pos,frame,size,_color,randFloat()*360.0f);
00350   }
00351 }
00352 
00353 ////////////////////////////////////////////////////////////////////
00354 //     Function: MeshDrawer::stream
00355 //       Access: Published
00356 //  Description: Draws a number of particles in a big line with a
00357 //               shift dictated by the offset.
00358 //               Frame contains u,v,u-size,v-size quadruple.
00359 ////////////////////////////////////////////////////////////////////
00360 void MeshDrawer::stream(const LVector3 &start, const LVector3 &stop, const LVector4 &frame, PN_stdfloat size, const LVector4 &_color,
00361         int number, PN_stdfloat offset) {
00362 
00363   offset = offset-floor(offset);
00364   LVector3 relative_pos = stop;
00365   LVector3 vec = stop - start;
00366   PN_stdfloat distance = vec.length();
00367   for(int i = 0; i < number; i++) {
00368     relative_pos = stop + vec * ((i-offset)*(distance/PN_stdfloat(number)));
00369     billboard(relative_pos,frame,size,_color);
00370   }
00371 }
00372 
00373 
00374 
00375 ////////////////////////////////////////////////////////////////////
00376 //     Function: MeshDrawer::geometry
00377 //       Access: Published
00378 //  Description: Draws the geometry that is inside this node path into
00379 //               the MeshDrawer object.  This performs a similar
00380 //               functions as RigidBodyCombiner but for very
00381 //               dynamic situations that share the same texture
00382 //               like physcal chunks of explosions.  
00383 //               It can be a little slow 
00384 ////////////////////////////////////////////////////////////////////
00385 void MeshDrawer::geometry(NodePath draw_node) {
00386   assert(_render.get_error_type() == NodePath::ET_ok);
00387 
00388   LVector4 color = LVector4(1,1,1,1);
00389   LVector3 vec[3];
00390   LVector2 uv[3];
00391 
00392   // process node
00393   NodePathCollection geom_collection = draw_node.find_all_matches("**/+GeomNode");
00394   for(int i=0; i < geom_collection.get_num_paths(); i++ ) {
00395     NodePath current_node_path = geom_collection.get_path(i);
00396     PT(GeomNode) geomNode = DCAST(GeomNode, current_node_path.node());
00397 
00398     // process geom node
00399     for(int j=0; j<geomNode->get_num_geoms(); j++) {
00400       CPT(Geom) geom = geomNode->get_geom(j);
00401       CPT(GeomVertexData) v_data = geom->get_vertex_data();
00402       GeomVertexReader *prim_vertex_reader = new GeomVertexReader(v_data, "vertex");
00403       GeomVertexReader *prim_uv_reader = new GeomVertexReader(v_data, "texcoord");
00404       for(int k=0; k <geom->get_num_primitives(); k++) {
00405         CPT(GeomPrimitive) prim1 = geom->get_primitive(k);
00406         CPT(GeomPrimitive) _prim  = prim1->decompose();
00407 
00408         // process primitive
00409         for(int p=0; p < _prim->get_num_primitives();p++) {
00410           int s = _prim->get_primitive_start(p);
00411           int e = _prim->get_primitive_end(p);
00412           int indx_over = 0;
00413 
00414           // process polygon
00415           for(int idx=s; idx<e; idx++) {
00416             int vidx = _prim->get_vertex(idx);
00417             prim_vertex_reader->set_row_unsafe(vidx);
00418             prim_uv_reader->set_row_unsafe(vidx);
00419             vec[indx_over] = _render.get_relative_point(
00420                             current_node_path,prim_vertex_reader->get_data3());
00421             uv[indx_over] = prim_uv_reader->get_data2();
00422             indx_over++;
00423             if (indx_over > 2) break;
00424           }
00425 
00426           // draw polygon
00427           tri(vec[0],color,uv[0],
00428           vec[1],color,uv[1],
00429           vec[2],color,uv[2]);
00430         }
00431         // if we are over budget just quit
00432         if( _clear_index > _end_clear_index) return;
00433       }
00434       // delete our reders
00435       delete prim_vertex_reader;
00436       delete prim_uv_reader;
00437     }
00438   }
00439 }
00440 
00441 
00442 
00443 ////////////////////////////////////////////////////////////////////
00444 //     Function: MeshDrawer::link_segment
00445 //       Access: Published
00446 //  Description: Stars or continues linked segment.
00447 //               Control position, frame, thickness and color with
00448 //               parameters.
00449 //               Frame contains u,v,u-size,v-size quadruple.
00450 ////////////////////////////////////////////////////////////////////
00451 void MeshDrawer::
00452 link_segment(const LVector3 &pos, const LVector4 &frame,
00453          PN_stdfloat thickness, const LVector4 &color) {
00454   assert(_render.get_error_type() == NodePath::ET_ok);
00455   assert(_camera.get_error_type() == NodePath::ET_ok);
00456   /*
00457    * X
00458    * ---X
00459    * ===0---X
00460    * ===0===0---X
00461    * ===0===0===O---X
00462    * ===0===0===0===End
00463    *
00464    * first call marks position X
00465    * second call moves position and promises to draw segment
00466    * it can't draw it yet because next segment might bend it
00467    * third call finally draws segment
00468    * and the chain continues till
00469    * link_segment_end to flush the linking segments is called.
00470    */
00471 
00472   // mark 1st position
00473   if(_at_start==0) {
00474     _last_pos = pos;
00475     _last_thickness = thickness;
00476     _last_color = color;
00477     _at_start=1;
00478     return;
00479   }
00480 
00481   LVector3 start = _last_pos;
00482   LVector3 stop = pos;
00483 
00484   LVector3 cam_start3d = _camera.get_relative_point(_render, start);
00485   LPoint2 cam_start2d = LVector2();
00486   LVector3 cam_stop3d = _camera.get_relative_point(_render, stop);
00487   LPoint2 cam_stop2d = LVector2();
00488 
00489   PT(Camera) camera = DCAST(Camera, _camera.node());
00490   PT(Lens) lens = camera->get_lens();
00491 
00492   lens->project(cam_start3d, cam_start2d);
00493   lens->project(cam_stop3d, cam_stop2d);
00494 
00495   LVector2 dif =  cam_stop2d - cam_start2d;
00496   PN_stdfloat rotation = atan2(dif.get_x(),dif.get_y());
00497 
00498   LVector3 now_v1 = start + _b1*(PN_stdfloat)(thickness*sin(rotation)) + _b2*(PN_stdfloat)(thickness*cos(rotation));
00499   LVector3 now_v4 = start + _b4*(PN_stdfloat)(thickness*sin(rotation)) + _b1*(PN_stdfloat)(thickness*cos(rotation));
00500   LVector3 now_v2 = stop + _b2*(PN_stdfloat)(thickness*sin(rotation)) + _b3*(PN_stdfloat)(thickness*cos(rotation));
00501   LVector3 now_v3 = stop + _b3*(PN_stdfloat)(thickness*sin(rotation)) + _b4*(PN_stdfloat)(thickness*cos(rotation));
00502 
00503   // mark the segment we going to draw
00504   // we need to draw it when we know what the next segment looks like
00505   // because it can bend it a little
00506   if(_at_start==1) {
00507     _last_v1 = now_v1;
00508     _last_v2 = now_v2;
00509     _last_v3 = now_v3;
00510     _last_v4 = now_v4;
00511     _at_start = 2;
00512     return;
00513   }
00514 
00515   // draw the last segment a little bent
00516   LVector3 v1 = _last_v1;
00517   LVector3 v2 = (_last_v2+now_v1)/2.0f;
00518   LVector3 v3 = (_last_v3+now_v4)/2.0f;
00519   LVector3 v4 = _last_v4;
00520 
00521   // compute this frame
00522   PN_stdfloat u = frame.get_x();
00523   PN_stdfloat v = frame.get_y();
00524   PN_stdfloat us = frame.get_z();
00525   PN_stdfloat vs = frame.get_w();
00526 
00527   tri(v1, _last_color, LVector2(u,v),
00528       v2, color, LVector2(u+us,v),
00529       v3, color, LVector2(u+us,v+vs));
00530   tri(v3, color, LVector2(u+us,v+vs),
00531       v4, _last_color, LVector2(u,v+vs),
00532       v1, _last_color, LVector2(u,v));
00533 
00534   // save this segment
00535   _last_v1 = v2;
00536   _last_v2 = now_v2;
00537   _last_v3 = now_v3;
00538   _last_v4 = v3;
00539 
00540   // make this position
00541   _last_pos = pos;
00542   _last_thickness = thickness;
00543   _last_color = color;
00544 }
00545 
00546 ////////////////////////////////////////////////////////////////////
00547 //     Function: MeshDrawer::link_segment_end
00548 //       Access: Published
00549 //  Description: Finish drawing linked segments, needs at least
00550 //               two calls to link_segment before it can end
00551 //               the linked segment.
00552 //               Frame contains u,v,u-size,v-size quadruple.
00553 ////////////////////////////////////////////////////////////////////
00554 void MeshDrawer::link_segment_end(const LVector4 &frame, const LVector4 &color)
00555 {
00556   PN_stdfloat u = frame.get_x();
00557   PN_stdfloat v = frame.get_y();
00558   PN_stdfloat us = frame.get_z();
00559   PN_stdfloat vs = frame.get_w();
00560 
00561   tri(_last_v1, _last_color, LVector2(u,v),
00562       _last_v2, color, LVector2(u+us,v),
00563       _last_v3, color, LVector2(u+us,v+vs));
00564   tri(_last_v3, color, LVector2(u+us,v+vs),
00565       _last_v4, _last_color, LVector2(u,v+vs),
00566       _last_v1, _last_color, LVector2(u,v));
00567 
00568   _at_start = 0;
00569 }
 All Classes Functions Variables Enumerations