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