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

📄 gu_font.c

📁 pmpmodavc102_sub_src,psp下很好的播放器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
PMP Mod
Copyright (C) 2006 Raphael

E-mail:   raphael@fx-world.org

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

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
font rendering system
*/
#include <pspkernel.h>#include <pspiofilemgr.h>#include <pspgu.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

#include "valloc.h"
#include "gu_font.h"



unsigned short __attribute__((aligned(16))) gu_font_clut[16];

struct gu_font_struct* gu_cur_font = 0;					// Current set font
static struct gu_font_manager_struct gu_font_manager;


static struct gu_glyph_cache_manager_struct gu_glyph_cache_manager;

static struct gu_glyph_cache_struct gu_glyph_temp_cache;		// temporary texture for bypassing glyph cache system


static int gu_font_initialized = 0;
static int gu_font_border = 1;
static int gu_font_color = 0xffffff;
static int gu_font_border_color = 0;


#define IsSet(val,flag) (val&flag)==flag

#define FONTHEIGHT (gu_cur_font==0?0:gu_cur_font->chars[(unsigned char)'I'].byte_height+3)
#define CHARWIDTH(c) (gu_cur_font==0?0:gu_cur_font->chars[(unsigned char)c].pixel_width)
#define CHARHEIGHT(c) (gu_cur_font==0?0:gu_cur_font->chars[(unsigned char)c].byte_height)


#ifdef DEBUG
void gu_debug_print_glyph_cache()
	{
	FILE* f = fopen("debug.txt","a+");
	if (!f) return;
	
	fprintf(f, "\nDEBUGPRINT GLYPH CACHE:\n");
	fprintf(f, "--------------------------------------------\n\n");	
	struct gu_glyph_cache_list_struct* list = gu_glyph_cache_manager.root;
	if (list == 0) return;
	int i = 1;
	while (list!=0)
		{
			{
			fprintf(f, "----------------\n");
			fprintf(f, "GLYPH CACHE NO. %i\n", i);
			fprintf(f, "list->\n");
			fprintf(f, "----------------\n");
			fprintf(f, "lru_index      : %i\n", list->lru_index);
			fprintf(f, "cache->cacheptr: 0x%x\n", list->cache->cacheptr);
			fprintf(f, "cache->size    : 0x%x\n", list->cache->size);
			fprintf(f, "cache->width   : %i\n", list->cache->width);
			fprintf(f, "cache->height  : %i\n", list->cache->height);
			fprintf(f, "cache->flags   : %i\n", list->cache->flags);
			fprintf(f, "cache->font_id : %i\n", list->cache->font_id);
			fprintf(f, "cache->dirty   : %i\n", list->cache->dirty);
			fprintf(f, "cache->string  : %s\n", list->cache->string);
			fprintf(f, "----------------\n\n");
			}
		list = list->next;
		i++;
		}
	fprintf(f,"\n\n--------------------------------------------\nFINISHED\n");
	fclose(f);
	}
	
void gu_debug_print_charset(){	if (gu_cur_font == 0) return;	FILE* f = fopen("debug.txt","a+");
	if (!f) return;	
	fprintf(f, "\nDEBUGPRINT CHARSET:\n");
	fprintf(f, "--------------------------------------------\n\n");		int i;
	char letter[2];
	letter[1] = '\0';
	for (i=0;i<256;i++)
		{
			{
			letter[0] = i;
			fprintf(f, "----------------\n");
			fprintf(f, "CHARACTER: %s(%i)\n", letter, i);
			fprintf(f, "----------------\n");
			fprintf(f, "byte_width     : %i\n", gu_cur_font->chars[i].byte_width);
			fprintf(f, "byte_height    : %i\n", gu_cur_font->chars[i].byte_height);
			fprintf(f, "x_offset       : %i\n", gu_cur_font->chars[i].x_offset);
			fprintf(f, "y_offset       : %i\n", gu_cur_font->chars[i].y_offset);
			fprintf(f, "pixel_width    : %i\n", gu_cur_font->chars[i].pixel_width);
			fprintf(f, "pixel_height   : %i\n", gu_cur_font->chars[i].pixel_height);
			}
		}
	fprintf(f,"\n\n--------------------------------------------\nFINISHED\n");
	fclose(f);}
