gnash-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-dev] Gnash source code analysis (WAS: Questions about trapezoids.


From: Udo Giacomozzi
Subject: [Gnash-dev] Gnash source code analysis (WAS: Questions about trapezoids...)
Date: Thu, 21 Sep 2006 21:26:20 +0200

I continue this discussion here for simplicity. :)


>> 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.

I'd say it's useful. For example, we could use it to specify the
framebuffer device (/dev/fbX) that should be used. That's a special
option for the AGG "GUI".


> I think set_current_root() should only be called when the uppermost
> movie is replaced with something else.

With other words, when I call _root.LoadMovieClip() ?


> 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.

Indeed. So set_current_root() is different from _root ?


>> 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.


Uhm, I think the original Flash player newer skips frames. When it
cannot render a frame in time, then the movie simply slows down.


>> 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...

Just curious: What's the problem with ref_counted? I'm not so
experienced with C++ (I prefer other programming languages) so I don't
know all tricks.. 


Let me write a summary of the most important classes involved. It's
still difficult to see Gnash as a whole for me. Correct me if I write
something incorrect or if something is missing.


movie_definition = The definition of a MovieClip (including the Movie
  itself). It's basically the library of the Movie. This is the base
  class without any methods implemented.

movie_def_impl = This is the definition implementation of the SWF
  parsing. It's the one that's actually useful.

movie_interface = A more appropriate name would be "movie_instance".
  It holds information for any stateful movie. The root movie is one
  of these and the same applies for sprites (MovieClips). Each
  interface/instance refers to exactly one movie_definition. So, if
  100 sprites of the same kind are displayed in the movie there will
  be 100 movie_interfaces but just one movie_definition for that kind
  of sprite.
  It's just a abstract class definition.

movie_root = This class is used to hold information (about the root
  movie (the SWF file). It is the top *instance* (interface) in the
  player. It contains the reference to a sprite_instance for the root
  movie. Strangely both movie_root and sprite_instance derive from
  movie_interface, so one could say the root movie has two
  instances..

sprite_instance = The source code says "Stateful Sprite object. Also
  known as a MovieClip.". The difference to movie_interface is that
  the latter is more generic. The sprite_instance handles
  ActionScript.
  
character_def = Abstract base class for all kinds of characters
  (their definition!).

character = (could be named "character_interface" or
  "character_instance"). It's the stateful instance of a character
  definition.

generic_character = since it is an instance, I guess this is a single
  letter (not it's font definition)? Would need some clarification
  here...

edit_test_character = can't find it in text.h, has this been removed?
  It is found in the online Doxygen reference. What's this anyway?

display_list = holds a list of "character" instances. Each
  movie_interface contains one DisplayList. It's the link between
  sprites (ActionScript) and characters (no ActionScript).

shape_character_def = Character definition for shapes and outlines.

button_character_definition = definition of a button. It holds one
  character definition for each one of four button states.

edge = a quadratic bezier curve. It has a anchor point (where it ends)
  and a control point (that stretches the curve in some direction). It
  is also used for straight lines, who are created artificially by
  copying the position of the anchor point to the control point. It is
  a segment of a shape, the starting point of the curve is defined by
  the previous edge.

path = list of edges, defines the original outline of a single shape
  (not the whole character, just one style).

tri_stripper = class that takes trapezoids and transforms them to
  triangles (to a "mesh_set").

mesh = list of straight lines that resemble the curves.

mesh_set = for each fill style used in a character, this class holds
  one (!) list of points (coordinates) that define the corners of each
  triangle. The list contains n+2 points where n is the number of
  triangles.

line_strip = a set of straight lines, used to draw outlines (this is
  passed to the renderer)

uhmm... did I forget anything important?


Additional notes about the Tesselator:
I analyzed this thing further and I think that I found out how it
works: The whole shape is transformed into trapezoids. Each trapezoid
is then split into two triangles by cutting the trapezoid from the
upper right to the lower left corner.
When the original shape was already a triangle, then it is transformed
to a trapezoid anyway (where two corners share the same coordinates).
This leads to two(!) triangles anyway (one of them being not visible
since two of his corners are equal).
Okay, now the triangles are arranged (and sometimes rotated) so that
they tend to share the most points. It will draw an imaginary line
along all the edges of the triangles later and so it tries to reduce
the number of points along the line.
The points of all triangles are stored in a list and when the
triangles are drawn it slides through that list taking always 3 points
but advancing only by one point, so having 3 points = 1 triangle,
4 points = 2 triangles, 5 points = 3 triangles, 6 points = 4 triangles
and so on. This is done for the whole shape ("character" may be more
appropriate now), even if it consists of two figures that do not touch
each other (like two rectangles).
To jump from one figure to another (or to a distant point in a single
figure), a imaginary triangle is inserted that again has two equal
corners (and thus is invisible). These triangles are even passed to
the renderer!
This process is done for each fill style of the character of course.

However, I wonder if this is really more efficient than just keeping a
list of independent triangles and avoiding the triangle sorting
completely.

For simplicity here is an example:

  0          1
   +--------+
   |      . |
   |    .   |
   |  .     |
   |.       |
   +--------+
  2         3,4
  
                 5,6        7
                  +--------+
                  |      . |
                  |    .   |
                  |  .     |
                  |.       |
                  +--------+
                 8          9

These are two rectangles with the same solid fill style (the dots show
where the triangles are drawn, but this line would not be visible).
The numbers show the order of the points like they are stored in the
mesh set. 

0-1-2 and 1-2-3 are two triangles that together make the first
rectangle.

2-3-4, 3-4-5 and 5-6-7 are invisible triangles (and thus needlessly
processed by the renderer!)

6-7-8 and 7-8-9 build the second rectangle.



> 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)

I see. So a definition contains the shape and the instance has
information about transformations, visibility etc.
What about the Flash drawing API? Technically it would fit better in
the definition part (because it creates information that otherwise
would be found in the SWF file). However, it is stateful information
that does exist only once. Or can I say, that by drawing a shape, I'm
defining it? Dunno..



>> 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)

Sorry, my information was not correct. :(

In Flash there exist only lines and quadratic curves - nothing else.
Before my tesselate_curve() patch there even were no lines. When you
draw a circle in Flash, it's actually built using eight (I think)
curves. You can see that when you try to drag the outline of the
circle in the IDE.

That's also the reason why the Flash drawing API has no circle() or
ellipse() method.

So no part of Gnash would ever need to deal with circles - they simply
don't exist (as a primitive).

If you think of it it is a genius approach... :)


>> 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.

Indeed. However, there is no such class (yet), right? Sorry, I'm
currently reading CVS sources of September 04th...


>> 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.


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

Good idea. I'll do that as soon as I know enough about Gnash..

internals.xml. Interesting. Excuse my ignorance, but how I read them?
Are they part of DoxyGen? I'm currently using the (old) online DoxyGen
pages, but could not find any "Internals" chapter there...

Udo





reply via email to

[Prev in Thread] Current Thread [Next in Thread]