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

📄 gameswf_fontlib.cpp

📁 一个开源的Flash 播放器,可以在Windows/Linux 上运行
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		int	iy0 = (int) ceilf(y0);		int	iy1 = (int) ceilf(y1);		float	dy = y1 - y0;		for (int y = iy0; y < iy1; y++)		{			if (y < 0) continue;			if (y >= s_glyph_render_size) return;			float	f = (y - y0) / dy;			int	xl = (int) ceilf(flerp(xl0, xl1, f));			int	xr = (int) ceilf(flerp(xr0, xr1, f));						xl = iclamp(xl, 0, s_glyph_render_size - 1);			xr = iclamp(xr, 0, s_glyph_render_size - 1);			if (xr > xl)			{				memset(s_render_buffer + y * s_glyph_render_size + xl,				       255,				       xr - xl);			}		}	}	struct draw_into_software_buffer : tesselate::trapezoid_accepter	// A trapezoid accepter that does B&W rendering into our	// software buffer.	{		// Overrides from trapezoid_accepter		virtual void	accept_trapezoid(int style, const tesselate::trapezoid& tr)		{			// Transform the coords.			float	x_scale = s_render_matrix.m_[0][0];			float	y_scale = s_render_matrix.m_[1][1];			float	x_offset = s_render_matrix.m_[0][2];			float	y_offset = s_render_matrix.m_[1][2];			float	y0 = tr.m_y0 * y_scale + y_offset;			float	y1 = tr.m_y1 * y_scale + y_offset;			float	lx0 = tr.m_lx0 * x_scale + x_offset;			float	lx1 = tr.m_lx1 * x_scale + x_offset;			float	rx0 = tr.m_rx0 * x_scale + x_offset;			float	rx1 = tr.m_rx1 * x_scale + x_offset;			// Draw into the software buffer.			software_trapezoid(y0, y1, lx0, lx1, rx0, rx1);		}		virtual void	accept_line_strip(int style, const point coords[], int coord_count)		{			assert(0);	// Shape glyphs should not contain lines.		}	};	static bool	render_glyph(rendered_glyph_info* rgi, const shape_character_def* sh)	// Render the given outline shape into a cached font texture.	// Return true if the glyph is not empty; false if it's	// totally empty.	// 	// Return fill in the image and offset members of the given	// rgi.	{		assert(rgi);		assert(sh);		assert(s_render_buffer);		//		// Tesselate and render the shape into a software buffer.		//		// Clear the render output to 0.		memset(s_render_buffer, 0, s_glyph_render_size * s_glyph_render_size);		// Look at glyph bounds; adjust origin to make sure		// the shape will fit in our output.		float	offset_x = 0.f;		float	offset_y = s_rendering_box;		rect	glyph_bounds;		sh->compute_bound(&glyph_bounds);		if (glyph_bounds.m_x_min < 0)		{			offset_x = - glyph_bounds.m_x_min;		}		if (glyph_bounds.m_y_max > 0)		{			offset_y = s_rendering_box - glyph_bounds.m_y_max;		}		s_render_matrix.set_identity();		s_render_matrix.concatenate_scale(s_glyph_render_size / s_rendering_box);		s_render_matrix.concatenate_translation(offset_x, offset_y);		// Tesselate & draw the shape.		draw_into_software_buffer	accepter;		sh->tesselate(s_rendering_box / s_glyph_render_size * 0.5f, &accepter);		//		// Process the results of rendering.		//		// Shrink the results down by a factor of 4x, to get		// antialiasing.  Also, analyze the data boundaries.		bool	any_nonzero_pixels = false;		int	min_x = s_glyph_nominal_size;		int	max_x = 0;		int	min_y = s_glyph_nominal_size;		int	max_y = 0;		Uint8*	output = new Uint8[s_glyph_nominal_size * s_glyph_nominal_size];		for (int j = 0; j < s_glyph_nominal_size; j++)		{			for (int i = 0; i < s_glyph_nominal_size; i++)			{				// Sum up the contribution to this output texel.				int	sum = 0;				for (int jj = 0; jj < OVERSAMPLE_FACTOR; jj++)				{					for (int ii = 0; ii < OVERSAMPLE_FACTOR; ii++)					{						Uint8	texel = s_render_buffer[							((j << OVERSAMPLE_BITS) + jj) * s_glyph_render_size							+ ((i << OVERSAMPLE_BITS) + ii)];						sum += texel;					}				}				sum >>= OVERSAMPLE_BITS;				sum >>= OVERSAMPLE_BITS;				if (sum > 0)				{					any_nonzero_pixels = true;					min_x = imin(min_x, i);					max_x = imax(max_x, i);					min_y = imin(min_y, j);					max_y = imax(max_y, j);				}				output[j * s_glyph_nominal_size + i] = (Uint8) sum;			}		}		if (any_nonzero_pixels)		{			// Fill in rendered_glyph_info.			rgi->m_image = new image::alpha(max_x - min_x + 1, max_y - min_y + 1);			rgi->m_offset_x = offset_x / s_rendering_box * s_glyph_nominal_size - min_x;			rgi->m_offset_y = offset_y / s_rendering_box * s_glyph_nominal_size - min_y;			// Copy the rendered glyph into the new image.			{for (int j = 0, n = rgi->m_image->m_height; j < n; j++)			{				memcpy(					image::scanline(rgi->m_image, j),					output + (min_y + j) * s_glyph_nominal_size + min_x,					rgi->m_image->m_width);			}}		}		else		{			// Glyph is empty; don't create an image for it.			return false;		}		delete [] output;	// @@ TODO should keep this around longer, instead of new/delete for each glyph		rgi->m_image_hash = rgi->m_image->compute_hash();		return true;	}	bool	try_to_reuse_previous_image(		const rendered_glyph_info& rgi,		const hash<unsigned int, const rendered_glyph_info*>& image_hash)	// See if we've already packed an identical glyph image for	// another glyph.  If so, then reuse it, and return true.	// If no reusable image, return false.	//	// Reusing identical images can be a huge win, especially for	// fonts that use the same dummy glyph for many undefined	// characters.	{		const rendered_glyph_info*	identical_image = NULL;		if (image_hash.get(rgi.m_image_hash, &identical_image))		{			// Found a match.  But is it *really* a match?  Do a			// bitwise compare.			if (*(rgi.m_image) == *(identical_image->m_image))			{				// Yes, a real bitwise match.  Use the previous				// image's texture data.				texture_glyph	identical_tg =					identical_image->					m_source_font->					get_texture_glyph(identical_image->m_glyph_index);				if (identical_tg.is_renderable() == false)				{					// The matching glyph hasn't been pushed into the font yet.					// Search for it in s_pending_glyphs.					bool	found_it = false;					for (int i = 0, n = s_pending_glyphs.size(); i < n; i++)					{						const pending_glyph_info&	pgi = s_pending_glyphs[i];						if (pgi.m_source_font == identical_image->m_source_font						    && pgi.m_glyph_index == identical_image->m_glyph_index)						{							// This is the one we want to alias with.							identical_tg = pgi.m_texture_glyph;							found_it = true;						}					}					if (found_it == false)					{						// Should not happen -- glyph should either be in the font, or in s_pending_glyphs.						assert(0);						return false;					}				}				texture_glyph	tg;				// copy the bitmap & uv data from identical_tg				tg = identical_tg;				// Use our own offset, in case it's different.				tg.m_uv_origin.m_x = tg.m_uv_bounds.m_x_min					+ rgi.m_offset_x / GLYPH_CACHE_TEXTURE_SIZE;				tg.m_uv_origin.m_y = tg.m_uv_bounds.m_y_min					+ rgi.m_offset_y / GLYPH_CACHE_TEXTURE_SIZE;				if (identical_tg.is_renderable())				{					// This image is already packed and has a valid bitmap_info.					// Push straight into our font.					rgi.m_source_font->add_texture_glyph(rgi.m_glyph_index, tg);				}				else				{					// Set bitmap_info and push into font once texture is done being packed.					s_pending_glyphs.push_back(						pending_glyph_info(							rgi.m_source_font,							rgi.m_glyph_index,							tg));				}				return true;			}			// else hash matched, but images didn't.		}		else		{#if 0#ifndef NDEBUG			// Sanity check the hash -- there should be no			// image in it that exactly matches this			// image.			for (hash<unsigned int, const rendered_glyph_info*>::const_iterator it = image_hash.begin();			     it != image_hash.end();			     ++it)			{				if (*(rgi.m_image) == *(it->second->m_image))				{					// bah!  what up???					unsigned int	hash_a = rgi.m_image->compute_hash();					unsigned int	hash_b = it->second->m_image->compute_hash();					log_msg("a = %x, b = %x\n", hash_a, hash_b);//xxxxx				}			}#endif // not NDEBUG#endif // 0		}		return false;	}	void	pack_and_assign_glyphs(array<rendered_glyph_info>* glyph_info, movie_definition_sub* owner)	// Pack the given glyphs into textures, and push the	// texture_glyph info into the source fonts.	//	// Re-arranges the glyphs (i.e. sorts them by size) but	// otherwise doesn't munge the array.	{		// Sort the glyphs by size (biggest first).		struct sorter		{			static int	sort_by_size(const void* a, const void* b)			// For qsort.			{				const rendered_glyph_info*	ga = (const rendered_glyph_info*) a;				const rendered_glyph_info*	gb = (const rendered_glyph_info*) b;				int	a_size = ga->m_image->m_width + ga->m_image->m_height;				int	b_size = gb->m_image->m_width + gb->m_image->m_height;				return b_size - a_size;			}		};		if (glyph_info->size())		{			qsort(&(*glyph_info)[0], glyph_info->size(), sizeof((*glyph_info)[0]), sorter::sort_by_size);		}		// Flag for whether we've processed this glyph yet.		array<bool>	packed;		packed.resize(glyph_info->size());		for (int i = 0, n = packed.size(); i < n; i++)		{			packed[i] = false;		}		// Share identical texture data where possible, by		// doing glyph image comparisons.		hash<unsigned int, const rendered_glyph_info*>	image_hash;		// Pack the glyphs.		{for (int i = 0, n = glyph_info->size(); i < n; )		{			int	index = i;			// Try to pack a glyph into the existing texture.			for (;;)			{				const rendered_glyph_info&	rgi = (*glyph_info)[index];				// First things first: are we identical to a glyph that has				// already been packed?				if (try_to_reuse_previous_image(rgi, image_hash))				{					packed[index] = true;					break;				}				int	raw_width = rgi.m_image->m_width;				int	raw_height = rgi.m_image->m_height;				// Need to pad around the outside.				int	width = raw_width + (PAD_PIXELS * 2);				int	height = raw_height + (PAD_PIXELS * 2);				assert(width < GLYPH_CACHE_TEXTURE_SIZE);				assert(height < GLYPH_CACHE_TEXTURE_SIZE);				// Does this glyph fit?				int	pack_x = 0, pack_y = 0;				ensure_cache_image_available();				if (pack_rectangle(&pack_x, &pack_y, width, height))				{					// Fits!					// Blit the output image into its new spot.					for (int j = 0; j < raw_height; j++)					{						memcpy(s_current_cache_image						       + (pack_y + PAD_PIXELS + j) * GLYPH_CACHE_TEXTURE_SIZE						       + pack_x + PAD_PIXELS,						       image::scanline(rgi.m_image, j),						       raw_width);					}					// Fill out the glyph info.					texture_glyph	tg;					tg.m_uv_origin.m_x = (pack_x + rgi.m_offset_x) / (GLYPH_CACHE_TEXTURE_SIZE);					tg.m_uv_origin.m_y = (pack_y + rgi.m_offset_y) / (GLYPH_CACHE_TEXTURE_SIZE);					tg.m_uv_bounds.m_x_min = float(pack_x) / (GLYPH_CACHE_TEXTURE_SIZE);					tg.m_uv_bounds.m_x_max = float(pack_x + width) / (GLYPH_CACHE_TEXTURE_SIZE);					tg.m_uv_bounds.m_y_min = float(pack_y) / (GLYPH_CACHE_TEXTURE_SIZE);					tg.m_uv_bounds.m_y_max = float(pack_y + height) / (GLYPH_CACHE_TEXTURE_SIZE);					// Fill in bitmap info and push into the source font later.					s_pending_glyphs.push_back(						pending_glyph_info(							rgi.m_source_font,							rgi.m_glyph_index,							tg));					// Add this into the hash so it can possibly be reused.					if (image_hash.get(rgi.m_image_hash, NULL) == false)					{						image_hash.add(rgi.m_image_hash, &rgi);					}					packed[index] = true;					break;				}				else				{					// Try the next unpacked glyph.					index++;					while (index < n && packed[index]) index++;					if (index >= n)					{						// None of the glyphs will fit.  Finish off this texture.						finish_current_texture(owner);						// And go around again.						index = i;					}				}			}			// Skip to the next unpacked glyph.			while (i < n && packed[i]) i++;		}}	}	static void	generate_font_bitmaps(array<rendered_glyph_info>* glyph_info, font* f, movie_definition_sub* owner)	// Render images for each of the font's glyphs, and put the	// info about them in the given array.	{		assert(glyph_info);		assert(f);		f->set_texture_glyph_nominal_size(s_glyph_nominal_size);		for (int i = 0, n = f->get_glyph_count(); i < n; i++)		{			if (f->get_texture_glyph(i).is_renderable() == false)			{				shape_character_def*	sh = f->get_glyph(i);				if (sh)				{					rect	glyph_bounds;					sh->compute_bound(&glyph_bounds);					if (glyph_bounds.width() < 0)					{						// Invalid width; this must be an empty glyph.						// Don't bother generating a texture for it.					}					else					{						// Add a glyph.						rendered_glyph_info	rgi;						rgi.m_source_font = f;						rgi.m_glyph_index = i;						if (render_glyph(&rgi, sh) == true)						{							glyph_info->push_back(rgi);						}						// else glyph is empty					}				}			}		}	}	float	get_texture_glyph_max_height(const font* f)	{		return 1024.0f / s_rendering_box * f->get_texture_glyph_nominal_size(); //  s_glyph_nominal_size;	}

⌨️ 快捷键说明

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