#endif

void gu_glyph_cache_safe_constructor(struct gu_glyph_cache_struct *p)
	{
	if (p==0) return;
	p->cacheptr = 0;
	p->width = 0;
	p->height = 0;
	p->flags = 0;
	p->string[0] = '\0';
	}


void gu_glyph_cache_safe_destructor(struct gu_glyph_cache_struct *p)
	{
	if (p==0) return;
	if (p->cacheptr!=0)
		vfree( p->cacheptr );
	p->cacheptr = 0;
	p->width = 0;
	p->height = 0;
	p->flags = 0;
	p->string[0] = '\0';
	p->dirty = 0;
	}

	
void gu_glyph_cache_list_safe_constructor(struct gu_glyph_cache_list_struct *p)
	{
	if (p==0) return;
	p->cache = 0;
	p->next = 0;
	p->prev = 0;
	p->lru_index = 0;
	}


void gu_glyph_cache_list_safe_destructor(struct gu_glyph_cache_list_struct *p)
	{
	if (p==0) return;
	gu_glyph_cache_list_safe_destructor(p->next);
	gu_glyph_cache_safe_destructor(p->cache);
	p->cache = 0;
	p->next = 0;
	p->prev = 0;
	p->lru_index = 0;
	}


struct gu_glyph_cache_struct* gu_glyph_cache_create( unsigned int size )
	{
	struct gu_glyph_cache_struct* p = malloc(sizeof(struct gu_glyph_cache_struct));
	if (p==0) return(0);
	
	gu_glyph_cache_safe_constructor(p);
	
	p->cacheptr = valloc( size );
	if (p->cacheptr==0)
		{
		free(p);
		return(0);
		}
	p->flags = GLYPH_CACHE_VRAM;
	p->size = size;
	p->dirty = 1;
	
	return(p);
	}


struct gu_glyph_cache_list_struct* gu_glyph_cache_list_create( unsigned int size )
	{
	struct gu_glyph_cache_list_struct *p = malloc(sizeof(struct gu_glyph_cache_list_struct));
	if (p==0) return(0);
	
	gu_glyph_cache_list_safe_constructor(p);
	
	p->cache = gu_glyph_cache_create( size );
	if (p->cache==0)
		{
		free(p);
		return(0);
		}
	
	return(p);
	}


char* gu_glyph_cache_init()
	{
	if (gu_font_initialized==1) return(0);
	
	gu_glyph_cache_manager.lru_counter = 0;
	gu_glyph_cache_manager.num_caches = 0;
	
	if (gu_glyph_cache_manager.root==0)
		gu_glyph_cache_manager.root = gu_glyph_cache_list_create( 256*MAX_CACHE_LINES*16 );
	
	if (gu_glyph_cache_manager.root==0)
		return("gu_glyph_cache_init: failed to create glyph cache root");
	
	gu_glyph_cache_manager.num_caches++;
	
	struct gu_glyph_cache_list_struct* new_cache;
	while(gu_glyph_cache_manager.num_caches<MAX_GLYPH_CACHES)
		{
		new_cache = gu_glyph_cache_list_create( 256*MAX_CACHE_LINES*16 );
		if (new_cache==0)
			break;
		new_cache->next = gu_glyph_cache_manager.root;
		gu_glyph_cache_manager.root->prev = new_cache;
		gu_glyph_cache_manager.root = new_cache;
		gu_glyph_cache_manager.num_caches++;
		}
	
	// Try to allocate temporary cache in VRAM first
	gu_glyph_cache_safe_constructor(&gu_glyph_temp_cache);
	//gu_glyph_temp_cache.cacheptr = valloc( 256*MAX_CACHE_LINES*16 );
	gu_glyph_temp_cache.flags = GLYPH_CACHE_VRAM;
	if (gu_glyph_temp_cache.cacheptr==0)
		{
		gu_glyph_temp_cache.cacheptr = memalign(16, 256*MAX_CACHE_LINES*16 );
		if (gu_glyph_temp_cache.cacheptr==0)
			return("gu_glyph_cache_init: memalign failed on gu_glyph_temp_cache");
		gu_glyph_temp_cache.flags = GLYPH_CACHE_SYSMEM;
		}
	gu_glyph_temp_cache.dirty = 1;		// temporary cache is always dirty
		
	return(0);
	}


