Add support for geometry with adjacency information

Example code: https://gist.github.com/rdb/7cebb8941b962c59d5a092048efb3855
This commit is contained in:
rdb 2018-03-01 21:14:12 +01:00
parent 4e640fcb60
commit 9638eb47eb
30 changed files with 1933 additions and 0 deletions

View File

@ -2381,6 +2381,15 @@ draw_triangles(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of disconnected triangles with adjacency information.
*/
bool GraphicsStateGuardian::
draw_triangles_adj(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of triangle strips.
*/
@ -2389,6 +2398,14 @@ draw_tristrips(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of triangle strips with adjacency information.
*/
bool GraphicsStateGuardian::
draw_tristrips_adj(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of triangle fans.
*/
@ -2414,6 +2431,14 @@ draw_lines(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of disconnected line segments with adjacency information.
*/
bool GraphicsStateGuardian::
draw_lines_adj(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of line strips.
*/
@ -2422,6 +2447,14 @@ draw_linestrips(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of line strips with adjacency information.
*/
bool GraphicsStateGuardian::
draw_linestrips_adj(const GeomPrimitivePipelineReader *, bool) {
return false;
}
/**
* Draws a series of disconnected points.
*/

View File

@ -371,16 +371,24 @@ public:
bool force);
virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_triangles_adj(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_tristrips_adj(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_trifans(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_patches(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_lines(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_lines_adj(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_linestrips(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_linestrips_adj(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_points(const GeomPrimitivePipelineReader *reader,
bool force);
virtual void end_draw_primitives();

View File

@ -653,6 +653,12 @@ reset() {
Geom::GR_line_strip |
Geom::GR_flat_last_vertex;
#ifndef OPENGLES
if (_supports_geometry_shaders) {
_supported_geom_rendering |= Geom::GR_adjacency;
}
#endif
_supports_point_parameters = false;
#ifdef OPENGLES_1
@ -4543,6 +4549,68 @@ draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
return true;
}
/**
* Draws a series of disconnected triangles with adjacency information.
*/
#ifndef OPENGLES
bool CLP(GraphicsStateGuardian)::
draw_triangles_adj(const GeomPrimitivePipelineReader *reader, bool force) {
// PStatGPUTimer timer(this, _draw_primitive_pcollector,
// reader->get_current_thread());
#ifndef NDEBUG
if (GLCAT.is_spam()) {
GLCAT.spam() << "draw_triangles_adj: " << *(reader->get_object()) << "\n";
}
#endif // NDEBUG
#ifdef SUPPORT_IMMEDIATE_MODE
if (_use_sender) {
draw_immediate_simple_primitives(reader, GL_TRIANGLES_ADJACENCY);
} else
#endif // SUPPORT_IMMEDIATE_MODE
{
int num_vertices = reader->get_num_vertices();
_vertices_tri_pcollector.add_level(num_vertices);
_primitive_batches_tri_pcollector.add_level(1);
if (reader->is_indexed()) {
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_TRIANGLES_ADJACENCY, num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer, _instance_count);
} else {
_glDrawRangeElements(GL_TRIANGLES_ADJACENCY,
reader->get_min_vertex(),
reader->get_max_vertex(),
num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer);
}
} else {
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawArraysInstanced(GL_TRIANGLES_ADJACENCY,
reader->get_first_vertex(),
num_vertices, _instance_count);
} else {
glDrawArrays(GL_TRIANGLES_ADJACENCY,
reader->get_first_vertex(),
num_vertices);
}
}
}
report_my_gl_errors();
return true;
}
#endif // OPENGLES
/**
* Draws a series of triangle strips.
*/
@ -4669,6 +4737,128 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
return true;
}
/**
* Draws a series of triangle strips with adjacency information.
*/
#ifndef OPENGLES
bool CLP(GraphicsStateGuardian)::
draw_tristrips_adj(const GeomPrimitivePipelineReader *reader, bool force) {
// PStatGPUTimer timer(this, _draw_primitive_pcollector,
// reader->get_current_thread());
report_my_gl_errors();
#ifndef NDEBUG
if (GLCAT.is_spam()) {
GLCAT.spam() << "draw_tristrips_adj: " << *(reader->get_object()) << "\n";
}
#endif // NDEBUG
#ifdef SUPPORT_IMMEDIATE_MODE
if (_use_sender) {
draw_immediate_composite_primitives(reader, GL_TRIANGLE_STRIP_ADJACENCY);
} else
#endif // SUPPORT_IMMEDIATE_MODE
{
if (reader->is_indexed() &&
(_supported_geom_rendering & GeomEnums::GR_strip_cut_index) != 0) {
// One long line strip, connected by strip cut indices.
if (_explicit_primitive_restart) {
glEnable(GL_PRIMITIVE_RESTART);
_glPrimitiveRestartIndex(reader->get_strip_cut_index());
}
int num_vertices = reader->get_num_vertices();
_vertices_tristrip_pcollector.add_level(num_vertices);
_primitive_batches_tristrip_pcollector.add_level(1);
if (reader->is_indexed()) {
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_TRIANGLE_STRIP_ADJACENCY, num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer, _instance_count);
} else {
_glDrawRangeElements(GL_TRIANGLE_STRIP_ADJACENCY,
reader->get_min_vertex(),
reader->get_max_vertex(),
num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer);
}
} else {
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawArraysInstanced(GL_TRIANGLE_STRIP_ADJACENCY,
reader->get_first_vertex(),
num_vertices, _instance_count);
} else {
glDrawArrays(GL_TRIANGLE_STRIP_ADJACENCY,
reader->get_first_vertex(),
num_vertices);
}
}
if (_explicit_primitive_restart) {
glDisable(GL_PRIMITIVE_RESTART);
}
} else {
// Send the individual triangle strips, stepping over the degenerate
// vertices.
CPTA_int ends = reader->get_ends();
_primitive_batches_tristrip_pcollector.add_level(ends.size());
if (reader->is_indexed()) {
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
int index_stride = reader->get_index_stride();
GeomVertexReader mins(reader->get_mins(), 0);
GeomVertexReader maxs(reader->get_maxs(), 0);
nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
unsigned int start = 0;
for (size_t i = 0; i < ends.size(); i++) {
_vertices_tristrip_pcollector.add_level(ends[i] - start);
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_TRIANGLE_STRIP_ADJACENCY, ends[i] - start,
get_numeric_type(reader->get_index_type()),
client_pointer + start * index_stride,
_instance_count);
} else {
_glDrawRangeElements(GL_TRIANGLE_STRIP_ADJACENCY,
mins.get_data1i(), maxs.get_data1i(),
ends[i] - start,
get_numeric_type(reader->get_index_type()),
client_pointer + start * index_stride);
}
start = ends[i] + 1;
}
} else {
unsigned int start = 0;
int first_vertex = reader->get_first_vertex();
for (size_t i = 0; i < ends.size(); i++) {
_vertices_tristrip_pcollector.add_level(ends[i] - start);
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawArraysInstanced(GL_TRIANGLE_STRIP_ADJACENCY, first_vertex + start,
ends[i] - start, _instance_count);
} else {
glDrawArrays(GL_TRIANGLE_STRIP_ADJACENCY, first_vertex + start,
ends[i] - start);
}
start = ends[i] + 1;
}
}
}
}
report_my_gl_errors();
return true;
}
#endif // OPENGLES
/**
* Draws a series of triangle fans.
*/
@ -4888,6 +5078,66 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
return true;
}
/**
* Draws a series of disconnected line segments with adjacency information.
*/
#ifndef OPENGLES
bool CLP(GraphicsStateGuardian)::
draw_lines_adj(const GeomPrimitivePipelineReader *reader, bool force) {
// PStatGPUTimer timer(this, _draw_primitive_pcollector,
// reader->get_current_thread());
#ifndef NDEBUG
if (GLCAT.is_spam()) {
GLCAT.spam() << "draw_lines_adj: " << *(reader->get_object()) << "\n";
}
#endif // NDEBUG
#ifdef SUPPORT_IMMEDIATE_MODE
if (_use_sender) {
draw_immediate_simple_primitives(reader, GL_LINES_ADJACENCY);
} else
#endif // SUPPORT_IMMEDIATE_MODE
{
int num_vertices = reader->get_num_vertices();
_vertices_other_pcollector.add_level(num_vertices);
_primitive_batches_other_pcollector.add_level(1);
if (reader->is_indexed()) {
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_LINES_ADJACENCY, num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer, _instance_count);
} else {
_glDrawRangeElements(GL_LINES_ADJACENCY,
reader->get_min_vertex(),
reader->get_max_vertex(),
num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer);
}
} else {
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawArraysInstanced(GL_LINES_ADJACENCY,
reader->get_first_vertex(),
num_vertices, _instance_count);
} else {
glDrawArrays(GL_LINES_ADJACENCY,
reader->get_first_vertex(),
num_vertices);
}
}
}
report_my_gl_errors();
return true;
}
#endif // OPENGLES
/**
* Draws a series of line strips.
*/
@ -5010,6 +5260,117 @@ draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
return true;
}
/**
* Draws a series of line strips with adjacency information.
*/
#ifndef OPENGLES
bool CLP(GraphicsStateGuardian)::
draw_linestrips_adj(const GeomPrimitivePipelineReader *reader, bool force) {
// PStatGPUTimer timer(this, _draw_primitive_pcollector,
// reader->get_current_thread());
report_my_gl_errors();
#ifndef NDEBUG
if (GLCAT.is_spam()) {
GLCAT.spam() << "draw_linestrips_adj: " << *(reader->get_object()) << "\n";
}
#endif // NDEBUG
#ifdef SUPPORT_IMMEDIATE_MODE
if (_use_sender) {
draw_immediate_composite_primitives(reader, GL_LINE_STRIP_ADJACENCY);
} else
#endif // SUPPORT_IMMEDIATE_MODE
{
if (reader->is_indexed() &&
(_supported_geom_rendering & GeomEnums::GR_strip_cut_index) != 0) {
// One long line strip, connected by strip cut indices.
if (_explicit_primitive_restart) {
glEnable(GL_PRIMITIVE_RESTART);
_glPrimitiveRestartIndex(reader->get_strip_cut_index());
}
int num_vertices = reader->get_num_vertices();
_vertices_other_pcollector.add_level(num_vertices);
_primitive_batches_other_pcollector.add_level(1);
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_LINE_STRIP_ADJACENCY, num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer, _instance_count);
} else {
_glDrawRangeElements(GL_LINE_STRIP_ADJACENCY,
reader->get_min_vertex(),
reader->get_max_vertex(),
num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer);
}
if (_explicit_primitive_restart) {
glDisable(GL_PRIMITIVE_RESTART);
}
} else {
// Send the individual line strips, stepping over the strip-cut indices.
CPTA_int ends = reader->get_ends();
_primitive_batches_other_pcollector.add_level(ends.size());
if (reader->is_indexed()) {
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
int index_stride = reader->get_index_stride();
GeomVertexReader mins(reader->get_mins(), 0);
GeomVertexReader maxs(reader->get_maxs(), 0);
nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
unsigned int start = 0;
for (size_t i = 0; i < ends.size(); i++) {
_vertices_other_pcollector.add_level(ends[i] - start);
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_LINE_STRIP_ADJACENCY, ends[i] - start,
get_numeric_type(reader->get_index_type()),
client_pointer + start * index_stride,
_instance_count);
} else {
_glDrawRangeElements(GL_LINE_STRIP_ADJACENCY,
mins.get_data1i(), maxs.get_data1i(),
ends[i] - start,
get_numeric_type(reader->get_index_type()),
client_pointer + start * index_stride);
}
start = ends[i] + 1;
}
} else {
unsigned int start = 0;
int first_vertex = reader->get_first_vertex();
for (size_t i = 0; i < ends.size(); i++) {
_vertices_other_pcollector.add_level(ends[i] - start);
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawArraysInstanced(GL_LINE_STRIP_ADJACENCY, first_vertex + start,
ends[i] - start, _instance_count);
} else {
glDrawArrays(GL_LINE_STRIP_ADJACENCY, first_vertex + start, ends[i] - start);
}
start = ends[i] + 1;
}
}
}
}
report_my_gl_errors();
return true;
}
#endif // OPENGLES
/**
* Draws a series of disconnected points.
*/

