On Tue, Sep 19, 2006 at 11:38:15PM +0200, Udo Giacomozzi wrote:

> Ok, since we already started the discussion I attached the current
> version of my notes to this mail. I hope it can be of some help - at
> least being a basis for this discussion.

Good work!
I attach some notes about your document, will come back on the
message body later.

--strk;
Thanks a lot!  Some notes by myself

[...]
> Player
> ------
> 
> There seem to be two gnash.cpp, one in gui/ and one in backend/, the latter 
> being more than twice as big. However, it appears that the one in gui/ is the 
> correct one because there has been some redesign of the internal Gnash 
> architecture (support for multiple front-/backends).

I confirm backend/gnash.cpp is obsoleted, and should actually be gone
from CVS now.

> gnash.cpp is used for both the standalone and the plugin mode. 

The plugin simply makes a system call to the 'gnash' executable, no
matter what the sources for it are :)
The plugin source is plugin/plugin.cpp

[...]
> The sound handlers are then being intialized, but I won't go any deeper there
> because it's currently far from my interest...
> 
> get_movie_info() (from server/impl.cpp) is then used to read the header of 
> the 
> SWF file. The size of the stage, frame rate etc. are retrieved this way. The
> function raises an exception when an error occurrs. Compressed SWF files seem
> to be supported (using ZLIB).

IFF you do have ZLIB, compressed SWF files *are* supported.
BTW, I was thinking about removing that call as it triggers double stream
creatino (once for get_movie_info and once for create_library_movie).
Movie info should be fetched from an already opened stream IMHO...

> There is a special code fragment for the SDL GUI which calls a 
> disableCoreTrap()
> function - probably a quick hack not really belonging there?

Most likely...

> The command line arguments are passed to the GUI, so that it may extract 
> additional settings from it (?).

I think this was the idea, but I don't think any gui is currently doing it.

[..]
> Using set_current_root() a global variable "s_current_root" is updated which
> probably reflects the current root MC ("_root" in Flash). This variable may be
> updated when an external movie is loaded and processed (via LoadMovieClip 
> Flash
> command I guess).

I think set_current_root() should only be called when the uppermost
movie is replaced with something else. The "_root" reference in Flash
is a "relative" one. Ie. you can have multiple "_root" movies in a single
run: one for each loaded SWF.

[...]
> The GUI
> -------
> 
> I'll continue my analysis using the GTK GUI and the Cairo backend. 
> 
> The class descendant is defined in gtksup.h and implemented in gtk.cpp. It
> does all the necessary stuff to initialize a GTK window.
> 
> A class member named "glue" is the interface to the backend, in this case 
> being
> the GtkCairoGlue class. It is initialized in GtkGui::Init (again passing 
> command
> line parameters). 
> 
> The "Gui" base class already defines a member called "_renderer" which is the 
> interface to the renderer class. The appropriate instance is created in 
> GtkGui::createWindow(), which in turn is called from within the main program. 
> 
> The file "gtk_glue_cairo.cpp" apparently is the connection between the GUI 
> and 
> the backend. It contains the actual code to *create* the renderer instance by
> calling itself gdk_cairo_create(). It doesn't do much more useful and I did 
> not
> yet find the reason for the "glue" class (just to avoid a few IFDEFs?).
> 
> For clarity, here is the complete call stack for creating the renderer:
> 
>   gui/gnash.cpp -> gui.createWindow(infile, width, height);
>     |
>   gui/gtk.cpp -> _renderer = glue.createRenderHandler();
>     |
>   gui/gtk_glue_cairo.cpp -> return create_render_handler_cairo(...);
>     |
>   backend/render_handler_cairo.cpp -> return new render_handler_cairo();
>   
> The frame delay (setCallback(), see above) is implemented using a GTK timer 
> with
> low priority that calls the method "advance_movie" from the base Gui class 
> (see
> gui/gui.cpp).
>  
> The GUI (in the "run" method) passes control to GTK via gtk_main(), which will
> take care of displaying it's window and call the "advance_movie" method 
> periodically. It will not exit before the application should be terminated 
> (gtk_quit() probably).
> 
> advance_movie() itself advances the root movie (MC) by one frame. The 
> parameter
> of  server/movie_instance.cpp:advance()  is a float which I don't understand 
> why. There are a bunch of stacked advanceXXXX() calls but generally a frame 
> advace would always be 1.0. Maybe floats are required for tweening where it
> would make sense, but I haven't checked this.

IIRC the float is the "time-left". I don't think it's working,
but theoretically it would skip something if run out of time.

