root/src/displaylist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. destroySWFDisplayItem
  2. destroySWFDisplayList
  3. newSWFDisplayList
  4. newSWFSpriteDisplayList
  5. SWFDisplayItem_replace
  6. SWFDisplayList_add
  7. SWFDisplayItem_remove
  8. SWFDisplayItem_removeFromList
  9. checkBlock
  10. SWFDisplayItem_getCharacter
  11. SWFDisplayItem_getDepth
  12. SWFDisplayItem_setDepth
  13. SWFDisplayItem_getMatrix
  14. SWFDisplayItem_move
  15. SWFDisplayItem_moveTo
  16. SWFDisplayItem_getPosition
  17. SWFDisplayItem_rotate
  18. SWFDisplayItem_rotateTo
  19. SWFDisplayItem_getRotation
  20. SWFDisplayItem_scale
  21. SWFDisplayItem_scaleTo
  22. SWFDisplayItem_getScale
  23. SWFDisplayItem_skewX
  24. SWFDisplayItem_skewXTo
  25. SWFDisplayItem_skewY
  26. SWFDisplayItem_skewYTo
  27. SWFDisplayItem_getSkew
  28. SWFDisplayItem_setMatrix
  29. SWFDisplayItem_setName
  30. SWFDisplayItem_setMaskLevel
  31. SWFDisplayItem_endMask
  32. SWFDisplayItem_setRatio
  33. SWFDisplayItem_setCXform
  34. SWFDisplayItem_setColorAdd
  35. SWFDisplayItem_setColorMult
  36. SWFDisplayItem_addAction
  37. SWFDisplayItem_addFilter
  38. SWFDisplayItem_setBlendMode
  39. SWFDisplayItem_cacheAsBitmap
  40. SWFDisplayList_setSoundStream
  41. SWFDisplayList_rewindSoundStream
  42. SWFDisplayList_writeBlocks
  43. SWFDisplayItem_flush

/*
    Ming, an SWF output library
    Copyright (C) 2002  Opaque Industries - http://www.opaque.net/

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdlib.h>
/* not used? #include <string.h> */
#include <math.h>

#include "blocks/placeobject.h"
#include "blocks/character.h"
#include "blocks/matrix.h"
#include "displaylist.h"
#include "position.h"
#include "blocks/soundstream.h"
#include "blocks/outputblock.h"
#include "blocks/button.h"
#include "blocks/videostream.h"
#include "blocks/blocktypes.h"
#include "blocks/filter.h"
#include "blocks/sprite.h"
#include "blocks/scalinggrid.h"
#include "libming.h"

#define ITEM_NEW                                                (1<<0)
#define ITEM_REMOVED                            (1<<1)
#define ITEM_TRANSFORMED                (1<<2)
#define ITEM_CXFORMCHANGED      (1<<3)
#define ITEM_RATIOCHANGED               (1<<4)

#define ITEM_CHANGED    (ITEM_TRANSFORMED|ITEM_CXFORMCHANGED|ITEM_RATIOCHANGED|ITEM_NEW)

struct SWFDisplayList_s
{
        SWFSoundStream soundStream;
        SWFDisplayItem head;
        SWFDisplayItem tail;    
        byte isSprite;
        int depth;
};


void
destroySWFDisplayItem(SWFDisplayItem displayItem)
{
        if ( displayItem->position )
                destroySWFPosition(displayItem->position);

        if ( displayItem->matrix )
                destroySWFMatrix(displayItem->matrix);

        /* character is freed in blocklist */

        free(displayItem);
}


void
destroySWFDisplayList(SWFDisplayList displayList)
{
        SWFDisplayItem item = displayList->head, next;

        while ( item != NULL )
        {
                next = item->next;
                destroySWFDisplayItem(item);
                item = next;
        }

        free(displayList);
}