View File

@ -288,16 +288,32 @@ public:
bool force);
virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader,
bool force);
#ifndef OPENGLES
virtual bool draw_triangles_adj(const GeomPrimitivePipelineReader *reader,
bool force);
#endif
virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader,
bool force);
#ifndef OPENGLES
virtual bool draw_tristrips_adj(const GeomPrimitivePipelineReader *reader,
bool force);
#endif
virtual bool draw_trifans(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_patches(const GeomPrimitivePipelineReader *reader,
bool force);
virtual bool draw_lines(const GeomPrimitivePipelineReader *reader,
bool force);
#ifndef OPENGLES
virtual bool draw_lines_adj(const GeomPrimitivePipelineReader *reader,
bool force);
#endif
virtual bool draw_linestrips(const GeomPrimitivePipelineReader *reader,
bool force);
#ifndef OPENGLES
virtual bool draw_linestrips_adj(const GeomPrimitivePipelineReader *reader,
bool force);
#endif
virtual bool draw_points(const GeomPrimitivePipelineReader *reader,
bool force);
virtual void end_draw_primitives();

View File

@ -20,11 +20,15 @@
#include "geomMunger.h"
#include "geomPrimitive.h"
#include "geomTriangles.h"
#include "geomTrianglesAdjacency.h"
#include "geomTristrips.h"
#include "geomTristripsAdjacency.h"
#include "geomTrifans.h"
#include "geomPatches.h"
#include "geomLines.h"
#include "geomLinesAdjacency.h"
#include "geomLinestrips.h"
#include "geomLinestripsAdjacency.h"
#include "geomPoints.h"
#include "geomVertexArrayData.h"
#include "geomVertexArrayFormat.h"
@ -546,14 +550,18 @@ ConfigureFn(config_gobj) {
GeomPipelineReader::init_type();
GeomContext::init_type();
GeomLines::init_type();
GeomLinesAdjacency::init_type();
GeomLinestrips::init_type();
GeomLinestripsAdjacency::init_type();
GeomMunger::init_type();
GeomPoints::init_type();
GeomPrimitive::init_type();
GeomPrimitivePipelineReader::init_type();
GeomTriangles::init_type();
GeomTrianglesAdjacency::init_type();
GeomTrifans::init_type();
GeomTristrips::init_type();
GeomTristripsAdjacency::init_type();
GeomPatches::init_type();
GeomVertexArrayData::init_type();
GeomVertexArrayDataHandle::init_type();
@ -601,11 +609,15 @@ ConfigureFn(config_gobj) {
// factory
Geom::register_with_read_factory();
GeomLines::register_with_read_factory();
GeomLinesAdjacency::register_with_read_factory();
GeomLinestrips::register_with_read_factory();
GeomLinestripsAdjacency::register_with_read_factory();
GeomPoints::register_with_read_factory();
GeomTriangles::register_with_read_factory();
GeomTrianglesAdjacency::register_with_read_factory();
GeomTrifans::register_with_read_factory();
GeomTristrips::register_with_read_factory();
GeomTristripsAdjacency::register_with_read_factory();
GeomPatches::register_with_read_factory();
GeomVertexArrayData::register_with_read_factory();
GeomVertexArrayFormat::register_with_read_factory();

View File

@ -212,6 +212,17 @@ make_patches() const {
return new_geom;
}
/**
* Returns a new Geom with each primitive converted into a corresponding
* version with adjacency information.
*/
INLINE PT(Geom) Geom::
make_adjacency() const {
PT(Geom) new_geom = make_copy();
new_geom->make_adjacency_in_place();
return new_geom;
}
/**
* Returns a sequence number which is guaranteed to change at least every time
* any of the primitives in the Geom is modified, or the set of primitives is

View File

@ -834,6 +834,42 @@ make_patches_in_place() {
nassertv(all_is_valid);
}
/**
* Replaces the GeomPrimitives within this Geom with corresponding versions
* with adjacency information. See GeomPrimitive::make_adjacency().
*
* Don't call this in a downstream thread unless you don't mind it blowing
* away other changes you might have recently made in an upstream thread.
*/
void Geom::
make_adjacency_in_place() {
Thread *current_thread = Thread::get_current_thread();
CDWriter cdata(_cycler, true, current_thread);
#ifndef NDEBUG
bool all_is_valid = true;
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_adjacency();
if (new_prim != nullptr) {
(*pi) = (GeomPrimitive *)new_prim.p();
#ifndef NDEBUG
if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
all_is_valid = false;
}
#endif
}
}
cdata->_modified = Geom::get_next_modified();
reset_geom_rendering(cdata);
clear_cache_stage(current_thread);
nassertv(all_is_valid);
}
/**
* Copies the primitives from the indicated Geom into this one. This does
* require that both Geoms contain the same fundamental type primitives, both

View File

@ -106,6 +106,7 @@ PUBLISHED:
INLINE PT(Geom) make_points() const;
INLINE PT(Geom) make_lines() const;
INLINE PT(Geom) make_patches() const;
INLINE PT(Geom) make_adjacency() const;
void decompose_in_place();
void doubleside_in_place();
@ -115,6 +116,7 @@ PUBLISHED:
void make_points_in_place();
void make_lines_in_place();
void make_patches_in_place();
void make_adjacency_in_place();
virtual bool copy_primitives_from(const Geom *other);

View File

@ -132,6 +132,9 @@ PUBLISHED:
// If a particular non-fill polygon mode is used.
GR_render_mode_wireframe= 0x40000,
GR_render_mode_point = 0x80000,
// The primitive has adjacency information.
GR_adjacency = 0x100000,
};
// The shade model specifies whether the per-vertex colors and normals

View File

@ -18,6 +18,7 @@
#include "graphicsStateGuardianBase.h"
#include "geomVertexReader.h"
#include "geomVertexWriter.h"
#include "geomLinesAdjacency.h"
TypeHandle GeomLines::_type_handle;
@ -67,6 +68,67 @@ get_primitive_type() const {
return PT_lines;
}
/**
* Adds adjacency information to this primitive. May return null if this type
* of geometry does not support adjacency information.
*/
CPT(GeomPrimitive) GeomLines::
make_adjacency() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomLinesAdjacency) adj = new GeomLinesAdjacency(get_usage_hint());
GeomPrimitivePipelineReader from(this, current_thread);
int num_vertices = from.get_num_vertices();
PT(GeomVertexArrayData) new_vertices = adj->make_index_data();
new_vertices->set_num_rows(num_vertices * 2);
// First, build a map of each vertex to its next vertex, and another map
// doing the exact reverse. Note that this only considers lines that are
// ordered the same way as being connected; we may need to change this.
map<int, int> forward_map, reverse_map;
for (int i = 0; i < num_vertices; i += 2) {
int v0 = from.get_vertex(i);
int v1 = from.get_vertex(i + 1);
forward_map[v0] = v1;
reverse_map[v1] = v0;
}
// Now build up the new vertex data. For each line, we insert the
// appropriate connecting vertex.
{
GeomVertexWriter to(new_vertices, 0);
for (int i = 0; i < num_vertices; i += 2) {
int v0 = from.get_vertex(i);
int v1 = from.get_vertex(i + 1);
auto it = reverse_map.find(v0);
if (it != reverse_map.end()) {
to.set_data1i(it->second);
} else {
// Um, no adjoining line segment? Just repeat the vertex, I guess.
to.set_data1i(v0);
}
to.set_data1i(v0);
to.set_data1i(v1);
// Do the same for the second vertex in the line.
it = forward_map.find(v1);
if (it != forward_map.end()) {
to.set_data1i(it->second);
} else {
to.set_data1i(v1);
}
}
nassertr(to.is_at_end(), nullptr);
}
adj->set_vertices(move(new_vertices));
return adj.p();
}
/**
* If the primitive type is a simple type in which all primitives have the
* same number of vertices, like lines, returns the number of vertices per

View File

@ -31,6 +31,8 @@ public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
CPT(GeomPrimitive) make_adjacency() const;
virtual int get_num_vertices_per_primitive() const;
virtual int get_min_num_vertices_per_primitive() const;

View File

@ -0,0 +1,132 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomLinesAdjacency.cxx
* @author rdb
* @date 2018-03-01
*/
#include "geomLinesAdjacency.h"
#include "pStatTimer.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
#include "geomVertexReader.h"
#include "geomVertexWriter.h"
TypeHandle GeomLinesAdjacency::_type_handle;
/**
*
*/
GeomLinesAdjacency::
GeomLinesAdjacency(GeomEnums::UsageHint usage_hint) :
GeomPrimitive(usage_hint)
{
}
/**
*
*/
GeomLinesAdjacency::
GeomLinesAdjacency(const GeomLinesAdjacency &copy) :
GeomPrimitive(copy)
{
}
/**
*
*/
GeomLinesAdjacency::
~GeomLinesAdjacency() {
}
/**
*
*/
PT(GeomPrimitive) GeomLinesAdjacency::
make_copy() const {
return new GeomLinesAdjacency(*this);
}
/**
* Returns the fundamental rendering type of this primitive: whether it is
* points, lines, or polygons.
*
* This is used to set up the appropriate antialiasing settings when
* AntialiasAttrib::M_auto is in effect; it also implies the type of primitive
* that will be produced when decompose() is called.
*/
GeomPrimitive::PrimitiveType GeomLinesAdjacency::
get_primitive_type() const {
return PT_lines;
}
/**
* Returns the set of GeomRendering bits that represent the rendering
* properties required to properly render this primitive.
*/
int GeomLinesAdjacency::
get_geom_rendering() const {
return GeomPrimitive::get_geom_rendering() | GR_adjacency;
}
/**
* If the primitive type is a simple type in which all primitives have the
* same number of vertices, like lines, returns the number of vertices per
* primitive. If the primitive type is a more complex type in which different
* primitives might have different numbers of vertices, for instance a line
* strip, returns 0.
*/
int GeomLinesAdjacency::
get_num_vertices_per_primitive() const {
return 4;
}
/**
* Returns the minimum number of vertices that must be added before
* close_primitive() may legally be called.
*/
int GeomLinesAdjacency::
get_min_num_vertices_per_primitive() const {
return 4;
}
/**
* Calls the appropriate method on the GSG to draw the primitive.
*/
bool GeomLinesAdjacency::
draw(GraphicsStateGuardianBase *gsg, const GeomPrimitivePipelineReader *reader,
bool force) const {
return gsg->draw_lines_adj(reader, force);
}
/**
* Tells the BamReader how to create objects of type Geom.
*/
void GeomLinesAdjacency::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
/**
* This function is called by the BamReader's factory when a new object of
* type Geom is encountered in the Bam file. It should create the Geom and
* extract its information from the file.
*/
TypedWritable *GeomLinesAdjacency::
make_from_bam(const FactoryParams &params) {
GeomLinesAdjacency *object = new GeomLinesAdjacency(UH_unspecified);
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
object->fillin(scan, manager);
return object;
}

