sdl_viewer.cpp
Basic example using
openvrml::browser.
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 # ifdef HAVE_CONFIG_H
00022 # include <config.h>
00023 # endif
00024
00025 # include <iostream>
00026 # include <fstream>
00027 # include <boost/algorithm/string/predicate.hpp>
00028 # include <boost/utility.hpp>
00029 # include <SDL.h>
00030 # include <openvrml/browser.h>
00031 # include <openvrml/gl/viewer.h>
00032 # ifdef _WIN32
00033 # include <windows.h>
00034 # endif
00035
00036 extern "C" Uint32 update_timer_callback(Uint32 interval, void * param);
00037
00038 namespace {
00039
00040 class resource_fetcher : public openvrml::resource_fetcher {
00041 private:
00042 virtual std::auto_ptr<openvrml::resource_istream>
00043 do_get_resource(const std::string & uri);
00044 };
00045
00046
00047 class sdl_error : public std::runtime_error {
00048 public:
00049 explicit sdl_error(const std::string & message);
00050 virtual ~sdl_error() throw ();
00051 };
00052
00053 class sdl_viewer : public openvrml::gl::viewer {
00054 friend Uint32 update_timer_callback(Uint32 interval, void * param);
00055
00056 static const Uint32 video_mode_flags;
00057
00058 SDL_TimerID update_timer_id;
00059 bool mouse_button_down;
00060
00061 public:
00062 static const int redraw_event_code = 1;
00063 static const int update_event_code = 2;
00064
00065 explicit sdl_viewer(const std::string & title) throw (sdl_error);
00066 virtual ~sdl_viewer() throw ();
00067
00068 void run();
00069
00070
00071
00072
00073 virtual void post_redraw();
00074 virtual void set_cursor(cursor_style c);
00075 virtual void swap_buffers();
00076 virtual void set_timer(double);
00077 };
00078 }
00079
00080 int main(int argc, char * argv[])
00081 {
00082 using std::cerr;
00083 using std::endl;
00084
00085 # ifdef _WIN32
00086 AllocConsole();
00087 FILE * out;
00088 freopen_s(&out, "conout$", "w", stdout);
00089 freopen_s(&out, "conout$", "w", stderr);
00090 # endif
00091
00092 if (argc < 2) {
00093 cerr << "Usage: " << argv[0] << " URL" << endl;
00094 return EXIT_FAILURE;
00095 }
00096
00097 try {
00098 using std::string;
00099 using std::vector;
00100
00101 const string url = argv[1];
00102
00103 sdl_viewer v(url);
00104 resource_fetcher fetcher;
00105 openvrml::browser b(fetcher, std::cout, std::cerr);
00106 b.viewer(&v);
00107
00108 vector<string> uri(1, url);
00109 vector<string> parameter;
00110 b.load_url(uri, parameter);
00111
00112 v.run();
00113 } catch (std::exception & ex) {
00114 cerr << ex.what() << endl;
00115 return EXIT_FAILURE;
00116 }
00117
00118 # ifdef _WIN32
00119 fclose(out);
00120 FreeConsole();
00121 # endif
00122
00123 return EXIT_SUCCESS;
00124 }
00125
00126 namespace {
00127
00128 std::auto_ptr<openvrml::resource_istream>
00129 resource_fetcher::do_get_resource(const std::string & uri)
00130 {
00131 using std::auto_ptr;
00132 using std::invalid_argument;
00133 using std::string;
00134 using openvrml::resource_istream;
00135
00136 class file_resource_istream : public resource_istream {
00137 std::string url_;
00138 std::filebuf buf_;
00139
00140 public:
00141 explicit file_resource_istream(const std::string & path):
00142 resource_istream(&this->buf_)
00143 {
00144 if (!this->buf_.open(path.c_str(),
00145 ios_base::in | ios_base::binary)) {
00146 this->setstate(ios_base::badbit);
00147 }
00148 }
00149
00150 void url(const std::string & str) throw (std::bad_alloc)
00151 {
00152 this->url_ = str;
00153 }
00154
00155 private:
00156 virtual const std::string do_url() const throw ()
00157 {
00158 return this->url_;
00159 }
00160
00161 virtual const std::string do_type() const throw ()
00162 {
00163
00164
00165
00166
00167
00168 using std::find;
00169 using std::string;
00170 using boost::algorithm::iequals;
00171 using boost::next;
00172 string media_type = "application/octet-stream";
00173 const string::const_reverse_iterator dot_pos =
00174 find(this->url_.rbegin(), this->url_.rend(), '.');
00175 if (dot_pos == this->url_.rend()
00176 || next(dot_pos.base()) == this->url_.end()) {
00177 return media_type;
00178 }
00179 const string::const_iterator hash_pos =
00180 find(next(dot_pos.base()), this->url_.end(), '#');
00181 const string ext(dot_pos.base(), hash_pos);
00182 if (iequals(ext, "wrl")) {
00183 media_type = openvrml::vrml_media_type;
00184 } else if (iequals(ext, "x3dv")) {
00185 media_type = openvrml::x3d_vrml_media_type;
00186 } else if (iequals(ext, "png")) {
00187 media_type = "image/png";
00188 } else if (iequals(ext, "jpg") || iequals(ext, "jpeg")) {
00189 media_type = "image/jpeg";
00190 }
00191 return media_type;
00192 }
00193
00194 virtual bool do_data_available() const throw ()
00195 {
00196 return !!(*this);
00197 }
00198 };
00199
00200 const string scheme = uri.substr(0, uri.find_first_of(':'));
00201 if (scheme != "file") {
00202 throw invalid_argument('\"' + scheme + "\" URI scheme not "
00203 "supported");
00204 }
00205
00206
00207
00208
00209
00210 static const string::size_type authority_start_index = 7;
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 string::size_type path_start_index =
00221 # ifdef _WIN32
00222 uri.find_first_of('/', authority_start_index) + 1;
00223 # else
00224 uri.find_first_of('/', authority_start_index);
00225 # endif
00226 string path = uri.substr(path_start_index);
00227
00228 auto_ptr<resource_istream> in(new file_resource_istream(path));
00229 static_cast<file_resource_istream *>(in.get())->url(uri);
00230
00231 return in;
00232 }
00233
00234 sdl_error::sdl_error(const std::string & message):
00235 std::runtime_error(message)
00236 {}
00237
00238 sdl_error::~sdl_error() throw ()
00239 {}
00240
00241 const Uint32 sdl_viewer::video_mode_flags(SDL_OPENGL | SDL_RESIZABLE);
00242
00243 sdl_viewer::sdl_viewer(const std::string & title) throw (sdl_error):
00244 update_timer_id(0),
00245 mouse_button_down(false)
00246 {
00247 static const size_t initial_width = 640;
00248 static const size_t initial_height = 480;
00249
00250 if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0) {
00251 throw sdl_error(SDL_GetError());
00252 }
00253 if (!SDL_SetVideoMode(initial_width,
00254 initial_height,
00255 0,
00256 sdl_viewer::video_mode_flags)) {
00257 throw sdl_error(SDL_GetError());
00258 }
00259 this->resize(initial_width, initial_height);
00260
00261 static const char * const icon = 0;
00262 SDL_WM_SetCaption(title.c_str(), icon);
00263 }
00264
00265 sdl_viewer::~sdl_viewer() throw ()
00266 {
00267 SDL_Quit();
00268 }
00269
00270 void sdl_viewer::run()
00271 {
00272 this->update();
00273 bool done = false;
00274 bool need_update = false;
00275 bool need_redraw = false;
00276 do {
00277 SDL_Event event = {};
00278 sdl_viewer::event_info viewer_event_info;
00279 while (SDL_PollEvent(&event)) {
00280 switch (event.type) {
00281 case SDL_VIDEOEXPOSE:
00282 this->post_redraw();
00283 break;
00284 case SDL_VIDEORESIZE:
00285 SDL_SetVideoMode(event.resize.w,
00286 event.resize.h,
00287 0,
00288 sdl_viewer::video_mode_flags);
00289 this->resize(event.resize.w, event.resize.h);
00290 this->post_redraw();
00291 break;
00292 case SDL_KEYDOWN:
00293 viewer_event_info.event = sdl_viewer::event_key_down;
00294 switch (event.key.keysym.sym) {
00295 case SDLK_HOME:
00296 viewer_event_info.what = sdl_viewer::key_home;
00297 break;
00298 case SDLK_LEFT:
00299 viewer_event_info.what = sdl_viewer::key_left;
00300 break;
00301 case SDLK_UP:
00302 viewer_event_info.what = sdl_viewer::key_up;
00303 break;
00304 case SDLK_RIGHT:
00305 viewer_event_info.what = sdl_viewer::key_right;
00306 break;
00307 case SDLK_DOWN:
00308 viewer_event_info.what = sdl_viewer::key_down;
00309 break;
00310 case SDLK_PAGEDOWN:
00311 viewer_event_info.what = sdl_viewer::key_page_down;
00312 break;
00313 case SDLK_PAGEUP:
00314 viewer_event_info.what = sdl_viewer::key_page_up;
00315 break;
00316 default:
00317 break;
00318 }
00319 this->input(&viewer_event_info);
00320 break;
00321 case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP:
00322 viewer_event_info.event = event.button.state == SDL_PRESSED
00323 ? sdl_viewer::event_mouse_click
00324 : sdl_viewer::event_mouse_release;
00325 viewer_event_info.what = event.button.button - 1;
00326 viewer_event_info.x = event.button.x;
00327 viewer_event_info.y = event.button.y;
00328 this->input(&viewer_event_info);
00329 break;
00330 case SDL_MOUSEMOTION:
00331 if (!event.motion.state) {
00332 viewer_event_info.event = sdl_viewer::event_mouse_move;
00333 viewer_event_info.x = event.motion.x;
00334 viewer_event_info.y = event.motion.y;
00335 this->input(&viewer_event_info);
00336 } else {
00337 for (Uint8 button = SDL_BUTTON_LEFT;
00338 button < 4;
00339 ++button) {
00340 if (event.motion.state & SDL_BUTTON(button)) {
00341 viewer_event_info.event =
00342 sdl_viewer::event_mouse_drag;
00343 viewer_event_info.what = button - 1;
00344 viewer_event_info.x = event.motion.x;
00345 viewer_event_info.y = event.motion.y;
00346 this->input(&viewer_event_info);
00347 }
00348 }
00349 }
00350 break;
00351 case SDL_QUIT:
00352 done = true;
00353 break;
00354 case SDL_USEREVENT:
00355 switch (event.user.code) {
00356 case redraw_event_code:
00357 need_redraw = true;
00358 break;
00359 case update_event_code:
00360 need_update = true;
00361 break;
00362 }
00363 break;
00364 default:
00365 break;
00366 }
00367 }
00368 if (need_update) {
00369 this->update();
00370 need_update = false;
00371 }
00372 if (need_redraw) {
00373 this->redraw();
00374 need_redraw = false;
00375 }
00376 } while (!done);
00377 }
00378
00379 void sdl_viewer::post_redraw()
00380 {
00381 SDL_Event redraw_event;
00382 redraw_event.type = SDL_USEREVENT;
00383 redraw_event.user.code = sdl_viewer::redraw_event_code;
00384 redraw_event.user.data1 = 0;
00385 redraw_event.user.data2 = 0;
00386 SDL_PushEvent(&redraw_event);
00387 }
00388
00389 void sdl_viewer::set_cursor(cursor_style)
00390 {}
00391
00392 void sdl_viewer::swap_buffers()
00393 {
00394 SDL_GL_SwapBuffers();
00395 }
00396
00397 Uint32 update_timer_callback(Uint32 , void * const param)
00398 {
00399 sdl_viewer & v = *static_cast<sdl_viewer *>(param);
00400 SDL_RemoveTimer(v.update_timer_id);
00401 v.update_timer_id = 0;
00402 SDL_Event update_event;
00403 update_event.type = SDL_USEREVENT;
00404 update_event.user.code = sdl_viewer::update_event_code;
00405 update_event.user.data1 = 0;
00406 update_event.user.data2 = 0;
00407 SDL_PushEvent(&update_event);
00408 return 0;
00409 }
00410
00411 void sdl_viewer::set_timer(const double t)
00412 {
00413 if (!this->update_timer_id) {
00414 const Uint32 interval = Uint32(1000.0 * t + 20);
00415 this->update_timer_id =
00416 SDL_AddTimer(interval, update_timer_callback, this);
00417 }
00418 }
00419 }