vertex buffers?

This commit is contained in:
David Rose 2005-03-18 03:32:08 +00:00
parent 01232c9e6f
commit 85b019feda
33 changed files with 1473 additions and 106 deletions

View File

@ -20,6 +20,7 @@
#include "graphicsStateGuardian.h"
#include "config_display.h"
#include "textureContext.h"
#include "dataContext.h"
#include "renderBuffer.h"
#include "colorAttrib.h"
#include "colorScaleAttrib.h"
@ -46,6 +47,8 @@ PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage"
PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active");
PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms");
PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active");
PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Prepared Bufferss");
PStatCollector GraphicsStateGuardian::_active_buffers_pcollector("Prepared Bufferss:Active");
PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes");
PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active");
PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory");
@ -267,6 +270,28 @@ void GraphicsStateGuardian::
release_geom(GeomContext *) {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::prepare_data
// Access: Public, Virtual
// Description: Prepares the indicated data array for retained-mode
// rendering.
////////////////////////////////////////////////////////////////////
DataContext *GraphicsStateGuardian::
prepare_data(qpGeomVertexArrayData *) {
return (DataContext *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::release_data
// Access: Public, Virtual
// Description: Frees the resources previously allocated via a call
// to prepare_data(), including deleting the DataContext
// itself, if necessary.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
release_data(DataContext *) {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_geom_munger
// Access: Public, Virtual
@ -1458,7 +1483,7 @@ add_to_texture_record(TextureContext *tc) {
// Access: Protected
// Description: Records that the indicated Geom has been drawn this
// frame. This function is only used to update the
// PStats current_texmem collector; it gets compiled out
// PStats active_geom collector; it gets compiled out
// if we aren't using PStats.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
@ -1469,6 +1494,23 @@ add_to_geom_record(GeomContext *gc) {
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::add_to_data_record
// Access: Protected
// Description: Records that the indicated data array has been drawn
// this frame. This function is only used to update the
// PStats active_buffers collector; it gets compiled out
// if we aren't using PStats.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
add_to_data_record(DataContext *dc) {
if (PStatClient::is_connected()) {
if (dc != (DataContext *)NULL && _current_datas.insert(dc).second) {
_active_buffers_pcollector.add_level(dc->_data->get_num_bytes());
}
}
}
#endif // DO_PSTATS
////////////////////////////////////////////////////////////////////

View File

@ -107,6 +107,9 @@ public:
virtual GeomContext *prepare_geom(Geom *geom);
virtual void release_geom(GeomContext *gc);
virtual DataContext *prepare_data(qpGeomVertexArrayData *data);
virtual void release_data(DataContext *gc);
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
virtual void set_state_and_transform(const RenderState *state,
@ -223,9 +226,11 @@ protected:
void init_frame_pstats();
void add_to_texture_record(TextureContext *tc);
void add_to_geom_record(GeomContext *gc);
void add_to_data_record(DataContext *dc);
pset<TextureContext *> _current_textures;
pset<GeomContext *> _current_geoms;
pset<DataContext *> _current_datas;
#else
INLINE void init_frame_pstats() { }
INLINE void add_to_texture_record(TextureContext *) { }
@ -308,6 +313,8 @@ public:
static PStatCollector _active_texusage_pcollector;
static PStatCollector _total_geom_pcollector;
static PStatCollector _active_geom_pcollector;
static PStatCollector _total_buffers_pcollector;
static PStatCollector _active_buffers_pcollector;
static PStatCollector _total_geom_node_pcollector;
static PStatCollector _active_geom_node_pcollector;
static PStatCollector _total_texmem_pcollector;

View File

@ -2684,7 +2684,7 @@ draw_triangles(const qpGeomTriangles *primitive) {
primitive->get_num_primitives(),
primitive->get_flat_first_vertices(),
D3DFMT_INDEX16,
_vertex_data->get_array_data(0),
_vertex_data->get_array(0)->get_data(),
_vertex_data->get_format()->get_array(0)->get_stride());
}
@ -2703,7 +2703,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
CPTA_ushort maxs = primitive->get_maxs();
nassertv(mins.size() == ends.size() && maxs.size() == ends.size());
CPTA_uchar array_data = _vertex_data->get_array_data(0);
CPTA_uchar array_data = _vertex_data->get_array(0)->get_data();
int stride = _vertex_data->get_format()->get_array(0)->get_stride();
unsigned int start = 0;

View File

@ -1925,7 +1925,8 @@ make_vertex_data(EggVertexPool *vertex_pool, const LMatrix4d &transform) {
qpGeomVertexFormat::register_format(new qpGeomVertexFormat(array_format));
// Now create a new GeomVertexData using the indicated format.
PT(qpGeomVertexData) vertex_data = new qpGeomVertexData(format);
PT(qpGeomVertexData) vertex_data =
new qpGeomVertexData(format, qpGeomVertexArrayData::UH_static);
// And fill the data from the vertex pool.
EggVertexPool::const_iterator vi;

View File

@ -632,7 +632,9 @@ load_default_model(const NodePath &parent) {
if (use_qpgeom) {
// New, experimental Geom code.
PT(qpGeomVertexData) vdata = new qpGeomVertexData(qpGeomVertexFormat::get_v3n3cpt2());
PT(qpGeomVertexData) vdata = new qpGeomVertexData
(qpGeomVertexFormat::get_v3n3cpt2(),
qpGeomVertexArrayData::UH_static);
qpGeomVertexIterator vertex(vdata, InternalName::get_vertex());
qpGeomVertexIterator normal(vdata, InternalName::get_normal());
qpGeomVertexIterator color(vdata, InternalName::get_color());
@ -1057,7 +1059,9 @@ load_image_as_model(const Filename &filename) {
}
if (use_qpgeom) {
PT(qpGeomVertexData) vdata = new qpGeomVertexData(qpGeomVertexFormat::get_v3t2());
PT(qpGeomVertexData) vdata = new qpGeomVertexData
(qpGeomVertexFormat::get_v3t2(),
qpGeomVertexArrayData::UH_static);
qpGeomVertexIterator vertex(vdata, InternalName::get_vertex());
qpGeomVertexIterator texcoord(vdata, InternalName::get_texcoord());

View File

@ -19,6 +19,9 @@
glstuff_src.cxx \
glstuff_src.h \
glstuff_undef_src.h \
glDataContext_src.cxx \
glDataContext_src.I \
glDataContext_src.h \
glGeomContext_src.cxx \
glGeomContext_src.I \
glGeomContext_src.h \

View File

@ -0,0 +1,30 @@
// Filename: glDataContext_src.I
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CLP(DataContext)::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CLP(DataContext)::
CLP(DataContext)(qpGeomVertexArrayData *data) :
DataContext(data)
{
_index = 0;
}

View File

@ -0,0 +1,19 @@
// Filename: glDataContext_src.cxx
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
TypeHandle CLP(DataContext)::_type_handle;

View File

@ -0,0 +1,52 @@
// Filename: glDataContext_src.h
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "dataContext.h"
////////////////////////////////////////////////////////////////////
// Class : GLDataContext
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_GL CLP(DataContext) : public DataContext {
public:
INLINE CLP(DataContext)(qpGeomVertexArrayData *data);
// This is the GL "name" of the data object.
GLuint _index;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
DataContext::init_type();
register_type(_type_handle, CLASSPREFIX_QUOTED "DataContext",
DataContext::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;
};
#include "glDataContext_src.I"

View File

@ -57,6 +57,7 @@
#include "vector_string.h"
#include "string_utils.h"
#include "pnmImage.h"
#include "config_gobj.h"
#ifdef DO_PSTATS
#include "pStatTimer.h"
#endif
@ -455,6 +456,47 @@ reset() {
_glActiveTexture = null_glActiveTexture;
}
_supports_buffers = false;
if (is_at_least_version(1, 5)) {
_supports_buffers = true;
_glGenBuffers = (PFNGLGENBUFFERSPROC)
get_extension_func(GLPREFIX_QUOTED, "GenBuffers");
_glBindBuffer = (PFNGLBINDBUFFERPROC)
get_extension_func(GLPREFIX_QUOTED, "BindBuffer");
_glBufferData = (PFNGLBUFFERDATAPROC)
get_extension_func(GLPREFIX_QUOTED, "BufferData");
_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)
get_extension_func(GLPREFIX_QUOTED, "BufferSubData");
_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)
get_extension_func(GLPREFIX_QUOTED, "DeleteBuffers");
} else if (has_extension("GL_ARB_vertex_buffer_object")) {
_supports_buffers = true;
_glGenBuffers = (PFNGLGENBUFFERSPROC)
get_extension_func(GLPREFIX_QUOTED, "GenBuffersARB");
_glBindBuffer = (PFNGLBINDBUFFERPROC)
get_extension_func(GLPREFIX_QUOTED, "BindBufferARB");
_glBufferData = (PFNGLBUFFERDATAPROC)
get_extension_func(GLPREFIX_QUOTED, "BufferDataARB");
_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)
get_extension_func(GLPREFIX_QUOTED, "BufferSubDataARB");
_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)
get_extension_func(GLPREFIX_QUOTED, "DeleteBuffersARB");
}
if (_supports_buffers) {
if (_glGenBuffers == NULL || _glBindBuffer == NULL ||
_glBufferData == NULL || _glBufferSubData == NULL ||
_glDeleteBuffers == NULL) {
GLCAT.warning()
<< "Buffers advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
_supports_buffers = false;
}
}
_glBlendEquation = NULL;
if (has_extension("GL_EXT_blend_minmax") || is_at_least_version(1, 2)) {
_glBlendEquation = (PFNGLBLENDEQUATIONPROC)
@ -1984,7 +2026,7 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
}
nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);
CPTA_uchar array_data;
const qpGeomVertexArrayData *array_data;
int num_components;
qpGeomVertexDataType::NumericType numeric_type;
int start;
@ -1993,8 +2035,9 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
if (_vertex_data->get_array_info(InternalName::get_vertex(),
array_data, num_components, numeric_type,
start, stride)) {
const unsigned char *client_pointer = setup_array_data(array_data);
GLP(VertexPointer)(num_components, get_numeric_type(numeric_type),
stride, array_data + start);
stride, client_pointer + start);
GLP(EnableClientState)(GL_VERTEX_ARRAY);
} else {
// No vertex data? No primitives!
@ -2005,8 +2048,9 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
_vertex_data->get_array_info(InternalName::get_normal(),
array_data, num_components, numeric_type,
start, stride)) {
const unsigned char *client_pointer = setup_array_data(array_data);
GLP(NormalPointer)(get_numeric_type(numeric_type), stride,
array_data + start);
client_pointer + start);
GLP(EnableClientState)(GL_NORMAL_ARRAY);
} else {
GLP(DisableClientState)(GL_NORMAL_ARRAY);
@ -2016,13 +2060,14 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
if (_vertex_data->get_array_info(InternalName::get_color(),
array_data, num_components, numeric_type,
start, stride)) {
const unsigned char *client_pointer = setup_array_data(array_data);
if (numeric_type == qpGeomVertexDataType::NT_packed_argb) {
// Temporary hack--this will probably reverse r and b.
GLP(ColorPointer)(4, GL_UNSIGNED_BYTE, stride, array_data + start);
GLP(ColorPointer)(4, GL_UNSIGNED_BYTE, stride, client_pointer + start);
} else {
GLP(ColorPointer)(num_components, get_numeric_type(numeric_type),
stride, array_data + start);
stride, client_pointer + start);
}
GLP(EnableClientState)(GL_COLOR_ARRAY);
@ -2040,8 +2085,9 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
_vertex_data->get_array_info(InternalName::get_texcoord(),
array_data, num_components, numeric_type,
start, stride)) {
const unsigned char *client_pointer = setup_array_data(array_data);
GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type),
stride, array_data + start);
stride, client_pointer + start);
GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
} else {
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
@ -2287,6 +2333,130 @@ release_geom(GeomContext *gc) {
delete ggc;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::prepare_data
// Access: Public, Virtual
// Description: Creates a new retained-mode representation of the
// given data, and returns a newly-allocated
// DataContext pointer to reference it. It is the
// responsibility of the calling function to later
// call release_data() with this same pointer (which
// will also delete the pointer).
//
// This function should not be called directly to
// prepare a data. Instead, call Data::prepare().
////////////////////////////////////////////////////////////////////
DataContext *CLP(GraphicsStateGuardian)::
prepare_data(qpGeomVertexArrayData *data) {
cerr << "prepare_data\n";
if (_supports_buffers) {
CLP(DataContext) *gdc = new CLP(DataContext)(data);
_glGenBuffers(1, &gdc->_index);
_glBindBuffer(GL_ARRAY_BUFFER, gdc->_index);
_glBufferData(GL_ARRAY_BUFFER, gdc->_data->get_num_bytes(),
gdc->_data->get_data(),
get_usage(gdc->_data->get_usage_hint()));
gdc->_modified = gdc->_data->get_modified();
report_my_gl_errors();
return gdc;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::apply_data
// Access: Public, Virtual
// Description: Makes the data the currently available data for
// rendering.
////////////////////////////////////////////////////////////////////
void CLP(GraphicsStateGuardian)::
apply_data(DataContext *dc) {
cerr << "apply_data\n";
nassertv(_supports_buffers);
CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc);
add_to_data_record(gdc);
_glBindBuffer(GL_ARRAY_BUFFER, gdc->_index);
if (gdc->_modified != gdc->_data->get_modified()) {
_glBufferSubData(GL_ARRAY_BUFFER, 0, gdc->_data->get_num_bytes(),
gdc->_data->get_data());
gdc->_modified = gdc->_data->get_modified();
}
report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::release_data
// Access: Public, Virtual
// Description: Frees the GL resources previously allocated for the
// data. This function should never be called
// directly; instead, call Data::release() (or simply
// let the Data destruct).
////////////////////////////////////////////////////////////////////
void CLP(GraphicsStateGuardian)::
release_data(DataContext *dc) {
cerr << "release_data\n";
nassertv(_supports_buffers);
CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc);
_glDeleteBuffers(1, &gdc->_index);
report_my_gl_errors();
gdc->_index = 0;
delete gdc;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::setup_array_data
// Access: Public
// Description: Internal function to bind a buffer object for the
// indicated data array, if appropriate, or to unbind a
// buffer object if it should be rendered from client
// memory.
//
// If the buffer object is bound, this function returns
// NULL (reprsenting the start of the buffer object in
// server memory); if the buffer object is not bound,
// this function returns the pointer to the data array
// in client memory, that is, the data array passed in.
////////////////////////////////////////////////////////////////////
const unsigned char *CLP(GraphicsStateGuardian)::
setup_array_data(const qpGeomVertexArrayData *data) {
if (!_supports_buffers) {
// No support for buffer objects; always render from client.
return data->get_data();
}
if (!vertex_buffers ||
data->get_usage_hint() == qpGeomVertexArrayData::UH_client) {
// The array specifies client rendering only, or buffer objects
// are configured off.
_glBindBuffer(GL_ARRAY_BUFFER, 0);
return data->get_data();
}
// Prepare the buffer object and bind it.
DataContext *dc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this);
nassertr(dc != (DataContext *)NULL, data->get_data());
CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc);
_glBindBuffer(GL_ARRAY_BUFFER, gdc->_index);
// NULL is the OpenGL convention for the first byte of the buffer.
return NULL;
}
#if 0
static int logs[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
4096, 0 };
@ -4406,6 +4576,32 @@ get_blend_func(ColorBlendAttrib::Operand operand) {
return GL_ZERO;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::get_usage
// Access: Public, Static
// Description: Maps from UsageHint to the GL symbol.
////////////////////////////////////////////////////////////////////
GLenum CLP(GraphicsStateGuardian)::
get_usage(qpGeomVertexArrayData::UsageHint usage_hint) {
switch (usage_hint) {
case qpGeomVertexArrayData::UH_stream:
return GL_STREAM_DRAW;
case qpGeomVertexArrayData::UH_static:
return GL_STATIC_DRAW;
case qpGeomVertexArrayData::UH_dynamic:
return GL_DYNAMIC_DRAW;
case qpGeomVertexArrayData::UH_client:
break;
}
GLCAT.error()
<< "Unexpected usage_hint " << (int)usage_hint << endl;
return GL_STATIC_DRAW;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::print_gfx_visual

View File

@ -37,6 +37,7 @@
#include "graphicsWindow.h"
#include "pset.h"
#include "pmap.h"
#include "qpgeomVertexArrayData.h"
#ifdef HAVE_CGGL
#include "cgShader.h"
#endif
@ -103,6 +104,11 @@ public:
virtual GeomContext *prepare_geom(Geom *geom);
virtual void release_geom(GeomContext *gc);
virtual DataContext *prepare_data(qpGeomVertexArrayData *data);
virtual void apply_data(DataContext *dc);
virtual void release_data(DataContext *dc);
const unsigned char *setup_array_data(const qpGeomVertexArrayData *data);
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
virtual void framebuffer_copy_to_texture
@ -236,6 +242,7 @@ protected:
static GLenum get_fog_mode_type(Fog::Mode m);
static GLenum get_blend_equation_type(ColorBlendAttrib::Mode mode);
static GLenum get_blend_func(ColorBlendAttrib::Operand operand);
static GLenum get_usage(qpGeomVertexArrayData::UsageHint usage_hint);
static CPT(RenderState) get_untextured_state();
static CPT(RenderState) get_smooth_state();
@ -326,6 +333,13 @@ public:
PFNGLACTIVETEXTUREPROC _glActiveTexture;
PFNGLMULTITEXCOORD2FVPROC _glMultiTexCoord2fv;
bool _supports_buffers;
PFNGLGENBUFFERSPROC _glGenBuffers;
PFNGLBINDBUFFERPROC _glBindBuffer;
PFNGLBUFFERDATAPROC _glBufferData;
PFNGLBUFFERSUBDATAPROC _glBufferSubData;
PFNGLDELETEBUFFERSPROC _glDeleteBuffers;
PFNGLBLENDEQUATIONPROC _glBlendEquation;
PFNGLBLENDCOLORPROC _glBlendColor;

View File

@ -63,6 +63,7 @@ void CLP(init_classes)() {
CLP(GraphicsStateGuardian)::init_type();
CLP(TextureContext)::init_type();
CLP(GeomContext)::init_type();
CLP(DataContext)::init_type();
PandaSystem *ps = PandaSystem::get_global_ptr();
ps->add_system(GLSYSTEM_NAME);

View File

@ -23,6 +23,7 @@
#include "glmisc_src.cxx"
#include "glTextureContext_src.cxx"
#include "glDataContext_src.cxx"
#include "glGeomContext_src.cxx"
#include "glGeomMunger_src.cxx"
#include "glCgShaderContext_src.cxx"

View File

@ -41,6 +41,7 @@
#include "glmisc_src.h"
#include "glTextureContext_src.h"
#include "glDataContext_src.h"
#include "glGeomContext_src.h"
#include "glGeomMunger_src.h"
#include "glCgShaderContext_src.h"

View File

@ -11,7 +11,9 @@
#define SOURCES \
boundedObject.I boundedObject.h \
config_gobj.h drawable.h \
config_gobj.h \
dataContext.I dataContext.h \
drawable.h \
geom.I geom.h \
geomContext.I geomContext.h \
geomLine.h geomLinestrip.h geomPoint.h geomPolygon.h \
@ -23,6 +25,7 @@
qpgeomTriangles.h \
qpgeomTristrips.h \
qpgeomTrifans.h \
qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
qpgeomVertexData.h qpgeomVertexData.I \
@ -44,7 +47,9 @@
#define INCLUDED_SOURCES \
boundedObject.cxx \
config_gobj.cxx drawable.cxx geom.cxx \
config_gobj.cxx \
dataContext.cxx \
drawable.cxx geom.cxx \
geomContext.cxx \
geomLine.cxx geomLinestrip.cxx geomPoint.cxx geomPolygon.cxx \
geomQuad.cxx geomSphere.cxx geomSprite.cxx geomTri.cxx \
@ -55,6 +60,7 @@
qpgeomTriangles.cxx \
qpgeomTristrips.cxx \
qpgeomTrifans.cxx \
qpgeomVertexArrayData.cxx \
qpgeomVertexArrayFormat.cxx \
qpgeomVertexCacheManager.cxx \
qpgeomVertexData.cxx \
@ -73,6 +79,7 @@
#define INSTALL_HEADERS \
boundedObject.I boundedObject.h \
config_gobj.h \
dataContext.I dataContext.h \
drawable.h geom.I geom.h \
textureContext.I textureContext.h \
geomLine.h \
@ -85,6 +92,7 @@
qpgeomTriangles.h \
qpgeomTristrips.h \
qpgeomTrifans.h \
qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
qpgeomVertexData.h qpgeomVertexData.I \

View File

@ -28,6 +28,7 @@
#include "qpgeomTriangles.h"
#include "qpgeomTristrips.h"
#include "qpgeomTrifans.h"
#include "qpgeomVertexArrayData.h"
#include "qpgeomVertexArrayFormat.h"
#include "qpgeomVertexData.h"
#include "qpgeomVertexFormat.h"
@ -38,6 +39,9 @@
#include "lens.h"
#include "texture.h"
#include "textureStage.h"
#include "textureContext.h"
#include "geomContext.h"
#include "dataContext.h"
#include "internalName.h"
#include "dconfig.h"
@ -81,6 +85,15 @@ ConfigVariableBool retained_mode
"GSG. Set it false to use only immediate mode, which sends the "
"vertices to the GSG every frame."));
ConfigVariableBool vertex_buffers
("vertex-buffers", false,
PRC_DESC("Set this true to allow the use of vertex buffers (or buffer "
"objects, as OpenGL dubs them) for rendering vertex data. This "
"can greatly improve rendering performance, especially on "
"higher-end graphics cards, at the cost of some additional "
"graphics memory (which might otherwise be used for textures "
"or offscreen buffers)."));
ConfigVariableBool use_qpgeom
("use-qpgeom", false,
PRC_DESC("A temporary variable while the experimental Geom rewrite is "
@ -163,9 +176,13 @@ ConfigureFn(config_gobj) {
qpGeomTriangles::init_type();
qpGeomTristrips::init_type();
qpGeomTrifans::init_type();
qpGeomVertexArrayData::init_type();
qpGeomVertexArrayFormat::init_type();
qpGeomVertexData::init_type();
qpGeomVertexFormat::init_type();
TextureContext::init_type();
GeomContext::init_type();
DataContext::init_type();
Material::init_type();
OrthographicLens::init_type();
MatrixLens::init_type();
@ -192,6 +209,7 @@ ConfigureFn(config_gobj) {
qpGeomTriangles::register_with_read_factory();
qpGeomTristrips::register_with_read_factory();
qpGeomTrifans::register_with_read_factory();
qpGeomVertexArrayData::register_with_read_factory();
qpGeomVertexArrayFormat::register_with_read_factory();
qpGeomVertexData::register_with_read_factory();
qpGeomVertexFormat::register_with_read_factory();

View File

@ -51,6 +51,7 @@ extern EXPCL_PANDA ConfigVariableInt max_texture_dimension;
extern EXPCL_PANDA ConfigVariableBool keep_texture_ram;
extern EXPCL_PANDA ConfigVariableBool keep_geom_ram;
extern EXPCL_PANDA ConfigVariableBool retained_mode;
extern EXPCL_PANDA ConfigVariableBool vertex_buffers;
extern EXPCL_PANDA ConfigVariableBool use_qpgeom;

View File

@ -0,0 +1,29 @@
// Filename: dataContext.I
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: DataContext::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE DataContext::
DataContext(qpGeomVertexArrayData *data) :
_data(data)
{
}

View File

@ -0,0 +1,21 @@
// Filename: dataContext.cxx
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "dataContext.h"
TypeHandle DataContext::_type_handle;

View File

@ -0,0 +1,71 @@
// Filename: dataContext.h
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef DATACONTEXT_H
#define DATACONTEXT_H
#include "pandabase.h"
#include "savedContext.h"
#include "updateSeq.h"
class qpGeomVertexArrayData;
////////////////////////////////////////////////////////////////////
// Class : DataContext
// Description : This is a special class object that holds all the
// information returned by a particular GSG to indicate
// the vertex data array's internal context identifier.
//
// This allows the GSG to cache the vertex data array in
// whatever way makes sense. For instance, DirectX can
// allocate a vertex buffer for the array. OpenGL can
// create a buffer object.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DataContext : public SavedContext {
public:
INLINE DataContext(qpGeomVertexArrayData *data);
// This cannot be a PT(qpGeomVertexArrayData), because the data and
// the GSG both own their DataContexts! That would create a
// circular reference count.
qpGeomVertexArrayData *_data;
UpdateSeq _modified;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
SavedContext::init_type();
register_type(_type_handle, "DataContext",
SavedContext::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;
};
#include "dataContext.I"
#endif

View File

@ -1,5 +1,6 @@
#include "boundedObject.cxx"
#include "dataContext.cxx"
#include "geom.cxx"
#include "geomLine.cxx"
#include "geomLinestrip.cxx"
@ -17,6 +18,7 @@
#include "qpgeomTriangles.cxx"
#include "qpgeomTristrips.cxx"
#include "qpgeomTrifans.cxx"
#include "qpgeomVertexArrayData.cxx"
#include "qpgeomVertexArrayFormat.cxx"
#include "qpgeomVertexCacheManager.cxx"
#include "qpgeomVertexData.cxx"

View File

@ -357,6 +357,146 @@ prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg) {
return gc;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::enqueue_data
// Access: Public
// Description: Indicates that a data array would like to be put on the
// list to be prepared when the GSG is next ready to
// do this (presumably at the next frame).
////////////////////////////////////////////////////////////////////
void PreparedGraphicsObjects::
enqueue_data(qpGeomVertexArrayData *data) {
MutexHolder holder(_lock);
_enqueued_datas.insert(data);
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::dequeue_data
// Access: Public
// Description: Removes a data array from the queued list of data
// arrays to be prepared. Normally it is not necessary
// to call this, unless you change your mind about
// preparing it at the last minute, since the data will
// automatically be dequeued and prepared at the next
// frame.
//
// The return value is true if the data array is
// successfully dequeued, false if it had not been
// queued.
////////////////////////////////////////////////////////////////////
bool PreparedGraphicsObjects::
dequeue_data(qpGeomVertexArrayData *data) {
MutexHolder holder(_lock);
EnqueuedDatas::iterator qi = _enqueued_datas.find(data);
if (qi != _enqueued_datas.end()) {
_enqueued_datas.erase(qi);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::release_data
// Access: Public
// Description: Indicates that a data context, created by a
// previous call to prepare_data(), is no longer
// needed. The driver resources will not be freed until
// some GSG calls update(), indicating it is at a
// stage where it is ready to release datas--this
// prevents conflicts from threading or multiple GSG's
// sharing datas (we have no way of knowing which
// graphics context is currently active, or what state
// it's in, at the time release_data is called).
////////////////////////////////////////////////////////////////////
void PreparedGraphicsObjects::
release_data(DataContext *gc) {
MutexHolder holder(_lock);
gc->_data->clear_prepared(this);
// We have to set the Data pointer to NULL at this point, since
// the Data itself might destruct at any time after it has been
// released.
gc->_data = (qpGeomVertexArrayData *)NULL;
bool removed = (_prepared_datas.erase(gc) != 0);
nassertv(removed);
_released_datas.insert(gc);
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::release_all_datas
// Access: Public
// Description: Releases all datas at once. This will force them
// to be reloaded into data memory for all GSG's that
// share this object. Returns the number of datas
// released.
////////////////////////////////////////////////////////////////////
int PreparedGraphicsObjects::
release_all_datas() {
MutexHolder holder(_lock);
int num_datas = (int)_prepared_datas.size();
Datas::iterator gci;
for (gci = _prepared_datas.begin();
gci != _prepared_datas.end();
++gci) {
DataContext *gc = (*gci);
gc->_data->clear_prepared(this);
gc->_data = (qpGeomVertexArrayData *)NULL;
_released_datas.insert(gc);
}
_prepared_datas.clear();
return num_datas;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::prepare_data_now
// Access: Public
// Description: Immediately creates a new DataContext for the
// indicated data and returns it. This assumes that
// the GraphicsStateGuardian is the currently active
// rendering context and that it is ready to accept new
// datas. If this is not necessarily the case, you
// should use enqueue_data() instead.
//
// Normally, this function is not called directly. Call
// Data::prepare_now() instead.
//
// The DataContext contains all of the pertinent
// information needed by the GSG to keep track of this
// one particular data, and will exist as long as the
// data is ready to be rendered.
//
// When either the Data or the
// PreparedGraphicsObjects object destructs, the
// DataContext will be deleted.
////////////////////////////////////////////////////////////////////
DataContext *PreparedGraphicsObjects::
prepare_data_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) {
MutexHolder holder(_lock);
// Ask the GSG to create a brand new DataContext. There might
// be several GSG's sharing the same set of datas; if so, it
// doesn't matter which of them creates the context (since they're
// all shared anyway).
DataContext *gc = gsg->prepare_data(data);
if (gc != (DataContext *)NULL) {
bool prepared = _prepared_datas.insert(gc).second;
nassertr(prepared, gc);
}
return gc;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::update
// Access: Public

View File

@ -22,12 +22,16 @@
#include "pandabase.h"
#include "referenceCount.h"
#include "texture.h"
#include "geom.h"
#include "qpgeomVertexArrayData.h"
#include "pointerTo.h"
#include "pStatCollector.h"
#include "pset.h"
#include "pmutex.h"
class TextureContext;
class GeomContext;
class DataContext;
class GraphicsStateGuardianBase;
////////////////////////////////////////////////////////////////////
@ -68,6 +72,14 @@ public:
GeomContext *prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg);
void enqueue_data(qpGeomVertexArrayData *data);
bool dequeue_data(qpGeomVertexArrayData *data);
void release_data(DataContext *gc);
int release_all_datas();
DataContext *prepare_data_now(qpGeomVertexArrayData *data,
GraphicsStateGuardianBase *gsg);
void update(GraphicsStateGuardianBase *gsg);
private:
@ -75,12 +87,16 @@ private:
typedef phash_set< PT(Texture) > EnqueuedTextures;
typedef phash_set<GeomContext *, pointer_hash> Geoms;
typedef phash_set< PT(Geom) > EnqueuedGeoms;
typedef phash_set<DataContext *, pointer_hash> Datas;
typedef phash_set< PT(qpGeomVertexArrayData) > EnqueuedDatas;
Mutex _lock;
Textures _prepared_textures, _released_textures;
EnqueuedTextures _enqueued_textures;
Geoms _prepared_geoms, _released_geoms;
EnqueuedGeoms _enqueued_geoms;
Datas _prepared_datas, _released_datas;
EnqueuedDatas _enqueued_datas;
static PStatCollector _total_texusage_pcollector;

View File

@ -389,7 +389,7 @@ recompute_bound() {
int start = data_type->get_start();
int num_components = data_type->get_num_components();
CPTA_uchar array_data = cdata->_data->get_array_data(array_index);
CPTA_uchar array_data = cdata->_data->get_array(array_index)->get_data();
if (stride == 3 * sizeof(PN_float32) && start == 0 && num_components == 3 &&
(array_data.size() % stride) == 0) {

View File

@ -560,7 +560,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
int start = data_type->get_start();
int num_components = data_type->get_num_components();
CPTA_uchar array_data = vertex_data->get_array_data(array_index);
CPTA_uchar array_data = vertex_data->get_array(array_index)->get_data();
PTA_ushort::const_iterator ii;
for (ii = cdata->_vertices.begin(); ii != cdata->_vertices.end(); ++ii) {

View File

@ -0,0 +1,167 @@
// Filename: qpgeomVertexArrayData.I
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::get_array_format
// Access: Published
// Description: Returns the format object that describes this array.
////////////////////////////////////////////////////////////////////
INLINE const qpGeomVertexArrayFormat *qpGeomVertexArrayData::
get_array_format() const {
return _array_format;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::get_usage_hint
// Access: Published
// Description: Returns the usage hint that describes to the
// rendering backend how often the vertex data will be
// modified and/or rendered. This is provided as a
// performance optimization only, and does not
// constraing actual usage; although it may be an
// important optimization.
//
// This may only be specified to the GeomVertexArrayData
// constructor. If you need to change it, you must
// create a new GeomVertexArrayData object (but you can
// just assign the same data pointer to the new object).
////////////////////////////////////////////////////////////////////
INLINE qpGeomVertexArrayData::UsageHint qpGeomVertexArrayData::
get_usage_hint() const {
return _usage_hint;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::get_data
// Access: Published
// Description: Returns a const pointer to the actual vertex data,
// for application code to directly examine (but not
// modify).
////////////////////////////////////////////////////////////////////
INLINE CPTA_uchar qpGeomVertexArrayData::
get_data() const {
CDReader cdata(_cycler);
return cdata->_data;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::modify_data
// Access: Published
// Description: Returns a modifiable pointer to the actual vertex
// array, so that application code may directly
// manipulate the vertices.
////////////////////////////////////////////////////////////////////
INLINE PTA_uchar qpGeomVertexArrayData::
modify_data() {
// Perform copy-on-write: if the reference count on the vertex data
// is greater than 1, assume some other GeomVertexData has the same
// pointer, so make a copy of it first.
CDWriter cdata(_cycler);
if (cdata->_data.get_ref_count() > 1) {
PTA_uchar orig_data = cdata->_data;
cdata->_data = PTA_uchar();
cdata->_data.v() = orig_data.v();
}
++(cdata->_modified);
return cdata->_data;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::set_data
// Access: Published
// Description: Replaces the vertex data array with a completely new
// array.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexArrayData::
set_data(CPTA_uchar array) {
CDWriter cdata(_cycler);
cdata->_data = (PTA_uchar &)array;
++(cdata->_modified);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::get_num_vertices
// Access: Published
// Description: Returns the number of vertices stored in the array,
// based on the number of bytes and the stride. This
// should be the same for all arrays within a given
// GeomVertexData object.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomVertexArrayData::
get_num_vertices() const {
return get_num_bytes() / _array_format->get_stride();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::clear_vertices
// Access: Published
// Description: Removes all of the vertices in the array.
// Functionally equivalent to set_num_vertices(0).
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexArrayData::
clear_vertices() {
set_data(PTA_uchar());
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::get_num_bytes
// Access: Published
// Description: Returns the number of bytes stored in the array.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomVertexArrayData::
get_num_bytes() const {
CDReader cdata(_cycler);
return cdata->_data.size();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::get_modified
// Access: Published
// Description: Returns a sequence number which is guaranteed to
// change at least every time the array vertex data is
// modified.
////////////////////////////////////////////////////////////////////
INLINE UpdateSeq qpGeomVertexArrayData::
get_modified() const {
CDReader cdata(_cycler);
return cdata->_modified;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::CData::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpGeomVertexArrayData::CData::
CData() {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpGeomVertexArrayData::CData::
CData(const qpGeomVertexArrayData::CData &copy) :
_data(copy._data),
_modified(copy._modified)
{
}

View File

@ -0,0 +1,360 @@
// Filename: qpgeomVertexArrayData.cxx
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "qpgeomVertexArrayData.h"
#include "preparedGraphicsObjects.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "pset.h"
TypeHandle qpGeomVertexArrayData::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::Default Constructor
// Access: Private
// Description: Constructs an invalid object. This is only used when
// reading from the bam file.
////////////////////////////////////////////////////////////////////
qpGeomVertexArrayData::
qpGeomVertexArrayData() {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
qpGeomVertexArrayData::
qpGeomVertexArrayData(const qpGeomVertexArrayFormat *array_format,
qpGeomVertexArrayData::UsageHint usage_hint) :
_array_format(array_format),
_usage_hint(usage_hint)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
qpGeomVertexArrayData::
qpGeomVertexArrayData(const qpGeomVertexArrayData &copy) :
_array_format(copy._array_format),
_usage_hint(copy._usage_hint),
_cycler(copy._cycler)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::Copy Assignment Operator
// Access: Private
// Description: Directly copying ArrayData objects by assignment is
// disallowed.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
operator = (const qpGeomVertexArrayData &) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
qpGeomVertexArrayData::
~qpGeomVertexArrayData() {
release_all();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::set_num_vertices
// Access: Published
// Description: Sets the length of the array to n vertices.
// Normally, you would not call this directly, since all
// of the arrays in a particular GeomVertexData must
// have the same number of vertices; instead, call
// GeomVertexData::set_num_vertices().
//
// The return value is true if the number of vertices
// was changed, false if the object already contained n
// vertices (or if there was some error).
////////////////////////////////////////////////////////////////////
bool qpGeomVertexArrayData::
set_num_vertices(int n) {
CDWriter cdata(_cycler);
int stride = _array_format->get_stride();
int delta = n - (cdata->_data.size() / stride);
if (delta != 0) {
if (cdata->_data.get_ref_count() > 1) {
// Copy-on-write: the data is already reffed somewhere else,
// so we're just going to make a copy.
PTA_uchar new_data;
new_data.reserve(n * stride);
new_data.insert(new_data.end(), n * stride, uchar());
memcpy(new_data, cdata->_data,
min((size_t)(n * stride), cdata->_data.size()));
cdata->_data = new_data;
} else {
// We've got the only reference to the data, so we can change
// it directly.
if (delta > 0) {
cdata->_data.insert(cdata->_data.end(), delta * stride, uchar());
} else {
cdata->_data.erase(cdata->_data.begin() + n * stride,
cdata->_data.end());
}
}
++(cdata->_modified);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::prepare
// Access: Published
// Description: Indicates that the data should be enqueued to be
// prepared in the indicated prepared_objects at the
// beginning of the next frame. This will ensure the
// data is already loaded into the GSG if it is expected
// to be rendered soon.
//
// Use this function instead of prepare_now() to preload
// datas from a user interface standpoint.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
prepare(PreparedGraphicsObjects *prepared_objects) {
prepared_objects->enqueue_data(this);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::prepare_now
// Access: Public
// Description: Creates a context for the data on the particular
// GSG, if it does not already exist. Returns the new
// (or old) DataContext. This assumes that the
// GraphicsStateGuardian is the currently active
// rendering context and that it is ready to accept new
// datas. If this is not necessarily the case, you
// should use prepare() instead.
//
// Normally, this is not called directly except by the
// GraphicsStateGuardian; a data does not need to be
// explicitly prepared by the user before it may be
// rendered.
////////////////////////////////////////////////////////////////////
DataContext *qpGeomVertexArrayData::
prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg) {
Contexts::const_iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
return (*ci).second;
}
DataContext *dc = prepared_objects->prepare_data_now(this, gsg);
if (dc != (DataContext *)NULL) {
_contexts[prepared_objects] = dc;
}
return dc;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::release
// Access: Public
// Description: Frees the data context only on the indicated object,
// if it exists there. Returns true if it was released,
// false if it had not been prepared.
////////////////////////////////////////////////////////////////////
bool qpGeomVertexArrayData::
release(PreparedGraphicsObjects *prepared_objects) {
Contexts::iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
DataContext *dc = (*ci).second;
prepared_objects->release_data(dc);
return true;
}
// Maybe it wasn't prepared yet, but it's about to be.
return prepared_objects->dequeue_data(this);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::release_all
// Access: Public
// Description: Frees the context allocated on all objects for which
// the data has been declared. Returns the number of
// contexts which have been freed.
////////////////////////////////////////////////////////////////////
int qpGeomVertexArrayData::
release_all() {
// We have to traverse a copy of the _contexts list, because the
// PreparedGraphicsObjects object will call clear_prepared() in response
// to each release_data(), and we don't want to be modifying the
// _contexts list while we're traversing it.
Contexts temp = _contexts;
int num_freed = (int)_contexts.size();
Contexts::const_iterator ci;
for (ci = temp.begin(); ci != temp.end(); ++ci) {
PreparedGraphicsObjects *prepared_objects = (*ci).first;
DataContext *dc = (*ci).second;
prepared_objects->release_data(dc);
}
// Now that we've called release_data() on every known context,
// the _contexts list should have completely emptied itself.
nassertr(_contexts.empty(), num_freed);
return num_freed;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::clear_prepared
// Access: Private
// Description: Removes the indicated PreparedGraphicsObjects table
// from the data array's table, without actually
// releasing the data array. This is intended to be
// called only from
// PreparedGraphicsObjects::release_data(); it should
// never be called by user code.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
clear_prepared(PreparedGraphicsObjects *prepared_objects) {
Contexts::iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
_contexts.erase(ci);
} else {
// If this assertion fails, clear_prepared() was given a
// prepared_objects which the data array didn't know about.
nassertv(false);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// qpGeomVertexArrayData.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritable::write_datagram(manager, dg);
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type qpGeomVertexArrayData is encountered
// in the Bam file. It should create the qpGeomVertexArrayData
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *qpGeomVertexArrayData::
make_from_bam(const FactoryParams &params) {
qpGeomVertexArrayData *object = new qpGeomVertexArrayData;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
object->fillin(scan, manager);
return object;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new qpGeomVertexArrayData.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
manager->read_cdata(scan, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::CData::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CycleData *qpGeomVertexArrayData::CData::
make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::CData::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::CData::
write_datagram(BamWriter *manager, Datagram &dg) const {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::CData::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int qpGeomVertexArrayData::CData::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = CycleData::complete_pointers(p_list, manager);
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::CData::fillin
// Access: Public, Virtual
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new qpGeomVertexArrayData.
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::CData::
fillin(DatagramIterator &scan, BamReader *manager) {
}

View File

@ -0,0 +1,164 @@
// Filename: qpgeomVertexArrayData.h
// Created by: drose (17Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef qpGEOMVERTEXARRAYDATA_H
#define qpGEOMVERTEXARRAYDATA_H
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "qpgeomVertexArrayFormat.h"
#include "pta_uchar.h"
#include "updateSeq.h"
#include "cycleData.h"
#include "cycleDataReader.h"
#include "cycleDataWriter.h"
#include "pipelineCycler.h"
#include "pmap.h"
class PreparedGraphicsObjects;
class DataContext;
////////////////////////////////////////////////////////////////////
// Class : qpGeomVertexArrayData
// Description : This is the data for one array of a GeomVertexData
// structure. Many GeomVertexData structures will only
// define one array; some will define multiple arrays.
// DirectX calls this concept a "stream".
//
// This object is just a block of data. See
// GeomVertexData for the organizing structure.
//
// This is part of the experimental Geom rewrite.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpGeomVertexArrayData : public TypedWritableReferenceCount {
private:
qpGeomVertexArrayData();
PUBLISHED:
enum UsageHint {
// UH_client: don't attempt to upload the data as a "vertex
// buffer"; always keep it on the client.
UH_client,
// UH_stream: the data will be created once, used to render a few
// times, and then discarded.
UH_stream,
// UH_static: the data will be created once, and used to render
// many times, without modification.
UH_static,
// UH_dynamic: the data will be repeatedly modified and
// re-rendered.
UH_dynamic,
};
qpGeomVertexArrayData(const qpGeomVertexArrayFormat *array_format,
UsageHint usage_hint);
qpGeomVertexArrayData(const qpGeomVertexArrayData &copy);
private:
void operator = (const qpGeomVertexArrayData &copy);
PUBLISHED:
virtual ~qpGeomVertexArrayData();
INLINE const qpGeomVertexArrayFormat *get_array_format() const;
INLINE UsageHint get_usage_hint() const;
INLINE CPTA_uchar get_data() const;
INLINE PTA_uchar modify_data();
INLINE void set_data(CPTA_uchar data);
INLINE int get_num_vertices() const;
bool set_num_vertices(int n);
INLINE void clear_vertices();
INLINE int get_num_bytes() const;
INLINE UpdateSeq get_modified() const;
void prepare(PreparedGraphicsObjects *prepared_objects);
public:
DataContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg);
bool release(PreparedGraphicsObjects *prepared_objects);
int release_all();
private:
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
CPT(qpGeomVertexArrayFormat) _array_format;
UsageHint _usage_hint;
// A GeomVertexArrayData keeps a list (actually, a map) of all the
// PreparedGraphicsObjects tables that it has been prepared into.
// Each PGO conversely keeps a list (a set) of all the Geoms that
// have been prepared there. When either destructs, it removes
// itself from the other's list.
typedef pmap<PreparedGraphicsObjects *, DataContext *> Contexts;
Contexts _contexts;
// This is the data that must be cycled between pipeline stages.
class EXPCL_PANDA CData : public CycleData {
public:
INLINE CData();
INLINE CData(const CData &copy);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
PTA_uchar _data;
UpdateSeq _modified;
};
PipelineCycler<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "qpGeomVertexArrayData",
TypedWritableReferenceCount::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 qpGeomVertexCacheManager;
friend class PreparedGraphicsObjects;
};
#include "qpgeomVertexArrayData.I"
#endif

View File

@ -34,11 +34,15 @@ get_format() const {
// Description: Sets the length of the array to n vertices in all of
// the various arrays (presumably by adding vertices).
// The new vertex data is uninitialized.
//
// The return value is true if the number of vertices
// was changed, false if the object already contained n
// vertices (or if there was some error).
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexData::
INLINE bool qpGeomVertexData::
set_num_vertices(int n) {
CDWriter cdata(_cycler);
do_set_num_vertices(n, cdata);
return do_set_num_vertices(n, cdata);
}
////////////////////////////////////////////////////////////////////
@ -55,17 +59,17 @@ get_num_arrays() const {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::get_array_data
// Function: qpGeomVertexData::get_array
// Access: Published
// Description: Returns a const pointer to the vertex data for the
// indicated array, for application code to directly
// examine (but not modify) the underlying vertex data.
////////////////////////////////////////////////////////////////////
INLINE CPTA_uchar qpGeomVertexData::
get_array_data(int array) const {
INLINE const qpGeomVertexArrayData *qpGeomVertexData::
get_array(int i) const {
CDReader cdata(_cycler);
nassertr(array >= 0 && array < (int)cdata->_arrays.size(), CPTA_uchar());
return cdata->_arrays[array];
nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
return cdata->_arrays[i];
}
////////////////////////////////////////////////////////////////////

View File

@ -43,15 +43,21 @@ qpGeomVertexData() {
// Description:
////////////////////////////////////////////////////////////////////
qpGeomVertexData::
qpGeomVertexData(const qpGeomVertexFormat *format) :
qpGeomVertexData(const qpGeomVertexFormat *format,
qpGeomVertexArrayData::UsageHint usage_hint) :
_format(format)
{
nassertv(_format->is_registered());
// Create some empty arrays as required by the format.
CDWriter cdata(_cycler);
cdata->_arrays.insert(cdata->_arrays.end(), _format->get_num_arrays(),
PTA_uchar());
int num_arrays = _format->get_num_arrays();
for (int i = 0; i < num_arrays; i++) {
PT(qpGeomVertexArrayData) array = new qpGeomVertexArrayData
(_format->get_array(i), usage_hint);
cdata->_arrays.push_back(array);
}
}
////////////////////////////////////////////////////////////////////
@ -125,7 +131,7 @@ get_num_vertices() const {
// Look up the answer on the first array (since any array will do).
int stride = _format->get_array(0)->get_stride();
return cdata->_arrays[0].size() / stride;
return cdata->_arrays[0]->get_num_bytes() / stride;
}
////////////////////////////////////////////////////////////////////
@ -137,6 +143,7 @@ get_num_vertices() const {
////////////////////////////////////////////////////////////////////
void qpGeomVertexData::
clear_vertices() {
clear_cache();
CDWriter cdata(_cycler);
nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
@ -144,12 +151,12 @@ clear_vertices() {
for (ai = cdata->_arrays.begin();
ai != cdata->_arrays.end();
++ai) {
(*ai).clear();
(*ai)->clear_vertices();
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::modify_array_data
// Function: qpGeomVertexData::modify_array
// Access: Published
// Description: Returns a modifiable pointer to the indicated vertex
// array, so that application code may directly
@ -157,27 +164,24 @@ clear_vertices() {
// the length of this array, since all of the arrays
// should be kept in sync--use add_vertices() instead.
////////////////////////////////////////////////////////////////////
PTA_uchar qpGeomVertexData::
modify_array_data(int array) {
qpGeomVertexArrayData *qpGeomVertexData::
modify_array(int i) {
// Perform copy-on-write: if the reference count on the vertex data
// is greater than 1, assume some other GeomVertexData has the same
// pointer, so make a copy of it first.
clear_cache();
CDWriter cdata(_cycler);
nassertr(array >= 0 && array < (int)cdata->_arrays.size(), PTA_uchar());
nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
if (cdata->_arrays[array].get_ref_count() > 1) {
PTA_uchar orig_data = cdata->_arrays[array];
cdata->_arrays[array] = PTA_uchar();
cdata->_arrays[array].v() = orig_data.v();
if (cdata->_arrays[i]->get_ref_count() > 1) {
cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]);
}
clear_cache();
return cdata->_arrays[array];
return cdata->_arrays[i];
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::set_array_data
// Function: qpGeomVertexData::set_array
// Access: Published
// Description: Replaces the indicated vertex data array with
// a completely new array. You should be careful that
@ -185,10 +189,11 @@ modify_array_data(int array) {
// unless you know what you are doing.
////////////////////////////////////////////////////////////////////
void qpGeomVertexData::
set_array_data(int array, PTA_uchar array_data) {
set_array(int i, const qpGeomVertexArrayData *array) {
clear_cache();
CDWriter cdata(_cycler);
nassertv(array >= 0 && array < (int)cdata->_arrays.size());
cdata->_arrays[array] = array_data;
nassertv(i >= 0 && i < (int)cdata->_arrays.size());
cdata->_arrays[i] = (qpGeomVertexArrayData *)array;
}
////////////////////////////////////////////////////////////////////
@ -205,7 +210,7 @@ get_num_bytes() const {
Arrays::const_iterator ai;
for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) {
num_bytes += (*ai).size();
num_bytes += (*ai)->get_num_bytes();
}
return num_bytes;
@ -257,33 +262,34 @@ convert_to(const qpGeomVertexFormat *new_format) const {
}
PStatTimer timer(_munge_data_pcollector);
PT(qpGeomVertexData) new_data = new qpGeomVertexData(new_format);
PT(qpGeomVertexData) new_data =
new qpGeomVertexData(new_format, qpGeomVertexArrayData::UH_client);
pset<int> done_arrays;
int num_arrays = _format->get_num_arrays();
int array;
int i;
// First, check to see if any arrays can be simply appropriated for
// the new format, without changing the data.
for (array = 0; array < num_arrays; ++array) {
for (i = 0; i < num_arrays; ++i) {
const qpGeomVertexArrayFormat *array_format =
_format->get_array(array);
_format->get_array(i);
bool array_done = false;
int new_num_arrays = new_format->get_num_arrays();
for (int new_array = 0;
new_array < new_num_arrays && !array_done;
++new_array) {
for (int new_i = 0;
new_i < new_num_arrays && !array_done;
++new_i) {
const qpGeomVertexArrayFormat *new_array_format =
new_format->get_array(new_array);
new_format->get_array(new_i);
if (new_array_format->is_data_subset_of(*array_format)) {
// Great! Just use the same data for this one.
new_data->set_array_data(new_array, (PTA_uchar &)get_array_data(array));
new_data->set_array(new_i, get_array(i));
array_done = true;
done_arrays.insert(new_array);
done_arrays.insert(new_i);
}
}
}
@ -292,27 +298,30 @@ convert_to(const qpGeomVertexFormat *new_format) const {
new_data->set_num_vertices(num_vertices);
// Now go back through and copy any data that's left over.
for (array = 0; array < num_arrays; ++array) {
CPTA_uchar array_data = get_array_data(array);
const qpGeomVertexArrayFormat *array_format =
_format->get_array(array);
for (i = 0; i < num_arrays; ++i) {
CPTA_uchar data = get_array(i)->get_data();
const qpGeomVertexArrayFormat *array_format = _format->get_array(i);
int num_data_types = array_format->get_num_data_types();
for (int di = 0; di < num_data_types; ++di) {
const qpGeomVertexDataType *data_type = array_format->get_data_type(di);
int new_array = new_format->get_array_with(data_type->get_name());
if (new_array >= 0 && done_arrays.count(new_array) == 0) {
int new_i = new_format->get_array_with(data_type->get_name());
if (new_i >= 0 && done_arrays.count(new_i) == 0) {
// The data type exists in the new format; we have to copy it.
PTA_uchar new_array_data = new_data->modify_array_data(new_array);
PT(qpGeomVertexArrayData) new_array_data = new
qpGeomVertexArrayData(*get_array(i));
new_data->set_array(new_i, new_array_data);
PTA_uchar new_data = new_array_data->modify_data();
const qpGeomVertexArrayFormat *new_array_format =
new_format->get_array(new_array);
new_format->get_array(new_i);
const qpGeomVertexDataType *new_data_type =
new_array_format->get_data_type(data_type->get_name());
new_data_type->copy_records
(new_array_data + new_data_type->get_start(),
(new_data + new_data_type->get_start(),
new_array_format->get_stride(),
array_data + data_type->get_start(), array_format->get_stride(),
data + data_type->get_start(), array_format->get_stride(),
data_type, num_vertices);
}
}
@ -397,7 +406,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
{
CDReader cdata(_cycler);
int array_size = (int)cdata->_arrays[array].size();
int array_size = (int)cdata->_arrays[array]->get_num_bytes();
if (element + data_type->get_total_bytes() > array_size) {
// Whoops, we need more vertices!
CDWriter cdataw(_cycler, cdata);
@ -405,7 +414,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
}
}
PTA_uchar array_data = modify_array_data(array);
PTA_uchar array_data = modify_array(array)->modify_data();
nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
switch (data_type->get_numeric_type()) {
@ -484,7 +493,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
void qpGeomVertexData::
get_data(int array, const qpGeomVertexDataType *data_type,
int vertex, float *data, int num_values) const {
CPTA_uchar array_data = get_array_data(array);
CPTA_uchar array_data = get_array(array)->get_data();
int stride = _format->get_array(array)->get_stride();
int element = vertex * stride + data_type->get_start();
nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
@ -561,7 +570,8 @@ get_data(int array, const qpGeomVertexDataType *data_type,
// which case none of the output parameters are valid).
////////////////////////////////////////////////////////////////////
bool qpGeomVertexData::
get_array_info(const InternalName *name, CPTA_uchar &array_data,
get_array_info(const InternalName *name,
const qpGeomVertexArrayData *&array_data,
int &num_components,
qpGeomVertexDataType::NumericType &numeric_type,
int &start, int &stride) const {
@ -712,45 +722,23 @@ remove_cache_entry(const qpGeomVertexFormat *modifier) const {
// Access: Private
// Description: The private implementation of set_num_vertices().
////////////////////////////////////////////////////////////////////
void qpGeomVertexData::
do_set_num_vertices(int n, CDWriter &cdata) {
nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
bool qpGeomVertexData::
do_set_num_vertices(int n, qpGeomVertexData::CDWriter &cdata) {
nassertr(_format->get_num_arrays() == (int)cdata->_arrays.size(), false);
bool any_changed = false;
for (size_t i = 0; i < cdata->_arrays.size(); i++) {
int stride = _format->get_array(i)->get_stride();
int delta = n - (cdata->_arrays[i].size() / stride);
if (delta != 0) {
if (cdata->_arrays[i]->set_num_vertices(n)) {
any_changed = true;
if (cdata->_arrays[i].get_ref_count() > 1) {
// Copy-on-write: the array is already reffed somewhere else,
// so we're just going to make a copy.
PTA_uchar new_array;
new_array.reserve(n * stride);
new_array.insert(new_array.end(), n * stride, uchar());
memcpy(new_array, cdata->_arrays[i],
min((size_t)(n * stride), cdata->_arrays[i].size()));
cdata->_arrays[i] = new_array;
} else {
// We've got the only reference to the array, so we can change
// it directly.
if (delta > 0) {
cdata->_arrays[i].insert(cdata->_arrays[i].end(), delta * stride, uchar());
} else {
cdata->_arrays[i].erase(cdata->_arrays[i].begin() + n * stride,
cdata->_arrays[i].end());
}
}
}
}
if (any_changed) {
clear_cache();
}
return any_changed;
}
////////////////////////////////////////////////////////////////////

View File

@ -23,6 +23,7 @@
#include "typedWritableReferenceCount.h"
#include "qpgeomVertexFormat.h"
#include "qpgeomVertexDataType.h"
#include "qpgeomVertexArrayData.h"
#include "internalName.h"
#include "cycleData.h"
#include "cycleDataReader.h"
@ -32,7 +33,6 @@
#include "pointerTo.h"
#include "pmap.h"
#include "pvector.h"
#include "pta_uchar.h"
class FactoryParams;
class qpGeomVertexDataType;
@ -62,7 +62,8 @@ class EXPCL_PANDA qpGeomVertexData : public TypedWritableReferenceCount {
private:
qpGeomVertexData();
PUBLISHED:
qpGeomVertexData(const qpGeomVertexFormat *format);
qpGeomVertexData(const qpGeomVertexFormat *format,
qpGeomVertexArrayData::UsageHint usage_hint);
qpGeomVertexData(const qpGeomVertexData &copy);
void operator = (const qpGeomVertexData &copy);
virtual ~qpGeomVertexData();
@ -70,13 +71,13 @@ PUBLISHED:
INLINE const qpGeomVertexFormat *get_format() const;
int get_num_vertices() const;
INLINE void set_num_vertices(int n);
INLINE bool set_num_vertices(int n);
void clear_vertices();
INLINE int get_num_arrays() const;
INLINE CPTA_uchar get_array_data(int array) const;
PTA_uchar modify_array_data(int array);
void set_array_data(int array, PTA_uchar array_data);
INLINE const qpGeomVertexArrayData *get_array(int i) const;
qpGeomVertexArrayData *modify_array(int i);
void set_array(int i, const qpGeomVertexArrayData *array);
int get_num_bytes() const;
@ -93,7 +94,8 @@ public:
void get_data(int array, const qpGeomVertexDataType *data_type,
int vertex, float *data, int num_values) const;
bool get_array_info(const InternalName *name, CPTA_uchar &array_data,
bool get_array_info(const InternalName *name,
const qpGeomVertexArrayData *&array_data,
int &num_components,
qpGeomVertexDataType::NumericType &numeric_type,
int &start, int &stride) const;
@ -111,7 +113,7 @@ private:
private:
CPT(qpGeomVertexFormat) _format;
typedef pvector<PTA_uchar> Arrays;
typedef pvector< PT(qpGeomVertexArrayData) > Arrays;
// We have to use reference-counting pointers here instead of having
// explicit cleanup in the GeomVertexFormat destructor, because the
@ -139,7 +141,7 @@ private:
typedef CycleDataWriter<CData> CDWriter;
private:
void do_set_num_vertices(int n, CDWriter &cdata);
bool do_set_num_vertices(int n, CDWriter &cdata);
static PStatCollector _munge_data_pcollector;

View File

@ -321,7 +321,7 @@ write_with_data(ostream &out, int indent_level,
indent(out, indent_level)
<< data->get_num_vertices() << " vertices.\n";
for (size_t i = 0; i < _arrays.size(); i++) {
CPTA_uchar array_data = data->get_array_data(i);
CPTA_uchar array_data = data->get_array(i)->get_data();
indent(out, indent_level)
<< "Array " << i << " (" << (void *)array_data.p() << "):\n";
_arrays[i]->write_with_data(out, indent_level + 2, data, i);

View File

@ -30,6 +30,7 @@ class RenderBuffer;
class GraphicsWindow;
class NodePath;
class DataContext;
class GeomContext;
class GeomNode;
class Geom;
@ -44,6 +45,7 @@ class GeomTristrip;
class GeomTrifan;
class GeomSphere;
class qpGeomVertexData;
class qpGeomVertexArrayData;
class qpGeomTriangles;
class qpGeomTristrips;
class qpGeomTrifans;
@ -132,6 +134,9 @@ public:
virtual GeomContext *prepare_geom(Geom *geom)=0;
virtual void release_geom(GeomContext *gc)=0;
virtual DataContext *prepare_data(qpGeomVertexArrayData *data)=0;
virtual void release_data(DataContext *gc)=0;
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state)=0;
virtual void set_state_and_transform(const RenderState *state,