View File

@ -0,0 +1,70 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomLinesAdjacency.h
* @author rdb
* @date 2018-03-01
*/
#ifndef GEOMLINESADJACENCY_H
#define GEOMLINESADJACENCY_H
#include "pandabase.h"
#include "geomPrimitive.h"
/**
* Defines a series of disconnected line segments with adjacency information,
* for use with geometry shaders.
*/
class EXPCL_PANDA_GOBJ GeomLinesAdjacency : public GeomPrimitive {
PUBLISHED:
explicit GeomLinesAdjacency(UsageHint usage_hint);
GeomLinesAdjacency(const GeomLinesAdjacency &copy);
virtual ~GeomLinesAdjacency();
ALLOC_DELETED_CHAIN(GeomLinesAdjacency);
public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
virtual int get_num_vertices_per_primitive() const;
virtual int get_min_num_vertices_per_primitive() const;
public:
virtual bool draw(GraphicsStateGuardianBase *gsg,
const GeomPrimitivePipelineReader *reader,
bool force) const;
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GeomPrimitive::init_type();
register_type(_type_handle, "GeomLinesAdjacency",
GeomPrimitive::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class Geom;
};
#endif

View File

@ -18,6 +18,7 @@
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
#include "geomLinestripsAdjacency.h"
TypeHandle GeomLinestrips::_type_handle;
@ -84,6 +85,86 @@ get_geom_rendering() const {
}
}
/**
* Adds adjacency information to this primitive. May return null if this type
* of geometry does not support adjacency information.
*/
CPT(GeomPrimitive) GeomLinestrips::
make_adjacency() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomLinestripsAdjacency) adj = new GeomLinestripsAdjacency(get_usage_hint());
GeomPrimitivePipelineReader from(this, current_thread);
int num_vertices = from.get_num_vertices();
CPTA_int ends = get_ends();
const int num_unused = 1;
// First, build a map of each vertex to its next vertex, and another map
// doing the exact reverse.
map<int, int> forward_map, reverse_map;
int vi = -num_unused;
int li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between linestrips.
vi += num_unused;
int end = ends[li];
nassertr(vi + 1 <= end, nullptr);
int v0 = from.get_vertex(vi++);
while (vi < end) {
int v1 = from.get_vertex(vi++);
forward_map[v0] = v1;
reverse_map[v1] = v0;
v0 = v1;
}
++li;
}
nassertr(vi == num_vertices, nullptr);
// Now build up the new vertex data. For each linestrip, we prepend and
// append the appropriate connecting vertices.
vi = -num_unused;
li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between linestrips.
vi += num_unused;
int end = ends[li];
nassertr(vi + 1 <= end, nullptr);
// Look for the line segment connected to the beginning of this strip.
int v0 = from.get_vertex(vi++);
auto it = reverse_map.find(v0);
if (it != reverse_map.end()) {
adj->add_vertex(it->second);
} else {
// Um, no adjoining line segment? Just repeat the vertex, I guess.
adj->add_vertex(v0);
}
// Add the actual vertices in the strip.
adj->add_vertex(v0);
int v1;
while (vi < end) {
v1 = from.get_vertex(vi++);
adj->add_vertex(v1);
}
// Do the same for the last vertex in the strip.
it = forward_map.find(v1);
if (it != forward_map.end()) {
adj->add_vertex(it->second);
} else {
adj->add_vertex(v1);
}
adj->close_primitive();
++li;
}
nassertr(vi == num_vertices, nullptr);
return adj.p();
}
/**
* Returns the minimum number of vertices that must be added before
* close_primitive() may legally be called.

View File

@ -31,6 +31,9 @@ public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
CPT(GeomPrimitive) make_adjacency() const;
virtual int get_min_num_vertices_per_primitive() const;
virtual int get_num_unused_vertices_per_primitive() const;

View File

@ -0,0 +1,210 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomLinestripsAdjacency.cxx
* @author rdb
* @date 2018-03-01
*/
#include "geomLinestripsAdjacency.h"
#include "geomLines.h"
#include "geomVertexRewriter.h"
#include "pStatTimer.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
TypeHandle GeomLinestripsAdjacency::_type_handle;
/**
*
*/
GeomLinestripsAdjacency::
GeomLinestripsAdjacency(GeomEnums::UsageHint usage_hint) :
GeomPrimitive(usage_hint)
{
}
/**
*
*/
GeomLinestripsAdjacency::
GeomLinestripsAdjacency(const GeomLinestripsAdjacency &copy) :
GeomPrimitive(copy)
{
}
/**
*
*/
GeomLinestripsAdjacency::
~GeomLinestripsAdjacency() {
}
/**
*
*/
PT(GeomPrimitive) GeomLinestripsAdjacency::
make_copy() const {
return new GeomLinestripsAdjacency(*this);
}
/**
* Returns the fundamental rendering type of this primitive: whether it is
* points, lines, or polygons.
*
* This is used to set up the appropriate antialiasing settings when
* AntialiasAttrib::M_auto is in effect; it also implies the type of primitive
* that will be produced when decompose() is called.
*/
GeomPrimitive::PrimitiveType GeomLinestripsAdjacency::
get_primitive_type() const {
return PT_lines;
}
/**
* Returns the set of GeomRendering bits that represent the rendering
* properties required to properly render this primitive.
*/
int GeomLinestripsAdjacency::
get_geom_rendering() const {
if (is_indexed()) {
if (get_num_primitives() > 1) {
return GR_line_strip | GR_indexed_other | GR_strip_cut_index | GR_adjacency;
} else {
return GR_line_strip | GR_indexed_other | GR_adjacency;
}
} else {
return GR_line_strip | GR_adjacency;
}
}
/**
* Returns the minimum number of vertices that must be added before
* close_primitive() may legally be called.
*/
int GeomLinestripsAdjacency::
get_min_num_vertices_per_primitive() const {
return 4;
}
/**
* Returns the number of vertices that are added between primitives that
* aren't, strictly speaking, part of the primitives themselves. This is
* used, for instance, to define degenerate triangles to connect otherwise
* disconnected triangle strips.
*/
int GeomLinestripsAdjacency::
get_num_unused_vertices_per_primitive() const {
return 1;
}
/**
* Calls the appropriate method on the GSG to draw the primitive.
*/
bool GeomLinestripsAdjacency::
draw(GraphicsStateGuardianBase *gsg, const GeomPrimitivePipelineReader *reader,
bool force) const {
return gsg->draw_linestrips_adj(reader, force);
}
/**
* Decomposes a complex primitive type into a simpler primitive type, for
* instance line strips to lines, and returns a pointer to the new primitive
* definition. If the decomposition cannot be performed, this might return
* the original object.
*
* This method is useful for application code that wants to iterate through
* the set of lines on the primitive without having to write handlers for each
* possible kind of primitive type.
*/
CPT(GeomPrimitive) GeomLinestripsAdjacency::
decompose_impl() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomLinesAdjacency) lines = new GeomLinesAdjacency(get_usage_hint());
lines->set_shade_model(get_shade_model());
GeomPrimitivePipelineReader from(this, current_thread);
int num_vertices = from.get_num_vertices();
CPTA_int ends = get_ends();
const int num_unused = 1;
int vi = -num_unused;
int li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between tristrips.
vi += num_unused;
int end = ends[li];
nassertr(vi + 3 <= end, lines.p());
int v0 = from.get_vertex(vi++);
int v1 = from.get_vertex(vi++);
int v2 = from.get_vertex(vi++);
while (vi < end) {
int v3 = from.get_vertex(vi++);
lines->add_vertex(v0);
lines->add_vertex(v1);
lines->add_vertex(v2);
lines->add_vertex(v3);
v0 = v1;
v1 = v2;
v2 = v3;
}
++li;
}
nassertr(vi == num_vertices, nullptr);
return lines.p();
}
/**
* Should be redefined to return true in any primitive that implements
* append_unused_vertices().
*/
bool GeomLinestripsAdjacency::
requires_unused_vertices() const {
return true;
}
/**
* Called when a new primitive is begun (other than the first primitive), this
* should add some degenerate vertices between primitives, if the primitive
* type requires that. The second parameter is the first vertex that begins
* the new primitive.
*/
void GeomLinestripsAdjacency::
append_unused_vertices(GeomVertexArrayData *vertices, int vertex) {
GeomVertexWriter to(vertices, 0);
to.set_row_unsafe(vertices->get_num_rows());
to.add_data1i(get_strip_cut_index());
}
/**
* Tells the BamReader how to create objects of type Geom.
*/
void GeomLinestripsAdjacency::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
/**
* This function is called by the BamReader's factory when a new object of
* type Geom is encountered in the Bam file. It should create the Geom and
* extract its information from the file.
*/
TypedWritable *GeomLinestripsAdjacency::
make_from_bam(const FactoryParams &params) {
GeomLinestripsAdjacency *object = new GeomLinestripsAdjacency(UH_unspecified);
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
object->fillin(scan, manager);
return object;
}

