abstract out PandaFramework etc.

This commit is contained in:
David Rose 2002-04-03 22:00:04 +00:00
parent ca6b643da5
commit e286a73dbb
13 changed files with 2055 additions and 656 deletions

View File

@ -1,38 +1,20 @@
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#begin static_lib_target
#begin lib_target
#define TARGET framework
#define BUILDING_DLL BUILDING_FRAMEWORK
#define LOCAL_LIBS \
putil collide loader sgmanip chan text chancfg cull \
pgraph putil collide loader sgmanip chan text chancfg cull \
pnmimage pnmimagetypes event
#define SOURCES \
config_framework.cxx config_framework.h framework.cxx framework.h
config_framework.cxx config_framework.h \
pandaFramework.cxx pandaFramework.I pandaFramework.h \
windowFramework.cxx windowFramework.I windowFramework.h
#define INSTALL_HEADERS \
framework.h
#end static_lib_target
#if $[HAVE_DX]
// USE_DX ensures DirectX dirs are on include&link lines
#define USE_DX yes
#begin static_lib_target
#define TARGET framework_multimon
#define LOCAL_LIBS \
putil collide loader sgmanip chan text chancfg cull \
pnmimage pnmimagetypes event wdxdisplay
#define SOURCES \
config_framework.cxx config_framework.h framework_multimon.cxx framework.h
#define INSTALL_HEADERS \
framework.h
#end static_lib_target
#endif
pandaFramework.I pandaFramework.h \
windowFramework.I windowFramework.h
#end lib_target

View File

@ -26,7 +26,6 @@ NotifyCategoryDef(framework, "");
ConfigureFn(config_framework) {
}
// This is the height above the ground your eye should maintain while
// driving using the "D" interface.
const double drive_height = config_framework.GetDouble("drive-height", 6.0);
const CollideMask drive_mask = config_framework.GetInt("drive-mask", ~0);
const int win_width = config_framework.GetInt("win-width", 640);
const int win_height = config_framework.GetInt("win-height", 480);
const bool fullscreen = config_framework.GetBool("fullscreen", false);

View File

@ -19,14 +19,14 @@
#ifndef CONFIG_FRAMEWORK_H
#define CONFIG_FRAMEWORK_H
#include <pandabase.h>
#include <notifyCategoryProxy.h>
#include <collideMask.h>
#include "pandabase.h"
#include "notifyCategoryProxy.h"
NotifyCategoryDecl(framework, EXPCL_EMPTY, EXPCL_EMPTY);
NotifyCategoryDecl(framework, EXPCL_FRAMEWORK, EXPCL_FRAMEWORK);
// Configure variables for framework package.
extern const double drive_height;
extern const CollideMask drive_mask;
extern const int win_width;
extern const int win_height;
extern const bool fullscreen;
#endif

View File