SWFDisplayList
newSWFDisplayList()
{
        SWFDisplayList list = (SWFDisplayList)malloc(sizeof(struct SWFDisplayList_s));

        /* If malloc failed, return NULL to signify this */
        if (NULL == list)
                return NULL;

        list->isSprite = FALSE;
        list->head = NULL;
        list->tail = NULL;
        list->soundStream = NULL;
        list->depth = 0;

        return list;
}


SWFDisplayList
newSWFSpriteDisplayList()
{
        SWFDisplayList list = (SWFDisplayList)malloc(sizeof(struct SWFDisplayList_s));

        /* If malloc failed, return NULL to signify this */
        if (NULL == list)
                return NULL;

        list->isSprite = TRUE;
        list->head = NULL;
        list->tail = NULL;
        list->soundStream = NULL;
        list->depth = 0;

        return list;
}

void
SWFDisplayItem_replace(SWFDisplayItem item, SWFCharacter character)
{
        item->character = character;
 
        if ( item->block )
                destroySWFPlaceObject2Block(item->block);
        item->block = newSWFPlaceObject2Block(item->depth);
        item->flags = ITEM_NEW;
        item->isPlaced = 0;
        SWFPlaceObject2Block_setMove(item->block);
        SWFPlaceObject2Block_setCharacter(item->block, character);
}

SWFDisplayItem
SWFDisplayList_add(SWFDisplayList list, SWFBlockList blocklist, SWFCharacter character)
{
        SWFDisplayItem item = (SWFDisplayItem) malloc(sizeof(struct SWFDisplayItem_s));

        /* If malloc failed, return NULL to signify this */
        if (NULL == item)
                return NULL;

        item->flags = ITEM_NEW;
        item->next = NULL;
        item->depth = ++list->depth;

        item->matrix = newSWFMatrix(1, 0, 0, 1, 0, 0);

        /* If newSWFMatrix() failed, return NULL to signify this */
        if (NULL == item->matrix)
        {
                free(item);
                return NULL;
        }

        item->position = newSWFPosition(item->matrix);

        /* If newSWFPosition() failed, return NULL to signify this */
        if (NULL == item->position)
        {
                destroySWFMatrix(item->matrix);
                free(item);
                return NULL;
        }

        item->block = newSWFPlaceObject2Block(item->depth);

        /* If newSWFPlaceObject2Block() failed, return NULL to signify this */
        if (NULL == item->block)
        {
                destroySWFPosition(item->position);
                destroySWFMatrix(item->matrix);
                free(item);
                return NULL;
        }

        item->character = character;
        item->isPlaced = 0;
        item->blocklist = blocklist;

        SWFPlaceObject2Block_setCharacter(item->block, character);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);

        if ( list->tail )
                list->tail->next = item;
        else
                list->head = item;
        
        item->prev = list->tail;
        list->tail = item;
        // back pointer for endmask
        item->list = list;
        return item;
}


void
SWFDisplayItem_remove(SWFDisplayItem item)
{
        item->flags |= ITEM_REMOVED;
}

void 
SWFDisplayItem_removeFromList(SWFDisplayItem item, SWFBlockList blocklist)
{
                SWFDisplayList list;
                
                if(item == NULL || item->list == NULL || blocklist == NULL)
                        return;

                list = item->list;
                if(item->next)
                        item->next->prev = item->prev;
                
                if(item->prev)
                        item->prev->next = item->next;          

                if(item == list->head)
                        list->head = item->next;
                if(item == list->tail)
                        list->tail = item->prev;

                if(item->isPlaced)
                        SWFBlockList_addBlock(blocklist,
                                (SWFBlock)newSWFRemoveObject2Block(item->depth));

                destroySWFDisplayItem(item);
}

static void
checkBlock(SWFDisplayItem item)
{
        if ( item->block == NULL )
                item->block = newSWFPlaceObject2Block(item->depth);

        if ( (item->flags & ITEM_NEW) == 0 )
                SWFPlaceObject2Block_setMove(item->block);
}


SWFCharacter
SWFDisplayItem_getCharacter(SWFDisplayItem item)
{
        return item->character;
}


