[SOLVED] Dynamic Size Primitives

So I’m updating a Geom rapidly, it’s essentially a set of points. Before, I had a fixed array length, and could just modify vertex data on the Geom, like so

// called once
PT(GeomVertexData) data = new GeomVertexData("", GeomVertexFormat::get_v3(), Geom::UH_static);
GeomVertexWriter vertex = GeomVertexWriter(data, "vertex");
for (int i=0; i<1000; i++) {
  vertex.add_data3f(0.0, 0.0, 0.0);
}
PT(GeomPoints) prim = new GeomPoints(UH_static);
prim->add_consecutive_vertices(0, 1000);
prim->close_primitive();
PT(Geom) geom_ = new Geom(data);
geom_->add_primitive(prim);
// called rapidly
PT(GeomVertexData) moddata = geom_->modify_vertex_data();
GeomVertexRewriter vertex = GeomVertexRewriter(moddata, "vertex");
while(!vertex.is_at_end()) {
  vertex.add_data3f(x, y, z);
}
geom_->clear_cache();

But now I want to be able to handle different sizes of points, so not always 1000 points as in this example.
I’d assume instead I just create a new GeomVertexData and just set_vertex_data(moddata) everytime. But I also need to create a new primitive now.
Or is there a more elegant way to modify these on the fly without having to create new VertexData arrays and Primitives and just modify their lengths?

Thanks

You can call GeomVertexData::set_num_rows() to shorten the rows to the number desired. (Actually, if you know the number of rows ahead of time, you get a performance boost for calling this first anyway, because it reduces the need for dynamic allocation.)

You can also call GeomPrimitive::clear_vertices() before filling it up with vertices again.

Or you can use the lower-level accessors to all of these objects if you really want to streamline operations and you’re not afraid to code to the metal and accept the risks that come along with that (including the possibility of your code failing on a future version of Panda that might rework these low-level accessors for some other reason).

But probably it’s better just to do the naive thing and completely replace the GeomVertexData and GeomPrimitive each time, because that’s easier and simpler, and is still going to give you perfectly good performance. Don’t optimize until you need to; spend your programming effort wisely.

David

Great, Ok.

That worked well, this is my final code.

// called once 
PT(GeomVertexData) data = new GeomVertexData("", GeomVertexFormat::get_v3(), Geom::UH_static); 
PT(GeomPoints) prim = new GeomPoints(UH_static); 
PT(Geom) geom_ = new Geom(data); 
geom_->add_primitive(prim);
// called rapidly 
PT(GeomVertexData) moddata = geom_->modify_vertex_data(); 
PT(GeomPrimitive) modprim = geom_->modify_primitive(0);

moddata->set_num_rows(newarrsize);
modprim->clear_vertices();
modprim->add_consecutive_vertices(0, newarrsize);
modprim->close_primitive();

GeomVertexRewriter vertex = GeomVertexRewriter(moddata, "vertex"); 
for(int i=0; i<newarrsize; i++) {
  vertex.add_data3f(x, y, z); 
} 
geom_->clear_cache(); 

and no performance issues. Thanks!

Alright, now I have a geom that increases by one vertex each time the loop runs, and i don’t want to redraw any of the other points, I just want to add a new point to the cloud.

What is the cleanest method to do this? I don’t want to have to redraw all the other points each time if I can avoid it.

Thanks

Just use GeomVertexWriter to add a new row to the vertex data, and use the GeomPrimitive::add_vertex() to add the reference to your GeomPoints object.

David

I think I’m doing that, but I must be using it incorrectly, here is my code

PT(GeomVertexData) moddata = geom_->modify_vertex_data(); 
PT(GeomPrimitive) modprim = geom_->modify_primitive(0);

moddata->set_num_rows(moddata->get_num_rows()+1);
modprim->add_vertex(modprim->get_num_vertices());
modprim->close_primitive();

GeomVertexWriter vertex = GeomVertexWriter(moddata, "vertex"); 
vertex.add_data3f(x, y, z); 
geom_->clear_cache();

And the setup is how I’m doing it as posted earlier in this thread.
But for some reason, I’m getting reader.check_valid(data_reader) each iteration, and nothing displayed.

The GeomVertexWriter starts at row 0. You need to explicitly set it to the row you wish to add:

GeomVertexWriter vertex(moddata, "vertex");
vertex.set_row(moddata->get_num_rows());
vertex.add_data3f(x, y, z); 

Note that you don’t need to call moddata->set_num_rows() explicitly. The point of add_data3f() is that it automatically calls set_num_rows() when you try to add a row beyond the last one. There’s also no reason to call geom->_clear_cache() explicitly.

David

Well it is drawing, but I’m still getting the assertion error (reader.check_valid(data_reader)) every vertex.add_data() call starting with the second one. And after a while, that just causes the program to hang.
Also, i explicitly call the clear_cache to avoid memory leaks I’ve had in the past using geometries this way.

The assertion error means your GeomPrimitive contains index numbers that exceed the number of rows in the GeomVertexData. So, maybe something’s incorrect with the value you passed to modprim->add_vertex()?

It’s not a bad idea to assert(modprim.check_valid(moddata)) yourself after you’ve made all of your changes, to ensure immediately that everything you’ve done is kosher. If that comes out false, you can examine the results with modprim->write(cerr, 0) and/or moddata->write(cerr, 0) and presumably spot the error directly.

David

Alright, that’s all working now. This geometry write issue was actually something completely different, clobbering of two different thread structures inside Panda.

Thanks for the help David!