# -*- mode: org; coding: iso-8859-15; -*- # # For all of you that use Emacs, the coding will be automatic. # for all others please save this file in ISO-8859-15 coding. # # This is a text-file. And also an Org-Mode file. # Please refers to: http://orgmode.org/ # # Org-Mode can be use with "text-file" (with a few formating # conventions. # # Once in Org-Mode, having loaded this file, you can create # the PDF with the binding: C-c C-e p # # You can create an HTML export with: C-c C-e h # #+TITLE: FreeWRL library interface #+Author: Michel Briand #+Email: michelbriand@free.fr #+Date: 2011-02-12 ## hyperref is in org-export-latex-default-packages-alist # For hyperref (included by default): #+LaTeX_CLASS_OPTIONS: [colorlinks=true,urlcolor=SteelBlue4,linkcolor=black,linktoc=none] #+LATEX_HEADER: \usepackage{babel} #+LATEX_HEADER: \usepackage{times} #+LATEX_HEADER: \usepackage[top=2.5cm, bottom=2.5cm, left=2.8cm, right=2.8cm]{geometry} #+LATEX_HEADER: \usepackage[hyperref,x11names]{xcolor} # For no-indented paragraphs: #+LATEX_HEADER: \setlength{\parindent}{0pt} #+LATEX_HEADER: \setlength{\parskip}{\medskipamount} * FreeWRL library specification ** Current situation *** Excerpt from libFreeWRL.h I stripped comments and platform specific code from =libFreeWRL.h=: #+begin_example const char *libFreeWRL_get_version(); typedef struct freewrl_params { ... } freewrl_params_t; extern freewrl_params_t fw_params; bool initFreeWRL(freewrl_params_t *params); void startFreeWRL(const char *url); void closeFreeWRL(); void terminateFreeWRL(); int ConsoleMessage(const char *fmt, ...); void create_EAI(); void create_MIDIEAI(); void doQuit(); bool Anchor_ReplaceWorld(); #define VIEWER_NONE 0 #define VIEWER_EXAMINE 1 #define VIEWER_WALK 2 #define VIEWER_EXFLY 3 #define VIEWER_FLY 4 #define VIEWER_YAWPITCHZOOM 5 void set_viewer_type(const int type); void setGeometry_from_cmdline(const char *gstring); void setSnapFile(const char* file); void setSnapTmp(const char* file); void setEaiVerbose(); void setScreenDist(const char *optArg); void setStereoParameter(const char *optArg); void setShutter(void); void setEyeDist(const char *optArg); void setAnaglyphParameter(const char *optArg); void setSideBySide(void); void setStereoBufferStyle(int); void initStereoDefaults(void); void setLineWidth(float lwidth); void setSnapGif(); void setPrintShot(); #define RUNNINGASPLUGIN (isBrowserPlugin) extern char *BrowserFullPath; extern int _fw_pipe, _fw_FD; extern int _fw_browser_plugin; extern int isBrowserPlugin; extern uintptr_t _fw_instance; extern char *keypress_string; void askForRefreshOK(); int checkRefresh(); void resetRefresh(); #+end_example *** What's used in the Linux front-end I gathered the functions really used in the front-end code: #+begin_example $ nm .libs/freewrl | sed -n '/ U /p' | sed -e 's/[ \t]*U //' | grep -v GLIBC ConsoleMessage doQuit initFreeWRL initStereoDefaults libFreeWRL_get_version setAnaglyphParameter setEaiVerbose setEyeDist setGeometry_from_cmdline setLineWidth setScreenDist setShutter setSideBySide setSnapFile setSnapGif setSnapTmp setStereoParameter startFreeWRL #+end_example Doing the same for data structures and global variables: #+begin_example $ nm .libs/freewrl | sed -n '/ B /p' | sed -e 's/.*[ \t]*B //' | grep -v GLIBC _fw_browser_plugin _fw_instance _fw_pipe isBrowserPlugin keypress_string params #+end_example Looking (quickly) into the code, I've found: *in* =src/bin/main.c= : freewrl_params_t *params = NULL; ** What to do to improve the situation *** Naming convention We have to decide about an enforced naming convention. Not to say that : gnu_or_open_source_convention is better than : MicrosoftOrSoCalledPolishNotation That's not my intent. But to make all the FreeWRL code homogeneous. Personnaly I feel the first more readeable. But feel free to comment / propose. *** Namespace All symbols that are visible outside must be declare in =libFreeWRL.h=. All platform specific cases should be handle through glue code. **** Data types All data types that can be used from outside (thus declared in =libFreeWRL.h=) must be consistently named: : typedef struct { .... } fwl_params_t; : extern int fwl_is_browser_plugin; : extern char *fwl_keypress_string; instead of: : typedef struct freewrl_params { .... } freewrl_params_t; : extern int isBrowserPlugin; : extern char *keypress_string; **** Functions All =libFreeWRL= functions that can be called from outside (thus declared in =libFreeWRL.h=) must be consistently named: : void fwl_init(); : void fwl_quit(); instead of: : bool initFreeWRL(freewrl_params_t *params); : void doQuit(); **** MACROs All macros that can be used from outside (thus declared in =libFreeWRL.h=) must be consistently named: : #define FWL_VIEWER_WALK 2 : #define FWL_IS_BROWSER_PLUGIN (fwl_is_browser_plugin) instead of: : #define VIEWER_WALK 2 : #define RUNNINGASPLUGIN (isBrowserPlugin) *** Graphic system initialization **** Current situation *Correct me if I'm wrong.* On =Linux= the front-end calls the library which initialize itself the =X11= display and the =GLX= context. Thus the front-end does not have the control here. On =Mac= the front-end initialize the =Aqua= display and the =AGL= context. On =Windows= the situation is somewhat similar to =Linux= (see =fwWindow32.c=). Let's call the graphical system initialization and variables the /context/. **** A more flexible method A method to make all platforms use the same codebase for the /context/. Beside the =fwl_params_t= structure that has to be extensively used we ought to create another data type for /context/ initialization. Let's call it =fwl_context_t= for the sake of simplicity. This data type shall be /anonymous/, that is /generic/. Then, each platform will have a /specific/ implementation of this type. I.e. a =fwl_context_x11_t=, =fwl_context_aqua_t=, =fwl_context_win_t=, ... This type will have two use cases. The first is when the front-end initializes itself the /context/. I.e. when it initializes the /context/ in a way that fits its specific needs. The front-end do that, then fills in the FreeWRL context with actual values for the library to access them when this is needed. The second use case is when the front-end delegate the graphical context initialization to the library. Through this data structure, the front-end can access the context variables if it needs. ***** Example Linux =GLX= context and =X11= window identifier in the specific =fwl_context_x11_t=: #+begin_example typedef struct { ... GLXContext ctx; Window win; ... } fwl_context_x11_t; #+end_example Windows =WGL= context and =Win32= window identifier in the specfic =fwl_context_win_t=: #+begin_example typedef struct { ... HGLRC ctx; HWND win; ... } fwl_context_x11_t; #+end_example *** Events **** Current situation All events, coming through a specific graphical system, must be translated into a common, generic event. Because the current situation is a mess. Each platform has its specificities about event. This prevent us to improve the user experience. This will be a concern for iPhone and Android... Example of the current situation with the event generated when the window geometry changes. You can see a lot of differences... *Linux* #+begin_example switch(event.type) { case ConfigureNotify: setScreenDim (event.xconfigure.width,event.xconfigure.height); break; #+end_example *Windows* #+begin_example switch( msg ) { case WM_SIZE: GetClientRect(hWnd, &rect); screenWidth = rect.right; /*used in mainloop render_pre setup_projection*/ screenHeight = rect.bottom; resize_GL(rect.right, rect.bottom); setScreenDim(rect.right,rect.bottom); break; #+end_example *Mac* Where is this ? In the front-end obviously. Then the front-end pass events to the library through the function =handle_aqua()=. **** How to improve Create a unique definition for events of all sorts. Let's call it =fwl_event_t= for the sake of simplicity. Create a function to translate an =<whatever platform>= event into a =fwl_event_t=. Create a function to eat an event. I.e. to act on the event. Create a system of callbacks. Then, two cases are possible: - the library runs the event loop (it has created the /context/). Default callbacks are programmed to be called for each interresting events. The list of default callbacks defines a /viewer behavior/ or an /actor/. I.e. /walk/ and /fly/ are two different /actors/. - the front-end is the master (it initialized the /context/ and controls the event loop). It programs callbacks for all the events it wants to eat itself. Then pass the event to the library. Which translates the event, and then to act upon it. The callbacks are called by the library /actor/ active at this time. *** OpenGL binding A /great job/ was accomplished when a lot of OpenGL calls where replaced by macros. That way a compile time selection of the rendering capabilities is possible. If this is possible, the job has to be finished: i.e. for all OpenGL calls. Basically we can see OpenGL-ES as a subset of OpenGL. But for FreeWRL to work correctly OpenGL-ES requires the use of =VBO=. *** An unique function to get/set libFreeWRL variables **** Purpose - all variables visible from outside the library that need an accessor (to trap changes, update other variables, ...) - all variables exposed to scripting language or external processes (SAI/EAI) that need an accessor (check type, check value, ...) **** Variable list - window (type is platform specific) - OpenGL window (type is platform specific) - GLX/AGL/WGL context (type is platform specific) - width - height - fullscreen (switch) - eai (switch) - verbose (switch) - collision (switch) - starting url (world base) - viewer mode - snap (switch) - snap directory - snap file pattern - EAI verbose (switch) - screen dist - stereo (switch) - shutter glass (switch) - eye dist - anaglyph - side by side (switch) - stereo buffer mode (switch) - line width - snap gif (not used?) - print shot (can't understand this?) - browser full path (need rework) - pipe and all plugin related variables (I rewriting this) - keypress_string (need rework) - ask for refresh, refresh switch or status (need rework) **** Implementation - a new include file could be created with the list of variables (it will be included in libFreeWRL.h when this step is finished) - a new source file could be created with the unique accessor function * Annexes ** Debug with Firefox Work with local Firefox $ export LD_LIBRARY_PATH=<path of local firefox>:$LD_LIBRARY_PATH In local firefox plugin dir: $ ln -s <path of development version of libFreeWRLplugin.so> libFreeWRLplugin.so Debug LD: $ export LD_WARN=yes $ export LD_DEBUG=all $ export LD_DEBUG_OUTPUT=/tmp/ld.log