int
SWFDisplayItem_getDepth(SWFDisplayItem item)
{
        return item->depth;
}


void
SWFDisplayItem_setDepth(SWFDisplayItem item, int depth)
{
        item->depth = depth;

        checkBlock(item);

        if ( (item->flags & ITEM_NEW) == 0 )
        {
                /* warn.. */
                return;
        }

        SWFPlaceObject2Block_setDepth(item->block, depth);
}


SWFMatrix
SWFDisplayItem_getMatrix(SWFDisplayItem item)
{
        checkBlock(item);
        return item->matrix;
}


void
SWFDisplayItem_move(SWFDisplayItem item, double x, double y)
{
        checkBlock(item);
        SWFPosition_move(item->position, x, y);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_moveTo(SWFDisplayItem item,  double x, double y)
{
        checkBlock(item);
        SWFPosition_moveTo(item->position, x, y);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_getPosition(SWFDisplayItem item, double *x, double *y)
{
        // returns the current position of this display item into the provided
        // pointers, respects NULL values

        checkBlock(item);
        SWFPosition_getXY(item->position, x, y);
}


void
SWFDisplayItem_rotate(SWFDisplayItem item, double degrees)
{
        checkBlock(item);
        SWFPosition_rotate(item->position, degrees);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_rotateTo(SWFDisplayItem item, double degrees)
{
        checkBlock(item);
        SWFPosition_rotateTo(item->position, degrees);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_getRotation(SWFDisplayItem item, double *degrees)
{
        // returns the current rotation of this display item into the given
        // pointer, respects NULL value

        checkBlock(item);

        if ( degrees != NULL )
                *degrees = SWFPosition_getRotation(item->position);
}


void
SWFDisplayItem_scale(SWFDisplayItem item, double xScale, double yScale)
{
        checkBlock(item);
        SWFPosition_scaleXY(item->position, xScale, yScale);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_scaleTo(SWFDisplayItem item, double xScale, double yScale)
{
        checkBlock(item);
        SWFPosition_scaleXYTo(item->position, xScale, yScale);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_getScale(SWFDisplayItem item, double *xScale, double *yScale)
{
        // returns the current x- and y-scale of this display item into the given
        // pointers, respects NULL values

        checkBlock(item);
        SWFPosition_getXYScale(item->position, xScale, yScale);
}


void
SWFDisplayItem_skewX(SWFDisplayItem item, double x)
{
        checkBlock(item);
        SWFPosition_skewX(item->position, x);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_skewXTo(SWFDisplayItem item, double x)
{
        checkBlock(item);
        SWFPosition_skewXTo(item->position, x);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_skewY(SWFDisplayItem item, double y)
{
        checkBlock(item);
        SWFPosition_skewY(item->position, y);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_skewYTo(SWFDisplayItem item, double y)
{
        checkBlock(item);
        SWFPosition_skewYTo(item->position, y);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}


void
SWFDisplayItem_getSkew(SWFDisplayItem item, double *xSkew, double *ySkew)
{
        // returns the current x- and y-skew of this display item into the given
        // pointers, respects NULL values

        checkBlock(item);
        SWFPosition_getXYSkew(item->position, xSkew, ySkew);
}


void
SWFDisplayItem_setMatrix(SWFDisplayItem item,
                         double a, double b, double c, double d, double x, double y)
{
        checkBlock(item);
        SWFPosition_setMatrix(item->position, a, b, c, d, x, y);
        SWFPlaceObject2Block_setMatrix(item->block, item->matrix);
}

/*
 * This function assigns a name to a display item.
 * The assigend name can be used in AS as a reference to this item
 */
void
SWFDisplayItem_setName(SWFDisplayItem item, const char *name)
{
        checkBlock(item);

        if ( (item->flags & ITEM_NEW) == 0 )
        {
                /* warn.. */
                return;
        }
        /* item->block is never null when ITEM_NEW set */
        SWFPlaceObject2Block_setName(item->block, name);
}

/* 
 * This function sets masklevel for the current display item
 * This item masks other display items above it. If this items
 * depth is 1 and its masklevel is set to 4, all items with depth
 * >= 5 are masked.
 */
void
SWFDisplayItem_setMaskLevel(SWFDisplayItem item, int masklevel)
{
        checkBlock(item);

        if ( (item->flags & ITEM_NEW) == 0 )
        {
                /* warn.. */
                return;
        }

        /* item->block is never null when ITEM_NEW set */
        SWFPlaceObject2Block_setMaskLevel(item->block, masklevel);
}


void
SWFDisplayItem_endMask(SWFDisplayItem item)
{
        checkBlock(item);
        SWFPlaceObject2Block_setMaskLevel(item->block, item->list->depth);
}


void
SWFDisplayItem_setRatio(SWFDisplayItem item, float ratio)
{
        int res;
        checkBlock(item);
        if(ratio < 0)
        {
                SWF_warn("SWFDisplayItem_setRatio: ratio must be inside [0...1]\n");
                ratio = 0;
        }
        else if (ratio > 1.0)
        {
                SWF_warn("SWFDisplayItem_setRatio: ratio must be inside [0...1]\n");
                ratio = 1.0;
        }
        res = (int)floor(ratio * 65535);
        SWFPlaceObject2Block_setRatio(item->block, res);
}


void
SWFDisplayItem_setCXform(SWFDisplayItem item, SWFCXform cXform)
{
        checkBlock(item);
        SWFPlaceObject2Block_setCXform(item->block, cXform);
}


void
SWFDisplayItem_setColorAdd(SWFDisplayItem item, int r, int g, int b, int a)
{
        checkBlock(item);
        SWFPlaceObject2Block_setColorAdd(item->block, r, g, b, a);
}


void
SWFDisplayItem_setColorMult(SWFDisplayItem item,
                                                                                                                float r, float g, float b, float a)
{
        checkBlock(item);
        SWFPlaceObject2Block_setColorMult(item->block, r, g, b, a);
}


void
SWFDisplayItem_addAction(SWFDisplayItem item, SWFAction action, int flags)
{
        checkBlock(item);

        if ( (item->flags & ITEM_NEW) == 0 )
        {
                /* warn.. */
                return;
        }

        /* item->block is never null when ITEM_NEW set */
        SWFPlaceObject2Block_addAction(item->block, action, flags);
}

/* 
 * adds a surface filter
 * Adds a bitmap filter to the display object. 
 * Also sets cache-as-bitmap flag. 
 * See SWFFilter for possible filter objects. Filter can 
 * only be applied to buttons, sprite/movieclips and text
 */ 
void SWFDisplayItem_addFilter(SWFDisplayItem item,
                              SWFFilter filter /* filter */)
{
        SWFBlock block;
        block = (SWFBlock)item->character;
        if(!SWFFilter_testBlockType(block->type))
        {
                SWF_warn("Filter can only be applied to buttons, sprite/movieclips and text\n");
                return;
        }
        checkBlock(item);
        SWFPlaceObject2Block_setCacheFlag(item->block, 1);
        SWFPlaceObject2Block_addFilter(item->block, filter);
        
}


/*
 * set blend mdoe
 * Sets an alternative blend mode instead of default alpha blend.
 * possible modes are:
 * SWFBLEND_MODE_NORMAL
 * SWFBLEND_MODE_LAYER
 * SWFBLEND_MODE_MULT
 * SWFBLEND_MODE_SCREEN
 * SWFBLEND_MODE_DARKEN
 * SWFBLEND_MODE_ADD
 * SWFBLEND_MODE_SUB
 * SWFBLEND_MODE_DIFF
 * SWFBLEND_MODE_DIFF
 * SWFBLEND_MODE_INV
 * SWFBLDEN_MODE_ALPHA
 * SWFBLEND_MDOE_ERASE
 * SWFBLEND_MDOE_OVERLAY
 * SWFBLEND_MODE_HARDLIGHT
 */
void SWFDisplayItem_setBlendMode(SWFDisplayItem item,
                        int mode /* blend mode */)
{
        checkBlock(item);
        SWFPlaceObject2Block_setBlendMode(item->block, mode);
}


/*
 * set cashing flag
 * If this flag ist set, the character can be cached as a bitmap. This might
 * improve rednering speed, if the object dos no change often.
 * This feature is for SWF version >= 8 only.
 */
void SWFDisplayItem_cacheAsBitmap(SWFDisplayItem item, 
        int flag /* flag 0 or 1 */)
{
        checkBlock(item);
        SWFPlaceObject2Block_setCacheFlag(item->block, flag);
}

void
SWFDisplayList_setSoundStream(SWFDisplayList list, SWFSoundStream stream)
{
        list->soundStream = stream;
}


void
SWFDisplayList_rewindSoundStream(SWFDisplayList list)
{
        // XXX - this is a hack, should be replaced..

        if ( list->soundStream )
                SWFSoundStream_rewind(list->soundStream);
}

void
SWFDisplayList_writeBlocks(SWFDisplayList list, SWFBlockList blocklist)
{
        SWFDisplayItem item = list->head, next;
        SWFCharacter character;

        if ( list->soundStream )
        {
                SWFBlock stream = SWFSoundStream_getStreamBlock(list->soundStream);

                if ( stream )
                        SWFBlockList_addBlock(blocklist, stream);
        }       

        while ( item != NULL )
        {
                character = item->character;

                //              if ( character != NULL )
                //                      SWFBlockList_resolveCharacterDependencies(blocklist, character);

                if ( item->flags & ITEM_REMOVED )
                {
                        next = item->next;
                        SWFDisplayItem_removeFromList(item, blocklist);
                        item = next;
                        continue;
                }
                
                if ( character != NULL &&
                                 !SWFBlock_isDefined((SWFBlock)character) &&
                                 !list->isSprite )
                {
                        SWFBlockList_addBlock(blocklist, (SWFBlock)character);
                }

                if ( item->block != NULL )
                {
                        if(!item->isPlaced && character->onPlace)
                                character->onPlace(item, blocklist);
                        SWFBlockList_addBlock(blocklist, (SWFBlock)item->block);
                        item->isPlaced = 1;
                }
                
                if (character && character->onFrame)
                        character->onFrame(item, blocklist);

                item->flags = 0;
                item->block = NULL;

                item = item->next;
        }
}

/* 
 * This function writes the item object immediately to the blocklist.
 * Usually MING waits with writing a display item until a frame is closed
 * through a nextFrame() call, because a display items state could be altered 
 * for the current frame. By using SWFDisplayItem_flush() MING does not wait 
 * and writes the frame immediately. Therefore a user can influence the 
 * swf tag oder. Changing a display items state after calling flush() takes 
 * effect in the next frame.
 */
void 
SWFDisplayItem_flush(SWFDisplayItem item /* item to write */)
{
        SWFCharacter character;
        if(item == NULL)
                return;
        
        character = item->character;
        if (item->flags & ITEM_REMOVED)
        {
                SWFDisplayItem_removeFromList(item, item->blocklist);
                return;
        }
                
        if (character != NULL && !SWFBlock_isDefined((SWFBlock)character))
        {
                SWFBlockList_addBlock(item->blocklist, (SWFBlock)character);
        }

        if ( item->block != NULL )
        {
                if(!item->isPlaced && character->onPlace)
                        character->onPlace(item, item->blocklist);
                SWFBlockList_addBlock(item->blocklist, (SWFBlock)item->block);
                item->isPlaced = 1;
        }

        item->flags = 0;
        item->block = NULL;
}

/*
 * Local variables:
 * tab-width: 2
 * c-basic-offset: 2
 * End:
 */

/* [<][>][^][v][top][bottom][index][help] */