mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
wip: web plugin
This commit is contained in:
parent
c61f5f2b64
commit
6f711392aa
40
direct/src/plugin/Sources.pp
Normal file
40
direct/src/plugin/Sources.pp
Normal file
@ -0,0 +1,40 @@
|
||||
// This directory is still experimental. Define HAVE_P3D_PLUGIN in
|
||||
// your Config.pp to build it.
|
||||
#define BUILD_DIRECTORY $[HAVE_P3D_PLUGIN]
|
||||
|
||||
#begin lib_target
|
||||
#define TARGET p3d_plugin
|
||||
|
||||
#define COMBINED_SOURCES \
|
||||
$[TARGET]_composite1.cxx
|
||||
|
||||
#define SOURCES \
|
||||
p3d_plugin.h \
|
||||
p3d_plugin_common.h \
|
||||
p3dInstance.h p3dInstance.I \
|
||||
p3dInstanceManager.h p3dInstanceManager.I \
|
||||
p3dPython.h p3dPython.I \
|
||||
p3dSession.h p3dSession.I
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
p3d_plugin.cxx \
|
||||
p3dInstance.cxx \
|
||||
p3dInstanceManager.cxx \
|
||||
p3dPython.cxx \
|
||||
p3dSession.cxx
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
p3d_plugin.h
|
||||
|
||||
#end lib_target
|
||||
|
||||
#begin bin_target
|
||||
#define TARGET panda3d
|
||||
|
||||
#define SOURCES \
|
||||
panda3d.cxx \
|
||||
$[if $[WINDOWS_PLATFORM],wingetopt.h wingetopt.c]
|
||||
|
||||
#define WIN_SYS_LIBS user32.lib gdi32.lib
|
||||
|
||||
#end bin_target
|
52
direct/src/plugin/p3dInstance.I
Normal file
52
direct/src/plugin/p3dInstance.I
Normal file
@ -0,0 +1,52 @@
|
||||
// Filename: p3dInstance.I
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_p3d_filename
|
||||
// Access: Public
|
||||
// Description: Returns the p3d filename that was passed to the
|
||||
// constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DInstance::
|
||||
get_p3d_filename() const {
|
||||
return _p3d_filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_session_key
|
||||
// Access: Public
|
||||
// Description: Returns a string that uniquely identifies this
|
||||
// session. This is a constructed string that includes
|
||||
// the supplied session_name, the python and panda
|
||||
// version, and the publisher, as well as any other
|
||||
// relevant details; it is guaranteed to be unique for
|
||||
// each unique session required for different
|
||||
// P3DInstances.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DInstance::
|
||||
get_session_key() const {
|
||||
return _session_key;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_python_version
|
||||
// Access: Public
|
||||
// Description: Returns a string that uniquely identifies this
|
||||
// instance's required Python version.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DInstance::
|
||||
get_python_version() const {
|
||||
return _python_version;
|
||||
}
|
214
direct/src/plugin/p3dInstance.cxx
Normal file
214
direct/src/plugin/p3dInstance.cxx
Normal file
@ -0,0 +1,214 @@
|
||||
// Filename: p3dInstance.cxx
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3dInstance.h"
|
||||
#include "p3dInstanceManager.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstance::
|
||||
P3DInstance(P3D_request_ready_func *func,
|
||||
const string &p3d_filename,
|
||||
P3D_window_type window_type,
|
||||
int win_x, int win_y,
|
||||
int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const P3D_token *tokens[], size_t tokens_size) :
|
||||
_func(func),
|
||||
_p3d_filename(p3d_filename),
|
||||
_window_type(window_type),
|
||||
_win_x(win_x), _win_y(win_y),
|
||||
_win_width(win_width), _win_height(win_height),
|
||||
_parent_window(parent_window)
|
||||
{
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
INIT_LOCK(_request_lock);
|
||||
|
||||
// For the moment, all sessions will be shared.
|
||||
/*
|
||||
ostringstream strm;
|
||||
strm << inst_mgr->get_unique_session_index();
|
||||
_session_key = strm.str();
|
||||
*/
|
||||
_session_key = "common";
|
||||
_python_version = "python24";
|
||||
|
||||
_session = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstance::
|
||||
~P3DInstance() {
|
||||
assert(_session == NULL);
|
||||
|
||||
DESTROY_LOCK(_request_lock);
|
||||
|
||||
// TODO: empty _pending_requests queue.
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::has_property
|
||||
// Access: Public
|
||||
// Description: Returns true if the instance has the named property,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstance::
|
||||
has_property(const string &property_name) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_property
|
||||
// Access: Public
|
||||
// Description: Returns the value of the named property, or empty
|
||||
// string if there is no such property. Properties are
|
||||
// created by the script run within the instance; they
|
||||
// are used for communicating between scripting
|
||||
// languages (for instance, communication between the
|
||||
// Python-based Panda application, and the Javascript on
|
||||
// the containing web page).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string P3DInstance::
|
||||
get_property(const string &property_name) const {
|
||||
return string();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::set_property
|
||||
// Access: Public
|
||||
// Description: Changes the value of the named property. It is an
|
||||
// error to call this on a property that does not
|
||||
// already exist.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
set_property(const string &property_name, const string &value) {
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::has_request
|
||||
// Access: Public
|
||||
// Description: Returns true if the instance has any pending requests
|
||||
// at the time of this call, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstance::
|
||||
has_request() {
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
bool any_requests = !_pending_requests.empty();
|
||||
RELEASE_LOCK(_request_lock);
|
||||
return any_requests;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_request
|
||||
// Access: Public
|
||||
// Description: Returns a newly-allocated P3D_request corresponding
|
||||
// to the pending request for the host, or NULL if there
|
||||
// is no pending request. If the return value is
|
||||
// non-NULL, it should eventually be passed back to
|
||||
// finish_request() for cleanup.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_request *P3DInstance::
|
||||
get_request() {
|
||||
P3D_request *result = NULL;
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
if (!_pending_requests.empty()) {
|
||||
result = _pending_requests.front();
|
||||
_pending_requests.pop_front();
|
||||
}
|
||||
RELEASE_LOCK(_request_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::add_request
|
||||
// Access: Public
|
||||
// Description: May be called in any thread to add a new P3D_request
|
||||
// to the pending_request queue for this instance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
add_request(P3D_request *request) {
|
||||
assert(request->_instance == this);
|
||||
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
_pending_requests.push_back(request);
|
||||
RELEASE_LOCK(_request_lock);
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
inst_mgr->signal_request_ready();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::finish_request
|
||||
// Access: Public
|
||||
// Description: Deallocates a previously-returned request from
|
||||
// get_request(). If handled is true, the request has
|
||||
// been handled by the host; otherwise, it has been
|
||||
// ignored.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
finish_request(P3D_request *request, bool handled) {
|
||||
assert(request != NULL);
|
||||
|
||||
// TODO. Delete sub-pieces more aggressively. Deal with handled flag.
|
||||
delete request;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::feed_url_stream
|
||||
// Access: Public
|
||||
// Description: Called by the host in response to a get_url or
|
||||
// post_url request, this sends the data retrieved from
|
||||
// the requested URL, a piece at a time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
feed_url_stream(int unique_id,
|
||||
P3D_result_code result_code,
|
||||
int http_status_code,
|
||||
size_t total_expected_data,
|
||||
const unsigned char *this_data,
|
||||
size_t this_data_size) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::fill_tokens
|
||||
// Access: Private
|
||||
// Description: Copies the C-style tokens array into the internal
|
||||
// C++-style _tokens vector.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
fill_tokens(const P3D_token *tokens[], size_t tokens_size) {
|
||||
for (size_t i = 0; i < tokens_size; ++i) {
|
||||
Token token;
|
||||
if (tokens[i]->_keyword != NULL) {
|
||||
token._keyword = tokens[i]->_keyword;
|
||||
}
|
||||
if (tokens[i]->_value != NULL) {
|
||||
token._value = tokens[i]->_value;
|
||||
}
|
||||
_tokens.push_back(token);
|
||||
}
|
||||
}
|
92
direct/src/plugin/p3dInstance.h
Normal file
92
direct/src/plugin/p3dInstance.h
Normal file
@ -0,0 +1,92 @@
|
||||
// Filename: p3dInstance.h
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3DINSTANCE_H
|
||||
#define P3DINSTANCE_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
class P3DSession;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DInstance
|
||||
// Description : This is an instance of a Panda3D window.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DInstance : public P3D_instance {
|
||||
public:
|
||||
P3DInstance(P3D_request_ready_func *func,
|
||||
const string &p3d_filename,
|
||||
P3D_window_type window_type,
|
||||
int win_x, int win_y,
|
||||
int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const P3D_token *tokens[], size_t tokens_size);
|
||||
~P3DInstance();
|
||||
|
||||
bool has_property(const string &property_name) const;
|
||||
string get_property(const string &property_name) const;
|
||||
void set_property(const string &property_name, const string &value);
|
||||
|
||||
bool has_request();
|
||||
P3D_request *get_request();
|
||||
void add_request(P3D_request *request);
|
||||
void finish_request(P3D_request *request, bool handled);
|
||||
|
||||
void feed_url_stream(int unique_id,
|
||||
P3D_result_code result_code,
|
||||
int http_status_code,
|
||||
size_t total_expected_data,
|
||||
const unsigned char *this_data,
|
||||
size_t this_data_size);
|
||||
|
||||
INLINE const string &get_p3d_filename() const;
|
||||
INLINE const string &get_session_key() const;
|
||||
INLINE const string &get_python_version() const;
|
||||
|
||||
private:
|
||||
void fill_tokens(const P3D_token *tokens[], size_t tokens_size);
|
||||
|
||||
class Token {
|
||||
public:
|
||||
string _keyword;
|
||||
string _value;
|
||||
};
|
||||
typedef vector<Token> Tokens;
|
||||
|
||||
P3D_request_ready_func *_func;
|
||||
string _p3d_filename;
|
||||
P3D_window_type _window_type;
|
||||
int _win_x, _win_y;
|
||||
int _win_width, _win_height;
|
||||
P3D_window_handle _parent_window;
|
||||
Tokens _tokens;
|
||||
|
||||
string _session_key;
|
||||
string _python_version;
|
||||
P3DSession *_session;
|
||||
|
||||
LOCK _request_lock;
|
||||
typedef deque<P3D_request *> Requests;
|
||||
Requests _pending_requests;
|
||||
|
||||
friend class P3DSession;
|
||||
friend class P3DPython;
|
||||
};
|
||||
|
||||
#include "p3dInstance.I"
|
||||
|
||||
#endif
|
36
direct/src/plugin/p3dInstanceManager.I
Normal file
36
direct/src/plugin/p3dInstanceManager.I
Normal file
@ -0,0 +1,36 @@
|
||||
// Filename: p3dInstanceManager.I
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_num_instances
|
||||
// Access: Public
|
||||
// Description: Returns the number of instances currently running
|
||||
// within the world.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int P3DInstanceManager::
|
||||
get_num_instances() const {
|
||||
return _instances.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_dll_filename
|
||||
// Access: Public
|
||||
// Description: Returns the DLL filename that was passed to
|
||||
// initialize().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DInstanceManager::
|
||||
get_dll_filename() const {
|
||||
return _dll_filename;
|
||||
}
|
255
direct/src/plugin/p3dInstanceManager.cxx
Normal file
255
direct/src/plugin/p3dInstanceManager.cxx
Normal file
@ -0,0 +1,255 @@
|
||||
// Filename: p3dInstanceManager.cxx
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3dInstanceManager.h"
|
||||
#include "p3dInstance.h"
|
||||
#include "p3dSession.h"
|
||||
#include "p3dPython.h"
|
||||
|
||||
P3DInstanceManager *P3DInstanceManager::_global_ptr;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::Constructor
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstanceManager::
|
||||
P3DInstanceManager() {
|
||||
_unique_session_index = 0;
|
||||
_current_python = NULL;
|
||||
|
||||
_request_seq = 0;
|
||||
#ifdef _WIN32
|
||||
_request_ready = CreateEvent(NULL, false, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::Destructor
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstanceManager::
|
||||
~P3DInstanceManager() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::initialize
|
||||
// Access: Public
|
||||
// Description: Called by the host at application startup, this
|
||||
// receives the name of the DLL that contains this code
|
||||
// (for patching purposes). It returns true if the DLL
|
||||
// is successfully initialized, false if it should be
|
||||
// immediately shut down and redownloaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstanceManager::
|
||||
initialize(const string &config_xml, const string &dll_filename) {
|
||||
_dll_filename = dll_filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::create_instance
|
||||
// Access: Public
|
||||
// Description: Returns a newly-allocated P3DInstance with the
|
||||
// indicated startup information.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstance *P3DInstanceManager::
|
||||
create_instance(P3D_request_ready_func *func,
|
||||
const string &p3d_filename,
|
||||
P3D_window_type window_type,
|
||||
int win_x, int win_y,
|
||||
int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const P3D_token *tokens[], size_t tokens_size) {
|
||||
P3DInstance *inst = new P3DInstance(func, p3d_filename,
|
||||
window_type, win_x, win_y,
|
||||
win_width, win_height, parent_window,
|
||||
tokens, tokens_size);
|
||||
_instances.insert(inst);
|
||||
|
||||
P3DSession *session;
|
||||
Sessions::iterator si = _sessions.find(inst->get_session_key());
|
||||
if (si == _sessions.end()) {
|
||||
session = new P3DSession(inst);
|
||||
bool inserted = _sessions.insert(Sessions::value_type(session->get_session_key(), session)).second;
|
||||
assert(inserted);
|
||||
} else {
|
||||
session = (*si).second;
|
||||
}
|
||||
|
||||
session->start_instance(inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::finish_instance
|
||||
// Access: Public
|
||||
// Description: Terminates and removes a previously-returned
|
||||
// instance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstanceManager::
|
||||
finish_instance(P3DInstance *inst) {
|
||||
Instances::iterator ii;
|
||||
ii = _instances.find(inst);
|
||||
assert(ii != _instances.end());
|
||||
_instances.erase(ii);
|
||||
|
||||
Sessions::iterator si = _sessions.find(inst->get_session_key());
|
||||
assert(si != _sessions.end());
|
||||
P3DSession *session = (*si).second;
|
||||
session->terminate_instance(inst);
|
||||
|
||||
// If that was the last instance in this session, terminate the
|
||||
// session.
|
||||
if (session->get_num_instances() == 0) {
|
||||
_sessions.erase(session->get_session_key());
|
||||
delete session;
|
||||
}
|
||||
|
||||
delete inst;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::check_request
|
||||
// Access: Public
|
||||
// Description: If a request is currently pending on any instance,
|
||||
// returns its pointer. Otherwise, returns NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstance *P3DInstanceManager::
|
||||
check_request() {
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3DInstance *inst = (*ii);
|
||||
if (inst->has_request()) {
|
||||
return inst;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::wait_request
|
||||
// Access: Public
|
||||
// Description: Does not return until a request is pending on some
|
||||
// instance, or until no instances remain. Use
|
||||
// check_request to retrieve the pending request. Due
|
||||
// to the possibility of race conditions, it is possible
|
||||
// for this function to return when there is in fact no
|
||||
// request pending (another thread may have extracted
|
||||
// the request first).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstanceManager::
|
||||
wait_request() {
|
||||
int seq = _request_seq;
|
||||
|
||||
while (true) {
|
||||
if (_instances.empty()) {
|
||||
return;
|
||||
}
|
||||
if (check_request() != (P3DInstance *)NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No pending requests; go to sleep.
|
||||
if (seq == _request_seq) {
|
||||
WaitForSingleObject(_request_ready, INFINITE);
|
||||
}
|
||||
seq = _request_seq;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::start_python
|
||||
// Access: Public
|
||||
// Description: Returns a P3DPython object corresponding to the
|
||||
// requested Python version. The P3DPython object is
|
||||
// loaded into the current memory address space; because
|
||||
// of Python version conflicts, only one version of
|
||||
// Python may be resident at a given time. Thus,
|
||||
// calling this will implicitly terminate any running
|
||||
// instances that are currently using a different
|
||||
// version of Python.
|
||||
//
|
||||
// This may return NULL if the Python interpreter cannot
|
||||
// be successfully started for some reason.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPython *P3DInstanceManager::
|
||||
start_python(const string &python_version) {
|
||||
if (_current_python != NULL && !_current_python->is_valid()) {
|
||||
// The current python has gone bad.
|
||||
delete _current_python;
|
||||
_current_python = NULL;
|
||||
}
|
||||
|
||||
if (_current_python != NULL && _current_python->get_python_version() != python_version) {
|
||||
// The current python is the wrong version. We should kill it and
|
||||
// all of the instances using it. TODO.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_current_python == NULL) {
|
||||
_current_python = new P3DPython(python_version);
|
||||
if (!_current_python->is_valid()) {
|
||||
// Couldn't successfully start Python.
|
||||
delete _current_python;
|
||||
_current_python = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return _current_python;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_unique_session_index
|
||||
// Access: Public
|
||||
// Description: Returns a number used to uniquify the session_key for
|
||||
// different instances. This number is guaranteed to be
|
||||
// different at each call.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int P3DInstanceManager::
|
||||
get_unique_session_index() {
|
||||
++_unique_session_index;
|
||||
return _unique_session_index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::signal_request_ready
|
||||
// Access: Public
|
||||
// Description: May be called in any thread to indicate that a new
|
||||
// P3D_request is available in some instance. This will
|
||||
// wake up a sleeping wait_request() call, if any.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstanceManager::
|
||||
signal_request_ready() {
|
||||
++_request_seq;
|
||||
#ifdef _WIN32
|
||||
SetEvent(_request_ready);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_global_ptr
|
||||
// Access: Public, Static
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DInstanceManager *P3DInstanceManager::
|
||||
get_global_ptr() {
|
||||
if (_global_ptr == NULL) {
|
||||
_global_ptr = new P3DInstanceManager;
|
||||
}
|
||||
return _global_ptr;
|
||||
}
|
90
direct/src/plugin/p3dInstanceManager.h
Normal file
90
direct/src/plugin/p3dInstanceManager.h
Normal file
@ -0,0 +1,90 @@
|
||||
// Filename: p3dInstanceManager.h
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3DINSTANCEMANAGER_H
|
||||
#define P3DINSTANCEMANAGER_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
class P3DInstance;
|
||||
class P3DSession;
|
||||
class P3DPython;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DInstanceManager
|
||||
// Description : This global class manages the set of instances in the
|
||||
// universe.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DInstanceManager {
|
||||
private:
|
||||
P3DInstanceManager();
|
||||
~P3DInstanceManager();
|
||||
|
||||
public:
|
||||
bool initialize(const string &config_xml, const string &dll_filename);
|
||||
|
||||
P3DInstance *
|
||||
create_instance(P3D_request_ready_func *func,
|
||||
const string &p3d_filename,
|
||||
P3D_window_type window_type,
|
||||
int win_x, int win_y,
|
||||
int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const P3D_token *tokens[], size_t tokens_size);
|
||||
|
||||
void
|
||||
finish_instance(P3DInstance *inst);
|
||||
|
||||
P3DInstance *check_request();
|
||||
void wait_request();
|
||||
|
||||
P3DPython *start_python(const string &python_version);
|
||||
|
||||
INLINE int get_num_instances() const;
|
||||
|
||||
INLINE const string &get_dll_filename() const;
|
||||
|
||||
int get_unique_session_index();
|
||||
void signal_request_ready();
|
||||
|
||||
static P3DInstanceManager *get_global_ptr();
|
||||
|
||||
private:
|
||||
string _dll_filename;
|
||||
string _p3d_root_directory;
|
||||
|
||||
typedef set<P3DInstance *> Instances;
|
||||
Instances _instances;
|
||||
|
||||
typedef map<string, P3DSession *> Sessions;
|
||||
Sessions _sessions;
|
||||
|
||||
P3DPython *_current_python;
|
||||
int _unique_session_index;
|
||||
|
||||
// Implements a condition-var like behavior.
|
||||
volatile int _request_seq;
|
||||
#ifdef _WIN32
|
||||
HANDLE _request_ready;
|
||||
#endif
|
||||
|
||||
static P3DInstanceManager *_global_ptr;
|
||||
};
|
||||
|
||||
#include "p3dInstanceManager.I"
|
||||
|
||||
#endif
|
49
direct/src/plugin/p3dPython.I
Normal file
49
direct/src/plugin/p3dPython.I
Normal file
@ -0,0 +1,49 @@
|
||||
// Filename: p3dPython.I
|
||||
// Created by: drose (04Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::get_python_version
|
||||
// Access: Public
|
||||
// Description: Returns a string that uniquely identifies this
|
||||
// Python version. You cannot have two different
|
||||
// versions of Python loaded simultaneously within the
|
||||
// same address space.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DPython::
|
||||
get_python_version() const {
|
||||
return _python_version;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::get_num_sessions
|
||||
// Access: Public
|
||||
// Description: Returns the number of sessions currently sharing
|
||||
// this Python address space.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int P3DPython::
|
||||
get_num_sessions() const {
|
||||
return _sessions.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::is_valid
|
||||
// Access: Public
|
||||
// Description: Returns true if the Python interpreter is up and
|
||||
// ready to run code, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool P3DPython::
|
||||
is_valid() const {
|
||||
return _is_valid;
|
||||
}
|
372
direct/src/plugin/p3dPython.cxx
Normal file
372
direct/src/plugin/p3dPython.cxx
Normal file
@ -0,0 +1,372 @@
|
||||
// Filename: p3dPython.cxx
|
||||
// Created by: drose (04Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3dPython.h"
|
||||
#include "p3dSession.h"
|
||||
#include "p3dInstanceManager.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPython::
|
||||
P3DPython(const string &python_version) {
|
||||
_python_version = python_version;
|
||||
_is_valid = false;
|
||||
|
||||
_runPackedApp = NULL;
|
||||
_setupWindow = NULL;
|
||||
_run = NULL;
|
||||
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
_program_name = inst_mgr->get_dll_filename();
|
||||
|
||||
size_t slash = _program_name.rfind('/');
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows tolerates slashes or backslashes. Look for the rightmost
|
||||
// of either.
|
||||
size_t backslash = _program_name.rfind('\\');
|
||||
if (backslash != string::npos && (slash == string::npos || backslash > slash)) {
|
||||
slash = backslash;
|
||||
}
|
||||
#endif
|
||||
|
||||
// _root_dir = _program_name.substr(0, slash);
|
||||
_root_dir = "C:/p3drun";
|
||||
|
||||
_py_argc = 1;
|
||||
_py_argv = (char **)malloc(2 * sizeof(char *));
|
||||
_py_argv[0] = (char *)_program_name.c_str();
|
||||
_py_argv[1] = NULL;
|
||||
|
||||
// Guess everything's OK.
|
||||
_is_valid = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::Destructor
|
||||
// Access: Public
|
||||
// Description: Terminates the python by shutting down Python and
|
||||
// stopping the subprocess.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPython::
|
||||
~P3DPython() {
|
||||
if (_python_module != NULL) {
|
||||
if (_is_valid) {
|
||||
Py_XDECREF(_runPackedApp);
|
||||
Py_XDECREF(_setupWindow);
|
||||
Py_XDECREF(_run);
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
FreeLibrary(_python_module);
|
||||
_python_module = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::start_session
|
||||
// Access: Public
|
||||
// Description: Starts the indicated session running within the
|
||||
// Python interpreter. For the moment, each session
|
||||
// must contain only a single P3DInstance, which is also
|
||||
// started.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPython::
|
||||
start_session(P3DSession *session, P3DInstance *inst) {
|
||||
assert(_is_valid);
|
||||
|
||||
assert(session->_python == NULL);
|
||||
assert(session->get_python_version() == _python_version);
|
||||
|
||||
// For now, only one session at a time is allowed.
|
||||
assert(_sessions.empty());
|
||||
|
||||
session->_python = this;
|
||||
bool inserted = _sessions.insert(session).second;
|
||||
assert(inserted);
|
||||
|
||||
_inst = inst;
|
||||
spawn_thread();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::terminate_session
|
||||
// Access: Public
|
||||
// Description: Removes the indicated session from the python, and
|
||||
// stops it. It is an error if the session is not
|
||||
// already running on this python.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPython::
|
||||
terminate_session(P3DSession *session) {
|
||||
join_thread();
|
||||
|
||||
if (session->_python == this) {
|
||||
session->_python = NULL;
|
||||
_sessions.erase(session);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::spawn_thread
|
||||
// Access: Private
|
||||
// Description: Starts the sub-thread. All calls to Python are made
|
||||
// within the sub-thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPython::
|
||||
spawn_thread() {
|
||||
#ifdef _WIN32
|
||||
_thread = CreateThread(NULL, 0, &win_thread_func, this, 0, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::join_thread
|
||||
// Access: Private
|
||||
// Description: Waits for the sub-thread to stop.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPython::
|
||||
join_thread() {
|
||||
cerr << "waiting for thread\n";
|
||||
|
||||
#ifdef _WIN32
|
||||
assert(_thread != NULL);
|
||||
WaitForSingleObject(_thread, INFINITE);
|
||||
CloseHandle(_thread);
|
||||
_thread = NULL;
|
||||
#endif
|
||||
cerr << "done waiting for thread\n";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::tr_init_python
|
||||
// Access: Private
|
||||
// Description: Initializes the Python interpreter. This method, and
|
||||
// all methods that interact with Python, is called only
|
||||
// within the sub-thread. Returns true if successful,
|
||||
// false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DPython::
|
||||
tr_init_python() {
|
||||
#ifdef _WIN32
|
||||
string python_dll_filename = _root_dir + string("/python24.dll");
|
||||
_python_module = LoadLibrary(python_dll_filename.c_str());
|
||||
if (_python_module == NULL) {
|
||||
// Couldn't load Python.
|
||||
cerr << "Unable to load " << python_dll_filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
Py_SetProgramName = (Py_SetProgramName_func *)GetProcAddress(_python_module, "Py_SetProgramName");
|
||||
PySys_SetArgv = (PySys_SetArgv_func *)GetProcAddress(_python_module, "PySys_SetArgv");
|
||||
Py_SetPythonHome = (Py_SetPythonHome_func *)GetProcAddress(_python_module, "Py_SetPythonHome");
|
||||
Py_Initialize = (Py_Initialize_func *)GetProcAddress(_python_module, "Py_Initialize");
|
||||
Py_Finalize = (Py_Finalize_func *)GetProcAddress(_python_module, "Py_Finalize");
|
||||
PyEval_InitThreads = (PyEval_InitThreads_func *)GetProcAddress(_python_module, "PyEval_InitThreads");
|
||||
PyEval_AcquireLock = (PyEval_AcquireLock_func *)GetProcAddress(_python_module, "PyEval_AcquireLock");
|
||||
PyEval_ReleaseLock = (PyEval_ReleaseLock_func *)GetProcAddress(_python_module, "PyEval_ReleaseLock");
|
||||
PyRun_SimpleString = (PyRun_SimpleString_func *)GetProcAddress(_python_module, "PyRun_SimpleString");
|
||||
PyErr_Print = (PyErr_Print_func *)GetProcAddress(_python_module, "PyErr_Print");
|
||||
Py_XDECREF = (Py_XDECREF_func *)GetProcAddress(_python_module, "Py_DecRef");
|
||||
PyImport_ImportModule = (PyImport_ImportModule_func *)GetProcAddress(_python_module, "PyImport_ImportModule");
|
||||
PyObject_SetAttrString = (PyObject_SetAttrString_func *)GetProcAddress(_python_module, "PyObject_SetAttrString");
|
||||
PyObject_GetAttrString = (PyObject_GetAttrString_func *)GetProcAddress(_python_module, "PyObject_GetAttrString");
|
||||
Py_BuildValue = (Py_BuildValue_func *)GetProcAddress(_python_module, "Py_BuildValue");
|
||||
PyObject_CallFunction = (PyObject_CallFunction_func *)GetProcAddress(_python_module, "PyObject_CallFunction");
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
if (Py_SetProgramName == NULL ||
|
||||
PySys_SetArgv == NULL ||
|
||||
Py_SetPythonHome == NULL ||
|
||||
Py_Initialize == NULL ||
|
||||
Py_Finalize == NULL ||
|
||||
PyEval_InitThreads == NULL ||
|
||||
PyEval_AcquireLock == NULL ||
|
||||
PyEval_ReleaseLock == NULL ||
|
||||
PyRun_SimpleString == NULL ||
|
||||
PyErr_Print == NULL ||
|
||||
Py_XDECREF == NULL ||
|
||||
PyImport_ImportModule == NULL ||
|
||||
PyObject_SetAttrString == NULL ||
|
||||
PyObject_GetAttrString == NULL ||
|
||||
Py_BuildValue == NULL ||
|
||||
PyObject_CallFunction == NULL) {
|
||||
// Couldn't get all of the needed Python functions for some reason.
|
||||
cerr << "Py_SetProgramName = " << Py_SetProgramName << "\n"
|
||||
<< "PySys_SetArgv = " << PySys_SetArgv << "\n"
|
||||
<< "Py_SetPythonHome = " << Py_SetPythonHome << "\n"
|
||||
<< "Py_Initialize = " << Py_Initialize << "\n"
|
||||
<< "Py_Finalize = " << Py_Finalize << "\n"
|
||||
<< "PyEval_InitThreads = " << PyEval_InitThreads << "\n"
|
||||
<< "PyEval_AcquireLock = " << PyEval_AcquireLock << "\n"
|
||||
<< "PyEval_ReleaseLock = " << PyEval_ReleaseLock << "\n"
|
||||
<< "PyRun_SimpleString = " << PyRun_SimpleString << "\n"
|
||||
<< "PyErr_Print = " << PyErr_Print << "\n"
|
||||
<< "Py_XDECREF = " << Py_XDECREF << "\n"
|
||||
<< "PyImport_ImportModule = " << PyImport_ImportModule << "\n"
|
||||
<< "PyObject_SetAttrString = " << PyObject_SetAttrString << "\n"
|
||||
<< "PyObject_GetAttrString = " << PyObject_GetAttrString << "\n"
|
||||
<< "Py_BuildValue = " << Py_BuildValue << "\n"
|
||||
<< "PyObject_CallFunction = " << PyObject_CallFunction << "\n"
|
||||
<< "\n";
|
||||
FreeLibrary(_python_module);
|
||||
_python_module = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// All right, initialize Python.
|
||||
Py_SetProgramName((char *)_program_name.c_str());
|
||||
Py_Initialize();
|
||||
Py_SetPythonHome((char *)_root_dir.c_str());
|
||||
PySys_SetArgv(_py_argc, _py_argv);
|
||||
|
||||
// Set sys.path appropriately.
|
||||
PyObject *sys = PyImport_ImportModule("sys");
|
||||
if (sys == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
|
||||
PyObject *path = Py_BuildValue("[s]", _root_dir.c_str());
|
||||
PyObject_SetAttrString(sys, "path", path);
|
||||
Py_XDECREF(path);
|
||||
Py_XDECREF(sys);
|
||||
|
||||
// Now load runappmf.pyd.
|
||||
PyObject *runappmf = PyImport_ImportModule("runappmf");
|
||||
if (runappmf == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
Py_XDECREF(runappmf);
|
||||
|
||||
// And get the pointers to the functions needed within the module.
|
||||
PyObject *appmf = PyImport_ImportModule("direct.showbase.RunAppMF");
|
||||
if (appmf == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
_runPackedApp = PyObject_GetAttrString(appmf, "runPackedApp");
|
||||
if (_runPackedApp == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
|
||||
if (_setupWindow == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
_run = PyObject_GetAttrString(appmf, "run");
|
||||
if (_run == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::tr_thread_run
|
||||
// Access: Private
|
||||
// Description: The main function for the sub-thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPython::
|
||||
tr_thread_run() {
|
||||
bool valid = true;
|
||||
if (!tr_init_python()) {
|
||||
// Couldn't get Python going.
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
string window_type;
|
||||
switch (_inst->_window_type) {
|
||||
case P3D_WT_embedded:
|
||||
window_type = "embedded";
|
||||
break;
|
||||
case P3D_WT_toplevel:
|
||||
window_type = "toplevel";
|
||||
break;
|
||||
case P3D_WT_fullscreen:
|
||||
window_type = "fullscreen";
|
||||
break;
|
||||
case P3D_WT_hidden:
|
||||
window_type = "hidden";
|
||||
break;
|
||||
}
|
||||
|
||||
PyObject *result = PyObject_CallFunction
|
||||
(_setupWindow, "siiiii", window_type.c_str(),
|
||||
_inst->_win_x, _inst->_win_y,
|
||||
_inst->_win_width, _inst->_win_height,
|
||||
#ifdef _WIN32
|
||||
(int)(_inst->_parent_window._hwnd)
|
||||
#endif
|
||||
);
|
||||
if (result == NULL) {
|
||||
PyErr_Print();
|
||||
valid = false;
|
||||
}
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
PyObject *result = PyObject_CallFunction(_runPackedApp, "[s]", _inst->get_p3d_filename().c_str());
|
||||
if (result == NULL) {
|
||||
PyErr_Print();
|
||||
valid = false;
|
||||
}
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
|
||||
_is_valid = valid;
|
||||
// Maybe signal the parent that we're ready?
|
||||
|
||||
if (valid) {
|
||||
// Call run(). This function won't return until the p3d app
|
||||
// exits.
|
||||
PyObject *result = PyObject_CallFunction(_run, "");
|
||||
if (result == NULL) {
|
||||
PyErr_Print();
|
||||
}
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
|
||||
// The instance has finished.
|
||||
P3D_request *request = new P3D_request;
|
||||
request->_instance = _inst;
|
||||
request->_request_type = P3D_RT_stop;
|
||||
_inst->add_request(request);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPython::win_thread_func
|
||||
// Access: Private, Static
|
||||
// Description: The Windows flavor of the thread callback function.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DWORD P3DPython::
|
||||
win_thread_func(LPVOID data) {
|
||||
((P3DPython *)data)->tr_thread_run();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
125
direct/src/plugin/p3dPython.h
Normal file
125
direct/src/plugin/p3dPython.h
Normal file
@ -0,0 +1,125 @@
|
||||
// Filename: p3dPython.h
|
||||
// Created by: drose (04Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3DPYTHON_H
|
||||
#define P3DPYTHON_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DPython
|
||||
// Description : Corresponds to a single instance of the Python
|
||||
// interpreter. Since Python is single-threaded and
|
||||
// global-namespace, there can only be one Python
|
||||
// instance in a given address space.
|
||||
//
|
||||
// Note that, due to Python's "NewInterpreter"
|
||||
// mechanism, it *might* be possible to have multiple
|
||||
// virtual interpreters within a single Python instance.
|
||||
// This will require some work to integrate successfully
|
||||
// with Panda, though, so it is not currently
|
||||
// implemented.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DPython {
|
||||
public:
|
||||
P3DPython(const string &python_version);
|
||||
~P3DPython();
|
||||
|
||||
INLINE const string &get_python_version() const;
|
||||
|
||||
void start_session(P3DSession *session, P3DInstance *inst);
|
||||
void terminate_session(P3DSession *session);
|
||||
|
||||
INLINE int get_num_sessions() const;
|
||||
INLINE bool is_valid() const;
|
||||
|
||||
private:
|
||||
void spawn_thread();
|
||||
void join_thread();
|
||||
|
||||
private:
|
||||
// Methods that run only within the sub-thread.
|
||||
bool tr_init_python();
|
||||
void tr_thread_run();
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI win_thread_func(LPVOID data);
|
||||
#endif
|
||||
|
||||
private:
|
||||
string _python_version;
|
||||
bool _is_valid;
|
||||
|
||||
string _root_dir;
|
||||
string _program_name;
|
||||
|
||||
int _py_argc;
|
||||
char **_py_argv;
|
||||
|
||||
typedef set<P3DSession *> Sessions;
|
||||
Sessions _sessions;
|
||||
|
||||
// Temporary.
|
||||
P3DInstance *_inst;
|
||||
|
||||
#ifdef _WIN32
|
||||
HMODULE _python_module;
|
||||
HANDLE _thread;
|
||||
#endif
|
||||
|
||||
typedef struct _object PyObject;
|
||||
|
||||
PyObject *_runPackedApp;
|
||||
PyObject *_setupWindow;
|
||||
PyObject *_run;
|
||||
|
||||
// Pointers to dynamically-loaded Python functions.
|
||||
typedef void Py_SetProgramName_func(char *name);
|
||||
typedef void PySys_SetArgv_func(int argc, char **argv);
|
||||
typedef void Py_SetPythonHome_func(char *name);
|
||||
typedef void Py_Initialize_func(void);
|
||||
typedef void Py_Finalize_func(void);
|
||||
typedef void PyEval_InitThreads_func(void);
|
||||
typedef void PyEval_AcquireLock_func(void);
|
||||
typedef void PyEval_ReleaseLock_func(void);
|
||||
typedef int PyRun_SimpleString_func(const char *command);
|
||||
typedef void PyErr_Print_func(void);
|
||||
typedef void Py_XDECREF_func(PyObject *o);
|
||||
typedef PyObject *PyImport_ImportModule_func(const char *name);
|
||||
typedef int PyObject_SetAttrString_func(PyObject *o, const char *attr_name, PyObject *v);
|
||||
typedef PyObject *PyObject_GetAttrString_func(PyObject *o, const char *attr_name);
|
||||
typedef PyObject *Py_BuildValue_func(const char *format, ...);
|
||||
typedef PyObject *PyObject_CallFunction_func(PyObject *callable, char *format, ...);
|
||||
|
||||
Py_SetProgramName_func *Py_SetProgramName;
|
||||
PySys_SetArgv_func *PySys_SetArgv;
|
||||
Py_SetPythonHome_func *Py_SetPythonHome;
|
||||
Py_Initialize_func *Py_Initialize;
|
||||
Py_Finalize_func *Py_Finalize;
|
||||
PyEval_InitThreads_func *PyEval_InitThreads;
|
||||
PyEval_AcquireLock_func *PyEval_AcquireLock;
|
||||
PyEval_ReleaseLock_func *PyEval_ReleaseLock;
|
||||
PyRun_SimpleString_func *PyRun_SimpleString;
|
||||
PyErr_Print_func *PyErr_Print;
|
||||
Py_XDECREF_func *Py_XDECREF;
|
||||
PyImport_ImportModule_func *PyImport_ImportModule;
|
||||
PyObject_SetAttrString_func *PyObject_SetAttrString;
|
||||
PyObject_GetAttrString_func *PyObject_GetAttrString;
|
||||
Py_BuildValue_func *Py_BuildValue;
|
||||
PyObject_CallFunction_func *PyObject_CallFunction;
|
||||
};
|
||||
|
||||
#include "p3dPython.I"
|
||||
|
||||
#endif
|
48
direct/src/plugin/p3dSession.I
Normal file
48
direct/src/plugin/p3dSession.I
Normal file
@ -0,0 +1,48 @@
|
||||
// Filename: p3dSession.I
|
||||
// Created by: drose (03Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::get_session_key
|
||||
// Access: Public
|
||||
// Description: Returns a string that uniquely identifies this
|
||||
// session. See P3dInstance::get_session_key().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DSession::
|
||||
get_session_key() const {
|
||||
return _session_key;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::get_python_version
|
||||
// Access: Public
|
||||
// Description: Returns a string that uniquely identifies this
|
||||
// session's required Python version.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &P3DSession::
|
||||
get_python_version() const {
|
||||
return _python_version;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::get_num_instances
|
||||
// Access: Public
|
||||
// Description: Returns the number of instances currently running
|
||||
// within the session. When this is zero, the session
|
||||
// may be safely deleted.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int P3DSession::
|
||||
get_num_instances() const {
|
||||
return _instances.size();
|
||||
}
|
93
direct/src/plugin/p3dSession.cxx
Normal file
93
direct/src/plugin/p3dSession.cxx
Normal file
@ -0,0 +1,93 @@
|
||||
// Filename: p3dSession.cxx
|
||||
// Created by: drose (03Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3dSession.h"
|
||||
#include "p3dInstance.h"
|
||||
#include "p3dInstanceManager.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::Constructor
|
||||
// Access: Public
|
||||
// Description: Creates a new session, corresponding to a new
|
||||
// subprocess with its own copy of Python. The initial
|
||||
// parameters for the session are taken from the
|
||||
// indicated instance object (but the instance itself is
|
||||
// not automatically started within the session).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DSession::
|
||||
P3DSession(P3DInstance *inst) {
|
||||
_session_key = inst->get_session_key();
|
||||
_python_version = inst->get_python_version();
|
||||
_python = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::Destructor
|
||||
// Access: Public
|
||||
// Description: Terminates the session by shutting down Python and
|
||||
// stopping the subprocess.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DSession::
|
||||
~P3DSession() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::start_instance
|
||||
// Access: Public
|
||||
// Description: Adds the indicated instance to the session, and
|
||||
// starts it running. It is an error if the instance
|
||||
// has been started anywhere else.
|
||||
//
|
||||
// The instance must have the same session_key as the
|
||||
// one that was passed to the P3DSession constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
start_instance(P3DInstance *inst) {
|
||||
assert(_python == NULL);
|
||||
assert(inst->_session == NULL);
|
||||
assert(inst->get_session_key() == _session_key);
|
||||
assert(inst->get_python_version() == _python_version);
|
||||
|
||||
inst->_session = this;
|
||||
bool inserted = _instances.insert(inst).second;
|
||||
assert(inserted);
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
P3DPython *python = inst_mgr->start_python(_python_version);
|
||||
if (python != NULL) {
|
||||
python->start_session(this, inst);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::terminate_instance
|
||||
// Access: Public
|
||||
// Description: Removes the indicated instance from the session, and
|
||||
// stops it. It is an error if the instance is not
|
||||
// already running on this session.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
terminate_instance(P3DInstance *inst) {
|
||||
if (_python != NULL) {
|
||||
_python->terminate_session(this);
|
||||
assert(_python == NULL);
|
||||
}
|
||||
|
||||
if (inst->_session == this) {
|
||||
inst->_session = NULL;
|
||||
_instances.erase(inst);
|
||||
}
|
||||
}
|
58
direct/src/plugin/p3dSession.h
Normal file
58
direct/src/plugin/p3dSession.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Filename: p3dSession.h
|
||||
// Created by: drose (03Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3DSESSION_H
|
||||
#define P3DSESSION_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
class P3DInstance;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DSession
|
||||
// Description : Corresponds to a single session: a subprocess with a
|
||||
// unique instance of Python running within it, which
|
||||
// might include one or more P3DInstance objects running
|
||||
// in the same memory space with each other.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DSession {
|
||||
public:
|
||||
P3DSession(P3DInstance *inst);
|
||||
~P3DSession();
|
||||
|
||||
INLINE const string &get_session_key() const;
|
||||
INLINE const string &get_python_version() const;
|
||||
|
||||
void start_instance(P3DInstance *inst);
|
||||
void terminate_instance(P3DInstance *inst);
|
||||
|
||||
INLINE int get_num_instances() const;
|
||||
|
||||
private:
|
||||
string _session_key;
|
||||
string _python_version;
|
||||
|
||||
P3DPython *_python;
|
||||
|
||||
typedef set<P3DInstance *> Instances;
|
||||
Instances _instances;
|
||||
|
||||
friend class P3DPython;
|
||||
};
|
||||
|
||||
#include "p3dSession.I"
|
||||
|
||||
#endif
|
166
direct/src/plugin/p3d_plugin.cxx
Normal file
166
direct/src/plugin/p3d_plugin.cxx
Normal file
@ -0,0 +1,166 @@
|
||||
// Filename: p3d_plugin.cxx
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
#include "p3dInstanceManager.h"
|
||||
#include "p3dInstance.h"
|
||||
|
||||
// Use a simple lock to protect the C-style API functions in this
|
||||
// module from parallel access by multiple threads in the host.
|
||||
|
||||
bool initialized_lock = false;
|
||||
LOCK _lock;
|
||||
|
||||
bool
|
||||
P3D_initialize(const char *config_xml, const char *dll_filename) {
|
||||
string config_xml_str;
|
||||
if (config_xml != NULL) {
|
||||
config_xml_str = config_xml;
|
||||
}
|
||||
|
||||
string dll_filename_str;
|
||||
if (dll_filename != NULL) {
|
||||
dll_filename_str = dll_filename;
|
||||
}
|
||||
|
||||
if (!initialized_lock) {
|
||||
INIT_LOCK(_lock);
|
||||
initialized_lock = true;
|
||||
}
|
||||
ACQUIRE_LOCK(_lock);
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
bool result = inst_mgr->initialize(config_xml_str, dll_filename_str);
|
||||
RELEASE_LOCK(_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
P3D_free_string(char *string) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
delete [] string;
|
||||
RELEASE_LOCK(_lock);
|
||||
}
|
||||
|
||||
P3D_instance *
|
||||
P3D_create_instance(P3D_request_ready_func *func,
|
||||
const char *p3d_filename,
|
||||
P3D_window_type window_type,
|
||||
int win_x, int win_y,
|
||||
int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const P3D_token *tokens[], size_t tokens_size) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
P3DInstance *result =
|
||||
inst_mgr->create_instance(func, p3d_filename, window_type,
|
||||
win_x, win_y, win_width, win_height,
|
||||
parent_window, tokens, tokens_size);
|
||||
RELEASE_LOCK(_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
P3D_instance_finish(P3D_instance *instance) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
inst_mgr->finish_instance((P3DInstance *)instance);
|
||||
RELEASE_LOCK(_lock);
|
||||
}
|
||||
|
||||
bool
|
||||
P3D_instance_has_property(P3D_instance *instance,
|
||||
const char *property_name) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
bool result = ((P3DInstance *)instance)->has_property(property_name);
|
||||
RELEASE_LOCK(_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *
|
||||
P3D_instance_get_property(P3D_instance *instance,
|
||||
const char *property_name) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
string value = ((P3DInstance *)instance)->get_property(property_name);
|
||||
|
||||
char *result = new char[value.length() + 1];
|
||||
RELEASE_LOCK(_lock);
|
||||
|
||||
memcpy(result, value.data(), value.length());
|
||||
result[value.length()] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
P3D_instance_set_property(P3D_instance *instance,
|
||||
const char *property_name,
|
||||
const char *value) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
((P3DInstance *)instance)->set_property(property_name, value);
|
||||
RELEASE_LOCK(_lock);
|
||||
}
|
||||
|
||||
P3D_request *
|
||||
P3D_instance_get_request(P3D_instance *instance) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
P3D_request *result = ((P3DInstance *)instance)->get_request();
|
||||
RELEASE_LOCK(_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
P3D_instance *
|
||||
P3D_check_request(bool wait) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
P3D_instance *inst = inst_mgr->check_request();
|
||||
|
||||
if (inst != NULL || !wait) {
|
||||
RELEASE_LOCK(_lock);
|
||||
return inst;
|
||||
}
|
||||
|
||||
// Now we have to block until a request is available.
|
||||
while (inst == NULL && inst_mgr->get_num_instances() != 0) {
|
||||
RELEASE_LOCK(_lock);
|
||||
inst_mgr->wait_request();
|
||||
ACQUIRE_LOCK(_lock);
|
||||
inst = inst_mgr->check_request();
|
||||
}
|
||||
|
||||
RELEASE_LOCK(_lock);
|
||||
return inst;
|
||||
}
|
||||
|
||||
void
|
||||
P3D_request_finish(P3D_request *request, bool handled) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
if (request != (P3D_request *)NULL) {
|
||||
((P3DInstance *)request->_instance)->finish_request(request, handled);
|
||||
}
|
||||
RELEASE_LOCK(_lock);
|
||||
}
|
||||
|
||||
void
|
||||
P3D_instance_feed_url_stream(P3D_instance *instance, int unique_id,
|
||||
P3D_result_code result_code,
|
||||
int http_status_code,
|
||||
size_t total_expected_data,
|
||||
const unsigned char *this_data,
|
||||
size_t this_data_size) {
|
||||
ACQUIRE_LOCK(_lock);
|
||||
((P3DInstance *)instance)->
|
||||
feed_url_stream(unique_id, result_code, http_status_code,
|
||||
total_expected_data, this_data, this_data_size);
|
||||
RELEASE_LOCK(_lock);
|
||||
}
|
||||
|
458
direct/src/plugin/p3d_plugin.h
Normal file
458
direct/src/plugin/p3d_plugin.h
Normal file
@ -0,0 +1,458 @@
|
||||
/* Filename: p3d_plugin.h
|
||||
* Created by: drose (28May09)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef P3D_PLUGIN_H
|
||||
#define P3D_PLUGIN_H
|
||||
|
||||
/* This file defines the C-level API to Panda's plugin system. This
|
||||
API is intended to provide basic functionality for loading and
|
||||
running Panda's .p3d files, particularly within a browser.
|
||||
|
||||
This plugin code is intended to be loaded and run as a standalone
|
||||
DLL. It will in turn be responsible for fetching and installing
|
||||
the appropriate version of Panda and Python, as well as any
|
||||
required supporting libraries.
|
||||
|
||||
Note that this code defines only the interface between the actual
|
||||
browser plugin and the Panda code. The actual plugin itself will
|
||||
be a separate piece of code, written in ActiveX or NPIP or whatever
|
||||
API is required for a given browser, which is designed to download
|
||||
and link with this layer.
|
||||
|
||||
The browser or launching application will be referred to as the
|
||||
"host" in this documentation. The host should load this plugin dll
|
||||
only once, but may then use it to create multiple simultaneous
|
||||
different instances of Panda windows.
|
||||
|
||||
Filenames passed through this interface are in native OS-specific
|
||||
form, e.g. with a leading drive letter and backslashes, not in
|
||||
Panda's Unix-like form (except on Unix-based OSes, of course).
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef BUILDING_P3D_PLUGIN
|
||||
#define EXPCL_P3D_PLUGIN __declspec(dllexport)
|
||||
#else
|
||||
#define EXPCL_P3D_PLUGIN __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#else /* _WIN32 */
|
||||
#define EXPCL_P3D_PLUGIN
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* In the following function prototypes, all functions are declared
|
||||
initially as typedefs only, and then the actual function references
|
||||
are finally declared at the end of this file, but only if
|
||||
P3D_PLUGIN_PROTOTYPES is defined. This is intended to allow
|
||||
including this file without building an implicit reference to the
|
||||
functions themselves, allowing the plugin library to be loaded via
|
||||
an explicit LoadLibrary() or equivalent call. */
|
||||
|
||||
/************************ GLOBAL FUNCTIONS **************************/
|
||||
|
||||
/* The following interfaces are global to the plugin space, as opposed
|
||||
to being specific to a particular instance. */
|
||||
|
||||
/* This function should be called immediately after the plugin is
|
||||
loaded. The config_xml parameter is the plugin configuration data,
|
||||
formatted as an XML stream (it contains the XML data itself; it is
|
||||
not a filename). The exact contents of this XML stream are
|
||||
documented elsewhere. This config_xml parameter may be the empty
|
||||
string or NULL; if so, the plugin will use its own internal default
|
||||
configuration.
|
||||
|
||||
The dll_filename parameter is the filename of the plugin's dll
|
||||
itself, which is needed for self-patching.
|
||||
|
||||
This function returns true if the plugin is valid, false otherwise.
|
||||
If it returns false, the host should not call any more functions in
|
||||
this API, and should immediately unload the DLL and (if possible)
|
||||
download a new one. */
|
||||
typedef bool
|
||||
P3D_initialize_func(const char *config_xml, const char *dll_filename);
|
||||
|
||||
/* This function frees a pointer returned by
|
||||
P3D_instance_get_property(), or another similar function that
|
||||
returns a dynamically-allocated string. */
|
||||
typedef void
|
||||
P3D_free_string_func(char *string);
|
||||
|
||||
/********************** INSTANCE MANAGEMENT **************************/
|
||||
|
||||
/* The following interfaces define the API to manage individual
|
||||
Panda3D instances. Each instance can display a separate 3-D
|
||||
graphics window simultaneously on the host or on the desktop. The
|
||||
instances operate generally independently of each other. */
|
||||
|
||||
/* This structure defines the handle to a single instance. The host
|
||||
may access the _request_pending member, which will be true if the
|
||||
host should call P3D_instance_get_request(). */
|
||||
typedef struct {
|
||||
bool _request_pending;
|
||||
|
||||
/* Additional opaque data may be stored here. */
|
||||
} P3D_instance;
|
||||
|
||||
/* This structure abstracts out the various window handle types for
|
||||
the different platforms. */
|
||||
typedef struct {
|
||||
#ifdef _WIN32
|
||||
HWND _hwnd;
|
||||
#endif
|
||||
} P3D_window_handle;
|
||||
|
||||
/* This enum lists the different kinds of window types that may be
|
||||
requested for the instance. These define the way that the instance
|
||||
will create its main Panda3D window. The instance will treat this
|
||||
as a request only; it is always free to create whatever kind of
|
||||
window it likes. */
|
||||
typedef enum {
|
||||
/* Embedded: the plugin window is embedded within the host window.
|
||||
This is the normal kind of window for an object embedded within a
|
||||
browser page. Pass a valid window handle in for parent_window,
|
||||
and valid coordinates on the parent window for win_x, win_y,
|
||||
win_width, win_height. */
|
||||
P3D_WT_embedded,
|
||||
|
||||
/* Toplevel: the plugin window is a toplevel window on the user's
|
||||
desktop. Pass valid desktop coordinates in for win_x, win_y,
|
||||
win_width, and win_height. If all of these are zero, the plugin
|
||||
will create a window wherever it sees fit. */
|
||||
P3D_WT_toplevel,
|
||||
|
||||
/* Fullscreen: the plugin window is a fullscreen window, completely
|
||||
overlaying the entire screen and changing the desktop resolution.
|
||||
Pass a valid desktop size in for win_width and win_height (win_x
|
||||
and win_y are ignored). If win_width and win_height are zero,
|
||||
the plugin will create a fullscreen window of its own preferred
|
||||
size. */
|
||||
P3D_WT_fullscreen,
|
||||
|
||||
/* Hidden: there is no window at all for the plugin. */
|
||||
P3D_WT_hidden,
|
||||
|
||||
} P3D_window_type;
|
||||
|
||||
|
||||
/* This function pointer must be passed to P3D_create_instance(),
|
||||
below. The host must pass in a pointer to a valid function in the
|
||||
host's address space, or NULL. If not NULL, this function will be
|
||||
called asynchronously by the plugin when the plugin needs to make a
|
||||
request from the host. After this notification has been received,
|
||||
the host should call P3D_instance_get_request() (at its
|
||||
convenience) to retrieve the actual plugin request. If the host
|
||||
passes NULL for this function pointer, asynchronous notifications
|
||||
will not be provided, and the host must be responsible for calling
|
||||
P3D_instance_get_request() from time to time. */
|
||||
|
||||
/* Note that, unlike the other func typedefs in this header file, this
|
||||
declaration is not naming a function within the plugin itself.
|
||||
Instead, it is a typedef for a function pointer that must be
|
||||
supplied by the host. */
|
||||
|
||||
typedef void
|
||||
P3D_request_ready_func(P3D_instance *instance);
|
||||
|
||||
/* This structure is used to represent a single keyword/value pair
|
||||
that appears within the embed syntax on the HTML page. An array of
|
||||
these values is passed to the P3D instance to represent all of the
|
||||
additional keywords that may appear within this syntax; it is up to
|
||||
the plugin to interpret these additional keywords correctly. */
|
||||
typedef struct {
|
||||
char *_keyword;
|
||||
char *_value;
|
||||
} P3D_token;
|
||||
|
||||
/* This function creates a new Panda3D instance. For p3d_filename
|
||||
pass the name of a file on disk that contains the contents of the
|
||||
p3d file that should be launched within the instance. For tokens,
|
||||
pass an array of P3D_token elements (above), which correspond to
|
||||
the user-supplied keyword/value pairs that may appear in the embed
|
||||
token within the HTML syntax; the host is responsible for
|
||||
allocating this array, and for deallocating it after this call (the
|
||||
plugin will make its own copy of the array). */
|
||||
|
||||
typedef P3D_instance *
|
||||
P3D_create_instance_func(P3D_request_ready_func *func,
|
||||
const char *p3d_filename,
|
||||
P3D_window_type window_type,
|
||||
int win_x, int win_y,
|
||||
int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const P3D_token *tokens[], size_t tokens_size);
|
||||
|
||||
|
||||
/* Call this function to interrupt a particular instance and stop it
|
||||
from rendering, for instance when the user navigates away from the
|
||||
page containing it. After calling this function, you should not
|
||||
reference the P3D_instance pointer again. */
|
||||
typedef void
|
||||
P3D_instance_finish_func(P3D_instance *instance);
|
||||
|
||||
|
||||
/********************** SCRIPTING SUPPORT **************************/
|
||||
|
||||
/* The following interfaces are provided to support controlling the
|
||||
plugin via JavaScript or related interfaces on the browser. */
|
||||
|
||||
/* Call this function to query whether the instance has a property of
|
||||
the indicated name. If this returns true, you may then query
|
||||
P3D_instance_get_property() or P3D_instance_set_property(). */
|
||||
typedef bool
|
||||
P3D_instance_has_property_func(P3D_instance *instance,
|
||||
const char *property_name);
|
||||
|
||||
/* Call this function to query the value of the indicated property.
|
||||
It is an error to call this if the property does not exist; call
|
||||
P3D_instance_has_property() first to ensure this is so. The return
|
||||
value has been dynamically allocated and should be passed to
|
||||
P3D_free_string() when it is no longer needed. */
|
||||
typedef char *
|
||||
P3D_instance_get_property_func(P3D_instance *instance,
|
||||
const char *property_name);
|
||||
|
||||
/* Call this function to set the value of the indicated property. */
|
||||
typedef void
|
||||
P3D_instance_set_property_func(P3D_instance *instance,
|
||||
const char *property_name,
|
||||
const char *value);
|
||||
|
||||
/********************** REQUEST HANDLING **************************/
|
||||
|
||||
/* The plugin may occasionally have an asynchronous request to pass up
|
||||
to the host. The following structures implement this interface.
|
||||
The design is intended to support single-threaded as well as
|
||||
multi-threaded implementations in the host; there is only the one
|
||||
callback function, P3D_request_ready (above), which may be called
|
||||
asynchronously by the plugin. The host should be careful that this
|
||||
callback function is protected from mutual access. The callback
|
||||
function implementation may be as simple as setting a flag that the
|
||||
host will later check within its main processing loop.
|
||||
|
||||
Once P3D_request_ready() has been received, the host should call
|
||||
P3D_instance_get_request() to query the nature of the request.
|
||||
This call may be made synchronously, i.e. within the host's main
|
||||
processing loop. After each request is serviced, the host should
|
||||
release the request via P3D_request_finish() and then call
|
||||
P3D_instance_get_request() again until that function returns NULL.
|
||||
|
||||
The requests themselves are implemented via a hierarchy of structs.
|
||||
Each request is stored in a different kind of struct, allowing the
|
||||
different requests to store a variety of data. An enumerated value
|
||||
indicates the particular request type retrieved. */
|
||||
|
||||
/* This represents the type of a request returned by
|
||||
P3D_instance_get_request. More types may be added later. */
|
||||
typedef enum {
|
||||
P3D_RT_stop,
|
||||
P3D_RT_new_config_xml,
|
||||
P3D_RT_patch,
|
||||
P3D_RT_get_url,
|
||||
P3D_RT_post_url,
|
||||
} P3D_request_type;
|
||||
|
||||
/* Structures corresponding to the request types in the above enum. */
|
||||
|
||||
/* A stop request. The instance would like to stop itself. No
|
||||
additional data is required. The host should respond by calling
|
||||
P3D_instance_finish(). */
|
||||
typedef struct {
|
||||
} P3D_request_stop;
|
||||
|
||||
/* A new config_xml request. The plugin has determined that its
|
||||
operating environment has changed, and that a new config.xml file
|
||||
should be stored for future sessions. The plugin passes a new
|
||||
config_xml data stream to the host, which should save it
|
||||
permanently within its own cache. The original config_xml should
|
||||
be replaced with this new stream; for all future sessions, when the
|
||||
host loads and starts the plugin DLL, it should pass this new
|
||||
config_xml stream to the P3D_initialize() function. */
|
||||
typedef struct {
|
||||
const char *_config_xml;
|
||||
} P3D_request_new_config_xml;
|
||||
|
||||
/* A patch request. The plugin has determined that it is out of date
|
||||
and needs to be patched. It has already applied the patch to
|
||||
itself, and the resulting patched dll is referenced in the request
|
||||
data. The host should respond by finishing all active instances,
|
||||
unloading the DLL, moving the patched dll onto the original DLL,
|
||||
and reloading the DLL and (optionally) restarting the instances. */
|
||||
typedef struct {
|
||||
const char *_patched_filename;
|
||||
} P3D_request_patch;
|
||||
|
||||
/* A get_url request. The plugin would like to retrieve data for a
|
||||
particular URL. The plugin is responsible for supplying a valid
|
||||
URL string, and a unique integer ID. The unique ID is needed to
|
||||
feed the results of the URL back to the plugin. If possible, the
|
||||
host should be prepared to handle multiple get_url requests in
|
||||
parallel, but it is allowed to handle them all one at a time if
|
||||
necessary. As data comes in from the url, the host should call
|
||||
P3D_instance_feed_url_stream().
|
||||
*/
|
||||
typedef struct {
|
||||
const char *_url;
|
||||
int _unique_id;
|
||||
} P3D_request_get_url;
|
||||
|
||||
/* A post_url request. Similar to get_url, but additional data is to
|
||||
be sent via POST to the indicated URL. The result of the POST is
|
||||
returned in a mechanism similar to get_url.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *_url;
|
||||
const char *_post_data;
|
||||
size_t _post_data_size;
|
||||
int _unique_id;
|
||||
} P3D_request_post_url;
|
||||
|
||||
/* This is the overall structure that represents a single request. It
|
||||
is returned by P3D_instance_get_request(). */
|
||||
typedef struct {
|
||||
P3D_instance *_instance;
|
||||
P3D_request_type _request_type;
|
||||
union {
|
||||
P3D_request_stop _stop;
|
||||
P3D_request_new_config_xml _new_config_xml;
|
||||
P3D_request_patch _patch;
|
||||
P3D_request_get_url _get_url;
|
||||
P3D_request_post_url _post_url;
|
||||
} _request;
|
||||
} P3D_request;
|
||||
|
||||
/* After a call to P3D_request_ready(), or from time to time in
|
||||
general, the host should call this function to see if there are any
|
||||
pending requests from the plugin. The function will return a
|
||||
freshly-allocated request if there is a request ready, or NULL if
|
||||
there are no requests. After a receipt of P3D_request_ready(),
|
||||
the host should call this function repeatedly until it returns NULL
|
||||
(there might be multiple requests for a single receipt of
|
||||
P3D_request_ready()). Each request should be processed, then
|
||||
released via P3D_request_finish(). */
|
||||
typedef P3D_request *
|
||||
P3D_instance_get_request_func(P3D_instance *instance);
|
||||
|
||||
/* This method may also be used to test whether a request to be ready.
|
||||
If any open instance has a pending request, this function will
|
||||
return a pointer to one of them (which you may then pass to
|
||||
P3D_instance_get_request_func). If no instances have a pending
|
||||
request, this function will return NULL. If wait is true, this
|
||||
function will never return NULL unless there are no instances open;
|
||||
instead, it will wait indefinitely until there is a request
|
||||
available.
|
||||
|
||||
Note that, due to race conditions, it is possible for this function
|
||||
to return a P3D_instance that does not in fact have any requests
|
||||
pending (another thread may have checked the request first). You
|
||||
should always verify that the return value of
|
||||
P3D_instance_get_request() is not NULL. */
|
||||
typedef P3D_instance *
|
||||
P3D_check_request_func(bool wait);
|
||||
|
||||
/* A request retrieved by P3D_instance_get_request() should eventually
|
||||
be passed here, after it has been handled, to deallocate its
|
||||
resources and prevent a memory leak. The 'handled' flag should be
|
||||
passed true if the host has handled the request, or false if it has
|
||||
ignored it (e.g. because it does not implement support for this
|
||||
particular request type). After calling this function, you should
|
||||
not reference the P3D_request pointer again. */
|
||||
typedef void
|
||||
P3D_request_finish_func(P3D_request *request, bool handled);
|
||||
|
||||
/* This code is passed to P3D_instance_feed_url_stream, below, as data
|
||||
is retrieved from the URL. */
|
||||
typedef enum {
|
||||
/* in progress: the query is still in progress, and another call
|
||||
will be made in the future. */
|
||||
P3D_RC_in_progress,
|
||||
|
||||
/* done: the query is done, and all data has been retrieved without
|
||||
error. This call represents the last of the data. */
|
||||
P3D_RC_done,
|
||||
|
||||
/* generic_error: some error other than an HTTP error has occurred,
|
||||
for instance, lack of connection to the server, or malformed URL.
|
||||
No more data will be forthcoming. */
|
||||
P3D_RC_generic_error,
|
||||
|
||||
/* An HTTP error has occurred, for instance 404. The particular
|
||||
status code will be supplied in the http_status_code parameter.
|
||||
There may or may not be data associated with this error as well.
|
||||
However, no more data will be delivered after this call. */
|
||||
P3D_RC_http_error,
|
||||
} P3D_result_code;
|
||||
|
||||
/* This function is used by the host to handle a get_url request,
|
||||
above. As it retrieves data from the URL, it should call this
|
||||
function from time to time to feed that data to the plugin.
|
||||
|
||||
instance and unique_id are from the original get_url() request.
|
||||
|
||||
result_code and http_status_code indicates the current status of
|
||||
the request, as described above; the call will be made again in the
|
||||
future if its result_code is P3D_RC_in_progress.
|
||||
|
||||
total_expected_data represents the host's best guess at the total
|
||||
amount of data that will be retrieved. It is acceptable if this
|
||||
guess doesn't match the actual data received at all. Set it to 0
|
||||
if the host has no idea. This value may change from one call to
|
||||
the next.
|
||||
|
||||
this_data and this_data_size describe the most recent block of data
|
||||
retrieved from the URL. Each chunk of data passed to this function
|
||||
is appended together by the plugin to define the total set of data
|
||||
retrieved from the URL. For a particular call to feed_url_stream,
|
||||
this may contain no data at all (e.g. this_data_size may be 0).
|
||||
*/
|
||||
typedef void
|
||||
P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id,
|
||||
P3D_result_code result_code,
|
||||
int http_status_code,
|
||||
size_t total_expected_data,
|
||||
const unsigned char *this_data,
|
||||
size_t this_data_size);
|
||||
|
||||
|
||||
#ifdef P3D_FUNCTION_PROTOTYPES
|
||||
|
||||
/* Define all of the actual prototypes for the above functions. */
|
||||
EXPCL_P3D_PLUGIN P3D_initialize_func P3D_initialize;
|
||||
EXPCL_P3D_PLUGIN P3D_free_string_func P3D_free_string;
|
||||
EXPCL_P3D_PLUGIN P3D_create_instance_func P3D_create_instance;
|
||||
EXPCL_P3D_PLUGIN P3D_instance_finish_func P3D_instance_finish;
|
||||
EXPCL_P3D_PLUGIN P3D_instance_has_property_func P3D_instance_has_property;
|
||||
EXPCL_P3D_PLUGIN P3D_instance_get_property_func P3D_instance_get_property;
|
||||
EXPCL_P3D_PLUGIN P3D_instance_set_property_func P3D_instance_set_property;
|
||||
EXPCL_P3D_PLUGIN P3D_instance_get_request_func P3D_instance_get_request;
|
||||
EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request;
|
||||
EXPCL_P3D_PLUGIN P3D_request_finish_func P3D_request_finish;
|
||||
EXPCL_P3D_PLUGIN P3D_instance_feed_url_stream_func P3D_instance_feed_url_stream;
|
||||
#endif /* P3D_FUNCTION_PROTOTYPES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* P3D_PLUGIN_H */
|
||||
|
||||
|
43
direct/src/plugin/p3d_plugin_common.h
Normal file
43
direct/src/plugin/p3d_plugin_common.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Filename: p3d_plugin_common.h
|
||||
// Created by: drose (29May09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3D_PLUGIN_COMMON
|
||||
#define P3D_PLUGIN_COMMON
|
||||
|
||||
// This header file is included by all C++ files in this directory; it
|
||||
// provides some common symbol declarations.
|
||||
|
||||
#define P3D_FUNCTION_PROTOTYPES
|
||||
#define BUILDING_P3D_PLUGIN
|
||||
|
||||
#include "p3d_plugin.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define INLINE inline
|
||||
|
||||
#ifdef _WIN32
|
||||
#define LOCK CRITICAL_SECTION
|
||||
#define INIT_LOCK(lock) InitializeCriticalSection(&(lock))
|
||||
#define ACQUIRE_LOCK(lock) EnterCriticalSection(&(lock))
|
||||
#define RELEASE_LOCK(lock) LeaveCriticalSection(&(lock))
|
||||
#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
5
direct/src/plugin/p3d_plugin_composite1.cxx
Normal file
5
direct/src/plugin/p3d_plugin_composite1.cxx
Normal file
@ -0,0 +1,5 @@
|
||||
#include "p3d_plugin.cxx"
|
||||
#include "p3dInstance.cxx"
|
||||
#include "p3dInstanceManager.cxx"
|
||||
#include "p3dPython.cxx"
|
||||
#include "p3dSession.cxx"
|
366
direct/src/plugin/panda3d.cxx
Normal file
366
direct/src/plugin/panda3d.cxx
Normal file
@ -0,0 +1,366 @@
|
||||
// Filename: panda3d.cxx
|
||||
// Created by: drose (03Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3d_plugin.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wingetopt.h"
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const string default_plugin_filename = "libp3d_plugin";
|
||||
|
||||
P3D_initialize_func *P3D_initialize;
|
||||
P3D_free_string_func *P3D_free_string;
|
||||
P3D_create_instance_func *P3D_create_instance;
|
||||
P3D_instance_finish_func *P3D_instance_finish;
|
||||
P3D_instance_has_property_func *P3D_instance_has_property;
|
||||
P3D_instance_get_property_func *P3D_instance_get_property;
|
||||
P3D_instance_set_property_func *P3D_instance_set_property;
|
||||
P3D_instance_get_request_func *P3D_instance_get_request;
|
||||
P3D_check_request_func *P3D_check_request;
|
||||
P3D_request_finish_func *P3D_request_finish;
|
||||
P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream;
|
||||
|
||||
bool
|
||||
load_plugin(const string &config_xml_filename,
|
||||
const string &p3d_plugin_filename) {
|
||||
string filename = p3d_plugin_filename;
|
||||
if (filename.empty()) {
|
||||
// Look for the plugin along the path.
|
||||
filename = default_plugin_filename;
|
||||
#ifdef _WIN32
|
||||
filename += ".dll";
|
||||
#else
|
||||
filename += ".so";
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
HMODULE module = LoadLibrary(filename.c_str());
|
||||
if (module == NULL) {
|
||||
// Couldn't load the DLL.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the full path to the DLL in case it was found along the path.
|
||||
static const buffer_size = 4096;
|
||||
static char buffer[buffer_size];
|
||||
if (GetModuleFileName(module, buffer, buffer_size) != 0) {
|
||||
if (GetLastError() != 0) {
|
||||
filename = buffer;
|
||||
}
|
||||
}
|
||||
cerr << filename << "\n";
|
||||
|
||||
// Now get all of the function pointers.
|
||||
P3D_initialize = (P3D_initialize_func *)GetProcAddress(module, "P3D_initialize");
|
||||
P3D_free_string = (P3D_free_string_func *)GetProcAddress(module, "P3D_free_string");
|
||||
P3D_create_instance = (P3D_create_instance_func *)GetProcAddress(module, "P3D_create_instance");
|
||||
P3D_instance_finish = (P3D_instance_finish_func *)GetProcAddress(module, "P3D_instance_finish");
|
||||
P3D_instance_has_property = (P3D_instance_has_property_func *)GetProcAddress(module, "P3D_instance_has_property");
|
||||
P3D_instance_get_property = (P3D_instance_get_property_func *)GetProcAddress(module, "P3D_instance_get_property");
|
||||
P3D_instance_set_property = (P3D_instance_set_property_func *)GetProcAddress(module, "P3D_instance_set_property");
|
||||
P3D_instance_get_request = (P3D_instance_get_request_func *)GetProcAddress(module, "P3D_instance_get_request");
|
||||
P3D_check_request = (P3D_check_request_func *)GetProcAddress(module, "P3D_check_request");
|
||||
P3D_request_finish = (P3D_request_finish_func *)GetProcAddress(module, "P3D_request_finish");
|
||||
P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)GetProcAddress(module, "P3D_instance_feed_url_stream");
|
||||
#endif // _WIN32
|
||||
|
||||
// Ensure that all of the function pointers have been found.
|
||||
if (P3D_initialize == NULL ||
|
||||
P3D_free_string == NULL ||
|
||||
P3D_create_instance == NULL ||
|
||||
P3D_instance_finish == NULL ||
|
||||
P3D_instance_has_property == NULL ||
|
||||
P3D_instance_get_property == NULL ||
|
||||
P3D_instance_set_property == NULL ||
|
||||
P3D_instance_get_request == NULL ||
|
||||
P3D_check_request == NULL ||
|
||||
P3D_request_finish == NULL ||
|
||||
P3D_instance_feed_url_stream == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Successfully loaded.
|
||||
if (!P3D_initialize(NULL, filename.c_str())) {
|
||||
// Oops, failure to initialize.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
handle_request(P3D_request *request) {
|
||||
bool handled = false;
|
||||
|
||||
switch (request->_request_type) {
|
||||
case P3D_RT_stop:
|
||||
P3D_instance_finish(request->_instance);
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Some request types are not handled.
|
||||
break;
|
||||
};
|
||||
|
||||
P3D_request_finish(request, handled);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
LONG WINAPI
|
||||
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
switch (msg) {
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
};
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void
|
||||
make_parent_window(P3D_window_handle &parent_window,
|
||||
int win_width, int win_height) {
|
||||
WNDCLASS wc;
|
||||
|
||||
HINSTANCE application = GetModuleHandle(NULL);
|
||||
ZeroMemory(&wc, sizeof(WNDCLASS));
|
||||
wc.lpfnWndProc = window_proc;
|
||||
wc.hInstance = application;
|
||||
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
||||
wc.lpszClassName = "panda3d";
|
||||
|
||||
if (!RegisterClass(&wc)) {
|
||||
cerr << "Could not register window class!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DWORD window_style =
|
||||
WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
|
||||
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
|
||||
WS_SIZEBOX | WS_MAXIMIZEBOX;
|
||||
|
||||
HWND toplevel_window =
|
||||
CreateWindow("panda3d", "Panda3D", window_style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, win_width, win_height,
|
||||
NULL, NULL, application, 0);
|
||||
if (!toplevel_window) {
|
||||
cerr << "Could not create toplevel window!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ShowWindow(toplevel_window, SW_SHOWNORMAL);
|
||||
|
||||
parent_window._hwnd = toplevel_window;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
void
|
||||
usage() {
|
||||
cerr
|
||||
<< "\nUsage:\n"
|
||||
<< " panda3d [opts] file.p3d [file_b.p3d file_c.p3d ...]\n\n"
|
||||
|
||||
<< "This program is used to execute a Panda3D application bundle stored\n"
|
||||
<< "in a .p3d file. Normally you only run one p3d bundle at a time,\n"
|
||||
<< "but it is possible to run multiple bundles simultaneously.\n\n"
|
||||
|
||||
<< "Options:\n\n"
|
||||
|
||||
<< " -c config.xml\n"
|
||||
<< " Specify the name of the config.xml file that informs the Panda\n"
|
||||
<< " plugin where to download patches and such. This is normally\n"
|
||||
<< " not necessary to specify, since it is already stored within\n"
|
||||
<< " the Panda plugin itself.\n\n"
|
||||
|
||||
<< " -p p3d_plugin.dll\n"
|
||||
<< " Specify the full path to the particular Panda plugin DLL to\n"
|
||||
<< " run. Normally, this will be found by searching in the usual\n"
|
||||
<< " places.\n\n"
|
||||
|
||||
<< " -t [toplevel|embedded|fullscreen|hidden]\n"
|
||||
<< " Specify the type of graphic window to create. If you specify "
|
||||
<< " \"embedded\", a new window is created to be the parent.\n\n"
|
||||
|
||||
<< " -s width,height\n"
|
||||
<< " Specify the size of the graphic window.\n\n"
|
||||
|
||||
<< " -o x,y\n"
|
||||
<< " Specify the position (origin) of the graphic window on the\n"
|
||||
<< " screen, or on the parent window.\n\n";
|
||||
}
|
||||
|
||||
bool
|
||||
parse_int_pair(char *arg, int &x, int &y) {
|
||||
char *endptr;
|
||||
x = strtol(arg, &endptr, 10);
|
||||
if (*endptr == ',') {
|
||||
y = strtol(endptr + 1, &endptr, 10);
|
||||
if (*endptr == '\0') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Some parse error on the string.
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
const char *optstr = "c:p:t:s:o:h";
|
||||
|
||||
string config_xml_filename;
|
||||
string p3d_plugin_filename;
|
||||
P3D_window_type window_type = P3D_WT_toplevel;
|
||||
int win_x = 0, win_y = 0;
|
||||
int win_width = 0, win_height = 0;
|
||||
|
||||
int flag = getopt(argc, argv, optstr);
|
||||
|
||||
while (flag != EOF) {
|
||||
switch (flag) {
|
||||
case 'c':
|
||||
config_xml_filename = optarg;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
p3d_plugin_filename = optarg;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if (strcmp(optarg, "toplevel") == 0) {
|
||||
window_type = P3D_WT_toplevel;
|
||||
} else if (strcmp(optarg, "embedded") == 0) {
|
||||
window_type = P3D_WT_embedded;
|
||||
} else if (strcmp(optarg, "fullscreen") == 0) {
|
||||
window_type = P3D_WT_fullscreen;
|
||||
} else if (strcmp(optarg, "hidden") == 0) {
|
||||
window_type = P3D_WT_hidden;
|
||||
} else {
|
||||
cerr << "Invalid value for -t: " << optarg << "\n";
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (!parse_int_pair(optarg, win_width, win_height)) {
|
||||
cerr << "Invalid value for -s: " << optarg << "\n";
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (!parse_int_pair(optarg, win_x, win_y)) {
|
||||
cerr << "Invalid value for -o: " << optarg << "\n";
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
flag = getopt(argc, argv, optstr);
|
||||
}
|
||||
|
||||
argc -= (optind-1);
|
||||
argv += (optind-1);
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!load_plugin(config_xml_filename, p3d_plugin_filename)) {
|
||||
cerr << "Unable to load Panda3D plugin.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
P3D_window_handle parent_window;
|
||||
if (window_type == P3D_WT_embedded) {
|
||||
// The user asked for an embedded window. Create a toplevel
|
||||
// window to be its parent, of the requested size.
|
||||
make_parent_window(parent_window, win_width, win_height);
|
||||
|
||||
// And center the graphics window within that parent window.
|
||||
win_x = (int)(win_width * 0.1);
|
||||
win_y = (int)(win_height * 0.1);
|
||||
win_width = (int)(win_width * 0.8);
|
||||
win_height = (int)(win_height * 0.8);
|
||||
}
|
||||
|
||||
// For now, only one instance at a time is supported. Ignore the
|
||||
// remaining command-line parameters.
|
||||
P3D_create_instance
|
||||
(NULL, argv[1],
|
||||
window_type, win_x, win_y, win_width, win_height, parent_window,
|
||||
NULL, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Wait for new messages from Windows, and new requests from the
|
||||
// plugin.
|
||||
MSG msg;
|
||||
int retval;
|
||||
retval = GetMessage(&msg, NULL, 0, 0);
|
||||
while (retval != 0) {
|
||||
if (retval == -1) {
|
||||
cerr << "Error processing message queue.\n";
|
||||
exit(1);
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
||||
// Check for new requests from the Panda3D plugin.
|
||||
P3D_instance *inst = P3D_check_request(false);
|
||||
while (inst != (P3D_instance *)NULL) {
|
||||
P3D_request *request = P3D_instance_get_request(inst);
|
||||
if (request != (P3D_request *)NULL) {
|
||||
handle_request(request);
|
||||
}
|
||||
inst = P3D_check_request(false);
|
||||
}
|
||||
retval = GetMessage(&msg, NULL, 0, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Now wait while we process pending requests.
|
||||
P3D_instance *inst = P3D_check_request(true);
|
||||
while (inst != (P3D_instance *)NULL) {
|
||||
P3D_request *request = P3D_instance_get_request(inst);
|
||||
if (request != (P3D_request *)NULL) {
|
||||
handle_request(request);
|
||||
}
|
||||
inst = P3D_check_request(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
// All instances have finished; we can exit.
|
||||
|
||||
return 0;
|
||||
}
|
75
direct/src/plugin/wingetopt.c
Normal file
75
direct/src/plugin/wingetopt.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
POSIX getopt for Windows
|
||||
|
||||
AT&T Public License
|
||||
|
||||
Code given out at the 1985 UNIFORUM conference in Dallas.
|
||||
*/
|
||||
|
||||
#ifndef __GNUC__
|
||||
|
||||
#include "wingetopt.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define NULL 0
|
||||
#define EOF (-1)
|
||||
#define ERR(s, c) if(opterr){\
|
||||
char errbuf[2];\
|
||||
errbuf[0] = c; errbuf[1] = '\n';\
|
||||
fputs(argv[0], stderr);\
|
||||
fputs(s, stderr);\
|
||||
fputc(c, stderr);}
|
||||
//(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
|
||||
//(void) write(2, s, (unsigned)strlen(s));\
|
||||
//(void) write(2, errbuf, 2);}
|
||||
|
||||
int opterr = 1;
|
||||
int optind = 1;
|
||||
int optopt;
|
||||
char *optarg;
|
||||
|
||||
int
|
||||
getopt(int argc, char **argv, const char *opts)
|
||||
{
|
||||
static int sp = 1;
|
||||
register int c;
|
||||
register char *cp;
|
||||
|
||||
if(sp == 1)
|
||||
if(optind >= argc ||
|
||||
argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
return(EOF);
|
||||
else if(strcmp(argv[optind], "--") == NULL) {
|
||||
optind++;
|
||||
return(EOF);
|
||||
}
|
||||
optopt = c = argv[optind][sp];
|
||||
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
|
||||
ERR(": illegal option -- ", c);
|
||||
if(argv[optind][++sp] == '\0') {
|
||||
optind++;
|
||||
sp = 1;
|
||||
}
|
||||
return('?');
|
||||
}
|
||||
if(*++cp == ':') {
|
||||
if(argv[optind][sp+1] != '\0')
|
||||
optarg = &argv[optind++][sp+1];
|
||||
else if(++optind >= argc) {
|
||||
ERR(": option requires an argument -- ", c);
|
||||
sp = 1;
|
||||
return('?');
|
||||
} else
|
||||
optarg = argv[optind++];
|
||||
sp = 1;
|
||||
} else {
|
||||
if(argv[optind][++sp] == '\0') {
|
||||
sp = 1;
|
||||
optind++;
|
||||
}
|
||||
optarg = NULL;
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
|
||||
#endif /* __GNUC__ */
|
32
direct/src/plugin/wingetopt.h
Normal file
32
direct/src/plugin/wingetopt.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
POSIX getopt for Windows
|
||||
|
||||
AT&T Public License
|
||||
|
||||
Code given out at the 1985 UNIFORUM conference in Dallas.
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#ifndef __GNUC__
|
||||
|
||||
#ifndef _WINGETOPT_H_
|
||||
#define _WINGETOPT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int opterr;
|
||||
extern int optind;
|
||||
extern int optopt;
|
||||
extern char *optarg;
|
||||
extern int getopt(int argc, char **argv, const char *opts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H_ */
|
||||
#endif /* __GNUC__ */
|
@ -30,29 +30,25 @@ default-model-extension .bam
|
||||
class ArgumentError(AttributeError):
|
||||
pass
|
||||
|
||||
def runPackedApp(args):
|
||||
if not args:
|
||||
raise ArgumentError, "No Panda app specified. Use:\npython RunAppMF.py app.mf"
|
||||
__packedAppEnvironmentInitialized = False
|
||||
|
||||
def initPackedAppEnvironment():
|
||||
""" This function sets up the Python environment suitably for
|
||||
running a packed app. It should only run once in any given
|
||||
session (and it includes logic to ensure this). """
|
||||
|
||||
global __packedAppEnvironmentInitialized
|
||||
if __packedAppEnvironmentInitialized:
|
||||
return
|
||||
|
||||
__packedAppEnvironmentInitialized = True
|
||||
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
|
||||
fname = Filename.fromOsSpecific(args[0])
|
||||
if not vfs.exists(fname):
|
||||
raise ArgumentError, "No such file: %s" % (args[0])
|
||||
|
||||
mf = Multifile()
|
||||
if not mf.openRead(fname):
|
||||
raise ArgumentError, "Not a Panda Multifile: %s" % (args[0])
|
||||
|
||||
# Clear *all* the mount points, including "/", so that we no
|
||||
# longer access the disk directly.
|
||||
vfs.unmountAll()
|
||||
|
||||
# Mount the Multifile under /mf, by convention, and make that our
|
||||
# "current directory".
|
||||
vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
|
||||
vfs.chdir(MultifileRoot)
|
||||
|
||||
# Make sure the directories on our standard Python path are mounted
|
||||
# read-only, so we can still load Python.
|
||||
for dirname in sys.path:
|
||||
@ -77,14 +73,6 @@ def runPackedApp(args):
|
||||
# Load the implicit App.prc file.
|
||||
loadPrcFileData(AppPrcFilename, AppPrc)
|
||||
|
||||
# Load any prc files in the root. We have to load them
|
||||
# explicitly, since the ConfigPageManager can't directly look
|
||||
# inside the vfs.
|
||||
for f in vfs.scanDirectory(MultifileRoot):
|
||||
if f.getFilename().getExtension() == 'prc':
|
||||
data = f.readFile(True)
|
||||
loadPrcFileData(f.getFilename().cStr(), data)
|
||||
|
||||
# Replace the builtin open and file symbols so user code will get
|
||||
# our versions by default, which can open and read files out of
|
||||
# the multifile.
|
||||
@ -93,10 +81,72 @@ def runPackedApp(args):
|
||||
os.listdir = file.listdir
|
||||
os.walk = file.walk
|
||||
|
||||
# Make "/mf" our "current directory", for running the multifiles
|
||||
# we plan to mount there.
|
||||
vfs.chdir(MultifileRoot)
|
||||
|
||||
def runPackedApp(args):
|
||||
if not args:
|
||||
raise ArgumentError, "No Panda app specified. Use:\npython RunAppMF.py app.mf"
|
||||
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
|
||||
fname = Filename.fromOsSpecific(args[0])
|
||||
if not vfs.exists(fname):
|
||||
raise ArgumentError, "No such file: %s" % (args[0])
|
||||
|
||||
fname.makeAbsolute()
|
||||
initPackedAppEnvironment()
|
||||
|
||||
mf = Multifile()
|
||||
if not mf.openRead(fname):
|
||||
raise ArgumentError, "Not a Panda Multifile: %s" % (args[0])
|
||||
|
||||
# Mount the Multifile under /mf, by convention.
|
||||
vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
|
||||
|
||||
# Load any prc files in the root. We have to load them
|
||||
# explicitly, since the ConfigPageManager can't directly look
|
||||
# inside the vfs. Use the Multifile interface to find the prc
|
||||
# files, rather than vfs.scanDirectory(), so we only pick up the
|
||||
# files in this particular multifile.
|
||||
for f in mf.getSubfileNames():
|
||||
fn = Filename(f)
|
||||
if fn.getDirname() == '' and fn.getExtension() == 'prc':
|
||||
pathname = '%s/%s' % (MultifileRoot, f)
|
||||
data = open(pathname, 'r').read()
|
||||
loadPrcFileData(pathname, data)
|
||||
|
||||
import main
|
||||
if hasattr(main, 'main') and callable(main.main):
|
||||
main.main()
|
||||
|
||||
def setupWindow(windowType, x, y, width, height, parent):
|
||||
if windowType == 'hidden':
|
||||
data = 'window-type none\n'
|
||||
else:
|
||||
data = 'window-type onscreen\n'
|
||||
|
||||
if windowType == 'fullscreen':
|
||||
data += 'fullscreen 1\n'
|
||||
else:
|
||||
data += 'fullscreen 0\n'
|
||||
|
||||
if windowType == 'embedded':
|
||||
data += 'parent-window-handle %s\n' % (parent)
|
||||
else:
|
||||
data += 'parent-window-handle 0\n'
|
||||
|
||||
if x or y:
|
||||
data += 'win-origin %s %s\n' % (x, y)
|
||||
if width or height:
|
||||
data += 'win-size %s %s\n' % (width, height)
|
||||
|
||||
loadPrcFileData("setupWindow", data)
|
||||
|
||||
def run():
|
||||
taskMgr.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
runPackedApp(sys.argv[1:])
|
||||
|
@ -36,15 +36,25 @@ linkDll = 'error'
|
||||
Python = None
|
||||
|
||||
# The directory that includes Python.h.
|
||||
PythonIPath = '/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5'
|
||||
PythonIPath = None
|
||||
|
||||
# The root directory of Microsoft Visual Studio (if relevant)
|
||||
MSVS = None
|
||||
|
||||
if sys.platform == 'win32':
|
||||
compileObj = "cl /wd4996 /Fo%(basename)s.obj /nologo /c /MD /Zi /O2 /Ob2 /EHsc /Zm300 /W3 %(filename)s"
|
||||
linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /out:%(basename)s.exe; mt -manifest %(basename)s.manifest -outputresource:%(basename)s.exe;2'
|
||||
linkDll = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /out:%(basename)s.dll; mt -manifest %(basename)s.manifest -outputresource:%(basename)s.dll;1'
|
||||
wtpython = '$WINTOOLS/sdk/python/Python-2.4.1'
|
||||
Python = Filename(ExecutionEnvironment.expandString(wtpython)).toOsSpecific()
|
||||
|
||||
MSVS = Filename('/c/Program Files/Microsoft Visual Studio .NET 2003').toOsSpecific()
|
||||
compileObj = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c /MD /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(python)s\Include" /I"%(python)s\PC" /I"%(msvs)s\Vc7\PlatformSDK\include" /I"%(msvs)s\Vc7\include" %(filename)s'
|
||||
linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /out:%(basename)s.exe %(basename)s.obj'
|
||||
linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(msvs)s\Vc7\PlatformSDK\lib" /LIBPATH:"%(msvs)s\Vc7\lib" /LIBPATH:"%(python)s\PCbuild" /out:%(basename)s.pyd %(basename)s.obj'
|
||||
|
||||
elif sys.platform == 'darwin':
|
||||
# OSX
|
||||
|
||||
PythonIPath = '/Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5'
|
||||
|
||||
compileObj = "gcc -fPIC -c -o %(basename)s.o -O2 -arch i386 -arch ppc -I %(pythonIPath)s %(filename)s"
|
||||
linkExe = "gcc -o %(basename)s %(basename)s.o -framework Python"
|
||||
linkDll = "gcc -shared -o %(basename)s.so %(basename)s.o -framework Python"
|
||||
@ -733,7 +743,7 @@ class Freezer:
|
||||
|
||||
initCode = dllInitCode % {
|
||||
'dllexport' : dllexport,
|
||||
'moduleName' : basename,
|
||||
'moduleName' : basename.split('.')[0],
|
||||
'newcount' : len(moduleList),
|
||||
}
|
||||
doCompile = self.compileDll
|
||||
@ -757,6 +767,8 @@ class Freezer:
|
||||
|
||||
def compileExe(self, filename, basename):
|
||||
compile = self.compileObj % {
|
||||
'python' : Python,
|
||||
'msvs' : MSVS,
|
||||
'pythonIPath' : PythonIPath,
|
||||
'filename' : filename,
|
||||
'basename' : basename,
|
||||
@ -766,6 +778,8 @@ class Freezer:
|
||||
raise StandardError
|
||||
|
||||
link = self.linkExe % {
|
||||
'python' : Python,
|
||||
'msvs' : MSVS,
|
||||
'filename' : filename,
|
||||
'basename' : basename,
|
||||
}
|
||||
@ -775,6 +789,8 @@ class Freezer:
|
||||
|
||||
def compileDll(self, filename, basename):
|
||||
compile = self.compileObj % {
|
||||
'python' : Python,
|
||||
'msvs' : MSVS,
|
||||
'pythonIPath' : PythonIPath,
|
||||
'filename' : filename,
|
||||
'basename' : basename,
|
||||
@ -784,6 +800,8 @@ class Freezer:
|
||||
raise StandardError
|
||||
|
||||
link = self.linkDll % {
|
||||
'python' : Python,
|
||||
'msvs' : MSVS,
|
||||
'filename' : filename,
|
||||
'basename' : basename,
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ Options:
|
||||
-o output
|
||||
Specifies the name of the resulting executable file to produce.
|
||||
If this ends in ".mf", a multifile is written instead of a frozen
|
||||
binary.
|
||||
binary. If it ends in ".dll", ".pyd", or ".so", a shared library
|
||||
is written.
|
||||
|
||||
-x module[,module...]
|
||||
Specifies a comma-separated list of Python modules to exclude from
|
||||
@ -85,10 +86,20 @@ if __name__ == '__main__':
|
||||
if len(args) != 1:
|
||||
usage(1, 'Only one main file may be specified.')
|
||||
|
||||
freezer.setMain(args[0])
|
||||
outputType = 'exe'
|
||||
bl = basename.lower()
|
||||
if bl.endswith('.mf'):
|
||||
outputType = 'mf'
|
||||
elif bl.endswith('.dll') or bl.endswith('.pyd') or bl.endswith('.so'):
|
||||
basename = os.path.splitext(basename)[0]
|
||||
outputType = 'dll'
|
||||
|
||||
freezer.addModule(args[0])
|
||||
if outputType != 'dll':
|
||||
freezer.setMain(args[0])
|
||||
freezer.done()
|
||||
|
||||
if basename.lower().endswith('.mf'):
|
||||
if outputType == 'mf':
|
||||
freezer.writeMultifile(basename)
|
||||
else:
|
||||
freezer.generateCode(basename)
|
||||
|
Loading…
x
Reference in New Issue
Block a user