void gu_glyph_cache_free()
	{
	if (IsSet(gu_glyph_temp_cache.flags,GLYPH_CACHE_VRAM))
		vfree( gu_glyph_temp_cache.cacheptr );
	else if (IsSet(gu_glyph_temp_cache.flags,GLYPH_CACHE_SYSMEM))
		free( gu_glyph_temp_cache.cacheptr );
		
	gu_glyph_temp_cache.flags = 0;
	gu_glyph_cache_list_safe_destructor( gu_glyph_cache_manager.root );
	gu_glyph_cache_manager.num_caches = 0;
	gu_glyph_cache_manager.lru_counter = 0;
	}


// return a pointer to a cache texture useable by the GU
struct gu_glyph_cache_struct* gu_glyph_cache_manager_get( char* s, int width, int height, int flags, int font_id )
	{
	if (IsSet(flags,FLAG_NOCACHE) || gu_glyph_cache_manager.num_caches==0)
		{
		if (gu_glyph_temp_cache.cacheptr==0) return(0);
		
		memset(gu_glyph_temp_cache.cacheptr, 0, 256*height);
		sceKernelDcacheWritebackAll();
		return(&gu_glyph_temp_cache);
		}
	
	// Check if a cache with s, flags and font_id already exists
	struct gu_glyph_cache_list_struct* list = gu_glyph_cache_manager.root;
	if (list == 0) return(0);
	while (list!=0)
		{
		if (list->cache->flags==(flags&FLAG_ALIGN_MASK) &&
			list->cache->font_id==font_id &&
			strcmp(list->cache->string,s)==0)
			{
			// cache-hit
			list->lru_index = gu_glyph_cache_manager.lru_counter++;
			list->cache->width = width;
			list->cache->height = height;
			list->cache->dirty = 0;			// cache doesn't need to be regenerated
			
			return(list->cache);
			}
		list = list->next;
		}
	
	list = gu_glyph_cache_manager.root;
	struct gu_glyph_cache_list_struct* lru = list;
	
	// cache-miss
	while (list->next!=0)
		{
		list = list->next;
		if (lru->lru_index>list->lru_index)
			lru = list;
		}
	
	lru->lru_index = gu_glyph_cache_manager.lru_counter++;
	if (lru->cache==0) return(0);
	lru->cache->width = width;
	lru->cache->height = height;
	lru->cache->dirty = 1;
	lru->cache->font_id = font_id;
	lru->cache->flags = (flags&FLAG_ALIGN_MASK);
	strncpy((char*)lru->cache->string,s,MAX_CACHE_STRING-1);
	memset(lru->cache->cacheptr, 0, 256*height );
	sceKernelDcacheWritebackAll();
	
	return(lru->cache);
	}