View File

@ -0,0 +1,75 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomLinestripsAdjacency.h
* @author rdb
* @date 2018-03-01
*/
#ifndef GEOMLINESTRIPSADJACENCY_H
#define GEOMLINESTRIPSADJACENCY_H
#include "pandabase.h"
#include "geomPrimitive.h"
/**
* Defines a series of line strips.
*/
class EXPCL_PANDA_GOBJ GeomLinestripsAdjacency : public GeomPrimitive {
PUBLISHED:
explicit GeomLinestripsAdjacency(UsageHint usage_hint);
GeomLinestripsAdjacency(const GeomLinestripsAdjacency &copy);
virtual ~GeomLinestripsAdjacency();
ALLOC_DELETED_CHAIN(GeomLinestripsAdjacency);
public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
virtual int get_min_num_vertices_per_primitive() const;
virtual int get_num_unused_vertices_per_primitive() const;
public:
virtual bool draw(GraphicsStateGuardianBase *gsg,
const GeomPrimitivePipelineReader *reader,
bool force) const;
protected:
virtual CPT(GeomPrimitive) decompose_impl() const;
virtual bool requires_unused_vertices() const;
virtual void append_unused_vertices(GeomVertexArrayData *vertices,
int vertex);
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GeomPrimitive::init_type();
register_type(_type_handle, "GeomLinestripsAdjacency",
GeomPrimitive::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class Geom;
};
#endif

View File

@ -1021,6 +1021,15 @@ make_patches() const {
return patches;
}
/**
* Adds adjacency information to this primitive. May return null if this type
* of geometry does not support adjacency information.
*/
CPT(GeomPrimitive) GeomPrimitive::
make_adjacency() const {
return nullptr;
}
/**
* Returns the number of bytes consumed by the primitive and its index
* table(s).

View File

@ -134,6 +134,7 @@ PUBLISHED:
CPT(GeomPrimitive) make_points() const;
CPT(GeomPrimitive) make_lines() const;
CPT(GeomPrimitive) make_patches() const;
virtual CPT(GeomPrimitive) make_adjacency() const;
int get_num_bytes() const;
INLINE int get_data_size_bytes() const;

View File

@ -17,6 +17,7 @@
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
#include "geomTrianglesAdjacency.h"
TypeHandle GeomTriangles::_type_handle;
@ -66,6 +67,76 @@ get_primitive_type() const {
return PT_polygons;
}
/**
* Adds adjacency information to this primitive. May return null if this type
* of geometry does not support adjacency information.
*/
CPT(GeomPrimitive) GeomTriangles::
make_adjacency() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomTrianglesAdjacency) adj = new GeomTrianglesAdjacency(get_usage_hint());
GeomPrimitivePipelineReader from(this, current_thread);
int num_vertices = from.get_num_vertices();
PT(GeomVertexArrayData) new_vertices = adj->make_index_data();
new_vertices->set_num_rows(num_vertices * 2);
// First, build a map of each triangle's halfedges to its opposing vertices.
map<pair<int, int>, int> edge_map;
for (int i = 0; i < num_vertices; i += 3) {
int v0 = from.get_vertex(i);
int v1 = from.get_vertex(i + 1);
int v2 = from.get_vertex(i + 2);
edge_map[make_pair(v0, v1)] = v2;
edge_map[make_pair(v1, v2)] = v0;
edge_map[make_pair(v2, v0)] = v1;
}
// Now build up the new vertex data. For each edge, we insert the
// appropriate connecting vertex.
{
GeomVertexWriter to(new_vertices, 0);
for (int i = 0; i < num_vertices; i += 3) {
int v0 = from.get_vertex(i);
int v1 = from.get_vertex(i + 1);
int v2 = from.get_vertex(i + 2);
// Get the third vertex of the triangle adjoining this edge.
to.set_data1(v0);
auto it = edge_map.find(make_pair(v1, v0));
if (it != edge_map.end()) {
to.set_data1i(it->second);
} else {
// Um, no adjoining triangle? Just repeat the vertex, I guess.
to.set_data1i(v0);
}
// Do the same for the other two edges.
to.set_data1(v1);
it = edge_map.find(make_pair(v2, v1));
if (it != edge_map.end()) {
to.set_data1i(it->second);
} else {
to.set_data1i(v1);
}
to.set_data1(v2);
it = edge_map.find(make_pair(v0, v2));
if (it != edge_map.end()) {
to.set_data1i(it->second);
} else {
to.set_data1i(v2);
}
}
nassertr(to.is_at_end(), nullptr);
}
adj->set_vertices(move(new_vertices));
return adj.p();
}
/**
* If the primitive type is a simple type in which all primitives have the
* same number of vertices, like triangles, returns the number of vertices per

View File

@ -31,6 +31,8 @@ public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
CPT(GeomPrimitive) make_adjacency() const;
virtual int get_num_vertices_per_primitive() const;
public:

View File

@ -0,0 +1,195 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomTrianglesAdjacency.cxx
* @author rdb
* @date 2018-03-01
*/
#include "geomTrianglesAdjacency.h"
#include "geomVertexRewriter.h"
#include "pStatTimer.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
TypeHandle GeomTrianglesAdjacency::_type_handle;
/**
*
*/
GeomTrianglesAdjacency::
GeomTrianglesAdjacency(GeomTrianglesAdjacency::UsageHint usage_hint) :
GeomPrimitive(usage_hint)
{
}
/**
*
*/
GeomTrianglesAdjacency::
GeomTrianglesAdjacency(const GeomTrianglesAdjacency &copy) :
GeomPrimitive(copy)
{
}
/**
*
*/
GeomTrianglesAdjacency::
~GeomTrianglesAdjacency() {
}
/**
*
*/
PT(GeomPrimitive) GeomTrianglesAdjacency::
make_copy() const {
return new GeomTrianglesAdjacency(*this);
}
/**
* Returns the fundamental rendering type of this primitive: whether it is
* points, lines, or polygons.
*
* This is used to set up the appropriate antialiasing settings when
* AntialiasAttrib::M_auto is in effect; it also implies the type of primitive
* that will be produced when decompose() is called.
*/
GeomPrimitive::PrimitiveType GeomTrianglesAdjacency::
get_primitive_type() const {
return PT_polygons;
}
/**
* Returns the set of GeomRendering bits that represent the rendering
* properties required to properly render this primitive.
*/
int GeomTrianglesAdjacency::
get_geom_rendering() const {
return GeomPrimitive::get_geom_rendering() | GR_adjacency;
}
/**
* If the primitive type is a simple type in which all primitives have the
* same number of vertices, like triangles, returns the number of vertices per
* primitive. If the primitive type is a more complex type in which different
* primitives might have different numbers of vertices, for instance a
* triangle strip, returns 0.
*/
int GeomTrianglesAdjacency::
get_num_vertices_per_primitive() const {
return 6;
}
/**
* Calls the appropriate method on the GSG to draw the primitive.
*/
bool GeomTrianglesAdjacency::
draw(GraphicsStateGuardianBase *gsg, const GeomPrimitivePipelineReader *reader,
bool force) const {
return gsg->draw_triangles_adj(reader, force);
}
/**
* The virtual implementation of doubleside().
*/
CPT(GeomPrimitive) GeomTrianglesAdjacency::
doubleside_impl() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomTrianglesAdjacency) reversed = new GeomTrianglesAdjacency(*this);
GeomPrimitivePipelineReader from(this, current_thread);
// This is like reverse(), except we don't clear the vertices first. That
// way we double the vertices up.
// First, rotate the original copy, if necessary, so the flat-firstflat-last
// nature of the vertices is consistent throughout the primitive.
bool needs_rotate = false;
switch (from.get_shade_model()) {
case SM_flat_first_vertex:
case SM_flat_last_vertex:
reversed = (GeomTrianglesAdjacency *)DCAST(GeomTrianglesAdjacency, reversed->rotate());
needs_rotate = true;
default:
break;
}
// Now append all the new vertices, in reverse order.
for (int i = from.get_num_vertices() - 1; i >= 0; --i) {
reversed->add_vertex(from.get_vertex(i));
}
// Finally, re-rotate the whole thing to get back to the original shade
// model.
if (needs_rotate) {
reversed = (GeomTrianglesAdjacency *)DCAST(GeomTrianglesAdjacency, reversed->rotate());
}
return reversed.p();
}
/**
* The virtual implementation of reverse().
*/
CPT(GeomPrimitive) GeomTrianglesAdjacency::
reverse_impl() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomTrianglesAdjacency) reversed = new GeomTrianglesAdjacency(*this);
GeomPrimitivePipelineReader from(this, current_thread);
reversed->clear_vertices();
for (int i = from.get_num_vertices() - 1; i >= 0; --i) {
reversed->add_vertex(from.get_vertex(i));
}
switch (from.get_shade_model()) {
case SM_flat_first_vertex:
reversed->set_shade_model(SM_flat_last_vertex);
reversed = (GeomTrianglesAdjacency *)DCAST(GeomTrianglesAdjacency, reversed->rotate());
break;
case SM_flat_last_vertex:
reversed->set_shade_model(SM_flat_first_vertex);
reversed = (GeomTrianglesAdjacency *)DCAST(GeomTrianglesAdjacency, reversed->rotate());
break;
default:
break;
}
return reversed.p();
}
/**
* Tells the BamReader how to create objects of type Geom.
*/
void GeomTrianglesAdjacency::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
/**
* This function is called by the BamReader's factory when a new object of
* type Geom is encountered in the Bam file. It should create the Geom and
* extract its information from the file.
*/
TypedWritable *GeomTrianglesAdjacency::
make_from_bam(const FactoryParams &params) {
GeomTrianglesAdjacency *object = new GeomTrianglesAdjacency(UH_unspecified);
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
object->fillin(scan, manager);
return object;
}