> Anyway, movie_interface::advance() probably has the following (unchecked) 
> tasks:
> 
>   - update the display list (that is, what is visible on the screen) according
>     to the new frame
>     
>   - apply tweening
>   
>   - process ActionScript code
>   
>   - define the current viewport?
>    
> It then calls display() of the root movie (movie_root class). That method 
> calls
> begin_display() of the renderer class and passes the current viewport, the 
> background color and the frame (=stage) size. The renderer normally clears the
> framebuffer by filling the viewport with the background color.
> 
> Then the more generic display() method (of movie_interface, or more exactly 
> sprite_instance) is called, which draws the display list and finally 
> end_display() is told to the renderer class to commit the current frame. 
> 
> More on the display() method in the next section!
> 
> Then gui::renderBuffer() is called, which again is located in gtk.cpp and 
> passes
> the call to glue::render(), which in the case of the Cairo backend does 
> nothing.
> This may be a function that can be used to swap a double buffer or tell 
> something to acceleration hardware but it seems that it's just a duplicate 
> for 
> end_display(), except that the call goes through the GUI and so may be used 
> to 
> blit the frame buffer on screen or something...
> 
>   NOTE: This function probably could be very useful for the AGG backend. The
>   backend would render the frame the same way for any platform / WM 
> combination.
>   The GUI then takes the finished frame buffer and blits it to the hardware
>   framebuffer (/dev/fb0), to some X window, or Windows GDI handle, or 
> whatever.
>   This last step would fit well into renderBuffer() directly.
>   
>  
> Rendering / Sprite instances
> ----------------------------
> 
> Back to the sprite_instance::display() method.
> 
> The sprite_instance class holds information for any existing (visible and 
> invisible) sprite on the stage. In the Flash world this would be a MovieClip 
> (MC) which itself can contain other MCs and stateful information such as 
> ActionScript variables. The root MC is basically a sprite too, just like any 
> MC has it's own timeline.
> 
> sprite_instance class inheritance:
> 
> 
>   ref_counted (server/ref_counted.h)
>     |
>   as_object (server/as_object.h)
>     |
>   movie_interface (server/movie_interface.h)
>     |
>   movie (server/movie.h)
>     |
>   character (server/character.h)
>     |
>   sprite_instance (server/sprite_instance.h)

... I hate the "movie_interface - movie" part, trying to get rid of it.
BTW, we should also get rid of ref_counted base...

As you can see it is an 'instance' being displaied, not a definition.
I'd like this to be true for all classes. The point is that a definition
is *fixed*, while an instance can change at runtime (transformed, moved)

> The sprite contains a member "m_display_list" which is of type "DisplayList" 
> (defined in server/dlist.h). This is the display list of the sprite, that is,
> what "characters" the sprite itself does contain. Each character has it's own
> "depth" which defines the order of which the characters have to be displayed.
> No two characters can be at the same depth.

DisplayList is one of the new classes (I rewrote it).
I guess you can tell by naming convention. The aim is to split existing
classes in smaller classes so it's easier to move them around.

> sprite_instance::display() passes the call to display_list::display() which 
> goes through the list of characters and calls their own display() method. 
> Since MCs can contain mask layers the sprite may inform the renderer about it.
> 
> Basically, before a character of a mask is rendered (the mask "begins"), the
> method renderer::begin_submit_mask() is called. Then normal rendering 
> operations follow until the mask is confirmed with 
> renderer::end_submit_mask().
> This enables the mask which remains active until render::disable_mask() is
> called.
> 
> Say, we have a rectangle A partially masked by circle B and a triangle C that
> does not have a mask (above it). This should work as follows:
> 
>   1. renderer::begin_submit_mask()
>   2. circle B is drawn
>   3. renderer::end_submit_mask()  --> the mask is now a circle
>   4. rectangle A is drawn, using the mask
>   5. render::disable_mask()  --> mask not required anymore
>   6. triangle C is drawn normally
>   
> The way how the specific character (which may be a MC of it's own) is being
> drawen depends on the character type (see following sections).
> 
> 
> Outlines and shapes
> -------------------
> 
> The file server/shape.h contains a few classes that are drawing primitives 
> (curves, shapes, ...). The'yre created while parsing the SWF file.

You mentioned we would be using these classes from the drawing API, right ?
So this might belong to a 'shapes' lib (or geometry lib, which we already have)

> When a line or curve is read from the SWF file it is being handled by
> server/parser/shape_character_def.cpp
> 
> It's read() method first loads the fill and line style. For a simple outline,
> there would be no fill. Then it reads the actual shape records.
> 
>   NOTE: Any shape (being it filled or not) begins in the SWF file with the
>   definiton of the fill styles, followed by the line styles and finally the
>   edges that define the shape itself. Along the edges path the previously
>   defined styles may be selected at any position.
>   
> Any shape consists of straight lines and/or curves. 
> 
> So read():
>   - calls read_fill_styles() to read all the necessary fill styles of the 
> shape
>   - calls read_line_styles() to do the same for the line styles
>   - reads the number of bits used for indexing fill and line styles later on
>   - loads the shape definition and stores it in the "current_path" variable
>   
> The current_path variable (of type "path") contains a list of objects of type 
> "edge". Straight lines are also stored as curves, whose control point equals 
> the anchor point. So, the path only contains a list of curves!
> 
> At the end the current_path is added to the class' "m_paths" vector.
> 
> The display() method of the class takes care that the path of the shape is 
> converted to a valid "mesh", that is a set of straight lines. This mesh is 
> also

I think it should be the display() method of a shape_character_instance instead.

> stored in some sort of cache so that it does not have to be re-calculated when
> it's not necessary (important speed optimization).

The cache invalidation should be automatic whenever the shape_instance is
updated (a matrix transfor applied, a new line being drawn, a clear, etc.)

> Of course these straight lines are an approximation of the curves and so the 
> display() method keeps track of the error. If it raises a certain tolerance, 
> then the mesh needs to be recalculated. This may be necessary when the total
> transformation matrix changes noticeably, for example when resizing a sprite.
> 
> The class "mesh_set" takes care of this (more on this later).
> 
> Regardless of whether the mesh has been loaded from cache or just 
> recalculated,
> it's own display() method is called to render it.     

Thus, I'd have the mesh_set an utility class for the shape_character_instance,
possibly only visible by it's implementation, to simplify code browsing.

[..]

That a great job you've been doing. I suggest writing these info
as Doxygen notes and also in the internals.xml file.

Thank you.
_______________________________________________
Gnash-dev mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/gnash-dev

Reply via email to