From a7132f9cf49c905effc73c80adee808dd9ad1aeb Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 13 Mar 2002 02:11:00 +0000 Subject: [PATCH] pgraph tweaks, chancfg, modelpool --- panda/src/chancfg/chancfg.I | 22 +- panda/src/chancfg/chancfg.cxx | 306 +++++++++++++++++++++++-- panda/src/chancfg/chancfg.h | 32 ++- panda/src/loader/Sources.pp | 20 +- panda/src/loader/loader_composite2.cxx | 1 + panda/src/loader/qpmodelPool.I | 131 +++++++++++ panda/src/loader/qpmodelPool.cxx | 161 +++++++++++++ panda/src/loader/qpmodelPool.h | 85 +++++++ panda/src/pgraph/pandaNode.cxx | 1 + panda/src/pgraph/qpnodePath.I | 18 +- panda/src/pgraph/qpnodePath.h | 1 + panda/src/putil/pipelineCyclerBase.I | 28 ++- panda/src/putil/pipelineCyclerBase.h | 2 +- 13 files changed, 767 insertions(+), 41 deletions(-) create mode 100644 panda/src/loader/qpmodelPool.I create mode 100644 panda/src/loader/qpmodelPool.cxx create mode 100644 panda/src/loader/qpmodelPool.h diff --git a/panda/src/chancfg/chancfg.I b/panda/src/chancfg/chancfg.I index c837b91bfd..da19858c9d 100644 --- a/panda/src/chancfg/chancfg.I +++ b/panda/src/chancfg/chancfg.I @@ -17,7 +17,7 @@ //////////////////////////////////////////////////////////////////// INLINE PT_NamedNode ChanConfig::get_group_node(const int node_index) const { - return _group_node[node_index]; + return _group_node[node_index]; } INLINE int ChanConfig::get_group_membership(const int dr_index) const { return _group_membership[dr_index]; @@ -35,3 +35,23 @@ return _graphics_window; } + + INLINE PandaNode *qpChanConfig::get_group_node(const int node_index) const { + return _group_node[node_index]; + } + INLINE int qpChanConfig::get_group_membership(const int dr_index) const { + return _group_membership[dr_index]; + } + INLINE int qpChanConfig::get_num_groups(void) const { + return _group_node.size(); + } + INLINE int qpChanConfig::get_num_drs(void) const { + return _display_region.size(); + } + INLINE PT(DisplayRegion) qpChanConfig::get_dr(const int dr_index) const { + return _display_region[dr_index]; + } + INLINE PT(GraphicsWindow) qpChanConfig::get_win(void) const { + return _graphics_window; + } + diff --git a/panda/src/chancfg/chancfg.cxx b/panda/src/chancfg/chancfg.cxx index 577621bf96..0eb5eea28a 100644 --- a/panda/src/chancfg/chancfg.cxx +++ b/panda/src/chancfg/chancfg.cxx @@ -17,20 +17,23 @@ //////////////////////////////////////////////////////////////////// #include "chancfg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "notify.h" +#include "displayRegion.h" +#include "graphicsChannel.h" +#include "hardwareChannel.h" +#include "camera.h" +#include "qpcamera.h" +#include "frustum.h" +#include "perspectiveLens.h" +#include "renderRelation.h" +#include "transformTransition.h" +#include "dSearchPath.h" +#include "dconfig.h" +#include "filename.h" +#include "pt_NamedNode.h" +#include "transformState.h" + #include -#include Configure(chanconfig); @@ -483,6 +486,283 @@ ChanConfig::ChanConfig(GraphicsPipe* pipe, std::string cfg, Node *render, return; } +void qpChanConfig::chan_eval(GraphicsWindow* win, WindowItem& W, LayoutItem& L, + SVec& S, + ChanViewport& V, int hw_offset, int xsize, int ysize, + const qpNodePath &render, bool want_cameras) { + int i = min(L.GetNumRegions(), int(S.size())); + int j; + SVec::iterator k; + std::vector< PT(PandaNode) >camera(W.getNumCameraGroups()); + //first camera is special cased to name "camera" for older code + camera[0] = new PandaNode("camera"); + for(int icam=1;icamget_channel(hw_offset); + } else + chan = win->get_channel((*k).getChan()); + // HW channels always start with the full area of the channel + v = ChanViewport(0.0f, 1.0f, 0.0f, 1.0f); + } else { + chan = win->get_channel(0); + } + ChanViewport v2(ChanScaleViewport(v, (*k).getViewport())); + PT(GraphicsLayer) layer = chan->make_layer(); + PT(DisplayRegion) dr = + layer->make_display_region(v2.left(), v2.right(), + v2.bottom(), v2.top()); + if (want_cameras && camera[0] != (PandaNode *)NULL) { + // now make a camera for it + PT(qpCamera) cam = new qpCamera(""); + dr->set_qpcamera(qpNodePath(cam)); + _display_region.push_back(dr); + SetupFOV fov = (*k).getFOV(); + // The distinction between ConsoleSize and DisplaySize + // is to handle display regions with orientations that + // are rotated 90 degrees left or right. For example, + // the model shop cave (LAIR) uses projectors on their + // sides, so that what's horizontal on the console is + // vertical in the cave (Display). + float xConsoleSize = xsize*(v2.right()-v2.left()); + float yConsoleSize = ysize*(v2.top()-v2.bottom()); + float xDisplaySize, yDisplaySize; + if ( (*k).getOrientation() == SetupItem::Left || + (*k).getOrientation() == SetupItem::Right ) { + xDisplaySize = yConsoleSize; + yDisplaySize = xConsoleSize; + } else { + xDisplaySize = xConsoleSize; + yDisplaySize = yConsoleSize; + } + fov = ChanResolveFOV(fov, xDisplaySize, yDisplaySize); + if (chancfg_cat->is_debug()) { + chancfg_cat->debug() << "ChanEval:: FOVhoriz = " << fov.getHoriz() + << " FOVvert = " << fov.getVert() << endl; + chancfg_cat->debug() << "ChanEval:: xsize = " << xsize + << " ysize = " << ysize << endl; + } + + // take care of the orientation + CPT(TransformState) orient; + float hFov, vFov; + + switch ((*k).getOrientation()) { + case SetupItem::Up: + hFov = fov.getHoriz(); vFov = fov.getVert(); + break; + case SetupItem::Down: + hFov = fov.getHoriz(); vFov = fov.getVert(); + orient = TransformState::make_mat + (LMatrix4f::rotate_mat_normaxis(180.0f, LVector3f::forward())); + break; + case SetupItem::Left: + // vertical and horizontal FOV are being switched + hFov = fov.getVert(); vFov = fov.getHoriz(); + orient = TransformState::make_mat + (LMatrix4f::rotate_mat_normaxis(90.0f, LVector3f::forward())); + break; + case SetupItem::Right: + // vertical and horizontal FOV are being switched + hFov = fov.getVert(); vFov = fov.getHoriz(); + orient = TransformState::make_mat + (LMatrix4f::rotate_mat_normaxis(-90.0f, LVector3f::forward())); + break; + } + + PT(Lens) lens = new PerspectiveLens; + lens->set_fov(hFov, vFov); + lens->set_near_far(1.0f, 10000.0f); + cam->set_lens(lens); + + // hfov and vfov for camera are switched from what was specified + // if the orientation is sideways. + if (chancfg_cat->is_debug()) + chancfg_cat->debug() << "ChanEval:: camera hfov = " + << lens->get_hfov() << " vfov = " + << lens->get_vfov() << endl; + cam->set_scene(render); + + camera[W.getCameraGroup(j)]->add_child(cam); + if (orient != (TransformState *)NULL) { + cam->set_transform(orient); + } + } + } + _group_node = camera; + return; +} + +qpChanConfig::qpChanConfig(GraphicsPipe* pipe, std::string cfg, const qpNodePath &render, + ChanCfgOverrides& overrides) { + ReadChanConfigData(); + // check to make sure we know everything we need to + if (!ConfigDefined(cfg)) { + chancfg_cat.error() + << "no window configuration called '" << cfg << "'" << endl; + _graphics_window = (GraphicsWindow*)0; + return; + } + WindowItem W = (*WindowDB)[cfg]; + + std::string l = W.getLayout(); + if (!LayoutDefined(l)) { + chancfg_cat.error() + << "No layout called '" << l << "'" << endl; + _graphics_window = (GraphicsWindow*)0; + return; + } + LayoutItem L = (*LayoutDB)[l]; + + SetupSyms s = W.getSetups(); + if (!ChanCheckSetups(s)) { + chancfg_cat.error() << "Setup failure" << endl; + _graphics_window = (GraphicsWindow*)0; + return; + } + + SVec S; + S.reserve(s.size()); + for (SetupSyms::iterator i=s.begin(); i!=s.end(); ++i) + S.push_back((*SetupDB)[(*i)]); + + // get the window data + int sizeX = chanconfig.GetInt("win-width", -1); + int sizeY = chanconfig.GetInt("win-height", -1); + if (overrides.defined(ChanCfgOverrides::SizeX)) + sizeX = overrides.getInt(ChanCfgOverrides::SizeX); + if (overrides.defined(ChanCfgOverrides::SizeY)) + sizeY = overrides.getInt(ChanCfgOverrides::SizeY); + if (sizeX < 0) { + if (sizeY < 0) { + if(chancfg_cat.is_debug()) + chancfg_cat.debug() << "Using default chan-window size\n"; + // take the default size + sizeX = W.getSizeX(); + sizeY = W.getSizeY(); + } else { + // vertical size is defined, compute horizontal keeping the aspect from + // the default + sizeX = (W.getSizeX() * sizeY) / W.getSizeY(); + } + } else if (sizeY < 0) { + // horizontal size is defined, compute vertical keeping the aspect from the + // default + sizeY = (W.getSizeY() * sizeX) / W.getSizeX(); + } + + int origX = chanconfig.GetInt("win-origin-x"); + int origY = chanconfig.GetInt("win-origin-y"); + origX = overrides.defined(ChanCfgOverrides::OrigX) ? + overrides.getInt(ChanCfgOverrides::OrigX) : origX; + origY = overrides.defined(ChanCfgOverrides::OrigY) ? + overrides.getInt(ChanCfgOverrides::OrigY) : origY; + + bool border = !chanconfig.GetBool("no-border", !W.getBorder()); + bool fullscreen = chanconfig.GetBool("fullscreen", false); + bool use_cursor = chanconfig.GetBool("cursor-visible", W.getCursor()); + int want_depth_bits = chanconfig.GetInt("want-depth-bits", 1); + int want_color_bits = chanconfig.GetInt("want-color-bits", 1); + + // visual? nope, that's handled with the mode. + uint mask = 0x0; // ?! this really should come from the win config + mask = overrides.defined(ChanCfgOverrides::Mask) ? + overrides.getUInt(ChanCfgOverrides::Mask) : mask; + std::string title = cfg; + title = overrides.defined(ChanCfgOverrides::Title) ? + overrides.getString(ChanCfgOverrides::Title) : title; + + GraphicsWindow::Properties props; + props._xorg = origX; + props._yorg = origY; + props._xsize = sizeX; + props._ysize = sizeY; + props._title = title; + props._mask = mask; + props._border = border; + props._fullscreen = fullscreen; + props._want_depth_bits = want_depth_bits; + props._want_color_bits = want_color_bits; + props._bCursorIsVisible = use_cursor; + + // stereo prep? + // DVR prep? + + bool want_cameras = overrides.defined(ChanCfgOverrides::Cameras) ? + overrides.getBool(ChanCfgOverrides::Cameras) : true; + + // open that sucker + PT(GraphicsWindow) win = pipe->make_window(props); + if(win == (GraphicsWindow *)NULL) { + chancfg_cat.error() << "Could not create window" << endl; + _graphics_window = (GraphicsWindow *)NULL; + return; + } + + // make channels and display regions + ChanViewport V(0.0f, 1.0f, 0.0f, 1.0f); + chan_eval(win, W, L, S, V, W.getChanOffset()+1, sizeX, sizeY, + render, want_cameras); + for(size_t dr_index=0; dr_index<_display_region.size(); dr_index++) + _group_membership.push_back(W.getCameraGroup(dr_index)); + + // sanity check + if (config_sanity_check) { + nout << "ChanConfig Sanity check:" << endl + << "window - " << (void*)win << endl + << " width = " << win->get_width() << " height = " << win->get_height() << endl + << " xorig = " << win->get_xorg() << " yorig = " << win->get_yorg()<< endl; + + int max_channel_index = win->get_max_channel_index(); + for (int c = 0; c < max_channel_index; c++) { + if (win->is_channel_defined(c)) { + GraphicsChannel *chan = win->get_channel(c); + nout << " Chan - " << (void*)chan << endl + << " window = " << (void*)(chan->get_window()) << endl + << " active = " << chan->is_active() << endl; + + int num_layers = chan->get_num_layers(); + for (int l = 0; l < num_layers; l++) { + GraphicsLayer *layer = chan->get_layer(l); + nout << " Layer - " << (void*)layer << endl + << " channel = " << (void*)(layer->get_channel()) << endl + << " active = " << layer->is_active() << endl; + + int num_drs = layer->get_num_drs(); + for (int d = 0; d < num_drs; d++) { + DisplayRegion *dr = layer->get_dr(d); + nout << " DR - " << (void*)dr << endl + << " layer = " << (void*)(dr->get_layer()) << endl; + float ll, rr, bb, tt; + dr->get_dimensions(ll, rr, bb, tt); + nout << " (" << ll << " " << rr << " " << bb << " " << tt << ")" << endl + << " camera = " << (void*)(dr->get_camera()) << endl; + Camera* cmm = dr->get_camera(); + if (cmm != (Camera*)0L) { + nout << " active = " << cmm->is_active() << endl; + int num_cam_drs = cmm->get_num_drs(); + for (int cd = 0; cd < num_cam_drs; cd++) + nout << " dr = " << (void*)cmm->get_dr(cd) << endl; + } + nout << " active = " << dr->is_active() << endl; + } + } + } + } + } + _graphics_window = win; + return; +} + diff --git a/panda/src/chancfg/chancfg.h b/panda/src/chancfg/chancfg.h index 2958a0f250..a9b69cc49f 100644 --- a/panda/src/chancfg/chancfg.h +++ b/panda/src/chancfg/chancfg.h @@ -19,16 +19,18 @@ #ifndef __CHANCFG_H__ #define __CHANCFG_H__ -#include +#include "pandabase.h" #include "chanlayout.h" #include "chansetup.h" #include "chanwindow.h" #include "chanshare.h" -#include -#include -#include +#include "graphicsPipe.h" +#include "graphicsWindow.h" +#include "pt_NamedNode.h" +#include "pandaNode.h" +#include "qpnodePath.h" #include "pmap.h" @@ -104,6 +106,7 @@ extern ChanCfgOverrides ChanOverrideNone; typedef pvector SVec; class NamedNode; + class EXPCL_PANDA ChanConfig { private: @@ -125,6 +128,27 @@ PUBLISHED: INLINE PT(GraphicsWindow) get_win(void) const; }; +class EXPCL_PANDA qpChanConfig +{ +private: + std::vector< PT(PandaNode) > _group_node; + std::vector< PT(DisplayRegion) > _display_region; + std::vector _group_membership; + PT(GraphicsWindow) _graphics_window; + void chan_eval(GraphicsWindow* win, WindowItem& W, LayoutItem& L, + SVec& S, ChanViewport& V, int hw_offset, + int xsize, int ysize, const qpNodePath &render, bool want_cameras); +PUBLISHED: + qpChanConfig(GraphicsPipe*, std::string, const qpNodePath &render, + ChanCfgOverrides& = ChanOverrideNone); + INLINE PandaNode *get_group_node(const int node_index) const; + INLINE int get_group_membership(const int dr_index) const; + INLINE int get_num_groups(void) const; + INLINE int get_num_drs(void) const; + INLINE PT(DisplayRegion) get_dr(const int dr_index) const; + INLINE PT(GraphicsWindow) get_win(void) const; +}; + #include "chancfg.I" #endif /* __CHANCFG_H__ */ diff --git a/panda/src/loader/Sources.pp b/panda/src/loader/Sources.pp index d5e75d52c3..9d52a6b196 100644 --- a/panda/src/loader/Sources.pp +++ b/panda/src/loader/Sources.pp @@ -9,19 +9,23 @@ #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ - bamFile.I bamFile.h config_loader.h loader.I loader.h \ - loaderFileType.h loaderFileTypeBam.h \ - loaderFileTypeRegistry.h modelPool.I modelPool.h + bamFile.I bamFile.h config_loader.h loader.I loader.h \ + loaderFileType.h loaderFileTypeBam.h \ + loaderFileTypeRegistry.h \ + modelPool.I modelPool.h \ + qpmodelPool.I qpmodelPool.h #define INCLUDED_SOURCES \ - bamFile.cxx config_loader.cxx loader.cxx loaderFileType.cxx \ - loaderFileTypeBam.cxx loaderFileTypeRegistry.cxx \ - modelPool.cxx + bamFile.cxx config_loader.cxx loader.cxx loaderFileType.cxx \ + loaderFileTypeBam.cxx loaderFileTypeRegistry.cxx \ + modelPool.cxx \ + qpmodelPool.cxx #define INSTALL_HEADERS \ bamFile.I bamFile.h loader.I loader.h loaderFileType.h \ - loaderFileTypeBam.h loaderFileTypeRegistry.h modelPool.I \ - modelPool.h + loaderFileTypeBam.h loaderFileTypeRegistry.h \ + modelPool.I modelPool.h \ + qpmodelPool.I qpmodelPool.h #define IGATESCAN all diff --git a/panda/src/loader/loader_composite2.cxx b/panda/src/loader/loader_composite2.cxx index 1631c114ff..bf20d95997 100644 --- a/panda/src/loader/loader_composite2.cxx +++ b/panda/src/loader/loader_composite2.cxx @@ -1,5 +1,6 @@ #include "modelPool.cxx" +#include "qpmodelPool.cxx" #include "loaderFileType.cxx" #include "loaderFileTypeBam.cxx" #include "loaderFileTypeRegistry.cxx" diff --git a/panda/src/loader/qpmodelPool.I b/panda/src/loader/qpmodelPool.I new file mode 100644 index 0000000000..34bc275874 --- /dev/null +++ b/panda/src/loader/qpmodelPool.I @@ -0,0 +1,131 @@ +// Filename: qpmodelPool.I +// Created by: drose (12Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::has_model +// Access: Public, Static +// Description: Returns true if the model has ever been loaded, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool qpModelPool:: +has_model(const string &filename) { + return get_ptr()->ns_has_model(filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::verify_model +// Access: Public, Static +// Description: Loads the given filename up as a model, if it has +// not already been loaded, and returns true to indicate +// success, or false to indicate failure. If this +// returns true, it is guaranteed that a subsequent call +// to load_model() with the same model name will +// return a valid Node pointer. +//////////////////////////////////////////////////////////////////// +INLINE bool qpModelPool:: +verify_model(const string &filename) { + return load_model(filename) != (PandaNode *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::load_model +// Access: Public, Static +// Description: Loads the given filename up as a model, if it has +// not already been loaded, and returns the new model. +// If a model with the same filename was previously +// loaded, returns that one instead. If the model +// file cannot be found, returns NULL. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *qpModelPool:: +load_model(const string &filename) { + return get_ptr()->ns_load_model(filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::add_model +// Access: Public, Static +// Description: Adds the indicated already-loaded model to the +// pool. The model will always replace any +// previously-loaded model in the pool that had the +// same filename. +//////////////////////////////////////////////////////////////////// +INLINE void qpModelPool:: +add_model(const string &filename, PandaNode *model) { + get_ptr()->ns_add_model(filename, model); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::release_model +// Access: Public, Static +// Description: Removes the indicated model from the pool, +// indicating it will never be loaded again; the model +// may then be freed. If this function is never called, +// a reference count will be maintained on every model +// every loaded, and models will never be freed. +//////////////////////////////////////////////////////////////////// +INLINE void qpModelPool:: +release_model(const string &filename) { + get_ptr()->ns_release_model(filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::release_all_models +// Access: Public, Static +// Description: Releases all models in the pool and restores the +// pool to the empty state. +//////////////////////////////////////////////////////////////////// +INLINE void qpModelPool:: +release_all_models() { + get_ptr()->ns_release_all_models(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::garbage_collect +// Access: Public, Static +// Description: Releases only those models in the pool that have a +// reference count of exactly 1; i.e. only those +// models that are not being used outside of the pool. +// Returns the number of models released. +//////////////////////////////////////////////////////////////////// +INLINE int qpModelPool:: +garbage_collect() { + return get_ptr()->ns_garbage_collect(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::list_contents +// Access: Public, Static +// Description: Lists the contents of the model pool to the +// indicated output stream. +//////////////////////////////////////////////////////////////////// +INLINE void qpModelPool:: +list_contents(ostream &out) { + get_ptr()->ns_list_contents(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::Constructor +// Access: Private +// Description: The constructor is not intended to be called +// directly; there's only supposed to be one qpModelPool +// in the universe and it constructs itself. +//////////////////////////////////////////////////////////////////// +INLINE qpModelPool:: +qpModelPool() { +} diff --git a/panda/src/loader/qpmodelPool.cxx b/panda/src/loader/qpmodelPool.cxx new file mode 100644 index 0000000000..82f296b1d8 --- /dev/null +++ b/panda/src/loader/qpmodelPool.cxx @@ -0,0 +1,161 @@ +// Filename: qpmodelPool.cxx +// Created by: drose (12Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "qpmodelPool.h" +#include "loader.h" +#include "config_loader.h" + + +qpModelPool *qpModelPool::_global_ptr = (qpModelPool *)NULL; + +static Loader _qpmodel_loader; + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_has_model +// Access: Private +// Description: The nonstatic implementation of has_model(). +//////////////////////////////////////////////////////////////////// +bool qpModelPool:: +ns_has_model(const string &filename) { + Models::const_iterator ti; + ti = _models.find(filename); + if (ti != _models.end()) { + // This model was previously loaded. + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_load_model +// Access: Private +// Description: The nonstatic implementation of load_model(). +//////////////////////////////////////////////////////////////////// +PandaNode *qpModelPool:: +ns_load_model(const string &filename) { + Models::const_iterator ti; + ti = _models.find(filename); + if (ti != _models.end()) { + // This model was previously loaded. + return (*ti).second; + } + + loader_cat.info() + << "Loading model " << filename << "\n"; + PT(PandaNode) node = _qpmodel_loader.qpload_sync(filename); + if (node.is_null()) { + // This model was not found. + return (PandaNode *)NULL; + } + + _models[filename] = node; + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_add_model +// Access: Private +// Description: The nonstatic implementation of add_model(). +//////////////////////////////////////////////////////////////////// +void qpModelPool:: +ns_add_model(const string &filename, PandaNode *model) { + // We blow away whatever model was there previously, if any. + _models[filename] = model; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_release_model +// Access: Private +// Description: The nonstatic implementation of release_model(). +//////////////////////////////////////////////////////////////////// +void qpModelPool:: +ns_release_model(const string &filename) { + Models::iterator ti; + ti = _models.find(filename); + if (ti != _models.end()) { + _models.erase(ti); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_release_all_models +// Access: Private +// Description: The nonstatic implementation of release_all_models(). +//////////////////////////////////////////////////////////////////// +void qpModelPool:: +ns_release_all_models() { + _models.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_garbage_collect +// Access: Private +// Description: The nonstatic implementation of garbage_collect(). +//////////////////////////////////////////////////////////////////// +int qpModelPool:: +ns_garbage_collect() { + int num_released = 0; + Models new_set; + + Models::iterator ti; + for (ti = _models.begin(); ti != _models.end(); ++ti) { + PandaNode *node = (*ti).second; + if (node->get_ref_count() == 1) { + if (loader_cat.is_debug()) { + loader_cat.debug() + << "Releasing " << (*ti).first << "\n"; + } + num_released++; + } else { + new_set.insert(new_set.end(), *ti); + } + } + + _models.swap(new_set); + return num_released; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::ns_list_contents +// Access: Private +// Description: The nonstatic implementation of list_contents(). +//////////////////////////////////////////////////////////////////// +void qpModelPool:: +ns_list_contents(ostream &out) { + out << _models.size() << " models:\n"; + Models::iterator ti; + for (ti = _models.begin(); ti != _models.end(); ++ti) { + out << " " << (*ti).first + << " (count = " << (*ti).second->get_ref_count() << ")\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpModelPool::get_ptr +// Access: Private, Static +// Description: Initializes and/or returns the global pointer to the +// one qpModelPool object in the system. +//////////////////////////////////////////////////////////////////// +qpModelPool *qpModelPool:: +get_ptr() { + if (_global_ptr == (qpModelPool *)NULL) { + _global_ptr = new qpModelPool; + } + return _global_ptr; +} diff --git a/panda/src/loader/qpmodelPool.h b/panda/src/loader/qpmodelPool.h new file mode 100644 index 0000000000..617b1e0426 --- /dev/null +++ b/panda/src/loader/qpmodelPool.h @@ -0,0 +1,85 @@ +// Filename: qpmodelPool.h +// Created by: drose (12Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef qpMODELPOOL_H +#define qpMODELPOOL_H + +#include "pandabase.h" + +#include "filename.h" +#include "pandaNode.h" +#include "pointerTo.h" + +#include "pmap.h" + +//////////////////////////////////////////////////////////////////// +// Class : ModelPool +// Description : This is the preferred interface for loading models. +// It unifies all references to the same filename, so +// that multiple attempts to load the same model will +// return the same pointer. Note that the default +// behavior is thus to make instances: use with caution. +// Use the copy_subgraph() method on Node (or use +// NodePath::copy_to) to make modifiable copies of the +// node. +// +// Unlike TexturePool, this class does not automatically +// resolve the model filenames before loading, so a +// relative path and an absolute path to the same model +// will appear to be different filenames. +// +// This does not presently support asynchronous loading, +// although it wouldn't be *too* difficult to add. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpModelPool { +PUBLISHED: + INLINE static bool has_model(const string &filename); + INLINE static bool verify_model(const string &filename); + INLINE static PandaNode *load_model(const string &filename); + + INLINE static void add_model(const string &filename, PandaNode *model); + INLINE static void release_model(const string &filename); + INLINE static void release_all_models(); + + INLINE static int garbage_collect(); + + INLINE static void list_contents(ostream &out); + +private: + INLINE qpModelPool(); + + bool ns_has_model(const string &filename); + PandaNode *ns_load_model(const string &filename); + void ns_add_model(const string &filename, PandaNode *model); + void ns_release_model(const string &filename); + void ns_release_all_models(); + int ns_garbage_collect(); + void ns_list_contents(ostream &out); + + static qpModelPool *get_ptr(); + + static qpModelPool *_global_ptr; + typedef pmap Models; + Models _models; +}; + +#include "qpmodelPool.I" + +#endif + + diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index a851a07405..df0617c6c4 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -487,6 +487,7 @@ add_child(PandaNode *child_node, int sort) { { PT(PandaNode) keep_child = child_node; remove_child(child_node); + CDWriter cdata(_cycler); CDWriter cdata_child(child_node->_cycler); diff --git a/panda/src/pgraph/qpnodePath.I b/panda/src/pgraph/qpnodePath.I index 139c71be76..cd23b0b0a5 100644 --- a/panda/src/pgraph/qpnodePath.I +++ b/panda/src/pgraph/qpnodePath.I @@ -32,13 +32,25 @@ qpNodePath() : { } +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::Constructor +// Access: Published +// Description: This constructs an empty qpNodePath with a single +// node. An ordinary PandaNode is created with the +// indicated name. +//////////////////////////////////////////////////////////////////// +INLINE qpNodePath:: +qpNodePath(const string &top_node_name) : + _error_type(ET_ok) +{ + PandaNode *top_node = new PandaNode(top_node_name); + _head = top_node->get_generic_component(); +} + //////////////////////////////////////////////////////////////////// // Function: qpNodePath::Constructor // Access: Published // Description: This constructs an empty qpNodePath with a single node. -// This path may now be extended by repeatedly calling -// push_back() with each node below that node in -// sequence. // // If the Node pointer is NULL, this quietly creates an // empty qpNodePath. diff --git a/panda/src/pgraph/qpnodePath.h b/panda/src/pgraph/qpnodePath.h index 372628c0f9..925267e870 100644 --- a/panda/src/pgraph/qpnodePath.h +++ b/panda/src/pgraph/qpnodePath.h @@ -68,6 +68,7 @@ PUBLISHED: }; INLINE qpNodePath(); + INLINE qpNodePath(const string &top_node_name); INLINE qpNodePath(PandaNode *top_node); INLINE qpNodePath(const qpNodePath ©); INLINE void operator = (const qpNodePath ©); diff --git a/panda/src/putil/pipelineCyclerBase.I b/panda/src/putil/pipelineCyclerBase.I index b7d84650c4..c09b9ab6a8 100644 --- a/panda/src/putil/pipelineCyclerBase.I +++ b/panda/src/putil/pipelineCyclerBase.I @@ -31,8 +31,7 @@ PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) : _data(initial_data), _pipeline(pipeline), _read_count(0), - _write_count(0), - _stage_count(0) + _write_count(0) { if (_pipeline == (Pipeline *)NULL) { _pipeline = Pipeline::get_render_pipeline(); @@ -49,8 +48,7 @@ PipelineCyclerBase(const PipelineCyclerBase ©) : _data(copy._data->make_copy()), _pipeline(copy._pipeline), _read_count(0), - _write_count(0), - _stage_count(0) + _write_count(0) { } @@ -61,7 +59,7 @@ PipelineCyclerBase(const PipelineCyclerBase ©) : //////////////////////////////////////////////////////////////////// INLINE void PipelineCyclerBase:: operator = (const PipelineCyclerBase ©) { - nassertv(_read_count == 0 && _write_count == 0 && _stage_count == 0); + nassertv(_read_count == 0 && _write_count == 0); _data = copy._data->make_copy(); _pipeline = copy._pipeline; } @@ -73,7 +71,7 @@ operator = (const PipelineCyclerBase ©) { //////////////////////////////////////////////////////////////////// INLINE PipelineCyclerBase:: ~PipelineCyclerBase() { - nassertv(_read_count == 0 && _write_count == 0 && _stage_count == 0); + nassertv(_read_count == 0 && _write_count == 0); } //////////////////////////////////////////////////////////////////// @@ -92,7 +90,9 @@ read() const { // This function isn't truly const, but it doesn't change the data // in any meaningful way, so we pretend it is. ((PipelineCyclerBase *)this)->_read_count++; - nassertr(_write_count == 0, _data); + + // It's not an error to grab a read pointer while someone else holds + // a read or a write pointer. return _data; } @@ -146,8 +146,14 @@ release_read(const CycleData *pointer) const { INLINE CycleData *PipelineCyclerBase:: write() { _write_count++; + + // It's an error to grab a write pointer while someone else holds a + // read pointer, because doing so may invalidate the read pointer. nassertr(_read_count == 0, _data); - nassertr(_write_count == 1, _data); + + // It's not an error to do this while someone else holds a write + // pointer, however. + return _data; } @@ -215,7 +221,7 @@ is_stage_unique(int n) const { INLINE CycleData *PipelineCyclerBase:: write_stage(int n) { nassertr(n == 0, (CycleData *)NULL); - _stage_count++; + _write_count++; return _data; } @@ -228,8 +234,8 @@ write_stage(int n) { INLINE void PipelineCyclerBase:: release_write_stage(int n, CycleData *pointer) { nassertv(n == 0 && pointer == _data); - nassertv(_stage_count > 0); - _stage_count--; + nassertv(_write_count > 0); + _write_count--; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/pipelineCyclerBase.h b/panda/src/putil/pipelineCyclerBase.h index 15195f53ad..eb28f8a281 100644 --- a/panda/src/putil/pipelineCyclerBase.h +++ b/panda/src/putil/pipelineCyclerBase.h @@ -62,7 +62,7 @@ public: private: PT(CycleData) _data; Pipeline *_pipeline; - short _read_count, _write_count, _stage_count; + short _read_count, _write_count; #endif // DO_PIPELINING };