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