/* sw always 16 so there's always 64bit to copy for each line		s1			s2  s = |xxxxxxxx|yyyyyyyy|				sx = 0  s1 << (3*4) = |000xxxxx|  s1 >> (5*4) = |xxx00000|  s2 << (3*4) = |000yyyyy|  s2 >> (5*4) = |yyy00000|  d = |00000000|00000000|00000000|		dx = 3  => d' = |000xxxxx|xxxyyyyy|yyy00000|	*/inline void gu_font_copy_glyph( int sx, int sy, int sh, char *s, int dx, int dy, char *d ){	int i;	if ((dx&0x7)==0) {		unsigned int* u32s = (unsigned int*)((unsigned int)s+((sx+(sy<<8)) >> 1));		unsigned int* u32d = (unsigned int*)((unsigned int)d+((dx+(dy<<9)) >> 1));		// can do fast copy		for (i=0;i<sh;i++) {		  // 32bit copy part		  *u32d++ = *u32s++;		  *u32d++ = *u32s++;		  u32s += (128-8)>>2;		  u32d += (256-8)>>2;		}	} else {	unsigned int* u32s = (unsigned int*)((unsigned int)s+((sx+(sy<<8)) >> 1));	unsigned int* u32d = (unsigned int*)((unsigned int)d+(((dx>>3)<<2)+(dy<<8)));	unsigned int mask = 0;	unsigned int shift = (dx&0x7)<<2;	for (i=0;i<(dx&0x7);i++) {		mask <<= 4;			mask |= 0xf;	}	for (i=0;i<sh;i++) {	  unsigned int s1 = *u32s++;	  unsigned int s2 = *u32s++;	  	  // copy first halfbytes	  *u32d++ = ((*u32d) & mask)|(s1 << shift);	// dst = |000xxxxx|	  	  *u32d++ = (s1 >> (32-shift)) | (s2 << shift);	// dst = |000xxxxx|xxxyyyyy|	  	  // copy last halfbytes	  *u32d++ = ((*u32d) & ~mask)|(s2 >> (32-shift));		// dst = |000xxxxx|xxxyyyyy|yyy00000|	  	  u32s += (128-8)>>2;	  u32d += (256-12)>>2;	}	}}inline void gu_font_cache_glyph( int x, int y, char c, char* cache )	{	int sx = (int)((unsigned char)c % 16)*16;	int sy = (int)((unsigned char)c / 16)*16;
	int sw = gu_cur_font->chars[(unsigned char)c].pixel_width;	int sh = gu_cur_font->chars[(unsigned char)c].byte_height;	int dx = x+gu_cur_font->chars[(unsigned char)c].x_offset;	int dy = y+gu_cur_font->chars[(unsigned char)c].y_offset;	if (dy<0) { sy-=dy; sh+=dy; dy=0; }	if (dx<0) { sx-=dx; sw+=dx; dx=0; }	if (dy+sh>=272) { sh=271-dy; }	//if (dx+sw>=480) { sw=479-dx; }	//sw = (sw+3)>>2;	if (sh==0 || sw==0) return;	/*if ((dx&0x3)==0)	  sceGuCopyImage(GU_PSM_4444,sx>>2,sy,sw,sh,256>>2,g_font_tex[g_cur_font],dx>>2,dy,512>>2,(void*)((unsigned int)g_glyph_cache | 0x40000000));	else*/	  gu_font_copy_glyph( sx, sy, sh, (char*)gu_cur_font->data, dx, dy, (char*)((unsigned int)cache | 0x40000000) );	}
inline void blit_fast( int x, int y, int w, int h, int x2, int y2 ){		int start;		for (start = 0; start < w; start += 64, x2 += 64)		{			struct VertexInt* vertices = (struct VertexInt*)sceGuGetMemory(2 * sizeof(struct VertexInt));			int width = (start + 64) < w ? 64 : w-start;			vertices[0].u = x + start; vertices[0].v = y;			vertices[0].color = 0x3000;			vertices[0].x = x2; vertices[0].y = y2; vertices[0].z = 0;			vertices[1].u = x + start + width; vertices[1].v = y + h;			vertices[1].color = 0x3000;			vertices[1].x = x2 + width; vertices[1].y = y2 + h; vertices[1].z = 0;			sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_COLOR_4444|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);		}}

int strpos( const char* s, const char c )	{	if (s==0) return -1;	char* t = s;	int i = 0;	while (*t!='\0' && *t!=c)
		{		t++;
		i++;		}
		if (*t!=c) return -1;	return i;	}


void gu_font_cache_string( char* s, int maxwidth, int flags, char* cache )
	{
	char* c = s;	int i = 0;	int x = 0;	int y = 10;	// don't know why this needs to be, with 0 it will draw the first line off-screen
	int linesize;
	int numlines = 0;			if (IsSet(flags,FLAG_ALIGN_CENTER))
		{			x = ((maxwidth-gu_font_line_width_get( s))/2);		}	else if (IsSet(flags,FLAG_ALIGN_RIGHT))		{		//linesize = strpos( s, '\n' );

⌨️ 快捷键说明

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