mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
restructure for OOP, use polling instead of threads
This commit is contained in:
parent
f38724aa92
commit
38c00a66f9
@ -12,31 +12,14 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This program must link with Panda for HTTPClient support. This
|
||||
// means it probably should be built with LINK_ALL_STATIC defined, so
|
||||
// we won't have to deal with confusing .dll or .so files that might
|
||||
// compete on the disk with the dynamically-loaded versions. There's
|
||||
// no competition in memory address space, though, because
|
||||
// p3d_plugin--the only file we dynamically link in--doesn't itself
|
||||
// link with Panda.
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "panda3d.h"
|
||||
#include "httpClient.h"
|
||||
#include "load_plugin.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "httpClient.h"
|
||||
#include "httpChannel.h"
|
||||
#include "ramfile.h"
|
||||
#include "thread.h"
|
||||
#include "pset.h"
|
||||
|
||||
#include "p3d_plugin.h"
|
||||
#include "load_plugin.h"
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
#include "gnu_getopt.h"
|
||||
#else
|
||||
@ -45,302 +28,24 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef pset<P3D_instance *> Instances;
|
||||
Instances _instances;
|
||||
|
||||
class URLGetterThread : public Thread {
|
||||
public:
|
||||
URLGetterThread(P3D_instance *instance,
|
||||
int unique_id,
|
||||
const URLSpec &url,
|
||||
const string &post_data);
|
||||
protected:
|
||||
virtual void thread_main();
|
||||
|
||||
private:
|
||||
P3D_instance *_instance;
|
||||
int _unique_id;
|
||||
URLSpec _url;
|
||||
string _post_data;
|
||||
};
|
||||
|
||||
URLGetterThread::
|
||||
URLGetterThread(P3D_instance *instance,
|
||||
int unique_id,
|
||||
const URLSpec &url,
|
||||
const string &post_data) :
|
||||
Thread(url, "URLGetter"),
|
||||
_instance(instance),
|
||||
_unique_id(unique_id),
|
||||
_url(url),
|
||||
_post_data(post_data)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Panda3D::
|
||||
Panda3D() {
|
||||
}
|
||||
|
||||
void URLGetterThread::
|
||||
thread_main() {
|
||||
HTTPClient *http = HTTPClient::get_global_ptr();
|
||||
|
||||
cerr << "Getting URL " << _url << "\n";
|
||||
|
||||
PT(HTTPChannel) channel = http->make_channel(false);
|
||||
if (_post_data.empty()) {
|
||||
channel->begin_get_document(_url);
|
||||
} else {
|
||||
channel->begin_post_form(_url, _post_data);
|
||||
}
|
||||
|
||||
Ramfile rf;
|
||||
channel->download_to_ram(&rf);
|
||||
|
||||
size_t bytes_sent = 0;
|
||||
while (channel->run() || rf.get_data_size() != 0) {
|
||||
if (rf.get_data_size() != 0) {
|
||||
// Got some new data.
|
||||
bool download_ok = P3D_instance_feed_url_stream
|
||||
(_instance, _unique_id, P3D_RC_in_progress,
|
||||
channel->get_status_code(),
|
||||
channel->get_file_size(),
|
||||
(const unsigned char *)rf.get_data().data(), rf.get_data_size());
|
||||
bytes_sent += rf.get_data_size();
|
||||
rf.clear();
|
||||
|
||||
if (!download_ok) {
|
||||
// The plugin doesn't care any more. Interrupt the download.
|
||||
cerr << "Download interrupted: " << _url
|
||||
<< ", after " << bytes_sent << " of " << channel->get_file_size()
|
||||
<< " bytes.\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All done.
|
||||
P3D_result_code status = P3D_RC_done;
|
||||
if (!channel->is_valid()) {
|
||||
if (channel->get_status_code() != 0) {
|
||||
status = P3D_RC_http_error;
|
||||
} else {
|
||||
status = P3D_RC_generic_error;
|
||||
}
|
||||
cerr << "Error getting URL " << _url << "\n";
|
||||
} else {
|
||||
cerr << "Done getting URL " << _url << ", got " << bytes_sent << " bytes\n";
|
||||
}
|
||||
|
||||
P3D_instance_feed_url_stream
|
||||
(_instance, _unique_id, status,
|
||||
channel->get_status_code(),
|
||||
bytes_sent, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
handle_request(P3D_request *request) {
|
||||
bool handled = false;
|
||||
|
||||
switch (request->_request_type) {
|
||||
case P3D_RT_stop:
|
||||
cerr << "Got P3D_RT_stop\n";
|
||||
P3D_instance_finish(request->_instance);
|
||||
_instances.erase(request->_instance);
|
||||
#ifdef _WIN32
|
||||
// Post a silly message to spin the event loop.
|
||||
PostMessage(NULL, WM_USER, 0, 0);
|
||||
#endif
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case P3D_RT_get_url:
|
||||
cerr << "Got P3D_RT_get_url\n";
|
||||
{
|
||||
PT(URLGetterThread) thread = new URLGetterThread
|
||||
(request->_instance, request->_request._get_url._unique_id,
|
||||
URLSpec(request->_request._get_url._url), "");
|
||||
thread->start(TP_normal, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_RT_post_url:
|
||||
cerr << "Got P3D_RT_post_url\n";
|
||||
{
|
||||
PT(URLGetterThread) thread = new URLGetterThread
|
||||
(request->_instance, request->_request._post_url._unique_id,
|
||||
URLSpec(request->_request._post_url._url),
|
||||
string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
|
||||
thread->start(TP_normal, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_RT_notify:
|
||||
// Ignore notifications.
|
||||
break;
|
||||
|
||||
default:
|
||||
// Some request types are not handled.
|
||||
cerr << "Unhandled request: " << request->_request_type << "\n";
|
||||
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
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
void
|
||||
make_parent_window(P3D_window_handle &parent_window,
|
||||
int win_width, int win_height) {
|
||||
// TODO.
|
||||
assert(false);
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
P3D_instance *
|
||||
create_instance(const string &arg, P3D_window_type window_type,
|
||||
int win_x, int win_y, int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const Filename &output_filename) {
|
||||
|
||||
string os_output_filename = output_filename.to_os_specific();
|
||||
P3D_token tokens[] = {
|
||||
{ "output_filename", os_output_filename.c_str() },
|
||||
{ "src", arg.c_str() },
|
||||
};
|
||||
int num_tokens = sizeof(tokens) / sizeof(P3D_token);
|
||||
|
||||
// If the supplied parameter name is a real file, pass it in on the
|
||||
// parameter list. Otherwise, assume it's a URL and let the plugin
|
||||
// download it.
|
||||
Filename p3d_filename = Filename::from_os_specific(arg);
|
||||
string os_p3d_filename;
|
||||
if (p3d_filename.exists()) {
|
||||
p3d_filename.make_absolute();
|
||||
os_p3d_filename = p3d_filename.to_os_specific();
|
||||
}
|
||||
|
||||
P3D_instance *inst = P3D_new_instance(NULL, NULL);
|
||||
|
||||
if (inst != NULL) {
|
||||
P3D_instance_setup_window
|
||||
(inst, window_type, win_x, win_y, win_width, win_height, parent_window);
|
||||
P3D_instance_start(inst, os_p3d_filename.c_str(), tokens, num_tokens);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
<< " -p " << get_plugin_basename() << "\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"
|
||||
|
||||
<< " -l output.log\n"
|
||||
<< " Specify the name of the file to receive the log output of the\n"
|
||||
<< " plugin process(es). The default is to send this output to the\n"
|
||||
<< " console.\n\n"
|
||||
|
||||
<< " -t [toplevel|embedded|fullscreen|hidden]\n"
|
||||
<< " Specify the type of graphic window to create. If you specify\n"
|
||||
<< " \"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[]) {
|
||||
/*
|
||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
char *targv[] = {
|
||||
"panda3d",
|
||||
"-tembedded",
|
||||
"c:/cygwin/home/drose/ralph.p3d",
|
||||
NULL,
|
||||
};
|
||||
char **argv = targv;
|
||||
int argc = 3;
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::run
|
||||
// Access: Public
|
||||
// Description: Starts the program going. Returns 0 on success,
|
||||
// nonzero on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int Panda3D::
|
||||
run(int argc, char *argv[]) {
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
const char *optstr = "p:l:t:s:o:h";
|
||||
@ -500,10 +205,10 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
inst = P3D_check_request(false);
|
||||
}
|
||||
|
||||
while (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
// spin, so we don't starve the download threads.
|
||||
// TODO: use a better mechanism here.
|
||||
Thread::force_yield();
|
||||
while (!_url_getters.empty() &&
|
||||
!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
// If there are no Windows messages, check the download tasks.
|
||||
run_getters();
|
||||
}
|
||||
retval = GetMessage(&msg, NULL, 0, 0);
|
||||
}
|
||||
@ -511,11 +216,10 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
cerr << "WM_QUIT\n";
|
||||
// WM_QUIT has been received. Terminate all instances, and fall
|
||||
// through.
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3D_instance_finish(*ii);
|
||||
while (!_instances.empty()) {
|
||||
P3D_instance *inst = *(_instances.begin());
|
||||
delete_instance(inst);
|
||||
}
|
||||
_instances.clear();
|
||||
|
||||
} else {
|
||||
// Not an embedded window, so we don't have our own window to
|
||||
@ -528,7 +232,7 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
handle_request(request);
|
||||
}
|
||||
}
|
||||
Thread::force_yield();
|
||||
run_getters();
|
||||
}
|
||||
}
|
||||
|
||||
@ -543,10 +247,378 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
handle_request(request);
|
||||
}
|
||||
}
|
||||
Thread::force_yield();
|
||||
run_getters();
|
||||
}
|
||||
|
||||
// All instances have finished; we can exit.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::run_getters
|
||||
// Access: Private
|
||||
// Description: Polls all of the active URL requests.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Panda3D::
|
||||
run_getters() {
|
||||
URLGetters::iterator gi;
|
||||
gi = _url_getters.begin();
|
||||
while (gi != _url_getters.end()) {
|
||||
URLGetter *getter = (*gi);
|
||||
if (getter->run()) {
|
||||
// This URLGetter is still working. Leave it.
|
||||
++gi;
|
||||
} else {
|
||||
// This URLGetter is done. Remove it and delete it.
|
||||
URLGetters::iterator dgi = gi;
|
||||
++gi;
|
||||
_url_getters.erase(dgi);
|
||||
delete getter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::handle_request
|
||||
// Access: Private
|
||||
// Description: Handles a single request received via the plugin API
|
||||
// from a p3d instance.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Panda3D::
|
||||
handle_request(P3D_request *request) {
|
||||
bool handled = false;
|
||||
|
||||
switch (request->_request_type) {
|
||||
case P3D_RT_stop:
|
||||
cerr << "Got P3D_RT_stop\n";
|
||||
delete_instance(request->_instance);
|
||||
#ifdef _WIN32
|
||||
// Post a silly message to spin the event loop.
|
||||
PostMessage(NULL, WM_USER, 0, 0);
|
||||
#endif
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case P3D_RT_get_url:
|
||||
cerr << "Got P3D_RT_get_url\n";
|
||||
{
|
||||
URLGetter *getter = new URLGetter
|
||||
(request->_instance, request->_request._get_url._unique_id,
|
||||
URLSpec(request->_request._get_url._url), "");
|
||||
_url_getters.insert(getter);
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_RT_post_url:
|
||||
cerr << "Got P3D_RT_post_url\n";
|
||||
{
|
||||
URLGetter *getter = new URLGetter
|
||||
(request->_instance, request->_request._post_url._unique_id,
|
||||
URLSpec(request->_request._post_url._url),
|
||||
string(request->_request._post_url._post_data, request->_request._post_url._post_data_size));
|
||||
_url_getters.insert(getter);
|
||||
}
|
||||
break;
|
||||
|
||||
case P3D_RT_notify:
|
||||
// Ignore notifications.
|
||||
break;
|
||||
|
||||
default:
|
||||
// Some request types are not handled.
|
||||
cerr << "Unhandled request: " << request->_request_type << "\n";
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::make_parent_window
|
||||
// Access: Private
|
||||
// Description: Creates a toplevel window to contain the embedded
|
||||
// instances. Windows implementation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Panda3D::
|
||||
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
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::make_parent_window
|
||||
// Access: Private
|
||||
// Description: Creates a toplevel window to contain the embedded
|
||||
// instances. OS X implementation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Panda3D::
|
||||
make_parent_window(P3D_window_handle &parent_window,
|
||||
int win_width, int win_height) {
|
||||
// TODO.
|
||||
assert(false);
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::create_instance
|
||||
// Access: Private
|
||||
// Description: Uses the plugin API to create a new P3D instance to
|
||||
// play a particular .p3d file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3D_instance *Panda3D::
|
||||
create_instance(const string &arg, P3D_window_type window_type,
|
||||
int win_x, int win_y, int win_width, int win_height,
|
||||
P3D_window_handle parent_window,
|
||||
const Filename &output_filename) {
|
||||
|
||||
string os_output_filename = output_filename.to_os_specific();
|
||||
P3D_token tokens[] = {
|
||||
{ "output_filename", os_output_filename.c_str() },
|
||||
{ "src", arg.c_str() },
|
||||
};
|
||||
int num_tokens = sizeof(tokens) / sizeof(P3D_token);
|
||||
|
||||
// If the supplied parameter name is a real file, pass it in on the
|
||||
// parameter list. Otherwise, assume it's a URL and let the plugin
|
||||
// download it.
|
||||
Filename p3d_filename = Filename::from_os_specific(arg);
|
||||
string os_p3d_filename;
|
||||
if (p3d_filename.exists()) {
|
||||
p3d_filename.make_absolute();
|
||||
os_p3d_filename = p3d_filename.to_os_specific();
|
||||
}
|
||||
|
||||
P3D_instance *inst = P3D_new_instance(NULL, NULL);
|
||||
|
||||
if (inst != NULL) {
|
||||
P3D_instance_setup_window
|
||||
(inst, window_type, win_x, win_y, win_width, win_height, parent_window);
|
||||
P3D_instance_start(inst, os_p3d_filename.c_str(), tokens, num_tokens);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::delete_instance
|
||||
// Access: Private
|
||||
// Description: Deletes the indicated instance and removes it from
|
||||
// the internal structures.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Panda3D::
|
||||
delete_instance(P3D_instance *inst) {
|
||||
P3D_instance_finish(inst);
|
||||
_instances.erase(inst);
|
||||
|
||||
// Make sure we also terminate any pending URLGetters associated
|
||||
// with this instance.
|
||||
URLGetters::iterator gi;
|
||||
gi = _url_getters.begin();
|
||||
while (gi != _url_getters.end()) {
|
||||
URLGetter *getter = (*gi);
|
||||
if (getter->get_instance() == inst) {
|
||||
URLGetters::iterator dgi = gi;
|
||||
++gi;
|
||||
_url_getters.erase(dgi);
|
||||
delete getter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::usage
|
||||
// Access: Private
|
||||
// Description: Reports the available command-line options.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Panda3D::
|
||||
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"
|
||||
|
||||
<< " -p " << get_plugin_basename() << "\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"
|
||||
|
||||
<< " -l output.log\n"
|
||||
<< " Specify the name of the file to receive the log output of the\n"
|
||||
<< " plugin process(es). The default is to send this output to the\n"
|
||||
<< " console.\n\n"
|
||||
|
||||
<< " -t [toplevel|embedded|fullscreen|hidden]\n"
|
||||
<< " Specify the type of graphic window to create. If you specify\n"
|
||||
<< " \"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";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::parse_int_pair
|
||||
// Access: Private
|
||||
// Description: Parses a string into an x,y pair of integers.
|
||||
// Returns true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Panda3D::
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::URLGetter::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
Panda3D::URLGetter::
|
||||
URLGetter(P3D_instance *instance, int unique_id,
|
||||
const URLSpec &url, const string &post_data) :
|
||||
_instance(instance),
|
||||
_unique_id(unique_id),
|
||||
_url(url),
|
||||
_post_data(post_data)
|
||||
{
|
||||
HTTPClient *http = HTTPClient::get_global_ptr();
|
||||
|
||||
cerr << "Getting URL " << _url << "\n";
|
||||
|
||||
_channel = http->make_channel(false);
|
||||
if (_post_data.empty()) {
|
||||
_channel->begin_get_document(_url);
|
||||
} else {
|
||||
_channel->begin_post_form(_url, _post_data);
|
||||
}
|
||||
|
||||
_channel->download_to_ram(&_rf);
|
||||
_bytes_sent = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Panda3D::URLGetter::run
|
||||
// Access: Public
|
||||
// Description: Polls the URLGetter for new results. Returns true if
|
||||
// the URL request is still in progress and run() should
|
||||
// be called again later, or false if the URL request
|
||||
// has been completed and run() should not be called
|
||||
// again.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Panda3D::URLGetter::
|
||||
run() {
|
||||
if (_channel->run() || _rf.get_data_size() != 0) {
|
||||
if (_rf.get_data_size() != 0) {
|
||||
// Got some new data.
|
||||
bool download_ok = P3D_instance_feed_url_stream
|
||||
(_instance, _unique_id, P3D_RC_in_progress,
|
||||
_channel->get_status_code(),
|
||||
_channel->get_file_size(),
|
||||
(const unsigned char *)_rf.get_data().data(), _rf.get_data_size());
|
||||
_bytes_sent += _rf.get_data_size();
|
||||
_rf.clear();
|
||||
|
||||
if (!download_ok) {
|
||||
// The plugin doesn't care any more. Interrupt the download.
|
||||
cerr << "Download interrupted: " << _url
|
||||
<< ", after " << _bytes_sent << " of " << _channel->get_file_size()
|
||||
<< " bytes.\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Still more to come; call this method again later.
|
||||
return true;
|
||||
}
|
||||
|
||||
// All done.
|
||||
P3D_result_code status = P3D_RC_done;
|
||||
if (!_channel->is_valid()) {
|
||||
if (_channel->get_status_code() != 0) {
|
||||
status = P3D_RC_http_error;
|
||||
} else {
|
||||
status = P3D_RC_generic_error;
|
||||
}
|
||||
cerr << "Error getting URL " << _url << "\n";
|
||||
} else {
|
||||
cerr << "Done getting URL " << _url << ", got " << _bytes_sent << " bytes\n";
|
||||
}
|
||||
|
||||
P3D_instance_feed_url_stream
|
||||
(_instance, _unique_id, status,
|
||||
_channel->get_status_code(),
|
||||
_bytes_sent, NULL, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
Panda3D program;
|
||||
return program.run(argc, argv);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user