⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gameswf_dlist.cpp

📁 一个开源的Flash 播放器,可以在Windows/Linux 上运行
💻 CPP
字号:
// gameswf_dlist.cpp	-- Thatcher Ulrich <tu@tulrich.com> 2003// This source code has been donated to the Public Domain.  Do// whatever you want with it.// A list of active characters.#include "gameswf_dlist.h"#include "gameswf_log.h"#include "gameswf_render.h"#include "gameswf.h"#include <typeinfo>namespace gameswf{	/*static*/ int	display_object_info::compare(const void* _a, const void* _b)	{		display_object_info*	a = (display_object_info*) _a;		display_object_info*	b = (display_object_info*) _b;		if (a->m_character->get_depth() < b->m_character->get_depth())		{			return -1;		}		else if (a->m_character->get_depth() == b->m_character->get_depth())		{			return 0;		}		else		{			return 1;		}	}		int	display_list::find_display_index(int depth)	// Find the index in the display list of the first object	// matching the given depth.  Failing that, return the index	// of the first object with a larger depth.	{		int	size = m_display_object_array.size();		if (size == 0)		{			return 0;		}				// Binary search.		int	jump = size >> 1;		int	index = jump;		for (;;)		{			jump >>= 1;			if (jump < 1) jump = 1;						if (depth > m_display_object_array[index].m_character->get_depth())			{				if (index == size - 1)				{					index = size;					break;				}				index += jump;			}			else if (depth < m_display_object_array[index].m_character->get_depth())			{				if (index == 0				    || depth > m_display_object_array[index - 1].m_character->get_depth())				{					break;				}				index -= jump;			}			else			{				// match -- scan backward to make sure this is the first entry with this depth.				//				// Linear.  But multiple objects with the same depth are only allowed for				// very old SWF's, so we don't really care.				for (;;)				{					if (index == 0					    || m_display_object_array[index - 1].m_character->get_depth() < depth)					{						break;					}					index--;				}				assert(m_display_object_array[index].m_character->get_depth() == depth);				assert(index == 0 || m_display_object_array[index - 1].m_character->get_depth() < depth);				break;			}		}				assert(index >= 0 && index <= size);				return index;	}		int	display_list::get_display_index(int depth)		// Like the above, but looks for an exact match, and returns -1 if failed.	{		int	index = find_display_index(depth);		if (index >= m_display_object_array.size()			|| get_display_object(index).m_character->get_depth() != depth)		{			// No object at that depth.			return -1;		}		return index;	}	character*	display_list::get_character_at_depth(int depth)	{		int	index = get_display_index(depth);		if (index != -1)		{			character*	ch = m_display_object_array[index].m_character.get_ptr();			if (ch->get_depth() == depth)			{				return ch;			}		}		return NULL;	}	character*	display_list::get_character_by_name(const tu_string& name)	{		// See if we have a match on the display list.		for (int i = 0, n = get_character_count(); i < n; i++)		{			character*	ch = get_character(i);			if (ch->get_name() == name.c_str())			{				// Found it.				return ch;			}		}		return NULL;	}	character*	display_list::get_character_by_name_i(const tu_stringi& name)	// Return first character with matching (case insensitive) name, if any.	{		// Search through dlist for a match.		for (int i = 0, n = get_character_count(); i < n; i++)		{			character*	ch = get_character(i);			if (name == ch->get_name().c_str())			{				// Found it.				return ch;			}		}		return NULL;	}	void	display_list::add_display_object(		character* ch, 		Uint16 depth,		bool replace_if_depth_is_occupied,		const cxform& color_xform, 		const matrix& mat, 		float ratio,		Uint16 clip_depth)	{//		IF_VERBOSE_DEBUG(log_msg("dl::add(%d, '%s')\n", depth, ch->get_name()));//xxxxx		assert(ch);				int	size = m_display_object_array.size();		int index = find_display_index(depth);		if (replace_if_depth_is_occupied)		{			// Eliminate an existing object if it's in the way.			if (index >= 0 && index < size)			{				display_object_info & dobj = m_display_object_array[index];				if (dobj.m_character->get_depth() == depth)				{					dobj.set_character(NULL);					m_display_object_array.remove(index);				}			}		}		else		{			// Caller wants us to allow multiple objects			// with the same depth.  find_display_index()			// returns the first matching depth, if there			// are any, so the new character will get			// inserted before all the others with the			// same depth.  This matches the semantics			// described by Alexi's SWF ref.  (This is all			// for legacy SWF compatibility anyway.)		}		ch->set_depth(depth);		display_object_info	di;		di.m_ref = true;		di.set_character(ch);		di.m_character->set_depth(depth);		di.m_character->set_cxform(color_xform);		di.m_character->set_matrix(mat);		di.m_character->set_ratio(ratio);		di.m_character->set_clip_depth(clip_depth);		// Insert into the display list...		assert(index == find_display_index(depth));				m_display_object_array.insert(index, di);		// do the frame1 actions (if applicable) and the "onClipEvent (load)" event.		ch->on_event_load();	}			void	display_list::move_display_object(		Uint16 depth,		bool use_cxform,		const cxform& color_xform,		bool use_matrix,		const matrix& mat,		float ratio,		Uint16 clip_depth)	// Updates the transform properties of the object at	// the specified depth.	{//		IF_VERBOSE_DEBUG(log_msg("dl::move(%d)\n", depth));//xxxxx		int	size = m_display_object_array.size();		if (size <= 0)		{			// error.			log_error("error: move_display_object() -- no objects on display list\n");			//			assert(0);			return;		}				int	index = find_display_index(depth);		if (index < 0 || index >= size)		{			// error.			log_error("error: move_display_object() -- can't find object at depth %d\n", depth);			//			assert(0);			return;		}				display_object_info&	di = m_display_object_array[index];		character*	ch = di.m_character.get_ptr();		if (ch->get_depth() != depth)		{			// error			log_error("error: move_display_object() -- no object at depth %d\n", depth);			//			assert(0);			return;		}		di.m_ref = true;		if (ch->get_accept_anim_moves() == false)		{			// This character is rejecting anim moves.  This happens after it			// has been manipulated by ActionScript.			return;		}		if (use_cxform)		{			ch->set_cxform(color_xform);		}		if (use_matrix)		{			ch->set_matrix(mat);		}		ch->set_ratio(ratio);		// move_display_object apparently does not change clip depth!  Thanks to Alexeev Vitaly.		// ch->set_clip_depth(clip_depth);	}			void	display_list::replace_display_object(		character* ch,		Uint16 depth,		bool use_cxform,		const cxform& color_xform,		bool use_matrix,		const matrix& mat,		float ratio,		Uint16 clip_depth)	// Puts a new character at the specified depth, replacing any	// existing character.  If use_cxform or use_matrix are false,	// then keep those respective properties from the existing	// character.	{//		IF_VERBOSE_DEBUG(log_msg("dl::replace(%d)\n", depth));//xxxxx		int	size = m_display_object_array.size();		int	index = find_display_index(depth);		if (index < 0 || index >= size)		{			// Error, no existing object found at depth.//			IF_VERBOSE_DEBUG(log_msg("dl::replace_display_object() no obj at depth %d\n", depth));			// Fallback -- add the object.			add_display_object(ch, depth, true, color_xform, mat, ratio, clip_depth);			return;		}				display_object_info&	di = m_display_object_array[index];		if (di.m_character->get_depth() != depth)		{			// error//			IF_VERBOSE_DEBUG(log_msg("warning: replace_display_object() -- no object at depth %d\n", depth));			return;		}				smart_ptr<character>	old_ch = di.m_character;		// Put the new character in its place.		assert(ch);		ch->set_depth(depth);		ch->restart();				// Set the display properties.		di.m_ref = true;		di.set_character(ch);		if (use_cxform)		{			ch->set_cxform(color_xform);		}		else		{			// Use the cxform from the old character.			ch->set_cxform(old_ch->get_cxform());		}		if (use_matrix)		{			ch->set_matrix(mat);		}		else		{			// Use the matrix from the old character.			ch->set_matrix(old_ch->get_matrix());		}		ch->set_ratio(ratio);		ch->set_clip_depth(clip_depth);	}			void	display_list::remove_display_object(Uint16 depth, int id)	// Removes the object at the specified depth.	{//		IF_VERBOSE_DEBUG(log_msg("dl::remove(%d)\n", depth));//xxxxx		int	size = m_display_object_array.size();		if (size <= 0)		{			// error.			log_error("remove_display_object: no characters in display list\n");			return;		}				int	index = find_display_index(depth);		if (index < 0		    || index >= size		    || get_character(index)->get_depth() != depth)		{			// error -- no character at the given depth.			log_error("remove_display_object: no character at depth %d\n", depth);			return;		}		assert(get_character(index)->get_depth() == depth);				if (id != -1)		{			// Caller specifies a specific id; scan forward til we find it.			for (;;)			{				if (get_character(index)->get_id() == id)				{					break;				}				if (index + 1 >= size				    || get_character(index + 1)->get_depth() != depth)				{					// Didn't find a match!					log_error("remove_display_object: no character at depth %d with id %d\n", depth, id);					return;				}				index++;			}			assert(index < size);			assert(get_character(index)->get_depth() == depth);			assert(get_character(index)->get_id() == id);		}		// Removing the character at get_display_object(index).		display_object_info&	di = m_display_object_array[index];				// Remove reference only.		di.m_ref = false;	}			void	display_list::clear()	// clear the display list.	{		int i, n = m_display_object_array.size();		for (i = 0; i < n; i++)		{			display_object_info&	di = m_display_object_array[i];			//character*	ch = m_display_object_array[i].m_character;			di.m_character->on_event(event_id::UNLOAD);		}				m_display_object_array.clear();	}			void	display_list::reset()	// reset the references to the display list.	{		//printf("### reset the display list!\n");		int i, n = m_display_object_array.size();		for (i = 0; i < n; i++)		{			m_display_object_array[i].m_ref = false;		}	}			void	display_list::update()	// remove unreferenced objects.	{		//printf("### update the display list!\n");				int r = 0;		int i, n = m_display_object_array.size();		for (i = n-1; i >= 0; i--)		{			display_object_info & dobj = m_display_object_array[i];						if (dobj.m_ref == false)			{				dobj.set_character(NULL);				m_display_object_array.remove(i);				r++;			}		}				//printf("### removed characters: %4d active characters: %4d\n", r, m_display_object_array.size());	}			void	display_list::advance(float delta_time)	// advance referenced characters.	{		int n = m_display_object_array.size();		for (int i = 0; i < n; i++)		{			// @@@@ TODO FIX: If array changes size due to			// character actions, the iteration may not be			// correct!			//			// What's the correct thing to do here?  Options:			//			// * copy the display list at the beginning,			// iterate through the copy			//			// * use (or emulate) a linked list instead of			// an array (still has problems; e.g. what			// happens if the next or current object gets			// removed from the dlist?)			//			// * iterate through current array in depth			// order.  Always find the next object using a			// search of current array (but optimize the			// common case where nothing has changed).			//			// * ???			//			// Need to test to see what Flash does.			if (n != m_display_object_array.size())			{				log_error("gameswf bug: dlist size changed due to character actions, bailing on update!\n");				break;			}			display_object_info & dobj = m_display_object_array[i];						if (dobj.m_ref == true)			{				character*	ch = dobj.m_character.get_ptr();				assert(ch);				ch->advance(delta_time);			}		}	}			void	display_list::display()	// Display the referenced characters. Lower depths	// are obscured by higher depths.	{		bool masked = false;		int highest_masked_layer = 0;				//log_msg("number of objects to be drawn %i\n", m_display_object_array.size());				for (int i = 0; i < m_display_object_array.size(); i++)		{			display_object_info&	dobj = m_display_object_array[i];			character*	ch = dobj.m_character.get_ptr();			assert(ch);			if (ch->get_visible() == false)			{				// Don't display.				continue;			}			if (ch->get_clip_depth() > 0)			{//				log_msg("depth %i, clip_depth %i\n", dobj.m_depth, dobj.m_clip_depth);			}			// check whether a previous mask should be disabled			if (masked)			{				if (ch->get_depth() > highest_masked_layer)				{//					log_msg("disabled mask before drawing depth %i\n", ch->get_depth());					masked = false;					// turn off mask					render::disable_mask();				}			}			// check whether this object should become mask			if (ch->get_clip_depth() > 0)			{				//log_msg("begin submit mask\n");				render::begin_submit_mask();			}						ch->display();			if (ch->get_clip_depth() > 0)			{//				log_msg("object drawn\n");			}						// if this object should have become a mask,			// inform the renderer that it now has all			// information about it			if (ch->get_clip_depth() > 0)			{				//log_msg("end submit mask\n");				render::end_submit_mask();				highest_masked_layer = ch->get_clip_depth();				masked = true;			}		}				if (masked)		{			// If a mask masks the scene all the way up to the highest			// layer, it will not be disabled at the end of drawing			// the display list, so disable it manually.			render::disable_mask();		}	}}// Local Variables:// mode: C++// c-basic-offset: 8 // tab-width: 8// indent-tabs-mode: t// End:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -