cleaner p3d scripts

This commit is contained in:
David Rose 2009-06-24 09:39:11 +00:00
parent db1043fc09
commit ec23ed2a43
18 changed files with 806 additions and 268 deletions

View File

@ -25,8 +25,10 @@
p3dPackage.h p3dPackage.I \
p3dProgressWindow.h p3dProgressWindow.I \
p3dSession.h p3dSession.I \
p3dSplashWindow.h p3dSplashWindow.I \
p3dWindowParams.h p3dWindowParams.I \
p3dWinProgressWindow.h p3dWinProgressWindow.I
p3dWinProgressWindow.h p3dWinProgressWindow.I \
p3dWinSplashWindow.h p3dWinSplashWindow.I
#define INCLUDED_SOURCES \
p3d_plugin.cxx \
@ -38,9 +40,11 @@
p3dMultifileReader.cxx \
p3dPackage.cxx \
p3dProgressWindow.cxx \
p3dSplashWindow.cxx \
p3dSession.cxx \
p3dWindowParams.cxx \
p3dWinProgressWindow.cxx
p3dWinProgressWindow.cxx \
p3dWinSplashWindow.cxx
#define INSTALL_HEADERS \
p3d_plugin.h

View File

@ -17,10 +17,18 @@
#include "p3dDownload.h"
#include "p3dSession.h"
#include "p3dPackage.h"
#include "p3dSplashWindow.h"
#include "p3dWinSplashWindow.h"
#include <sstream>
#include <algorithm>
#ifdef _WIN32
typedef P3DWinSplashWindow SplashWindowType;
#else
typedef P3DSplashWindow SplashWindowType;
#endif
int P3DInstance::_next_instance_id = 0;
////////////////////////////////////////////////////////////////////
@ -43,6 +51,8 @@ P3DInstance(P3D_request_ready_func *func, void *user_data) :
INIT_LOCK(_request_lock);
_session = NULL;
_splash_window = NULL;
_instance_window_opened = false;
_requested_stop = false;
}
@ -65,6 +75,11 @@ P3DInstance::
}
_packages.clear();
if (_splash_window != NULL) {
delete _splash_window;
_splash_window = NULL;
}
// TODO: empty _pending_requests queue and _downloads map.
// TODO: Is it possible for someone to delete an instance while a
@ -82,6 +97,11 @@ set_fparams(const P3DFileParams &fparams) {
_got_fparams = true;
_fparams = fparams;
// Update the splash window.
if (_splash_window != NULL) {
_splash_window->set_fparams(_fparams);
}
// This also sets up some internal data based on the contents of the
// above file and the associated tokens.
@ -106,6 +126,17 @@ set_wparams(const P3DWindowParams &wparams) {
_got_wparams = true;
_wparams = wparams;
// Update or create the splash window.
if (!_instance_window_opened) {
if (_splash_window == NULL) {
_splash_window = new SplashWindowType(this);
_splash_window->open_window();
} else {
_splash_window->set_wparams(_wparams);
}
}
// Update the instance in the sub-process.
if (_session != NULL) {
TiXmlDocument *doc = new TiXmlDocument;
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");

View File

@ -25,6 +25,7 @@
#include <tinyxml.h>
class P3DSession;
class P3DSplashWindow;
class P3DDownload;
class P3DPackage;
@ -85,6 +86,8 @@ private:
string _session_key;
string _python_version;
P3DSession *_session;
P3DSplashWindow *_splash_window;
bool _instance_window_opened;
typedef vector<P3DPackage *> Packages;
Packages _packages;

View File

@ -88,37 +88,46 @@ P3DPythonRun::
////////////////////////////////////////////////////////////////////
bool P3DPythonRun::
run_python() {
// Now load runappmf.pyd.
PyObject *runappmf = PyImport_ImportModule("runappmf");
if (runappmf == NULL) {
// First, load runp3d_frozen.pyd. Since this is a magic frozen pyd,
// importing it automatically makes all of its frozen contents
// available to import as well.
PyObject *runp3d_frozen = PyImport_ImportModule("runp3d_frozen");
if (runp3d_frozen == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(runappmf);
Py_DECREF(runp3d_frozen);
// And get the pointers to the functions needed within the module.
PyObject *appmf = PyImport_ImportModule("direct.showbase.RunAppMF");
if (appmf == NULL) {
// So now we can import the module itself.
PyObject *runp3d = PyImport_ImportModule("direct.showutil.runp3d");
if (runp3d == NULL) {
PyErr_Print();
return false;
}
_setP3DFilename = PyObject_GetAttrString(appmf, "setP3DFilename");
if (_setP3DFilename == NULL) {
// Get the pointers to the objects needed within the module.
PyObject *AppRunner = PyObject_GetAttrString(runp3d, "AppRunner");
if (AppRunner == NULL) {
PyErr_Print();
return false;
}
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
if (_setupWindow == NULL) {
// Construct an instance of AppRunner.
_runner = PyObject_CallFunction(AppRunner, "");
if (_runner == NULL) {
PyErr_Print();
return false;
}
_taskMgr = PyObject_GetAttrString(appmf, "taskMgr");
Py_DECREF(AppRunner);
// Get the global TaskManager.
_taskMgr = PyObject_GetAttrString(runp3d, "taskMgr");
if (_taskMgr == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(appmf);
Py_DECREF(runp3d);
// Now add check_comm() as a task.
_check_comm_task = new GenericAsyncTask("check_comm", st_check_comm, this);
@ -359,8 +368,8 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) {
xtoken = xtoken->NextSiblingElement("token");
}
PyObject *result = PyObject_CallFunction
(_setP3DFilename, "sO", p3d_filename.c_str(), token_list);
PyObject *result = PyObject_CallMethod
(_runner, "setP3DFilename", "sO", p3d_filename.c_str(), token_list);
Py_DECREF(token_list);
if (result == NULL) {
@ -415,10 +424,10 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
}
#endif
// TODO: direct this into the particular instance. Requires
// specialized ShowBase replacement.
PyObject *result = PyObject_CallFunction
(_setupWindow, "siiiii", window_type.c_str(),
// TODO: direct this into the particular instance. This will
// require a specialized ShowBase replacement.
PyObject *result = PyObject_CallMethod
(_runner, "setupWindow", "siiiii", window_type.c_str(),
win_x, win_y, win_width, win_height,
parent_window_handle);
if (result == NULL) {

View File

@ -95,8 +95,7 @@ private:
int _py_argc;
char **_py_argv;
PyObject *_setP3DFilename;
PyObject *_setupWindow;
PyObject *_runner;
PyObject *_taskMgr;
PT(GenericAsyncTask) _check_comm_task;

View File

@ -24,9 +24,9 @@
#endif
#ifdef _WIN32
typedef P3DWinProgressWindow ProgressWinType;
typedef P3DWinProgressWindow ProgressWindowType;
#else
typedef P3DProgressWindow ProgressWinType;
typedef P3DProgressWindow ProgressWindowType;
#endif
////////////////////////////////////////////////////////////////////
@ -173,9 +173,9 @@ start_instance(P3DInstance *inst) {
_panda3d_callback = new P3DProgressWindow(_panda3d, this, inst);
} else {
// For a non-hidden window, create an instance of
// ProgressWinType, which is typedeffed above to be the kind
// ProgressWindowType, which is typedeffed above to be the kind
// of class that actually does manifest a window.
_panda3d_callback = new ProgressWinType(_panda3d, this, inst);
_panda3d_callback = new ProgressWindowType(_panda3d, this, inst);
}
*/
_panda3d->set_callback(_panda3d_callback);

View File

@ -0,0 +1,34 @@
// Filename: p3dSplashWindow.I
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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: P3DSplashWindow::get_fparams
// Access: Public
// Description: Returns the current file parameters.
////////////////////////////////////////////////////////////////////
inline const P3DFileParams &P3DSplashWindow::
get_fparams() const {
return _fparams;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::get_wparams
// Access: Public
// Description: Returns the current window parameters.
////////////////////////////////////////////////////////////////////
inline const P3DWindowParams &P3DSplashWindow::
get_wparams() const {
return _wparams;
}

View File

@ -0,0 +1,79 @@
// Filename: p3dSplashWindow.cxx
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 "p3dSplashWindow.h"
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DSplashWindow::
P3DSplashWindow(P3DInstance *inst) :
_inst(inst),
_fparams(inst->get_fparams()),
_wparams(inst->get_wparams())
{
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
P3DSplashWindow::
~P3DSplashWindow() {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_fparams
// Access: Public, Virtual
// Description: Sets up the file parameters for the window.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_fparams(const P3DFileParams &fparams) {
_fparams = fparams;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_wparams
// Access: Public, Virtual
// Description: Changes the window parameters, e.g. to resize or
// reposition the window; or sets the parameters for the
// first time, creating the initial window.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_wparams(const P3DWindowParams &wparams) {
_wparams = wparams;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::open_window
// Access: Public, Virtual
// Description: Creates the splash window.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
open_window() {
nout << "P3DSplashWindow::open_window()\n" << flush;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::close_window
// Access: Public, Virtual
// Description: Closes the window created above.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
close_window() {
nout << "P3DSplashWindow::close_window()\n" << flush;
}

View File

@ -0,0 +1,57 @@
// Filename: p3dSplashWindow.h
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3DSPLASHWINDOW_H
#define P3DSPLASHWINDOW_H
#include "p3d_plugin_common.h"
#include "p3dFileParams.h"
#include "p3dWindowParams.h"
class P3DInstance;
////////////////////////////////////////////////////////////////////
// Class : P3DSplashWindow
// Description : This window is displayed temporarily, in place of an
// instance's actual window, during the initial launch
// of an applet, and also during the initial download of
// Panda3D code if necessary.
//
// This is the base implementation; it contains no
// specific code to open a window.
////////////////////////////////////////////////////////////////////
class P3DSplashWindow {
public:
P3DSplashWindow(P3DInstance *inst);
virtual ~P3DSplashWindow();
virtual void set_fparams(const P3DFileParams &fparams);
inline const P3DFileParams &get_fparams() const;
virtual void set_wparams(const P3DWindowParams &wparams);
inline const P3DWindowParams &get_wparams() const;
virtual void open_window();
virtual void close_window();
protected:
P3DInstance *_inst;
P3DFileParams _fparams;
P3DWindowParams _wparams;
};
#include "p3dSplashWindow.I"
#endif

View File

@ -0,0 +1,14 @@
// Filename: p3dWinSplashWindow.I
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,170 @@
// Filename: p3dWinSplashWindow.cxx
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 "p3dWinSplashWindow.h"
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DWinSplashWindow::
P3DWinSplashWindow(P3DInstance *inst) :
P3DSplashWindow(inst)
{
_hwnd = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
P3DWinSplashWindow::
~P3DWinSplashWindow() {
close_window();
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::open_window
// Access: Public, Virtual
// Description: Creates the splash window.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
open_window() {
P3DSplashWindow::open_window();
WNDCLASS wc;
HINSTANCE application = GetModuleHandle(NULL);
static bool registered_class = false;
if (!registered_class) {
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = window_proc;
wc.hInstance = application;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = "panda3d_splash";
if (!RegisterClass(&wc)) {
nout << "Could not register window class!\n";
}
registered_class = true;
}
int x = CW_USEDEFAULT;
int y = CW_USEDEFAULT;
if (_wparams.get_win_x() != 0 && _wparams.get_win_y() != 0) {
x = _wparams.get_win_x();
y = _wparams.get_win_y();
}
int width = 320;
int height = 240;
if (_wparams.get_win_width() != 0 && _wparams.get_win_height() != 0) {
width = _wparams.get_win_width();
height = _wparams.get_win_height();
}
if (_wparams.get_window_type() == P3D_WT_embedded) {
// Create an embedded window.
DWORD window_style =
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
HWND parent_hwnd = _wparams.get_parent_window()._hwnd;
_hwnd =
CreateWindow("panda3d_splash", "Panda3D", window_style,
x, y, width, height,
parent_hwnd, NULL, application, 0);
if (!_hwnd) {
nout << "Could not create embedded window!\n";
return;
}
} else {
// Create a toplevel window.
DWORD window_style =
WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
WS_SIZEBOX | WS_MAXIMIZEBOX;
_hwnd =
CreateWindow("panda3d_splash", "Panda3D", window_style,
x, y, width, height,
NULL, NULL, application, 0);
if (!_hwnd) {
nout << "Could not create toplevel window!\n";
return;
}
ShowWindow(_hwnd, SW_SHOWNORMAL);
}
}
// Ensure the main window is visible now.
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::close_window
// Access: Public, Virtual
// Description: Closes the window created above.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
close_window() {
P3DSplashWindow::close_window();
if (_hwnd) {
ShowWindow(_hwnd, SW_HIDE);
CloseWindow(_hwnd);
_hwnd = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::window_proc
// Access: Private, Static
// Description: The windows event-processing handler.
////////////////////////////////////////////////////////////////////
LONG P3DWinSplashWindow::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_DRAWITEM:
// Draw a text label placed within the window.
{
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
FillRect(dis->hDC, &(dis->rcItem), WHITE_BRUSH);
static const int text_buffer_size = 512;
char text_buffer[text_buffer_size];
GetWindowText(dis->hwndItem, text_buffer, text_buffer_size);
HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT);
SelectObject(dis->hDC, font);
SetBkColor(dis->hDC, 0x00ffffff);
DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem),
DT_BOTTOM | DT_CENTER | DT_SINGLELINE);
}
};
return DefWindowProc(hwnd, msg, wparam, lparam);
}
#endif // _WIN32

View File

@ -0,0 +1,51 @@
// Filename: p3dWinSplashWindow.h
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3DWINSPLASHWINDOW_H
#define P3DWINSPLASHWINDOW_H
#include "p3d_plugin_common.h"
#ifdef _WIN32
#include "p3dSplashWindow.h"
#include "p3d_lock.h"
#include <windows.h>
////////////////////////////////////////////////////////////////////
// Class : P3DWinSplashWindow
// Description : This is the Windows implementation of the
// initial-download window.
////////////////////////////////////////////////////////////////////
class P3DWinSplashWindow : public P3DSplashWindow {
public:
P3DWinSplashWindow(P3DInstance *inst);
virtual ~P3DWinSplashWindow();
virtual void open_window();
virtual void close_window();
private:
static LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
private:
HWND _hwnd;
};
#include "p3dWinSplashWindow.I"
#endif // _WIN32
#endif

View File

@ -7,6 +7,8 @@
#include "p3dMultifileReader.cxx"
#include "p3dPackage.cxx"
#include "p3dProgressWindow.cxx"
#include "p3dSplashWindow.cxx"
#include "p3dSession.cxx"
#include "p3dWindowParams.cxx"
#include "p3dWinProgressWindow.cxx"
#include "p3dWinSplashWindow.cxx"

View File

@ -324,7 +324,6 @@ NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) {
////////////////////////////////////////////////////////////////////
int32
NPP_WriteReady(NPP instance, NPStream *stream) {
logfile << "WriteReady\n";
// We're supposed to return the maximum amount of data the plugin is
// prepared to handle. Gee, I don't know. As much as you can give
// me, I guess.
@ -340,9 +339,6 @@ NPP_WriteReady(NPP instance, NPStream *stream) {
int32
NPP_Write(NPP instance, NPStream *stream, int32 offset,
int32 len, void *buffer) {
logfile << "Write " << stream->url
<< ", " << len << "\n" << flush;
PPInstance *inst = (PPInstance *)(instance->pdata);
assert(inst != NULL);

View File

@ -1,231 +0,0 @@
""" This module can serve as a startup script to play a Panda
application packed within a .mf file. Run via:
python RunAppMF.py app.mf
This is currently experimental, but the intent is to work towards a
prepackaged Panda distributable, designed to run applications exactly
like this.
Also see MakeAppMF.py.
"""
import sys
from direct.showbase import VFSImporter
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath, HTTPClient
from direct.stdpy import file
from direct.task.TaskManagerGlobal import taskMgr
import os
import __builtin__
MultifileRoot = '/mf'
# This defines the default prc file that is implicitly loaded with an
# application.
AppPrcFilename = 'App.prc'
AppPrc = """
default-model-extension .bam
"""
class ArgumentError(AttributeError):
pass
__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
# We need to make sure sys.stdout maps to sys.stderr instead, so
# if someone makes an unadorned print command within Python code,
# it won't muck up the data stream between parent and child.
sys.stdout = sys.stderr
vfs = VirtualFileSystem.getGlobalPtr()
# Clear *all* the mount points, including "/", so that we no
# longer access the disk directly.
vfs.unmountAll()
# Make sure the directories on our standard Python path are mounted
# read-only, so we can still load Python.
for dirname in sys.path:
vfs.mount(dirname, dirname, vfs.MFReadOnly)
# Also mount some standard directories read-write (temporary and
# app-data directories).
tdir = Filename.temporary('', '')
for dirname in set([ tdir.getDirname(),
Filename.getTempDirectory().cStr(),
Filename.getUserAppdataDirectory().cStr(),
Filename.getCommonAppdataDirectory().cStr() ]):
vfs.mount(dirname, dirname, 0)
# Now set up Python to import this stuff.
VFSImporter.register()
sys.path = [ MultifileRoot ] + sys.path
# Put our root directory on the model-path and prc-path, too.
getModelPath().prependDirectory(MultifileRoot)
# Load the implicit App.prc file.
loadPrcFileData(AppPrcFilename, AppPrc)
# 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.
__builtin__.file = file.file
__builtin__.open = file.open
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)
gotWindow = False
gotP3DFilename = False
started = False
def startIfReady():
global gotWindow, gotP3DFilename, started
if started:
return
if gotWindow and gotP3DFilename:
started = True
import main
if hasattr(main, 'main') and callable(main.main):
main.main()
def setP3DFilename(p3dFilename, tokens = []):
tokenDict = dict(tokens)
fname = Filename.fromOsSpecific(p3dFilename)
if not p3dFilename:
# If we didn't get a literal filename, we have to download it
# from the URL. TODO: make this a smarter temporary filename?
fname = Filename.temporary('', 'p3d_')
fname.setExtension('p3d')
p3dFilename = fname.toOsSpecific()
src = tokenDict.get('src', None)
if not src:
raise ArgumentError, "No Panda app specified."
http = HTTPClient.getGlobalPtr()
hc = http.getDocument(src)
if not hc.downloadToFile(fname):
fname.unlink()
raise ArgumentError, "Couldn't download %s" % (src)
# Set a hook on sys.exit to delete the temporary file.
oldexitfunc = getattr(sys, 'exitfunc', None)
def deleteTempFile(fname = fname, oldexitfunc = oldexitfunc):
fname.unlink()
if oldexitfunc:
oldexitfunc()
sys.exitfunc = deleteTempFile
vfs = VirtualFileSystem.getGlobalPtr()
if not vfs.exists(fname):
raise ArgumentError, "No such file: %s" % (p3dFilename)
fname.makeAbsolute()
initPackedAppEnvironment()
mf = Multifile()
if not mf.openRead(fname):
raise ArgumentError, "Not a Panda Multifile: %s" % (p3dFilename)
# 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)
global gotP3DFilename
gotP3DFilename = True
startIfReady()
windowPrc = None
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)
global windowPrc
if windowPrc:
unloadPrcFile(windowPrc)
windowPrc = loadPrcFileData("setupWindow", data)
global gotWindow
gotWindow = True
startIfReady()
def parseSysArgs():
""" Converts sys.argv into (p3dFilename, tokens). """
if len(sys.argv) < 2 or not sys.argv[1]:
raise ArgumentError, "No Panda app specified. Use:\npython RunAppMF.py app.mf"
tokens = []
for token in sys.argv[2:]:
if '=' in token:
keyword, value = token.split('=', 1)
else:
keyword = token
value = ''
tokens.append((keyword.lower(), value))
p3dFilename = Filename.fromOsSpecific(sys.argv[1])
osFilename = p3dFilename.toOsSpecific()
if not p3dFilename.exists():
# If the filename doesn't exist, it must be a URL.
osFilename = ''
if 'src' not in dict(tokens):
tokens.append(('src', sys.argv[1]))
return (osFilename, tokens)
if __name__ == '__main__':
gotWindow = True
try:
setP3DFilename(*parseSysArgs())
except ArgumentError, e:
print e.args[0]
sys.exit(1)
run()

View File

@ -0,0 +1,53 @@
#define INSTALL_SCRIPTS packp3d.py runp3d.py
// Generate an appropriate script to invoke the above Python files.
// On Windows, we generate a batch file; on other platforms (including
// Cygwin), we generate a sh script.
#define install_dir $[$[upcase $[PACKAGE]]_INSTALL]
#define install_bin_dir $[or $[INSTALL_BIN_DIR],$[install_dir]/bin]
#define python $[PYTHON_COMMAND]
#if $[USE_DEBUG_PYTHON]
#define python $[PYTHON_DEBUG_COMMAND]
#endif
#foreach scriptname packp3d runp3d
#if $[eq $[PLATFORM],Win32]
#set INSTALL_SCRIPTS $[INSTALL_SCRIPTS] $[scriptname].bat
#else
#set INSTALL_SCRIPTS $[INSTALL_SCRIPTS] $[scriptname]
#endif
#if $[eq $[PLATFORM],Win32]
#output $[scriptname].bat notouch
@echo off
rem #### Generated automatically by $[PPREMAKE] $[PPREMAKE_VERSION] from $[notdir $[THISFILENAME]].
rem ################################# DO NOT EDIT ###########################
$[python] -u $[osfilename $[install_bin_dir]/$[scriptname].py] %1 %2 %3 %4 %5 %6 %7 %8 %9
#end $[scriptname].bat
#else // Win32
#output $[scriptname] binary notouch
#! /bin/sh
#### Generated automatically by $[PPREMAKE] $[PPREMAKE_VERSION] from $[notdir $[THISFILENAME]].
################################# DO NOT EDIT ###########################
#if $[CTPROJS]
# This script was generated while the user was using the ctattach
# tools. That had better still be the case.
#if $[WINDOWS_PLATFORM]
$[python] -u `cygpath -w $DIRECT/built/bin/$[scriptname].py` "$@"
#else
$[python] -u $DIRECT/built/bin/$[scriptname].py "$@"
#endif
#else
$[python] -u '$[osfilename $[install_bin_dir]/$[scriptname].py]' "$@"
#endif
#end $[scriptname]
#endif // Win32
#end scriptname

View File

@ -1,9 +1,15 @@
"""
This module will pack a Panda application, consisting of a
directory tree of .py files and models, into a multifile for
distribution and running with RunAppMF.py. To run it, use:
#! /usr/bin/env python
python MakeAppMF.py [opts] app.mf
"""
This module will pack a Panda application, consisting of a directory
tree of .py files and models, into a p3d file for convenient
distribution. The resulting p3d file can be run by the Panda3D
runtime executable, or by the Panda3D web browser plugin.
Usage:
packp3d.py [opts] app.p3d
Options:
@ -23,6 +29,10 @@ Options:
(this is preferable to having the module start itself immediately
upon importing).
Note that your main.py must *not* call run(). This call should
not be part of the p3d file--the Panda3D runtime must be free to
call it, not your code!
-c [py,pyc,pyo]
Specifies the compilation mode of python files. 'py' means to
@ -335,7 +345,7 @@ def makePackedApp(args):
sys.exit(1)
if not args:
raise ArgumentError, "No destination app specified. Use:\npython MakeAppMF.py app.mf"
raise ArgumentError, "No destination app specified. Use:\npackp3d.py app.p3d"
multifile_name = args[0]
if len(args) > 1:

257
direct/src/showutil/runp3d.py Executable file
View File

@ -0,0 +1,257 @@
#! /usr/bin/env python
"""
This module is intended to be compiled into the Panda3D runtime
distributable, but it can also be run directly via the Python
interpreter. It will run a Panda3D applet--a p3d file--that has
previously been generated via packp3d.py.
Usage:
runp3d.py app.p3d [keyword=value [keyword=value ...] ]
The command-line keywords mimic the additional parameters that may
appear in HTML syntax when the p3d file appears on a web page. These
are passed as given to the app, which may decide what to do with them.
See pack3d.py for a script that generates these p3d files.
"""
import sys
from direct.showbase import VFSImporter
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath, HTTPClient
from direct.stdpy import file
from direct.task.TaskManagerGlobal import taskMgr
import os
import __builtin__
MultifileRoot = '/mf'
# This defines the default prc file that is implicitly loaded with an
# application.
AppPrcFilename = 'App.prc'
AppPrc = """
default-model-extension .bam
"""
class ArgumentError(AttributeError):
pass
class AppRunner(DirectObject):
def __init__(self):
DirectObject.__init__(self)
self.packedAppEnvironmentInitialized = False
self.gotWindow = False
self.gotP3DFilename = False
self.started = False
self.windowPrc = None
def initPackedAppEnvironment(self):
""" 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). """
if self.packedAppEnvironmentInitialized:
return
self.packedAppEnvironmentInitialized = True
# We need to make sure sys.stdout maps to sys.stderr instead, so
# if someone makes an unadorned print command within Python code,
# it won't muck up the data stream between parent and child.
sys.stdout = sys.stderr
vfs = VirtualFileSystem.getGlobalPtr()
# Clear *all* the mount points, including "/", so that we no
# longer access the disk directly.
vfs.unmountAll()
# Make sure the directories on our standard Python path are mounted
# read-only, so we can still load Python.
for dirname in sys.path:
vfs.mount(dirname, dirname, vfs.MFReadOnly)
# Also mount some standard directories read-write (temporary and
# app-data directories).
tdir = Filename.temporary('', '')
for dirname in set([ tdir.getDirname(),
Filename.getTempDirectory().cStr(),
Filename.getUserAppdataDirectory().cStr(),
Filename.getCommonAppdataDirectory().cStr() ]):
vfs.mount(dirname, dirname, 0)
# Now set up Python to import this stuff.
VFSImporter.register()
sys.path = [ MultifileRoot ] + sys.path
# Put our root directory on the model-path and prc-path, too.
getModelPath().prependDirectory(MultifileRoot)
# Load the implicit App.prc file.
loadPrcFileData(AppPrcFilename, AppPrc)
# 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.
__builtin__.file = file.file
__builtin__.open = file.open
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 startIfReady(self):
if self.started:
return
if self.gotWindow and self.gotP3DFilename:
self.started = True
# Hang a hook so we know when the window is actually opened.
self.acceptOnce('window-event', self.windowEvent)
import main
if hasattr(main, 'main') and callable(main.main):
main.main()
def setP3DFilename(self, p3dFilename, tokens = []):
tokenDict = dict(tokens)
fname = Filename.fromOsSpecific(p3dFilename)
if not p3dFilename:
# If we didn't get a literal filename, we have to download it
# from the URL. TODO: make this a smarter temporary filename?
fname = Filename.temporary('', 'p3d_')
fname.setExtension('p3d')
p3dFilename = fname.toOsSpecific()
src = tokenDict.get('src', None)
if not src:
raise ArgumentError, "No Panda app specified."
http = HTTPClient.getGlobalPtr()
hc = http.getDocument(src)
if not hc.downloadToFile(fname):
fname.unlink()
raise ArgumentError, "Couldn't download %s" % (src)
# Set a hook on sys.exit to delete the temporary file.
oldexitfunc = getattr(sys, 'exitfunc', None)
def deleteTempFile(fname = fname, oldexitfunc = oldexitfunc):
fname.unlink()
if oldexitfunc:
oldexitfunc()
sys.exitfunc = deleteTempFile
vfs = VirtualFileSystem.getGlobalPtr()
if not vfs.exists(fname):
raise ArgumentError, "No such file: %s" % (p3dFilename)
fname.makeAbsolute()
self.initPackedAppEnvironment()
mf = Multifile()
if not mf.openRead(fname):
raise ArgumentError, "Not a Panda Multifile: %s" % (p3dFilename)
# 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)
self.gotP3DFilename = True
self.startIfReady()
def setupWindow(self, 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)
if self.windowPrc:
unloadPrcFile(self.windowPrc)
self.windowPrc = loadPrcFileData("setupWindow", data)
self.gotWindow = True
self.startIfReady()
def windowEvent(self, win):
print "Got window event in runp3d"
# TODO: feed this information back to the plugin host.
def parseSysArgs(self):
""" Converts sys.argv into (p3dFilename, tokens). """
import getopt
opts, args = getopt.getopt(sys.argv[1:], 'h')
for option, value in opts:
if option == '-h':
print __doc__
sys.exit(1)
if not args or not args[0]:
raise ArgumentError, "No Panda app specified. Use:\nrunp3d.py app.p3d"
tokens = []
for token in args[1:]:
if '=' in token:
keyword, value = token.split('=', 1)
else:
keyword = token
value = ''
tokens.append((keyword.lower(), value))
p3dFilename = Filename.fromOsSpecific(sys.argv[1])
osFilename = p3dFilename.toOsSpecific()
if not p3dFilename.exists():
# If the filename doesn't exist, it must be a URL.
osFilename = ''
if 'src' not in dict(tokens):
tokens.append(('src', sys.argv[1]))
return (osFilename, tokens)
if __name__ == '__main__':
runner = AppRunner()
runner.gotWindow = True
try:
runner.setP3DFilename(*runner.parseSysArgs())
except ArgumentError, e:
print e.args[0]
sys.exit(1)
run()