View File

@ -0,0 +1,72 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomTrianglesAdjacency.h
* @author rdb
* @date 2018-03-01
*/
#ifndef GEOMTRIANGLESADJACENCY_H
#define GEOMTRIANGLESADJACENCY_H
#include "pandabase.h"
#include "geomPrimitive.h"
/**
* Defines a series of disconnected triangles, with adjacency information.
*/
class EXPCL_PANDA_GOBJ GeomTrianglesAdjacency : public GeomPrimitive {
PUBLISHED:
explicit GeomTrianglesAdjacency(UsageHint usage_hint);
GeomTrianglesAdjacency(const GeomTrianglesAdjacency &copy);
virtual ~GeomTrianglesAdjacency();
ALLOC_DELETED_CHAIN(GeomTrianglesAdjacency);
public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
virtual int get_num_vertices_per_primitive() const;
public:
virtual bool draw(GraphicsStateGuardianBase *gsg,
const GeomPrimitivePipelineReader *reader,
bool force) const;
protected:
virtual CPT(GeomPrimitive) doubleside_impl() const;
virtual CPT(GeomPrimitive) reverse_impl() const;
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GeomPrimitive::init_type();
register_type(_type_handle, "GeomTrianglesAdjacency",
GeomPrimitive::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class Geom;
};
#endif

View File

@ -18,6 +18,7 @@
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
#include "geomTristripsAdjacency.h"
TypeHandle GeomTristrips::_type_handle;
@ -80,6 +81,143 @@ get_geom_rendering() const {
}
}
/**
* Adds adjacency information to this primitive. May return null if this type
* of geometry does not support adjacency information.
*/
CPT(GeomPrimitive) GeomTristrips::
make_adjacency() const {
Thread *current_thread = Thread::get_current_thread();
PT(GeomTristripsAdjacency) adj = new GeomTristripsAdjacency(get_usage_hint());
CPTA_int ends = get_ends();
GeomPrimitivePipelineReader from(this, current_thread);
int num_vertices = from.get_num_vertices();
const int num_unused = 2;
// First, build a map of each triangle's halfedges to its opposing vertices.
map<pair<int, int>, int> edge_map;
int vi = -num_unused;
int li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between tristrips.
vi += num_unused;
int end = ends[li];
nassertr(vi + 2 <= end, nullptr);
int v0 = from.get_vertex(vi++);
int v1 = from.get_vertex(vi++);
int v2 = from.get_vertex(vi);
edge_map[make_pair(v0, v1)] = v2;
while (true) {
v2 = from.get_vertex(vi++);
edge_map[make_pair(v2, v0)] = v1;
if (vi >= end) {
// Edge at the end of the strip
edge_map[make_pair(v1, v2)] = v0;
break;
}
v0 = v1;
v1 = v2;
v2 = from.get_vertex(vi++);
edge_map[make_pair(v0, v2)] = v1;
if (vi >= end) {
// Edge at the end of the strip
edge_map[make_pair(v2, v1)] = v0;
break;
}
v0 = v1;
v1 = v2;
}
++li;
}
nassertr(vi == num_vertices, nullptr);
// Now build up the new vertex data. For each edge, we insert the
// appropriate connecting vertex.
vi = -num_unused;
li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between tristrips.
vi += num_unused;
int end = ends[li];
nassertr(vi + 2 <= end, nullptr);
int v0 = from.get_vertex(vi++);
int v1 = from.get_vertex(vi++);
int v2;
adj->add_vertex(v0);
// Get the third vertex of the triangle adjoining this edge.
auto it = edge_map.find(make_pair(v1, v0));
if (it != edge_map.end()) {
adj->add_vertex(it->second);
} else {
// Um, no adjoining triangle? Just repeat the vertex, I guess.
adj->add_vertex(v0);
}
adj->add_vertex(v1);
while (true) {
v2 = from.get_vertex(vi++);
it = edge_map.find(make_pair(v0, v2));
if (it != edge_map.end()) {
adj->add_vertex(it->second);
} else {
adj->add_vertex(v1);
}
adj->add_vertex(v2);
if (vi >= end) {
// Edge at the end of the strip
it = edge_map.find(make_pair(v2, v1));
if (it != edge_map.end()) {
adj->add_vertex(it->second);
} else {
adj->add_vertex(v2);
}
break;
}
v0 = v1;
v1 = v2;
v2 = from.get_vertex(vi++);
it = edge_map.find(make_pair(v2, v0));
if (it != edge_map.end()) {
adj->add_vertex(it->second);
} else {
adj->add_vertex(v1);
}
adj->add_vertex(v2);
if (vi >= end) {
// Edge at the end of the strip
it = edge_map.find(make_pair(v1, v2));
if (it != edge_map.end()) {
adj->add_vertex(it->second);
} else {
adj->add_vertex(v1);
}
break;
}
v0 = v1;
v1 = v2;
}
adj->close_primitive();
++li;
}
nassertr(vi == num_vertices, nullptr);
return adj.p();
}
/**
* Returns the minimum number of vertices that must be added before
* close_primitive() may legally be called.

View File

@ -31,6 +31,9 @@ public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
CPT(GeomPrimitive) make_adjacency() const;
virtual int get_min_num_vertices_per_primitive() const;
virtual int get_num_unused_vertices_per_primitive() const;

View File

@ -0,0 +1,161 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomTristripsAdjacency.cxx
* @author rdb
* @date 2018-03-01
*/
#include "geomTristripsAdjacency.h"
#include "geomTriangles.h"
#include "geomVertexRewriter.h"
#include "pStatTimer.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "graphicsStateGuardianBase.h"
TypeHandle GeomTristripsAdjacency::_type_handle;
/**
*
*/
GeomTristripsAdjacency::
GeomTristripsAdjacency(GeomTristripsAdjacency::UsageHint usage_hint) :
GeomPrimitive(usage_hint)
{
}
/**
*
*/
GeomTristripsAdjacency::
GeomTristripsAdjacency(const GeomTristripsAdjacency &copy) :
GeomPrimitive(copy)
{
}
/**
*
*/
GeomTristripsAdjacency::
~GeomTristripsAdjacency() {
}
/**
*
*/
PT(GeomPrimitive) GeomTristripsAdjacency::
make_copy() const {
return new GeomTristripsAdjacency(*this);
}
/**
* Returns the fundamental rendering type of this primitive: whether it is
* points, lines, or polygons.
*
* This is used to set up the appropriate antialiasing settings when
* AntialiasAttrib::M_auto is in effect; it also implies the type of primitive
* that will be produced when decompose() is called.
*/
GeomPrimitive::PrimitiveType GeomTristripsAdjacency::
get_primitive_type() const {
return PT_polygons;
}
/**
* Returns the set of GeomRendering bits that represent the rendering
* properties required to properly render this primitive.
*/
int GeomTristripsAdjacency::
get_geom_rendering() const {
if (is_indexed()) {
if (get_num_primitives() > 1) {
return GR_triangle_strip | GR_indexed_other | GR_strip_cut_index | GR_adjacency;
} else {
return GR_triangle_strip | GR_indexed_other | GR_adjacency;
}
} else {
return GR_triangle_strip | GR_adjacency;
}
}
/**
* Returns the minimum number of vertices that must be added before
* close_primitive() may legally be called.
*/
int GeomTristripsAdjacency::
get_min_num_vertices_per_primitive() const {
return 6;
}
/**
* Returns the number of vertices that are added between primitives that
* aren't, strictly speaking, part of the primitives themselves. This is
* used, for instance, to define degenerate triangles to connect otherwise
* disconnected triangle strips.
*/
int GeomTristripsAdjacency::
get_num_unused_vertices_per_primitive() const {
return 1;
}
/**
* Calls the appropriate method on the GSG to draw the primitive.
*/
bool GeomTristripsAdjacency::
draw(GraphicsStateGuardianBase *gsg, const GeomPrimitivePipelineReader *reader,
bool force) const {
return gsg->draw_tristrips_adj(reader, force);
}
/**
* Should be redefined to return true in any primitive that implements
* append_unused_vertices().
*/
bool GeomTristripsAdjacency::
requires_unused_vertices() const {
return true;
}
/**
* Called when a new primitive is begun (other than the first primitive), this
* should add some degenerate vertices between primitives, if the primitive
* type requires that. The second parameter is the first vertex that begins
* the new primitive.
*/
void GeomTristripsAdjacency::
append_unused_vertices(GeomVertexArrayData *vertices, int vertex) {
GeomVertexWriter to(vertices, 0);
to.set_row_unsafe(vertices->get_num_rows());
to.add_data1i(get_strip_cut_index());
}
/**
* Tells the BamReader how to create objects of type Geom.
*/
void GeomTristripsAdjacency::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
/**
* This function is called by the BamReader's factory when a new object of
* type Geom is encountered in the Bam file. It should create the Geom and
* extract its information from the file.
*/
TypedWritable *GeomTristripsAdjacency::
make_from_bam(const FactoryParams &params) {
GeomTristripsAdjacency *object = new GeomTristripsAdjacency(UH_unspecified);
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
object->fillin(scan, manager);
return object;
}