@ -0,0 +1,139 @@
// Filename: pandaFramework.I
// Created by: drose (02Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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: PandaFramework::get_graphics_engine
// Access: Public
// Description: Returns the GraphicsEngine that is used to render all
// the windows in the framework. Normally there's no
// reason for user code to mess with this.
////////////////////////////////////////////////////////////////////
INLINE GraphicsEngine *PandaFramework::
get_graphics_engine() {
return &_engine;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_data_root
// Access: Public
// Description: Returns the root of the data graph. This is the
// graph of nodes that is traversed to control the
// inputs from user devices like the mouse and keyboard.
////////////////////////////////////////////////////////////////////
INLINE const qpNodePath &PandaFramework::
get_data_root() const {
return _data_root;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_event_handler
// Access: Public
// Description: Returns the EventHandler object that serves events in
// the framework. This is primarily used to dispatch on
// keypresses and such.
////////////////////////////////////////////////////////////////////
INLINE EventHandler &PandaFramework::
get_event_handler() {
return _event_handler;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_window_title
// Access: Public
// Description: Specifies the title that is set for all subsequently
// created windows.
////////////////////////////////////////////////////////////////////
INLINE void PandaFramework::
set_window_title(const string &title) {
_window_title = title;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_num_windows
// Access: Public
// Description: Returns the number of windows that are currently
// open.
////////////////////////////////////////////////////////////////////
INLINE int PandaFramework::
get_num_windows() const {
return _windows.size();
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_window
// Access: Public
// Description: Returns the nth window currently open.
////////////////////////////////////////////////////////////////////
INLINE WindowFramework *PandaFramework::
get_window(int n) const {
nassertr(n >= 0 && n < (int)_windows.size(), NULL);
return _windows[n];
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_wireframe
// Access: Public
// Description: Returns the current state of the wireframe flag.
////////////////////////////////////////////////////////////////////
INLINE bool PandaFramework::
get_wireframe() const {
return _wireframe_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_texture
// Access: Public
// Description: Returns the current state of the texture flag.
////////////////////////////////////////////////////////////////////
INLINE bool PandaFramework::
get_texture() const {
return _texture_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_two_sided
// Access: Public
// Description: Returns the current state of the two_sided flag.
////////////////////////////////////////////////////////////////////
INLINE bool PandaFramework::
get_two_sided() const {
return _two_sided_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_lighting
// Access: Public
// Description: Returns the current state of the lighting flag.
////////////////////////////////////////////////////////////////////
INLINE bool PandaFramework::
get_lighting() const {
return _lighting_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_exit_flag
// Access: Public
// Description: Sets the flag that indicates it is time for the
// application to exit. The application will actually
// exit at the end of the current frame.
////////////////////////////////////////////////////////////////////
INLINE void PandaFramework::
set_exit_flag() {
_exit_flag = true;
}

View File

@ -0,0 +1,530 @@
// Filename: pandaFramework.cxx
// Created by: drose (02Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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 "pandaFramework.h"
#include "clockObject.h"
#include "pStatClient.h"
#include "eventQueue.h"
#include "qpdataGraphTraverser.h"
#include "interactiveGraphicsPipe.h"
#include "config_framework.h"
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PandaFramework::
PandaFramework() :
_event_handler(EventQueue::get_global_event_queue())
{
_is_open = false;
_made_default_pipe = false;
_data_root = qpNodePath("data");
_window_title = "Panda";
_start_time = 0.0;
_frame_count = 0;
_wireframe_enabled = false;
_texture_enabled = true;
_two_sided_enabled = false;
_lighting_enabled = false;
_default_keys_enabled = false;
_exit_flag = false;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
PandaFramework::
~PandaFramework() {
if (_is_open) {
close_framework();
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::open_framework
// Access: Public
// Description: Should be called once at the beginning of the
// application to initialize Panda (and the framework)
// for use. The command-line arguments should be passed
// in so Panda can remove any arguments that it
// recognizes as special control parameters.
////////////////////////////////////////////////////////////////////
void PandaFramework::
open_framework(int &argc, char **&argv) {
if (_is_open) {
return;
}
_is_open = true;
reset_frame_rate();
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::close_framework
// Access: Public
// Description: Should be called at the end of an application to
// close Panda. This is optional, as the destructor
// will do the same thing.
////////////////////////////////////////////////////////////////////
void PandaFramework::
close_framework() {
if (!_is_open) {
return;
}
close_all_windows();
// We should define this function on GraphicsEngine.
// _engine.remove_all_windows();
_event_handler.remove_all_hooks();
_is_open = false;
_made_default_pipe = false;
_default_pipe.clear();
_start_time = 0.0;
_frame_count = 0;
_wireframe_enabled = false;
_two_sided_enabled = false;
_lighting_enabled = false;
_default_keys_enabled = false;
_exit_flag = false;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_default_pipe
// Access: Public
// Description: Returns the default pipe. This is the GraphicsPipe
// that all windows in the framework will be created on,
// unless otherwise specified in open_window(). It is
// usually the primary graphics interface on the local
// machine.
//
// If the default pipe has not yet been created, this
// creates it.
//
// The return value is the default pipe, or NULL if no
// default pipe could be created.
////////////////////////////////////////////////////////////////////
GraphicsPipe *PandaFramework::
get_default_pipe() {
nassertr(_is_open, NULL);
if (!_made_default_pipe) {
make_default_pipe();
_made_default_pipe = true;
}
return _default_pipe;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_default_window_props
// Access: Public, Virtual
// Description: Fills in the indicated window properties structure
// according to the normal window properties for this
// application.
////////////////////////////////////////////////////////////////////
void PandaFramework::
get_default_window_props(GraphicsWindow::Properties &props) {
props._xorg = 0;
props._yorg = 0;
props._xsize = win_width;
props._ysize = win_height;
props._fullscreen = fullscreen;
props._title = _window_title;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::open_window
// Access: Public
// Description: Opens a new window, using the default parameters.
// Returns the new WindowFramework if successful, or
// NULL if not.
////////////////////////////////////////////////////////////////////
WindowFramework *PandaFramework::
open_window(GraphicsPipe *pipe) {
nassertr(_is_open, NULL);
GraphicsWindow::Properties props;
get_default_window_props(props);
return open_window(props, pipe);
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::open_window
// Access: Public
// Description: Opens a new window using the indicated properties.
// (You may initialize the properties to their default
// values by calling get_default_window_props() first.)
//
// Returns the new WindowFramework if successful, or
// NULL if not.
////////////////////////////////////////////////////////////////////
WindowFramework *PandaFramework::
open_window(const GraphicsWindow::Properties &props, GraphicsPipe *pipe) {
if (pipe == (GraphicsPipe *)NULL) {
pipe = get_default_pipe();
if (pipe == (GraphicsPipe *)NULL) {
// Can't get a pipe.
return NULL;
}
}
nassertr(_is_open, NULL);
WindowFramework *wf = make_window_framework();
_windows.push_back(wf);
GraphicsWindow *win = wf->open_window(props, pipe);
if (win != (GraphicsWindow *)NULL) {
_engine.add_window(win);
}
return wf;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::close_window
// Access: Public
// Description: Closes the nth window and removes it from the list.
////////////////////////////////////////////////////////////////////
void PandaFramework::
close_window(int n) {
nassertv(n >= 0 && n < (int)_windows.size());
WindowFramework *wf = _windows[n];
GraphicsWindow *win = wf->get_graphics_window();
if (win != (GraphicsWindow *)NULL) {
_engine.remove_window(win);
}
wf->close_window();
delete wf;
_windows.erase(_windows.begin() + n);
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::close_all_windows
// Access: Public
// Description: Closes all currently open windows and empties the
// list of windows.
////////////////////////////////////////////////////////////////////
void PandaFramework::
close_all_windows() {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
WindowFramework *wf = (*wi);
GraphicsWindow *win = wf->get_graphics_window();
if (win != (GraphicsWindow *)NULL) {
_engine.remove_window(win);
}
wf->close_window();
delete wf;
}
_windows.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::report_frame_rate
// Access: Public
// Description: Reports the currently measured average frame rate to
// the indicated ostream.
////////////////////////////////////////////////////////////////////
void PandaFramework::
report_frame_rate(ostream &out) const {
double now = ClockObject::get_global_clock()->get_frame_time();
double delta = now - _start_time;
int frame_count = ClockObject::get_global_clock()->get_frame_count();
int num_frames = frame_count - _frame_count;
if (num_frames > 0) {
out << num_frames << " frames in " << delta << " seconds.\n";
double fps = ((double)num_frames) / delta;
out << fps << " fps average (" << 1000.0 / fps << "ms)\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::reset_frame_rate
// Access: Public
// Description: Resets the frame rate computation.
////////////////////////////////////////////////////////////////////
void PandaFramework::
reset_frame_rate() {
_start_time = ClockObject::get_global_clock()->get_frame_time();
_frame_count = ClockObject::get_global_clock()->get_frame_count();
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_wireframe
// Access: Public
// Description: Sets the wireframe state on all windows.
////////////////////////////////////////////////////////////////////
void PandaFramework::
set_wireframe(bool enable) {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
WindowFramework *wf = (*wi);
wf->set_wireframe(enable);
}
_wireframe_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_texture
// Access: Public
// Description: Sets the texture state on all windows.
////////////////////////////////////////////////////////////////////
void PandaFramework::
set_texture(bool enable) {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
WindowFramework *wf = (*wi);
wf->set_texture(enable);
}
_texture_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_two_sided
// Access: Public
// Description: Sets the two_sided state on all windows.
////////////////////////////////////////////////////////////////////
void PandaFramework::
set_two_sided(bool enable) {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
WindowFramework *wf = (*wi);
wf->set_two_sided(enable);
}
_two_sided_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_lighting
// Access: Public
// Description: Sets the lighting state on all windows.
////////////////////////////////////////////////////////////////////
void PandaFramework::
set_lighting(bool enable) {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
WindowFramework *wf = (*wi);
wf->set_lighting(enable);
}
_lighting_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::enable_default_keys
// Access: Public
// Description: Sets callbacks on the event handler to handle all of
// the normal viewer keys, like t to toggle texture, ESC
// or q to quit, etc.
////////////////////////////////////////////////////////////////////
void PandaFramework::
enable_default_keys() {
if (!_default_keys_enabled) {
do_enable_default_keys();
_default_keys_enabled = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::do_frame
// Access: Public, Virtual
// Description: Renders one frame and performs all associated
// processing. Returns true if we should continue
// rendering, false if we should exit. This is normally
// called only from main_loop().
////////////////////////////////////////////////////////////////////
bool PandaFramework::
do_frame() {
nassertr(_is_open, false);
qpDataGraphTraverser dg_trav;
dg_trav.traverse(_data_root.node());
_event_handler.process_events();
_engine.render_frame();
return !_exit_flag;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::main_loop
// Access: Public
// Description: Called to yield control to the panda framework. This
// function does not return until set_exit_flag() has
// been called.
////////////////////////////////////////////////////////////////////
void PandaFramework::
main_loop() {
while (do_frame()) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::make_window_framework
// Access: Protected, Virtual
// Description: Creates a new WindowFramework object. This is
// provided as a hook so derived PandaFramework classes
// can create custom WindowFramework objects.
////////////////////////////////////////////////////////////////////
WindowFramework *PandaFramework::
make_window_framework() {
return new WindowFramework(this);
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::make_default_pipe
// Access: Protected, Virtual
// Description: Creates the default GraphicsPipe that will contain
// all windows that are not opened on a specific pipe.
////////////////////////////////////////////////////////////////////
void PandaFramework::
make_default_pipe() {
// We use the GraphicsPipe factory to make us a renderable pipe
// without knowing exactly what kind of pipes we have available. We
// don't care, so long as we can render to it interactively.
// This depends on the shared library or libraries (DLL's to you
// Windows folks) that have been loaded in at runtime from the
// load-display Configrc variable.
GraphicsPipe::resolve_modules();
nout << "Known pipe types:" << endl;
GraphicsPipe::get_factory().write_types(nout, 2);
_default_pipe = GraphicsPipe::get_factory().
make_instance(InteractiveGraphicsPipe::get_class_type());
if (_default_pipe == (GraphicsPipe*)NULL) {
nout << "No interactive pipe is available! Check your Configrc!\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::do_enable_default_keys
// Access: Protected, Virtual
// Description: The implementation of enable_default_keys().
////////////////////////////////////////////////////////////////////
void PandaFramework::
do_enable_default_keys() {
_event_handler.add_hook("escape", event_esc, this);
_event_handler.add_hook("q", event_esc, this);
_event_handler.add_hook("f", event_f, this);
_event_handler.add_hook("w", event_w, this);
_event_handler.add_hook("t", event_t, this);
_event_handler.add_hook("b", event_b, this);
_event_handler.add_hook("l", event_l, this);
_event_handler.add_hook("shift-s", event_S, this);
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_esc
// Access: Protected, Static
// Description: Default handler for ESC or q key: exit the
// application.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_esc(CPT_Event, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->_exit_flag = true;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_f
// Access: Protected, Static
// Description: Default handler for f key: report and reset frame
// rate.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_f(CPT_Event, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->report_frame_rate(nout);
self->reset_frame_rate();
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_w
// Access: Protected, Static
// Description: Default handler for w key: toggle wireframe.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_w(CPT_Event, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->set_wireframe(!self->get_wireframe());
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_t
// Access: Protected, Static
// Description: Default handler for t key: toggle texture.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_t(CPT_Event, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->set_texture(!self->get_texture());
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_b
// Access: Protected, Static
// Description: Default handler for b key: toggle backface (two-sided
// rendering).
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_b(CPT_Event, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->set_two_sided(!self->get_two_sided());
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_l
// Access: Protected, Static
// Description: Default handler for l key: toggle lighting.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_l(CPT_Event, void *data) {
PandaFramework *self = (PandaFramework *)data;
self->set_lighting(!self->get_lighting());
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::event_S
// Access: Protected, Static
// Description: Default handler for shift-S key: activate stats.
////////////////////////////////////////////////////////////////////
void PandaFramework::
event_S(CPT_Event, void *data) {
#ifdef DO_PSTATS
nout << "Connecting to stats host" << endl;
PStatClient::connect();
#else
nout << "Stats host not supported." << endl;
#endif
}

View File

@ -0,0 +1,131 @@
// Filename: pandaFramework.h
// Created by: drose (02Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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 PANDAFRAMEWORK_H
#define PANDAFRAMEWORK_H
#include "pandabase.h"
#include "windowFramework.h"
#include "qpnodePath.h"
#include "eventHandler.h"
#include "graphicsPipe.h"
#include "graphicsEngine.h"
#include "graphicsWindow.h"
#include "pointerTo.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : PandaFramework
// Description : This class serves to provide a high-level framework
// for basic applications that use Panda in simple ways
// (like opening a window to view models, etc.).
////////////////////////////////////////////////////////////////////
class EXPCL_FRAMEWORK PandaFramework {
public:
PandaFramework();
virtual ~PandaFramework();
void open_framework(int &argc, char **&argv);
void close_framework();
GraphicsPipe *get_default_pipe();
INLINE GraphicsEngine *get_graphics_engine();
INLINE const qpNodePath &get_data_root() const;
INLINE EventHandler &get_event_handler();
INLINE void set_window_title(const string &title);
virtual void get_default_window_props(GraphicsWindow::Properties &props);
WindowFramework *open_window(GraphicsPipe *pipe = NULL);
WindowFramework *open_window(const GraphicsWindow::Properties &props,
GraphicsPipe *pipe = NULL);
INLINE int get_num_windows() const;
INLINE WindowFramework *get_window(int n) const;
void close_window(int n);
void close_all_windows();
void report_frame_rate(ostream &out) const;
void reset_frame_rate();
void set_wireframe(bool enable);
void set_texture(bool enable);
void set_two_sided(bool enable);
void set_lighting(bool enable);
INLINE bool get_wireframe() const;
INLINE bool get_texture() const;
INLINE bool get_two_sided() const;
INLINE bool get_lighting() const;
void enable_default_keys();
virtual bool do_frame();
void main_loop();
INLINE void set_exit_flag();
protected:
virtual WindowFramework *make_window_framework();
virtual void make_default_pipe();
virtual void do_enable_default_keys();
static void event_esc(CPT_Event, void *data);
static void event_f(CPT_Event, void *data);
static void event_w(CPT_Event, void *data);
static void event_t(CPT_Event, void *data);
static void event_b(CPT_Event, void *data);
static void event_l(CPT_Event, void *data);
static void event_S(CPT_Event, void *data);
private:
bool _is_open;
bool _made_default_pipe;
string _window_title;
PT(GraphicsPipe) _default_pipe;
GraphicsEngine _engine;
qpNodePath _data_root;
EventHandler _event_handler;
typedef pvector<WindowFramework *> Windows;
Windows _windows;
// For counting frame rate.
double _start_time;
int _frame_count;
bool _wireframe_enabled;
bool _texture_enabled;
bool _two_sided_enabled;
bool _lighting_enabled;
bool _default_keys_enabled;
bool _exit_flag;
};
#include "pandaFramework.I"
#endif

View File

@ -0,0 +1,104 @@
// Filename: windowFramework.I
// Created by: drose (02Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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: WindowFramework::get_panda_framework
// Access: Public
// Description: Returns a pointer to the associated PandaFramework
// object.
////////////////////////////////////////////////////////////////////
INLINE PandaFramework *WindowFramework::
get_panda_framework() const {
return _panda_framework;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_graphics_window
// Access: Public
// Description: Returns a pointer to the underlying GraphicsWindow
// object.
////////////////////////////////////////////////////////////////////
INLINE GraphicsWindow *WindowFramework::
get_graphics_window() const {
return _window;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_num_cameras
// Access: Public
// Description: Returns the number of 3-d cameras associated with the
// window. A window usually has only one camera, but it
// may have multiple cameras if there are multiple
// display regions within the window.
////////////////////////////////////////////////////////////////////
INLINE int WindowFramework::
get_num_cameras() const {
return _cameras.size();
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_camera
// Access: Public
// Description: Returns the nth camera associated with the window.
////////////////////////////////////////////////////////////////////
INLINE qpCamera *WindowFramework::
get_camera(int n) const {
nassertr(n >= 0 && n < (int)_cameras.size(), NULL);
return _cameras[n];
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_wireframe
// Access: Public
// Description: Returns the current state of the wireframe flag.
////////////////////////////////////////////////////////////////////
INLINE bool WindowFramework::
get_wireframe() const {
return _wireframe_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_texture
// Access: Public
// Description: Returns the current state of the texture flag.
////////////////////////////////////////////////////////////////////
INLINE bool WindowFramework::
get_texture() const {
return _texture_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_two_sided
// Access: Public
// Description: Returns the current state of the two_sided flag.
////////////////////////////////////////////////////////////////////
INLINE bool WindowFramework::
get_two_sided() const {
return _two_sided_enabled;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_lighting
// Access: Public
// Description: Returns the current state of the lighting flag.
////////////////////////////////////////////////////////////////////
INLINE bool WindowFramework::
get_lighting() const {
return _lighting_enabled;
}

View File

@ -0,0 +1,520 @@
// Filename: windowFramework.cxx
// Created by: drose (02Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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 "windowFramework.h"
#include "pandaFramework.h"
#include "mouseAndKeyboard.h"
#include "qpbuttonThrower.h"
#include "qptrackball.h"
#include "qptransform2sg.h"
#include "dSearchPath.h"
#include "filename.h"
#include "loader.h"
#include "keyboardButton.h"
#include "geomTri.h"
#include "texturePool.h"
#include "textureAttrib.h"
#include "perspectiveLens.h"
#include "auto_bind.h"
#include "ambientLight.h"
#include "directionalLight.h"
#include "lightAttrib.h"
// This number is chosen arbitrarily to override any settings in model
// files.
static const int override_priority = 100;
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
WindowFramework::
WindowFramework(PandaFramework *panda_framework) :
_panda_framework(panda_framework)
{
_alight = (AmbientLight *)NULL;
_dlight = (DirectionalLight *)NULL;
_got_keyboard = false;
_got_trackball = false;
_got_lights = false;
_wireframe_enabled = false;
_texture_enabled = true;
_two_sided_enabled = false;
_lighting_enabled = false;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::Destructor
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
WindowFramework::
~WindowFramework() {
close_window();
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::open_window
// Access: Protected
// Description: Opens the actual window. This is normally called
// only from PandaFramework::open_window().
////////////////////////////////////////////////////////////////////
GraphicsWindow *WindowFramework::
open_window(const GraphicsWindow::Properties &props, GraphicsPipe *pipe) {
nassertr(_window == (GraphicsWindow *)NULL, _window);
_window = pipe->make_window(props);
// Set up a 3-d camera for the window by default.
make_camera();
return _window;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::close_window
// Access: Protected
// Description: Closes the window. This is normally called
// from PandaFramework::close_window().
////////////////////////////////////////////////////////////////////
void WindowFramework::
close_window() {
_window.clear();
_camera_group.remove_node();
_render.remove_node();
_render_2d.remove_node();
_mouse.remove_node();
_alight = (AmbientLight *)NULL;
_dlight = (DirectionalLight *)NULL;
_got_keyboard = false;
_got_trackball = false;
_got_lights = false;
_wireframe_enabled = false;
_texture_enabled = true;
_two_sided_enabled = false;
_lighting_enabled = false;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_camera_group
// Access: Public
// Description: Returns the node above the collection of 3-d cameras
// in the scene graph. This node may be moved around to
// represent the viewpoint.
////////////////////////////////////////////////////////////////////
const qpNodePath &WindowFramework::
get_camera_group() {
if (_camera_group.is_empty()) {
_camera_group = get_render().attach_new_node("camera_group");
}
return _camera_group;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_render
// Access: Public
// Description: Returns the root of the 3-d scene graph.
////////////////////////////////////////////////////////////////////
const qpNodePath &WindowFramework::
get_render() {
if (_render.is_empty()) {
_render = qpNodePath("render");
// This is maybe here temporarily, and maybe not.
_render.set_two_sided(0);
}
return _render;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_render_2d
// Access: Public
// Description: Returns the root of the 2-d scene graph.
////////////////////////////////////////////////////////////////////
const qpNodePath &WindowFramework::
get_render_2d() {
if (_render_2d.is_empty()) {
_render_2d = qpNodePath("render_2d");
}
return _render_2d;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::get_mouse
// Access: Public
// Description: Returns the node in the data graph corresponding to
// the mouse associated with this window.
////////////////////////////////////////////////////////////////////
const qpNodePath &WindowFramework::
get_mouse() {
if (_mouse.is_empty()) {
qpNodePath data_root = _panda_framework->get_data_root();
qpMouseAndKeyboard *mouse_node =
new qpMouseAndKeyboard(_window, 0, "mouse");
_mouse = data_root.attach_new_node(mouse_node);
}
return _mouse;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::enable_keyboard
// Access: Public
// Description: Creates a ButtonThrower to listen to button presses
// and throw them as events.
////////////////////////////////////////////////////////////////////
void WindowFramework::
enable_keyboard() {
if (_got_keyboard) {
return;
}
qpNodePath mouse = get_mouse();
PT(qpButtonThrower) bt = new qpButtonThrower("kb-events");
ModifierButtons mods;
mods.add_button(KeyboardButton::shift());
mods.add_button(KeyboardButton::control());
mods.add_button(KeyboardButton::alt());
bt->set_modifier_buttons(mods);
mouse.attach_new_node(bt);
_got_keyboard = true;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::setup_trackball
// Access: Public
// Description: Sets up the mouse to trackball around the camera.
////////////////////////////////////////////////////////////////////
void WindowFramework::
setup_trackball() {
if (_got_trackball) {
return;
}
qpNodePath mouse = get_mouse();
qpNodePath camera = get_camera_group();
PT(qpTrackball) trackball = new qpTrackball("trackball");
trackball->set_pos(LVector3f::forward() * 50.0);
mouse.attach_new_node(trackball);
PT(qpTransform2SG) tball2cam = new qpTransform2SG("tball2cam");
tball2cam->set_node(camera.node());
trackball->add_child(tball2cam);
_got_trackball = true;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::load_models
// Access: Public
// Description: Loads up all the model files listed in the indicated
// argument list. If first_arg is supplied, it is the
// first argument in the list to consider.
//
// Returns true if all models loaded successfully, or
// false if at least one of them had an error.
////////////////////////////////////////////////////////////////////
bool WindowFramework::
load_models(const qpNodePath &parent, int argc, char *argv[], int first_arg) {
pvector<Filename> files;
for (int i = first_arg; i < argc && argv[i] != (char *)NULL; i++) {
files.push_back(Filename::from_os_specific(argv[i]));
}
return load_models(parent, files);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::load_models
// Access: Public
// Description: Loads up all the model files listed in the indicated
// argument list.
//
// Returns true if all models loaded successfully, or
// false if at least one of them had an error.
////////////////////////////////////////////////////////////////////
bool WindowFramework::
load_models(const qpNodePath &parent, const pvector<Filename> &files) {
bool all_ok = true;
qpNodePath render = get_render();
pvector<Filename>::const_iterator fi;
for (fi = files.begin(); fi != files.end(); ++fi) {
const Filename &filename = (*fi);
qpNodePath model = load_model(parent, filename);
if (model.is_empty()) {
all_ok = false;
}
}
return all_ok;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::load_model
// Access: Public
// Description: Loads up the indicated model and returns the new
// NodePath, or the empty NodePath if the model could
// not be loaded.
////////////////////////////////////////////////////////////////////
qpNodePath WindowFramework::
load_model(const qpNodePath &parent, Filename filename) {
nout << "Loading " << filename << "\n";
// First, we always try to resolve a filename from the current
// directory. This means a local filename will always be found
// before the model path is searched.
DSearchPath local_path(".");
filename.resolve_filename(local_path);
Loader loader;
PT(PandaNode) node = loader.qpload_sync(filename);
if (node == (PandaNode *)NULL) {
nout << "Unable to load " << filename << "\n";
return qpNodePath::not_found();
}
return parent.attach_new_node(node);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::load_default_model
// Access: Public
// Description: Loads our favorite blue triangle. This is intended
// to provide some default geometry to have *something*
// to look at for testing, when no other models are
// provided.
////////////////////////////////////////////////////////////////////
qpNodePath WindowFramework::
load_default_model(const qpNodePath &parent) {
PTA_Vertexf coords;
PTA_TexCoordf uvs;
PTA_Normalf norms;
PTA_Colorf colors;
PTA_ushort cindex;
coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
uvs.push_back(TexCoordf(0.0, 0.0));
uvs.push_back(TexCoordf(1.0, 0.0));
uvs.push_back(TexCoordf(0.0, 1.0));
norms.push_back(Normalf::back());
colors.push_back(Colorf(0.5, 0.5, 1.0, 1.0));
cindex.push_back(0);
cindex.push_back(0);
cindex.push_back(0);
PT(GeomTri) geom = new GeomTri;
geom->set_num_prims(1);
geom->set_coords(coords);
geom->set_texcoords(uvs, G_PER_VERTEX);
geom->set_normals(norms, G_PER_PRIM);
geom->set_colors(colors, G_PER_VERTEX, cindex);
CPT(RenderState) state = RenderState::make_empty();
Texture *tex = TexturePool::load_texture("rock-floor.rgb");
if (tex != (Texture *)NULL) {
tex->set_minfilter(Texture::FT_linear);
tex->set_magfilter(Texture::FT_linear);
state = state->add_attrib(TextureAttrib::make(tex));
}
qpGeomNode *geomnode = new qpGeomNode("tri");
geomnode->add_geom(geom, state);
return parent.attach_new_node(geomnode);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::loop_animations
// Access: Public
// Description: Looks for characters and their matching animation
// files in the scene graph; binds and loops any
// matching animations found.
////////////////////////////////////////////////////////////////////
void WindowFramework::
loop_animations() {
// If we happened to load up both a character file and its matching
// animation file, attempt to bind them together now and start the
// animations looping.
auto_bind(get_render().node(), _anim_controls, ~0);
_anim_controls.loop_all(true);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::set_wireframe
// Access: Public
// Description: Forces wireframe state (true) or restores default
// rendering (false).
////////////////////////////////////////////////////////////////////
void WindowFramework::
set_wireframe(bool enable) {
if (enable == _wireframe_enabled) {
return;
}
qpNodePath render = get_render();
if (enable) {
render.set_render_mode_wireframe(override_priority);
render.set_two_sided(true, override_priority);
} else {
render.clear_render_mode();
if (!_two_sided_enabled) {
render.clear_two_sided();
}
}
_wireframe_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::set_texture
// Access: Public
// Description: Forces textures off (false) or restores default
// rendering (true).
////////////////////////////////////////////////////////////////////
void WindowFramework::
set_texture(bool enable) {
if (enable == _texture_enabled) {
return;
}
qpNodePath render = get_render();
if (!enable) {
render.set_texture_off(override_priority);
} else {
render.clear_texture();
}
_texture_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::set_two_sided
// Access: Public
// Description: Forces two-sided rendering (true) or restores default
// rendering (false).
////////////////////////////////////////////////////////////////////
void WindowFramework::
set_two_sided(bool enable) {
if (enable == _two_sided_enabled) {
return;
}
qpNodePath render = get_render();
if (enable) {
render.set_two_sided(true, override_priority);
} else {
if (!_wireframe_enabled) {
render.clear_two_sided();
}
}
_two_sided_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::set_lighting
// Access: Public
// Description: Turns lighting on (true) or off (false).
////////////////////////////////////////////////////////////////////
void WindowFramework::
set_lighting(bool enable) {
if (enable == _lighting_enabled) {
return;
}
qpNodePath render = get_render();
if (enable) {
if (!_got_lights) {
setup_lights();
}
render.node()->set_attrib(LightAttrib::make(LightAttrib::O_add,
_alight, _dlight));
} else {
render.node()->clear_attrib(LightAttrib::get_class_type());
}
_lighting_enabled = enable;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::make_camera
// Access: Protected
// Description: Makes a new 3-d camera for the window.
////////////////////////////////////////////////////////////////////
PT(qpCamera) WindowFramework::
make_camera() {
// Get the first channel on the window. This will be the only
// channel on non-SGI hardware.
PT(GraphicsChannel) channel = _window->get_channel(0);
// Make a layer on the channel to hold our display region.
PT(GraphicsLayer) layer = channel->make_layer();
// And create a display region that covers the entire window.
PT(DisplayRegion) dr = layer->make_display_region();
// Finally, we need a camera to associate with the display region.
PT(qpCamera) camera = new qpCamera("camera");
qpNodePath camera_np = get_camera_group().attach_new_node(camera);
_cameras.push_back(camera);
PT(Lens) lens = new PerspectiveLens;
lens->set_film_size(_window->get_width(), _window->get_height());
camera->set_lens(lens);
camera->set_scene(get_render());
dr->set_qpcamera(camera_np);
return camera;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::setup_lights
// Access: Protected
// Description: Makes light nodes and attaches them to the camera for
// viewing the scene.
////////////////////////////////////////////////////////////////////
void WindowFramework::
setup_lights() {
if (_got_lights) {
return;
}
qpNodePath camera_group = get_camera_group();
qpNodePath light_group = camera_group.attach_new_node("lights");
_alight = new AmbientLight("ambient");
_alight->set_color(Colorf(0.2f, 0.2f, 0.2f, 1.0f));
_dlight = new DirectionalLight("directional");
light_group.attach_new_node(_alight);
light_group.attach_new_node(_dlight);
_got_lights = true;
}

View File

@ -0,0 +1,117 @@
// Filename: windowFramework.h
// Created by: drose (02Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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 WINDOWFRAMEWORK_H
#define WINDOWFRAMEWORK_H
#include "pandabase.h"
#include "qpnodePath.h"
#include "qpcamera.h"
#include "graphicsWindow.h"
#include "animControlCollection.h"
#include "filename.h"
#include "pointerTo.h"
#include "pvector.h"
class PandaFramework;
class AmbientLight;
class DirectionalLight;
////////////////////////////////////////////////////////////////////
// Class : WindowFramework
// Description : This encapsulates the data that is normally
// associated with a single window that we've opened.
////////////////////////////////////////////////////////////////////
class EXPCL_FRAMEWORK WindowFramework {
protected:
WindowFramework(PandaFramework *panda_framework);
virtual ~WindowFramework();
GraphicsWindow *open_window(const GraphicsWindow::Properties &props,
GraphicsPipe *pipe);
void close_window();
public:
INLINE PandaFramework *get_panda_framework() const;
INLINE GraphicsWindow *get_graphics_window() const;
const qpNodePath &get_camera_group();
INLINE int get_num_cameras() const;
INLINE qpCamera *get_camera(int n) const;
const qpNodePath &get_render();
const qpNodePath &get_render_2d();
const qpNodePath &get_mouse();
void enable_keyboard();
void setup_trackball();
bool load_models(const qpNodePath &parent,
int argc, char *argv[], int first_arg = 1);
bool load_models(const qpNodePath &parent,
const pvector<Filename> &files);
qpNodePath load_model(const qpNodePath &parent, Filename filename);
qpNodePath load_default_model(const qpNodePath &parent);
void loop_animations();
void set_wireframe(bool enable);
void set_texture(bool enable);
void set_two_sided(bool enable);
void set_lighting(bool enable);
INLINE bool get_wireframe() const;
INLINE bool get_texture() const;
INLINE bool get_two_sided() const;
INLINE bool get_lighting() const;
protected:
PT(qpCamera) make_camera();
void setup_lights();
private:
PandaFramework *_panda_framework;
PT(GraphicsWindow) _window;
qpNodePath _camera_group;
typedef pvector< PT(qpCamera) > Cameras;
Cameras _cameras;
qpNodePath _render;
qpNodePath _render_2d;
AnimControlCollection _anim_controls;
qpNodePath _mouse;
AmbientLight *_alight;
DirectionalLight *_dlight;
bool _got_keyboard;
bool _got_trackball;
bool _got_lights;
bool _wireframe_enabled;
bool _texture_enabled;
bool _two_sided_enabled;
bool _lighting_enabled;
friend class PandaFramework;
};
#include "windowFramework.I"
#endif

View File

@ -21,8 +21,37 @@
/* See dtoolsymbols.h for a rant on the purpose of this file. */
/* Note that the symbols declared in this file appear in alphabetical
order. Also note that we must use C-style comments only here, not
C++-style comments, since this file is occasionally included by a C
file. */
#if defined(WIN32_VC) && !defined(CPPPARSER) && !defined(LINK_ALL_STATIC)
#ifdef BUILDING_FRAMEWORK
#define EXPCL_FRAMEWORK __declspec(dllexport)
#define EXPTP_FRAMEWORK
#else
#define EXPCL_FRAMEWORK __declspec(dllimport)
#define EXPTP_FRAMEWORK extern
#endif
#ifdef BUILDING_LINUX_AUDIO
#define EXPCL_LINUX_AUDIO __declspec(dllexport)
#define EXPTP_LINUX_AUDIO
#else
#define EXPCL_LINUX_AUDIO __declspec(dllimport)
#define EXPTP_LINUX_AUDIO extern
#endif
#ifdef BUILDING_MILES_AUDIO
#define EXPCL_MILES_AUDIO __declspec(dllexport)
#define EXPTP_MILES_AUDIO
#else
#define EXPCL_MILES_AUDIO __declspec(dllimport)
#define EXPTP_MILES_AUDIO extern
#endif
#ifdef BUILDING_PANDA
#define EXPCL_PANDA __declspec(dllexport)
#define EXPTP_PANDA
@ -31,6 +60,14 @@
#define EXPTP_PANDA extern
#endif
#ifdef BUILDING_PANDACR
#define EXPCL_PANDACR __declspec(dllexport)
#define EXPTP_PANDACR
#else
#define EXPCL_PANDACR __declspec(dllimport)
#define EXPTP_PANDACR extern
#endif
#ifdef BUILDING_PANDADX
#define EXPCL_PANDADX __declspec(dllexport)
#define EXPTP_PANDADX
@ -71,14 +108,6 @@
#define EXPTP_PANDAGL extern
#endif
#ifdef BUILDING_PANDACR
#define EXPCL_PANDACR __declspec(dllexport)
#define EXPTP_PANDACR
#else
#define EXPCL_PANDACR __declspec(dllimport)
#define EXPTP_PANDACR extern
#endif
#ifdef BUILDING_PANDAGLUT
#define EXPCL_PANDAGLUT __declspec(dllexport)
#define EXPTP_PANDAGLUT
@ -111,27 +140,23 @@
#define EXPTP_SHADER extern
#endif
#ifdef BUILDING_MILES_AUDIO
#define EXPCL_MILES_AUDIO __declspec(dllexport)
#define EXPTP_MILES_AUDIO
#else
#define EXPCL_MILES_AUDIO __declspec(dllimport)
#define EXPTP_MILES_AUDIO extern
#endif
#ifdef BUILDING_LINUX_AUDIO
#define EXPCL_LINUX_AUDIO __declspec(dllexport)
#define EXPTP_LINUX_AUDIO
#else
#define EXPCL_LINUX_AUDIO __declspec(dllimport)
#define EXPTP_LINUX_AUDIO extern
#endif
#else /* !WIN32_VC */
#define EXPCL_FRAMEWORK
#define EXPTP_FRAMEWORK
#define EXPCL_LINUX_AUDIO
#define EXPTP_LINUX_AUDIO
#define EXPCL_MILES_AUDIO
#define EXPTP_MILES_AUDIO
#define EXPCL_PANDA
#define EXPTP_PANDA
#define EXPCL_PANDACR
#define EXPTP_PANDACR
#define EXPCL_PANDADX
#define EXPTP_PANDADX
@ -147,9 +172,6 @@
#define EXPCL_PANDAGL
#define EXPTP_PANDAGL
#define EXPCL_PANDACR
#define EXPTP_PANDACR
#define EXPCL_PANDAGLUT
#define EXPTP_PANDAGLUT
@ -162,15 +184,6 @@
#define EXPCL_SHADER
#define EXPTP_SHADER
#define EXPCL_MILES_AUDIO
#define EXPTP_MILES_AUDIO
#define EXPCL_LINUX_AUDIO
#define EXPTP_LINUX_AUDIO
#define EXPCL_FRAMEWORK
#define EXPTP_FRAMEWORK
#endif /* WIN32_VC */
#if defined(WIN32_VC) && !defined(CPPPARSER)

View File

@ -10,21 +10,12 @@
#if $[LINK_ALL_STATIC]
// If we're statically linking, we need to explicitly link with
// at least one graphics renderer.
#define LOCAL_LIBS pandacr pandagl pandadx $[LOCAL_LIBS]
#define LOCAL_LIBS pandagl pandadx $[LOCAL_LIBS]
// And we might like to have the egg loader available.
#define LOCAL_LIBS pandaegg $[LOCAL_LIBS]
#endif
#define UNIX_SYS_LIBS m
#begin bin_target
#define TARGET demo
#define SOURCES \
demo.cxx
#end bin_target
#begin bin_target
#define TARGET pview
@ -34,138 +25,8 @@
#end bin_target
#begin test_bin_target
#define TARGET open_window
#define TARGET pgrid
#define SOURCES \
open_window.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] pandacr pandagl pandadx
#end test_bin_target
#if $[HAVE_DX]
#begin test_bin_target
#define TARGET demo_multimon
#define SOURCES \
demo.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] pandadx framework_multimon
#end test_bin_target
#endif
#begin test_bin_target
#define TARGET downloader
#define SOURCES \
downloader_test.cxx
#define USE_ZLIB yes
#define TARGET_IF_ZLIB yes
#end test_bin_target
#begin test_bin_target
#define TARGET herc
#define SOURCES \
herc.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET loader
#define SOURCES \
loader_test.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET lod
#define SOURCES \
lod_test.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET min_herc
#define SOURCES \
min_herc.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET min_shader
#define SOURCES \
min_shader.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET panda
#define SOURCES \
panda.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET shader
#define SOURCES \
shader_test.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET test_eggWrite
#define SOURCES \
test_eggWrite.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET test_particles
#define SOURCES \
test_particles.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] physics particlesystem
#end test_bin_target
#begin test_bin_target
#define TARGET test_sprite_particles
#define SOURCES \
test_sprite_particles.cxx
#define LOCAL_LIBS $[LOCAL_LIBS] physics particlesystem
#end test_bin_target
#begin test_bin_target
#define TARGET test_recparticles
#define SOURCES \
test_recparticles.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET text
#define SOURCES \
text_test.cxx
#end test_bin_target
#begin test_bin_target
#define TARGET vrpn_demo
#define SOURCES \
vrpn_demo.cxx
pgrid.cxx
#end test_bin_target

429
panda/src/testbed/pgrid.cxx Normal file
View File

@ -0,0 +1,429 @@
// Filename: pgrid.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// 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 "pandaFramework.h"
#include "pandaNode.h"
#include "transformState.h"
#include "clockObject.h"
#include "string_utils.h"
#include "pvector.h"
#include <getopt.h>
#define RANDFRAC (rand()/(float)(RAND_MAX))
class GriddedFilename {
public:
Filename _filename;
int _count;
qpNodePath _model;
};
typedef pvector<GriddedFilename> GriddedFilenames;
typedef struct {
// for rot moving
float xcenter,ycenter;
float xoffset,yoffset;
float ang1,ang1_vel;
float ang2,ang2_vel;
float radius;
// for moving
float xstart,ystart;
float xend,yend;
float xdel,ydel,timedel;
double starttime,endtime;
double vel;
LMatrix4f rotmat;
PandaNode *node;
} gridded_file_info;
typedef pvector<gridded_file_info> GriddedInfoArray;
typedef enum {None,Rotation,LinearMotion} GriddedMotionType;
#define GRIDCELLSIZE 5.0
static int gridwidth; // cells/side
#define MIN_WANDERAREA_DIMENSION 120.0
static float grid_pos_offset; // origin of grid
static float wander_area_pos_offset;
static GriddedMotionType gridmotiontype = None;
// making these fns to get around ridiculous VC++ matrix inlining bugs at Opt2
static void
move_gridded_stuff(GriddedMotionType gridmotiontype,
gridded_file_info *InfoArr, int size) {
double now = ClockObject::get_global_clock()->get_frame_time();
LMatrix4f tmat1,tmat2,xfm_mat;
for(int i = 0; i < size; i++) {
double time_delta = (now-InfoArr[i].starttime);
#define DO_FP_MODULUS(VAL,MAXVAL) \
{if(VAL > MAXVAL) {int idivresult = (int)(VAL / (float)MAXVAL); VAL=VAL-idivresult*MAXVAL;} else \
if(VAL < -MAXVAL) {int idivresult = (int)(VAL / (float)MAXVAL); VAL=VAL+idivresult*MAXVAL;}}
// probably should use panda lerps for this stuff, but I dont understand how
if(gridmotiontype==Rotation) {
InfoArr[i].ang1=time_delta*InfoArr[i].ang1_vel;
DO_FP_MODULUS(InfoArr[i].ang1,360.0);
InfoArr[i].ang2=time_delta*InfoArr[i].ang2_vel;
DO_FP_MODULUS(InfoArr[i].ang2,360.0);
// xforms happen left to right
LVector2f new_center = LVector2f(InfoArr[i].radius,0.0) *
LMatrix3f::rotate_mat(InfoArr[i].ang1);
LVector3f translate_vec(InfoArr[i].xcenter+new_center._v.v._0,
InfoArr[i].ycenter+new_center._v.v._1,
0.0);
const LVector3f rotation_axis(0.0, 0.0, 1.0);
tmat1 = LMatrix4f::rotate_mat_normaxis(InfoArr[i].ang2,rotation_axis);
tmat2 = LMatrix4f::translate_mat(translate_vec);
xfm_mat = tmat1 * tmat2;
} else {
float xpos,ypos;
if(now>InfoArr[i].endtime) {
InfoArr[i].starttime = now;
xpos = InfoArr[i].xstart = InfoArr[i].xend;
ypos = InfoArr[i].ystart = InfoArr[i].yend;
InfoArr[i].xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
InfoArr[i].yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
float xdel = InfoArr[i].xdel = InfoArr[i].xend-InfoArr[i].xstart;
float ydel = InfoArr[i].ydel = InfoArr[i].yend-InfoArr[i].ystart;
InfoArr[i].endtime = now + csqrt(xdel*xdel+ydel*ydel)/InfoArr[i].vel;
InfoArr[i].timedel = InfoArr[i].endtime - InfoArr[i].starttime;
const LVector3f rotate_axis(0.0, 0.0, 1.0);
float ang = rad_2_deg(atan2(-xdel,ydel));
InfoArr[i].rotmat= LMatrix4f::rotate_mat_normaxis(ang,rotate_axis);
} else {
float timefrac= time_delta/InfoArr[i].timedel;
xpos = InfoArr[i].xdel*timefrac+InfoArr[i].xstart;
ypos = InfoArr[i].ydel*timefrac+InfoArr[i].ystart;
}
LVector3f translate_vec(xpos, ypos, 0.0);
LMatrix4f tmat2 = LMatrix4f::translate_mat(translate_vec);
xfm_mat = InfoArr[i].rotmat * tmat2;
}
InfoArr[i].node->set_transform(TransformState::make_mat(xfm_mat));
}
}
bool
get_command_line_opts(int &argc, char **&argv) {
// Use getopt() to decode the optional command-line parameters.
// extern char *optarg;
extern int optind;
const char *options = "rm";
int flag = getopt(argc, argv, options);
while (flag != EOF) {
switch (flag) {
case 'r':
gridmotiontype = Rotation;
break;
case 'm':
gridmotiontype = LinearMotion;
break;
case '?':
nout << "Invalid parameter.\n";
return false;
}
flag = getopt(argc, argv, options);
}
argv += (optind - 1);
argc -= (optind - 1);
return true;
}
void
get_command_line_filenames(int argc, char *argv[],
pvector<Filename> &static_filenames,
GriddedFilenames &gridded_filenames) {
for (int i = 1; i < argc && argv[i] != (char *)NULL; i++) {
const string &arg = argv[i];
size_t comma = arg.find(',');
if (comma == string::npos) {
// No comma in the filename, so it must be an ordinary static file.
static_filenames.push_back(Filename::from_os_specific(arg));
} else {
// A comma in the filename indicates a gridded file. The syntax
// is filename,count where count represents the number of times
// the file is repeated.
string name = arg.substr(0, comma);
string count_str = arg.substr(comma + 1);
int count;
if (!string_to_int(count_str, count)) {
nout << "Ignoring invalid number: " << count_str << "\n";
count = 1;
} else if (count <= 0) {
nout << "Ignoring inappropriate number: " << count << "\n";
count = 1;
}
GriddedFilename gf;
gf._filename = Filename::from_os_specific(name);
gf._count = count;
gridded_filenames.push_back(gf);
}
}
}
void
load_gridded_models(WindowFramework *window,
GriddedFilenames &filenames,
GriddedInfoArray &info_arr) {
// Load up all the files indicated in the list of gridded filenames
// and store them in the given vector.
// First, load up each model from disk once, and store them all
// separate from the scene graph. Also count up the total number of
// models we'll be putting in the grid.
int grid_count = 0;
qpNodePath models("models");
GriddedFilenames::iterator fi;
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
GriddedFilename &gf = (*fi);
gf._model = window->load_model(models, gf._filename);
if (!gf._model.is_empty()) {
grid_count += gf._count;
}
}
info_arr.clear();
info_arr.reserve(grid_count);
// Compute the integer square root of grid_count, so that we put our
// models in a nice square grid.
gridwidth=1;
while(gridwidth*gridwidth < grid_count) {
gridwidth++;
}
grid_pos_offset = -gridwidth*GRIDCELLSIZE/2.0;
wander_area_pos_offset = -max(fabs(grid_pos_offset),MIN_WANDERAREA_DIMENSION/2.0);
// Now walk through the list again, copying models into the scene
// graph as we go.
float xpos = grid_pos_offset;
float ypos = grid_pos_offset;
srand( (unsigned)time( NULL ) );
double now = ClockObject::get_global_clock()->get_frame_time();
int model_count = 0;
int passnum = 0;
bool loaded_any;
qpNodePath render = window->get_render();
do {
loaded_any = false;
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
const GriddedFilename &gf = (*fi);
if (!gf._model.is_empty() && gf._count > passnum) {
loaded_any = true;
// Copy this model into the scene graph, and assign it a
// position on the grid.
string model_name = format_string(++model_count);
qpNodePath model = render.attach_new_node(model_name);
gf._model.copy_to(model);
gridded_file_info info;
info.node = model.node();
LMatrix4f xfm_mat,tmat1,tmat2;
if(gridmotiontype==Rotation) {
#define MIN_REVOLUTION_ANGVEL 30
#define MAX_REVOLUTION_ANGVEL 60
#define MIN_ROTATION_ANGVEL 30
#define MAX_ROTATION_ANGVEL 600
#define MAX_RADIUS 4.0*GRIDCELLSIZE
#define MIN_RADIUS 0.1*GRIDCELLSIZE
info.starttime = now;
info.xcenter=xpos;
info.ycenter=ypos;
info.ang1=RANDFRAC * 360.0;
info.ang1_vel=((MAX_REVOLUTION_ANGVEL-MIN_REVOLUTION_ANGVEL) * RANDFRAC) + MIN_REVOLUTION_ANGVEL;
info.ang2=RANDFRAC * 360.0;
info.ang2_vel=((MAX_ROTATION_ANGVEL-MIN_ROTATION_ANGVEL) * RANDFRAC) + MIN_ROTATION_ANGVEL;
info.radius = (RANDFRAC * (MAX_RADIUS-MIN_RADIUS)) + MIN_RADIUS;
if(RANDFRAC>0.5) {
info.ang1_vel=-info.ang1_vel;
}
if(RANDFRAC>0.5) {
info.ang2_vel=-info.ang2_vel;
}
// xforms happen left to right
LVector2f new_center = LVector2f(info.radius,0.0) *
LMatrix3f::rotate_mat(info.ang1);
const LVector3f rotate_axis(0.0, 0.0, 1.0);
LVector3f translate_vec(xpos+new_center._v.v._0,
ypos+new_center._v.v._1,
0.0);
LMatrix4f::rotate_mat_normaxis(info.ang2,rotate_axis,tmat1);
tmat2 = LMatrix4f::translate_mat(translate_vec);
xfm_mat = tmat1 * tmat2;
} else if(gridmotiontype==LinearMotion) {
#define MIN_VEL 2.0
#define MAX_VEL (fabs(wander_area_pos_offset))
info.vel=((MAX_VEL-MIN_VEL) * RANDFRAC) + MIN_VEL;
info.xstart=xpos;
info.ystart=ypos;
info.xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
info.yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
info.starttime = now;
float xdel = info.xdel = info.xend-info.xstart;
float ydel = info.ydel = info.yend-info.ystart;
info.endtime = csqrt(xdel*xdel+ydel*ydel)/info.vel;
info.timedel = info.endtime - info.starttime;
const LVector3f rotate_axis(0.0, 0.0, 1.0);
float ang = rad_2_deg(atan2(-xdel,ydel));
LMatrix4f::rotate_mat_normaxis(ang,rotate_axis,info.rotmat);
LVector3f translate_vec(xpos, ypos, 0.0);
LMatrix4f tmat2 = LMatrix4f::translate_mat(translate_vec);
xfm_mat = info.rotmat * tmat2;
} else {
LVector3f translate_vec(xpos, ypos, 0.0);
xfm_mat = LMatrix4f::translate_mat(translate_vec);
}
info.node->set_transform(TransformState::make_mat(xfm_mat));
info_arr.push_back(info);
if((model_count % gridwidth) == 0) {
xpos= -gridwidth*GRIDCELLSIZE/2.0;
ypos+=GRIDCELLSIZE;
} else {
xpos+=GRIDCELLSIZE;
}
}
}
passnum++;
} while (loaded_any);
// Finally, remove the source models we loaded up. Not a real big deal.
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
GriddedFilename &gf = (*fi);
if (!gf._model.is_empty()) {
gf._model.remove_node();
}
}
}
int
main(int argc, char *argv[]) {
PandaFramework framework;
vector_string args;
framework.open_framework(argc, argv);
framework.set_window_title("Gridded Object Viewer");
if (!get_command_line_opts(argc, argv)) {
return (1);
}
// Extract the remaining arguments into two lists of files: those
// with a grid parameter, and those without.
pvector<Filename> static_filenames;
GriddedFilenames gridded_filenames;
get_command_line_filenames(argc, argv, static_filenames, gridded_filenames);
WindowFramework *window = framework.open_window();
if (window != (WindowFramework *)NULL) {
// We've successfully opened a window.
window->enable_keyboard();
window->setup_trackball();
window->load_models(window->get_render(), static_filenames);
GriddedInfoArray info_arr;
load_gridded_models(window, gridded_filenames, info_arr);
window->loop_animations();
framework.enable_default_keys();
while (framework.do_frame()) {
if (!info_arr.empty() && gridmotiontype) {
move_gridded_stuff(gridmotiontype, &info_arr[0], info_arr.size());
}
}
}
framework.report_frame_rate(nout);
return (0);
}

View File

@ -16,453 +16,27 @@
//
////////////////////////////////////////////////////////////////////
#include "graphicsWindow.h"
#include "graphicsChannel.h"
#include "graphicsLayer.h"
#include "graphicsEngine.h"
#include "graphicsPipe.h"
#include "interactiveGraphicsPipe.h"
#include "displayRegion.h"
#include "qpcamera.h"
#include "perspectiveLens.h"
#include "pandaNode.h"
#include "textureAttrib.h"
#include "clockObject.h"
#include "qpgeomNode.h"
#include "geomTri.h"
#include "texture.h"
#include "texturePool.h"
#include "dSearchPath.h"
#include "loader.h"
#include "auto_bind.h"
#include "pStatClient.h"
#include "notify.h"
#include "qpnodePath.h"
#include "cullBinManager.h"
#include "mouseAndKeyboard.h"
#include "qpbuttonThrower.h"
#include "qptrackball.h"
#include "qptransform2sg.h"
#include "modifierButtons.h"
#include "keyboardButton.h"
#include "event.h"
#include "eventQueue.h"
#include "eventHandler.h"
#include "qpdataGraphTraverser.h"
#include "lightAttrib.h"
#include "ambientLight.h"
#include "directionalLight.h"
// Use dconfig to read a few Configrc variables.
Configure(config_pview);
ConfigureFn(config_pview) {
}
static const int win_width = config_pview.GetInt("win-width", 640);
static const int win_height = config_pview.GetInt("win-height", 480);
// As long as this is true, the main loop will continue running.
bool run_flag = true;
// These are referenced in both event_w() and in event_b().
bool wireframe = false;
bool two_sided = false;
bool lighting = false;
// These are used by report_frame_rate().
double start_time = 0.0;
int start_frame_count = 0;
// A priority number high enough to override any model file settings.
static const int override_priority = 100;
// This is the main scene graph.
qpNodePath render;
// And this is the camera node.
qpNodePath camera_np;
void
report_frame_rate() {
double now = ClockObject::get_global_clock()->get_frame_time();
double delta = now - start_time;
int frame_count = ClockObject::get_global_clock()->get_frame_count();
int num_frames = frame_count - start_frame_count;
if (num_frames > 0) {
nout << endl << num_frames << " frames in " << delta << " seconds" << endl;
double x = ((double)num_frames) / delta;
nout << x << " fps average (" << 1000.0 / x << "ms)" << endl;
// Reset the frame rate counter for the next press of 'f'.
start_time = now;
start_frame_count = frame_count;
}
}
PT(GraphicsPipe)
make_pipe() {
// We use the GraphicsPipe factory to make us a renderable pipe
// without knowing exactly what kind of pipes we have available. We
// don't care, so long as we can render to it interactively.
// This depends on the shared library or libraries (DLL's to you
// Windows folks) that have been loaded in at runtime from the
// load-display Configrc variable.
GraphicsPipe::resolve_modules();
nout << "Known pipe types:" << endl;
GraphicsPipe::get_factory().write_types(nout, 2);
PT(GraphicsPipe) pipe;
pipe = GraphicsPipe::get_factory().
make_instance(InteractiveGraphicsPipe::get_class_type());
if (pipe == (GraphicsPipe*)0L) {
nout << "No interactive pipe is available! Check your Configrc!\n";
exit(1);
}
return pipe;
}
PT(GraphicsWindow)
make_window(GraphicsPipe *pipe, GraphicsEngine *engine) {
// Now create a window on that pipe.
GraphicsWindow::Properties window_prop;
window_prop._xorg = 0;
window_prop._yorg = 0;
window_prop._xsize = win_width;
window_prop._ysize = win_height;
window_prop._title = "Panda Viewer";
// window_prop._fullscreen = true;
PT(GraphicsWindow) window = pipe->make_window(window_prop);
engine->add_window(window);
return window;
}
PT(qpCamera)
make_camera(GraphicsWindow *window) {
// Get the first channel on the window. This will be the only
// channel on non-SGI hardware.
PT(GraphicsChannel) channel = window->get_channel(0);
// Make a layer on the channel to hold our display region.
PT(GraphicsLayer) layer = channel->make_layer();
// And create a display region that covers the entire window.
PT(DisplayRegion) dr = layer->make_display_region();
// Finally, we need a camera to associate with the display region.
PT(qpCamera) camera = new qpCamera("camera");
PT(Lens) lens = new PerspectiveLens;
lens->set_film_size(win_width, win_height);
camera->set_lens(lens);
dr->set_qpcamera(qpNodePath(camera));
return camera;
}
void
make_default_geometry(PandaNode *parent) {
PTA_Vertexf coords;
PTA_TexCoordf uvs;
PTA_Normalf norms;
PTA_Colorf colors;
PTA_ushort cindex;
coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
uvs.push_back(TexCoordf(0.0, 0.0));
uvs.push_back(TexCoordf(1.0, 0.0));
uvs.push_back(TexCoordf(0.0, 1.0));
norms.push_back(Normalf::back());
colors.push_back(Colorf(0.5, 0.5, 1.0, 1.0));
cindex.push_back(0);
cindex.push_back(0);
cindex.push_back(0);
PT(GeomTri) geom = new GeomTri;
geom->set_num_prims(1);
geom->set_coords(coords);
geom->set_texcoords(uvs, G_PER_VERTEX);
geom->set_normals(norms, G_PER_PRIM);
geom->set_colors(colors, G_PER_VERTEX, cindex);
CPT(RenderState) state = RenderState::make_empty();
Texture *tex = TexturePool::load_texture("rock-floor.rgb");
if (tex != (Texture *)NULL) {
tex->set_minfilter(Texture::FT_linear);
tex->set_magfilter(Texture::FT_linear);
state = state->add_attrib(TextureAttrib::make(tex));
}
qpGeomNode *geomnode = new qpGeomNode("tri");
parent->add_child(geomnode);
geomnode->add_geom(geom, state);
}
void
get_models(PandaNode *parent, int argc, char *argv[]) {
if (argc < 2) {
// In the absence of any models on the command line, load up a
// default triangle so we at least have something to look at.
make_default_geometry(parent);
} else {
Loader loader;
DSearchPath local_path(".");
for (int i = 1; i < argc; i++) {
Filename filename = argv[i];
nout << "Loading " << filename << "\n";
// First, we always try to resolve a filename from the current
// directory. This means a local filename will always be found
// before the model path is searched.
filename.resolve_filename(local_path);
PT(PandaNode) node = loader.qpload_sync(filename);
if (node == (PandaNode *)NULL) {
nout << "Unable to load " << filename << "\n";
} else {
node->ls(nout, 0);
parent->add_child(node);
}
}
}
}
PandaNode *
setup_mouse(PandaNode *data_root, GraphicsWindow *window) {
qpMouseAndKeyboard *mouse = new qpMouseAndKeyboard(window, 0, "mouse");
data_root->add_child(mouse);
// Create a ButtonThrower to throw events from the keyboard.
PT(qpButtonThrower) bt = new qpButtonThrower("kb-events");
ModifierButtons mods;
mods.add_button(KeyboardButton::shift());
mods.add_button(KeyboardButton::control());
mods.add_button(KeyboardButton::alt());
bt->set_modifier_buttons(mods);
mouse->add_child(bt);
return mouse;
}
void
setup_trackball(PandaNode *mouse, qpCamera *camera) {
PT(qpTrackball) trackball = new qpTrackball("trackball");
trackball->set_pos(LVector3f::forward() * 50.0);
mouse->add_child(trackball);
PT(qpTransform2SG) tball2cam = new qpTransform2SG("tball2cam");
tball2cam->set_node(camera);
trackball->add_child(tball2cam);
}
void
event_esc(CPT_Event) {
// The Escape or q key was pressed. Exit the application.
run_flag = false;
}
void
event_f(CPT_Event) {
// 'f' : report frame rate.
report_frame_rate();
}
void
event_t(CPT_Event) {
// 't' : toggle texture.
static bool texture_off = false;
texture_off = !texture_off;
if (texture_off) {
nout << "Disabling texturing.\n";
render.set_texture_off(override_priority);
} else {
nout << "Enabling texturing.\n";
render.clear_texture();
}
}
void
event_w(CPT_Event) {
// 'w' : toggle wireframe.
wireframe = !wireframe;
if (wireframe) {
nout << "Setting wireframe mode.\n";
render.set_render_mode_wireframe(override_priority);
render.set_two_sided(true, override_priority);
} else {
nout << "Clearing wireframe mode.\n";
render.clear_render_mode();
if (!two_sided) {
render.clear_two_sided();
}
}
}
void
event_b(CPT_Event) {
// 'b' : toggle backfacing.
two_sided = !two_sided;
if (two_sided) {
nout << "Showing back-facing polygons.\n";
render.set_two_sided(true, override_priority);
} else {
nout << "Hiding back-facing polygons.\n";
if (!wireframe) {
render.clear_two_sided();
}
}
}
void
event_s(CPT_Event) {
// 's' : toggle state sorting by putting everything into the 'unsorted' bin.
static bool sorting_off = false;
sorting_off = !sorting_off;
if (sorting_off) {
nout << "Disabling state sorting.\n";
render.set_bin("unsorted", 0, override_priority);
} else {
nout << "Enabling state sorting.\n";
render.clear_bin();
}
}
void
event_S(CPT_Event) {
// shift 'S' : active PStats.
#ifdef DO_PSTATS
nout << "Connecting to stats host" << endl;
PStatClient::connect();
#else
nout << "Stats host not supported." << endl;
#endif
}
void
event_A(CPT_Event) {
// shift 'A' : deactive PStats.
#ifdef DO_PSTATS
if (PStatClient::is_connected()) {
nout << "Disconnecting from stats host" << endl;
PStatClient::disconnect();
} else {
nout << "Stats host is already disconnected." << endl;
}
#else
nout << "Stats host not supported." << endl;
#endif
}
void
event_l(CPT_Event) {
// 'l' : toggle lighting.
lighting = !lighting;
if (lighting) {
nout << "Enabling lighting.\n";
static bool lights_created = false;
static PT(AmbientLight) alight;
static PT(DirectionalLight) dlight;
if (!lights_created) {
alight = new AmbientLight("ambient");
alight->set_color(Colorf(0.2f, 0.2f, 0.2f, 1.0f));
dlight = new DirectionalLight("directional");
camera_np.attach_new_node(alight);
camera_np.attach_new_node(dlight);
lights_created = true;
}
// Enable lights on the top node.
render.node()->set_attrib(LightAttrib::make(LightAttrib::O_add, alight, dlight));
} else {
nout << "Disabling lighting.\n";
// Remove the lights from the top node.
render.node()->clear_attrib(LightAttrib::get_class_type());
}
}
#include "pandaFramework.h"
int
main(int argc, char *argv[]) {
// First, we need a GraphicsPipe, before we can open a window.
PT(GraphicsPipe) pipe = make_pipe();
PandaFramework framework;
framework.open_framework(argc, argv);
framework.set_window_title("Panda Viewer");
// We also need a GraphicsEngine to manage the rendering process.
GraphicsEngine *engine = new GraphicsEngine;
WindowFramework *window = framework.open_window();
if (window != (WindowFramework *)NULL) {
// We've successfully opened a window.
// Now open a window and get a camera.
PT(GraphicsWindow) window = make_window(pipe, engine);
PT(qpCamera) camera = make_camera(window);
window->enable_keyboard();
window->setup_trackball();
window->load_models(window->get_render(), argc, argv);
window->loop_animations();
// Now we just need to make a scene graph for the camera to render.
render = qpNodePath("render");
camera_np = render.attach_new_node(camera);
camera->set_scene(render);
framework.enable_default_keys();
framework.main_loop();
}
// This is maybe here temporarily, and maybe not.
render.set_two_sided(0);
// Set up a data graph for tracking user input.
PT(PandaNode) data_root = new PandaNode("data_root");
PandaNode *mouse = setup_mouse(data_root, window);
setup_trackball(mouse, camera);
qpDataGraphTraverser dg_trav;
// Use an event handler to manage keyboard events.
EventHandler event_handler(EventQueue::get_global_event_queue());
event_handler.add_hook("escape", event_esc);
event_handler.add_hook("q", event_esc);
event_handler.add_hook("f", event_f);
event_handler.add_hook("t", event_t);
event_handler.add_hook("w", event_w);
event_handler.add_hook("b", event_b);
event_handler.add_hook("s", event_s);
event_handler.add_hook("shift-s", event_S);
event_handler.add_hook("shift-a", event_A);
event_handler.add_hook("l", event_l);
// Put something in the scene graph to look at.
get_models(render.node(), argc, argv);
// If we happened to load up both a character file and its matching
// animation file, attempt to bind them together now and start the
// animations looping.
AnimControlCollection anim_controls;
auto_bind(render.node(), anim_controls, ~0);
anim_controls.loop_all(true);
// Tick the clock once so we won't count the time spent loading up
// files, above, in our frame rate average.
ClockObject::get_global_clock()->tick();
// This is our main update loop. Loop here until someone
// (e.g. event_esc) sets run_flag to false.
while (run_flag) {
dg_trav.traverse(data_root);
event_handler.process_events();
engine->render_frame();
}
report_frame_rate();
delete engine;
framework.report_frame_rate(nout);
return (0);
}