View File

@ -0,0 +1,73 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file geomTristripsAdjacency.h
* @author rdb
* @date 2018-03-01
*/
#ifndef GEOMTRISTRIPSADJACENCY_H
#define GEOMTRISTRIPSADJACENCY_H
#include "pandabase.h"
#include "geomPrimitive.h"
/**
* Defines a series of triangle strips.
*/
class EXPCL_PANDA_GOBJ GeomTristripsAdjacency : public GeomPrimitive {
PUBLISHED:
explicit GeomTristripsAdjacency(UsageHint usage_hint);
GeomTristripsAdjacency(const GeomTristripsAdjacency &copy);
virtual ~GeomTristripsAdjacency();
ALLOC_DELETED_CHAIN(GeomTristripsAdjacency);
public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
virtual int get_min_num_vertices_per_primitive() const;
virtual int get_num_unused_vertices_per_primitive() const;
public:
virtual bool draw(GraphicsStateGuardianBase *gsg,
const GeomPrimitivePipelineReader *reader,
bool force) const;
protected:
virtual bool requires_unused_vertices() const;
virtual void append_unused_vertices(GeomVertexArrayData *vertices,
int vertex);
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GeomPrimitive::init_type();
register_type(_type_handle, "GeomTristripsAdjacency",
GeomPrimitive::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class Geom;
};
#endif

View File

@ -10,14 +10,18 @@
#include "geomContext.cxx"
#include "geomEnums.cxx"
#include "geomLines.cxx"
#include "geomLinesAdjacency.cxx"
#include "geomLinestrips.cxx"
#include "geomLinestripsAdjacency.cxx"
#include "geomMunger.cxx"
#include "geomPatches.cxx"
#include "geomPoints.cxx"
#include "geomPrimitive.cxx"
#include "geomTriangles.cxx"
#include "geomTrianglesAdjacency.cxx"
#include "geomTrifans.cxx"
#include "geomTristrips.cxx"
#include "geomTristripsAdjacency.cxx"
#include "geomVertexAnimationSpec.cxx"
#include "geomVertexArrayData.cxx"
#include "geomVertexArrayFormat.cxx"

View File

@ -201,11 +201,15 @@ public:
const GeomVertexDataPipelineReader *data_reader,
bool force)=0;
virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_triangles_adj(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_tristrips_adj(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_trifans(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_patches(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_lines(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_lines_adj(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_linestrips_adj(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual bool draw_points(const GeomPrimitivePipelineReader *reader, bool force)=0;
virtual void end_draw_primitives()=0;

View File

@ -0,0 +1,83 @@
from panda3d import core
def test_geom_triangles_adjacency():
prim = core.GeomTriangles(core.GeomEnums.UH_static)
prim.add_vertex(0)
prim.add_vertex(1)
prim.add_vertex(2)
prim.close_primitive()
prim.add_vertex(2)
prim.add_vertex(1)
prim.add_vertex(3)
prim.close_primitive()
adj = prim.make_adjacency()
verts = adj.get_vertex_list()
assert tuple(verts) == (
0, 0, 1, 3, 2, 2,
2, 0, 1, 1, 3, 3,
)
def test_geom_lines_adjacency():
prim = core.GeomLines(core.GeomEnums.UH_static)
prim.add_vertex(0)
prim.add_vertex(1)
prim.close_primitive()
prim.add_vertex(1)
prim.add_vertex(2)
prim.close_primitive()
prim.add_vertex(2)
prim.add_vertex(3)
prim.close_primitive()
adj = prim.make_adjacency()
verts = adj.get_vertex_list()
assert tuple(verts) == (
0, 0, 1, 2,
0, 1, 2, 3,
1, 2, 3, 3,
)
def test_geom_linestrips_adjacency():
prim = core.GeomLinestrips(core.GeomEnums.UH_static)
prim.add_vertex(0)
prim.add_vertex(1)
prim.close_primitive()
prim.add_vertex(1)
prim.add_vertex(2)
prim.add_vertex(3)
prim.close_primitive()
prim.add_vertex(3)
prim.add_vertex(4)
prim.add_vertex(5)
prim.add_vertex(6)
prim.close_primitive()
adj = prim.make_adjacency()
verts = adj.get_vertex_list()
cut = adj.get_strip_cut_index()
assert tuple(verts) == (
0, 0, 1, 2,
cut,
0, 1, 2, 3, 4,
cut,
2, 3, 4, 5, 6, 6,
)
# Check that it decomposes properly to a lines-adjacency primitive
prim = adj.decompose()
assert isinstance(prim, core.GeomLinesAdjacency)
verts = prim.get_vertex_list()
assert tuple(verts) == (
0, 0, 1, 2,
0, 1, 2, 3,
1, 2, 3, 4,
2, 3, 4, 5,
3, 4, 5, 6,
4, 5, 6, 6,
)