/*************************************************************** ** ** Broadcom Corp. Confidential ** Copyright 2002 Broadcom Corp. All Rights Reserved. ** ** THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED ** SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. ** YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT ** SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. ** ** Description: bgfx core implementation ** ** Created: 8/22/2002 by Jeffrey P. Fisher ** ** ** ****************************************************************/ /** include files **/ #include "bgfx.h" #define ZORDER_TUNNEL 3 #define ZORDER_FX 2 #define ZORDER_TOP 1 #define ZORDER_BOTTOM 0 #define SURF_WIDTH 720 #define BGFX_MIN(x,y) ((x < y) ? x : y) #define bgfx_clut8_to_rgb(clut,c) (uint32_t)(clut[c]) /* blit row a1 to clut 8 destination */ static inline void bgfx_render_a1_to_clut4( uint8_t *src, uint8_t *dst, int width, uint8_t c, int odd_pixel ) { int i; BGFX_TRACE(("%p,%p,%d,0x%02x\n",src,dst,width,c)); for (i = 0; i < width; i++) { if (src[i>>3] & (1<<(7-(i%8)))) { if (odd_pixel & 1) { *dst &= 0xF0; *dst |= (c & 0xF); } else { *dst &= 0xF; *dst |= (c & 0xF) << 4; } BGFX_TRACE(("%d,",i)); } if (odd_pixel) { odd_pixel = 0; dst++; } else odd_pixel = 1; } BGFX_TRACE(("\n")); } /* blit row a8 to clut 8 destination */ static inline void bgfx_render_a8_to_clut4( uint8_t *src, uint8_t *dst, int width, uint8_t c ) { int i; for (i = 0; i < width; i++) { if (*src > 0x80) { if (i & 1) { *dst &= 0xF0; *dst |= (c & 0xF); } else { *dst &= 0xF; *dst |= (c & 0xF) << 4; } } BGFX_TRACE(("0x%02x(0x%02x)",*src,*dst)); if (i & 1) dst++; src++; } BGFX_TRACE(("\n")); } /* blit row a1 to clut 8 destination */ static inline void bgfx_render_a1_to_clut8( uint8_t *src, uint8_t *dst, int width, uint8_t c ) { int i; BGFX_TRACE(("%p,%p,%d,0x%02x\n",src,dst,width,c)); for (i = 0; i < width; i++) { if (src[i>>3] & (1<<(7-(i%8)))) { *dst = c; BGFX_TRACE(("%d,",i)); } dst++; } BGFX_TRACE(("\n")); } /* blit row a8 to clut 8 destination */ static inline void bgfx_render_a8_to_clut8( uint8_t *src, uint8_t *dst, int width, uint8_t c ) { int i; for (i = 0; i < width; i++) { if (*src > 0x80) { *dst = c; } BGFX_TRACE(("0x%02x(0x%02x)",*src,*dst)); dst++; src++; } BGFX_TRACE(("\n")); } /* blit row a1 to 8888 ARGB destination */ static inline void bgfx_render_a1_to_rgb( uint8_t *src, uint8_t *dst, int width, uint32_t c ) { int i; BGFX_TRACE(("%p,%p,%d,0x%02lx\n",src,dst,width,c)); for (i = 0; i < width; i++) { if (src[i>>3] & (1<<(7-(i%8)))) { *((uint32_t*)dst) = c; BGFX_TRACE(("%d,",i)); } dst += 4; } BGFX_TRACE(("\n")); } /* blit row a8 to 8888 ARGB destination */ /* #define BGFX_BLEND(a,rs,rd) (((rs * a)/0xFF) + (rd - ((a * rd)/0xFF)) & 0xFF) */ #define BGFX_BLEND(a,rs,rd) ((a * (rs-rd) >> 8) + rd) static inline void bgfx_render_a8_to_rgb( uint8_t *src, uint8_t *dst, int width, uint32_t c) { register int i; register uint32_t a,r,g,b; register uint32_t a_src; register uint32_t r_src = (c >> 16) & 0xFF; register uint32_t g_src = (c >> 8) & 0xFF; register uint32_t b_src = (c >> 0) & 0xFF; for (i = 0; i < width; i++) { a_src = *src; a = dst[3]; r = dst[2]; g = dst[1]; b = dst[0]; *((uint32_t*)dst) = (a << 24) | (BGFX_BLEND(a_src,r_src,r) << 16) | (BGFX_BLEND(a_src,g_src,g) << 8) | BGFX_BLEND(a_src,b_src,b); BGFX_TRACE(("0x%02x(0x%08x)",*src,*((uint32_t*)dst))); dst += 4; src++; } BGFX_TRACE(("\n")); } /****************************************************************} * INPUTS: io and protection function structures * OUTPUTS: none * RETURNS: non-zero on failure * FUNCTION: initialize sgl, primarily for handling freetype * ****************************************************************/ int bgfx_init(bgfx_io_t *io_p,bgfx_prot_t *prot_p) { bgfx_config(io_p,prot_p); return bgfx_font_init(); } /****************************************************************} * INPUTS: none * OUTPUTS: none * RETURNS: non-zero on failure * FUNCTION: release sgl global resources, primarily for handling freetype * ****************************************************************/ void bgfx_done(void) { bgfx_font_done(); } /****************************************************************} * bgfx_create * * INPUTS: node_name - name of the node to create surface in * p - surface structure to initialize * OUTPUTS: none * RETURNS: non-zero on failure * FUNCTION: initialize and create the surface. * ****************************************************************/ int bgfx_create(bgfx_surf_p p,uint16_t width,uint16_t height, uint8_t *ptr, uint16_t pitch, bgfx_palette_t *palette, uint32_t flags) { BGFX_DEBUG(("bgfx_create flags = 0x%08x\n",flags)); BGFX_MEMSET(p,0,sizeof(bgfx_surf_t)); if (!ptr && (flags & BGFX_SURF_PRIMARY)) { BGFX_DEBUG(("bgfx_create BGFX_SURF_FULLSCREEN requires valid memory ptr.\n")); } p->bpp = BGFX_SURF_GET_BPP(flags); BGFX_DEBUG(("bgfx_create bpp = %d.\n",p->bpp)); if ((p->bpp == 0) || ((flags & BGFX_SURF_RGB) && (p->bpp != 32))) { BGFX_DEBUG(("bgfx_create invalid bpp = %d.\n",p->bpp)); return -1; } p->flags = flags; if (ptr) { p->surface.pitch = pitch; p->surface.buf = ptr; p->surface.width = width; p->surface.height = height; } else { p->surface.pitch = width * p->bpp / 8; if (p->surface.pitch & 0x1) p->surface.pitch += 1; p->surface.width = width; p->surface.height = height; p->surface.buf = BGFX_MALLOC(p->surface.pitch * p->surface.height); p->flags |= BGFX_SURF_ALLOC; } if (palette) { BGFX_MEMCPY(&p->palette,palette,sizeof(bgfx_palette_t)); } return 0; } /**************************************************************** * bgfx_destroy * * INPUTS: p - surface structure * OUTPUTS: none * RETURNS: none * FUNCTION: free up surface resources * ****************************************************************/ void bgfx_destroy(bgfx_surf_p p) { if (p->flags & BGFX_SURF_ALLOC) { BGFX_FREE(p->surface.buf); return; } } /**************************************************************** * bgfx_fill_rect * * INPUTS: p - surface structure * OUTPUTS: w,h,flags - surface width,height and flags * RETURNS: none * FUNCTION: Return surface information (width,height, and flags) * ****************************************************************/ void bgfx_get_info(bgfx_surf_p p,uint16_t *w,uint16_t *h,uint16_t *pitch, uint32_t *flags) { *w = p->surface.width; *h = p->surface.height; *pitch = p->surface.pitch; *flags = p->flags; } /**************************************************************** * bgfx_get_palette * * INPUTS: p - surface structure * OUTPUTS: palette_p - return current palette * RETURNS: none * FUNCTION: get the current palett * ****************************************************************/ void bgfx_get_palette(bgfx_surf_p p,bgfx_palette_t *palette_p) { BGFX_MEMCPY(palette_p,&p->palette,sizeof(bgfx_palette_t)); } /**************************************************************** * bgfx_set_palette * * INPUTS: p - surface structure * palette_p - the palette * OUTPUTS: none * RETURNS: none * FUNCTION: set the global system palette * ****************************************************************/ void bgfx_set_palette(bgfx_surf_p p, bgfx_palette_t *palette_p) { BGFX_MEMCPY(&p->palette,palette_p,sizeof(bgfx_palette_t)); } /**************************************************************** * bgfx_set_pixel * * INPUTS: p - surface structure * x,y - coordinates * c - pixel value * OUTPUTS: none * RETURNS: none * FUNCTION: set the pixel at x,y * ****************************************************************/ void bgfx_set_pixel(bgfx_surf_p p,uint16_t x,uint16_t y,bgfx_pixel c) { uint8_t *dst; if ((x >= p->surface.width) || (y >= p->surface.height)) { BGFX_DEBUG(("bgfx_set_pixel param error (%p,%d,%d)\n",p,x,y)); return; } dst = (uint8_t*)p->surface.buf; dst += y * p->surface.pitch + (x * p->bpp)/8; if (p->flags & BGFX_SURF_RGB) { *((uint32_t*)dst) = c; bgfx_cacheflush(dst,4); } else if (p->bpp == 8) { *dst = (uint8_t)c; bgfx_cacheflush(dst,1); } else { if (x & 1) { *dst &= 0xF0; *dst |= (uint8_t)(c & 0xF); } else { *dst &= 0xF; *dst |= (uint8_t)((c & 0xF) << 4); } bgfx_cacheflush(dst,1); } } /**************************************************************** * bgfx_get_pixel * * INPUTS: p - surface structure * x,y - coordinates * c - pixel value * OUTPUTS: none * RETURNS: none * FUNCTION: get the pixel value at x,y. The bgfx_color will be the * actual pixel value. * * NOTE: Not supported for RGB surfaces. To get a pixel for RGB access buf * directly. * ****************************************************************/ bgfx_pixel bgfx_get_pixel(bgfx_surf_p p,uint16_t x,uint16_t y) { uint8_t *dst; if ((x >= p->surface.width) || (y >= p->surface.height)) { BGFX_DEBUG(("bgfx_get_pixel param error (%p,%d,%d)\n",p,x,y)); return 0; } dst = (uint8_t*)p->surface.buf; dst += y * p->surface.pitch + (x * p->bpp)/8; if (p->flags & BGFX_SURF_RGB) { return *((uint32_t*)dst); } else if (p->bpp == 8) { return *dst; } /* p->bpp == 4 */ if (x & 1) { return (*dst & 0xF0); } return (*dst >> 4); } /**************************************************************** * bgfx_h_draw_line * * INPUTS: p - surface structure * x1,x2,y - coordinates * c - pixel value * OUTPUTS: none * RETURNS: none * FUNCTION: Draw a horizontal line make of pixels defined by the value c. * * JPF - these need to be optimized * ****************************************************************/ void bgfx_h_draw_line(bgfx_surf_p p,uint16_t x1,uint16_t x2,uint16_t y, bgfx_pixel c) { int w = x2 - x1; if (w < 0) { w = -w; bgfx_fill_rect(p,x2,y,(uint16_t)w,1, c); } else { bgfx_fill_rect(p,x1,y,(uint16_t)w,1, c); } } /**************************************************************** * bgfx_v_draw_line * * INPUTS: p - surface structure * x,y1,y2 - coordinates * c - pixel value * OUTPUTS: none * RETURNS: none * FUNCTION: Draw a vertical line make of pixels defined by the value c. * * JPF - these need to be optimized * ****************************************************************/ void bgfx_v_draw_line(bgfx_surf_p p,uint16_t x,uint16_t y1,uint16_t y2, bgfx_pixel c) { uint8_t *dst; uint16_t h = y2 - y1; if ((y2 <= y1) || (x >= p->surface.width)) { BGFX_DEBUG(("bgfx_v_draw_line param error (%p,%d,%d,%d,0x%02lx)\n",p,x,y1,y2,c)); return; } if (h > p->surface.height - y1) h = p->surface.height - y1; dst = (uint8_t*)p->surface.buf; dst += y1 * p->surface.pitch + x * p->bpp/8; if (p->flags & BGFX_SURF_RGB) { while (h--) { *((uint32_t*)dst) = c; dst += p->surface.pitch; } } else if (p->bpp == 8) { while (h--) { *dst = (uint8_t)c; dst += p->surface.pitch; } } else { while (h--) { if (x & 1) { *dst &= 0xF0; *dst |= (uint8_t)(c & 0xF); } else { *dst &= 0xF; *dst |= (uint8_t)((c & 0xF) << 4); } dst += p->surface.pitch; } } bgfx_cacheflush(p->surface.buf,p->surface.pitch * p->surface.height); } /**************************************************************** * bgfx_fill_rect * * INPUTS: p - surface structure * x1,x2,y1,y2 - coordinates * c - pixel value * OUTPUTS: none * RETURNS: none * FUNCTION: Fill the rectangle with pixels defined by the value c. * * JPF - these need to be optimized * ****************************************************************/ /* TODO create optimized version of memset */ #if 0 static inline void *bgfx_memset(void *dest,int c,size_t count) { uint8_t *d = dest; for(;count>0;count--) { *d++ = c; } return dest; } #else #define bgfx_memset BGFX_MEMSET #endif void bgfx_fill_rect(bgfx_surf_p p,uint16_t x,uint16_t y,uint16_t w,uint16_t h, bgfx_pixel c) { uint8_t *tdst; uint16_t i; uint8_t *dst; uint16_t j; if (y + h > p->surface.height) h = p->surface.height - y; if (w + x > p->surface.width) w = p->surface.width - x; dst = (uint8_t*)p->surface.buf; dst += y * p->surface.pitch + x * p->bpp/8; if (p->flags & BGFX_SURF_RGB) { for (j = 0; j < h; ++j) { tdst = dst; for (i = 0; i < w; ++i) { *((uint32_t*)tdst) = c; tdst += p->bpp/8; } dst += p->surface.pitch; } } else if (p->bpp == 8) { for (j = 0; j < h; ++j) { bgfx_memset(dst,(uint8_t)c,w); dst += p->surface.pitch; } } else { unsigned char two_pixel = (uint8_t)((c << 4) | c); for (j = 0; j < h; ++j) { unsigned int num_bytes = (w * p->bpp)/8; if (x & 1) { *dst &= 0xF0; *dst |= (uint8_t)(c & 0xF); if (w & 1) { bgfx_memset(&dst[1],two_pixel,num_bytes); } else { bgfx_memset(&dst[1],two_pixel,num_bytes - 1); dst[num_bytes] &= 0x0F; dst[num_bytes] |= (uint8_t)((c & 0xF) << 4); } } else { if (w & 1) { bgfx_memset(dst,two_pixel,num_bytes); dst[num_bytes] &= 0x0F; dst[num_bytes] |= (uint8_t)((c & 0xF) << 4); } else bgfx_memset(dst,two_pixel,num_bytes); } dst += p->surface.pitch; } } bgfx_cacheflush(p->surface.buf,p->surface.pitch * p->surface.height); } /**************************************************************** * bgfx_render_glyph * * INPUTS: p - surface structure * x,y - coordinates * a_char - character to render * font_p - font definition * c - color * OUTPUTS: none * RETURNS: character advance * FUNCTION: Fill the rectangle with pixels defined by the value c. * ****************************************************************/ #define IT_OFFSET 3 static inline int bgfx_render_glyph(bgfx_surf_p p,uint16_t x,uint16_t y, const unsigned long a_char, bgfx_font_t *font_p,bgfx_pixel c, bgfx_glyph_t * p_bgfx_glyph,bgfx_text_style style) { int max_width,ybase; uint16_t row; uint8_t *src,*dst; bgfx_glyph_t * bgfx_glyph = p_bgfx_glyph; unsigned char glyph_width; /* width of the rendered character bitmap in pixels */ unsigned char glyph_height; /* height of the rendered character bitmap in pixels */ ybase = y; if (x > p->surface.width) { BGFX_TRACE(("bgfx_render_glyph x > width (%d,%d)\n",x,p->surface.width)); return 0; } /* if using glyph cache use the get glyph rather than render directly to surface buffer */ if (!bgfx_glyph && (font_p->cache_size > 0)) { bgfx_glyph = bgfx_get_glyph(font_p,a_char); } if (!bgfx_glyph) { BGFX_DEBUG(("bgfx_render_glyph could not load glyph 0x%08lx\n",a_char)); return 0; } BGFX_TRACE(("bgfx_render_glyph glyph (%p,%d,%d)\n",bgfx_glyph->buf,bgfx_glyph->height,bgfx_glyph->width)); glyph_width = bgfx_glyph->width; glyph_height = bgfx_glyph->height; if (bgfx_glyph->left + x > 0) x += bgfx_glyph->left; if (y-bgfx_glyph->top > 0) y -= bgfx_glyph->top; else y = 0; if (glyph_height + y > p->surface.height) glyph_height = p->surface.height - y; if (glyph_width + x > p->surface.width) glyph_width = p->surface.width - x; src = (uint8_t*)bgfx_glyph->buf; dst = (uint8_t*)p->surface.buf; BGFX_TRACE(("bgfx_render_glyph suface (%p(y = %d,x = %d,pitch = %d,bpp = %d)\n",dst,y,x,p->surface.pitch, p->bpp)); dst += y * p->surface.pitch + x * p->bpp/8; if (style & eBGFX_ITALIC) max_width = BGFX_MIN(glyph_width + IT_OFFSET, p->surface.width - x); else max_width = BGFX_MIN(glyph_width, p->surface.width - x); if (max_width <= 0) { if (glyph_width != 0) { BGFX_TRACE(("bgfx_render_glyph glyph_width = %d\n", glyph_width)); } return bgfx_glyph->advance; } /* Render mono glyph */ if (font_p->format & BGFX_MONO) { BGFX_TRACE(("bgfx_render_glyph Alpha 1 font\n")); if (p->flags & BGFX_SURF_RGB) { for (row = 0; row < glyph_height; row++) { bgfx_render_a1_to_rgb( src, dst, max_width,c ); src += bgfx_glyph->pitch; dst += p->surface.pitch; } } else if (p->bpp == 8) { for (row = 0; row < glyph_height; row++) { bgfx_render_a1_to_clut8( src, dst, max_width,c ); src += bgfx_glyph->pitch; dst += p->surface.pitch; } } else { uint16_t adjx = x; for (row = 0; row < glyph_height; row++) { if (style & eBGFX_ITALIC) { adjx = x + IT_OFFSET - ((row * IT_OFFSET)/glyph_height); dst = (uint8_t*)p->surface.buf; dst += (y + row) * p->surface.pitch + adjx * p->bpp/8; } bgfx_render_a1_to_clut4( src, dst, max_width,c, adjx & 0x1 ); src += bgfx_glyph->pitch; dst += p->surface.pitch; } } } else /* Render 8 bit grayscale glyph */ { BGFX_TRACE(("bgfx_render_glyph Alpha 8 font\n")); if (p->flags & BGFX_SURF_RGB) { for (row = 0; row < glyph_height; row++) { bgfx_render_a8_to_rgb( src, dst, glyph_width,c); src += bgfx_glyph->pitch; dst += p->surface.pitch; } } else if (p->bpp == 8) { for (row = 0; row < glyph_height; row++) { bgfx_render_a8_to_clut8( src, dst, glyph_width,c ); src += bgfx_glyph->pitch; dst += p->surface.pitch; } } else { for (row = 0; row < glyph_height; row++) { bgfx_render_a8_to_clut4( src, dst, glyph_width,c ); src += bgfx_glyph->pitch; dst += p->surface.pitch; } } } if (style & eBGFX_UNDERLINE) bgfx_h_draw_line(p,x,x + bgfx_glyph->advance,ybase,c); return bgfx_glyph->advance; } /**************************************************************** * bgfx_draw_text * * INPUTS: p - surface structure * x,y - coordinates * str_p - array of 32-bit unicode characters str_len - number of 32-bit characters in array * font_p - font definition * c - color * OUTPUTS: none * RETURNS: none * FUNCTION: Fill the rectangle with pixels defined by the value c. * ****************************************************************/ void bgfx_draw_text(bgfx_surf_p p,uint16_t x,uint16_t y, const unsigned long *str_p, int str_len, bgfx_font_t *font_p,bgfx_pixel c, bgfx_text_style style) { int offset; BGFX_TRACE(("bgfx_draw_text %ld characters.\n",str_len)); for (offset = 0; offset < str_len; offset++) { x += bgfx_render_glyph(p,x,y, str_p[offset], font_p,c,NULL,style); } bgfx_cacheflush(p->surface.buf,p->surface.pitch * p->surface.height); } /**************************************************************** * bgfx_draw_text_box * * INPUTS: p - surface structure * x,y - coordinates * width,height - width and hegith of the text box to draw * str_p - array of 32-bit unicode characters str_len - number of 32-bit characters in array * font_p - font definition * c - color line_spacing - line space * OUTPUTS: none * RETURNS: none * FUNCTION: Fill the rectangle with pixels defined by the value c. * ****************************************************************/ #define MAX_TEXT_BOX_CHARS 512 #define MAX_LINES 16 static unsigned long s_test_char = 0x00000057UL; /* TODO: Might want to improve macro to check for chars other than spaces */ #define BGFX_IS_BREAK(x) ((x == 0x00000020) ? 1 : 0) void bgfx_draw_text_box(bgfx_surf_p p,uint16_t x,uint16_t y, uint16_t width, uint16_t height, const unsigned long *str_p, int str_len, bgfx_font_t *font_p,bgfx_pixel c, uint16_t line_spacing) { int offset,bw_off,line_idx; static bgfx_glyph_t * p_bgfx_glyph[MAX_TEXT_BOX_CHARS]; /* Not thread safe */ static uint8_t brk_loc[MAX_TEXT_BOX_CHARS]; uint16_t max_h[MAX_LINES],ch_w,test_max_h,bot; bgfx_glyph_t *p_test_glyph; BGFX_TRACE(("bgfx_draw_text_box(%d,%d,%d,%d,%d) %ld characters.\n",x,y,width,height,line_spacing,str_len)); if (str_len > MAX_TEXT_BOX_CHARS) { BGFX_DEBUG(("bgfx_draw_text %d > %d maximum characters.\n",str_len,MAX_TEXT_BOX_CHARS)); str_len = MAX_TEXT_BOX_CHARS; } bot = y + height; p_test_glyph = bgfx_get_glyph(font_p,s_test_char); if (p_test_glyph) test_max_h = p_test_glyph->height; else test_max_h = 0; for (line_idx = 0; line_idx < MAX_LINES; ++line_idx) max_h[line_idx] = test_max_h; ch_w = 0; line_idx = 0; for (offset = 0; offset < str_len; offset++) { brk_loc[offset] = 0; p_bgfx_glyph[offset] = bgfx_get_glyph(font_p,str_p[offset]); if (p_bgfx_glyph[offset] == NULL) { BGFX_DEBUG(("%s:%d str[%d] = 0x%08x\n",__FUNCTION__,__LINE__,offset,str_p[offset])); /* if not a printable charactor, then use space instead */ p_bgfx_glyph[offset] = bgfx_get_glyph(font_p,0x00000020); continue; } ch_w += p_bgfx_glyph[offset]->advance; if (p_bgfx_glyph[offset]->height > max_h[line_idx]) max_h[line_idx] = p_bgfx_glyph[offset]->height; if (ch_w >= width) { line_idx++; for (bw_off = offset - 1; bw_off >= 0; --bw_off) { if (brk_loc[bw_off]) { bw_off = -1; break; } if (BGFX_IS_BREAK(str_p[bw_off])) { brk_loc[bw_off] = 1; break; } } /* last resort, break on preceding character */ if (bw_off < 0) { brk_loc[offset - 1] = 1; ch_w = p_bgfx_glyph[offset]->advance; } else { offset = bw_off; ch_w = 0; } } } /* offset y so text is inside box */ line_idx = 0; #ifdef BGFX_VARIABL_LINE_HEIGHT y += max_h[line_idx]; #else y += test_max_h; #endif ch_w = 0; for (offset = 0; (offset < str_len) && (line_idx < MAX_LINES); offset++) { if (brk_loc[offset]) { line_idx++; ch_w = 0; #ifdef BGFX_VARIABL_LINE_HEIGHT y += line_spacing + max_h[line_idx]; if ((y - max_h[line_idx]) > bot) break; #else y += line_spacing + test_max_h; if ((y - test_max_h) > bot) break; #endif continue; } ch_w += bgfx_render_glyph(p,x + ch_w,y, str_p[offset], font_p,c,p_bgfx_glyph[offset],eBGFX_NORMAL); } bgfx_cacheflush(p->surface.buf,p->surface.pitch * p->surface.height); } /**************************************************************** * bgfx_render_file * * INPUTS: p - surface structure * x,y - coordinates * file_p - file to get image from * set_palette - use the palette in the file to set the * global palette. * OUTPUTS: none * RETURNS: non-zero on error * FUNCTION: Render the image in the file to the x,y location * ****************************************************************/ int bgfx_render_file(bgfx_surf_p p,uint16_t x,uint16_t y, void *file_p,int set_palette) { bcm_raw_8_t header; int result = -1; static uint8_t tbuf[SURF_WIDTH]; uint16_t row,rows,rowbytes; uint8_t *dst_ptr; int palette_bytes; uint16_t i; uint8_t *r_ptr,*tdst; if (bgfx_read(&header,1,sizeof(header),file_p) == sizeof(header)) { if (header.type != RAW_TYPE || header.version != RAW_VERSION) { BGFX_DEBUG(("bgfx_render_file failed version,type invalid(0x%08lx,0x%08lx)\n",header.type,header.version)); return -1; } BGFX_TRACE(("header.version = 0x%08lx\n",header.version)); BGFX_TRACE(("header.type = 0x%08lx\n",header.type)); BGFX_TRACE(("header.clut_size = %d\n",header.clut_size)); BGFX_TRACE(("header.color_key = 0x%02x\n",header.color_key)); BGFX_TRACE(("header.pitch = %ld\n",header.pitch)); BGFX_TRACE(("header.width = 0x%08x\n",header.width)); BGFX_TRACE(("header.height = 0x%08x\n",header.height)); palette_bytes = (sizeof(unsigned long) * header.clut_size); if (bgfx_read(&p->palette,1,palette_bytes,file_p) == palette_bytes) { if (set_palette && (header.clut_size == PALETTE_SIZE)) bgfx_set_palette(p,&p->palette); } if ((header.width == p->surface.width) && (header.height == p->surface.height) && (p->surface.pitch == header.pitch) && (x == 0) && (y == 0) && !(p->flags & BGFX_SURF_RGB)) { BGFX_TRACE(("Fast Render\n")); bgfx_read(p->surface.buf,1,header.pitch*header.height,file_p); } else if ((p->palette.clut[header.color_key] & 0xFF000000) != 0) { BGFX_TRACE(("Render - no color key\n")); rowbytes = BGFX_MIN(header.width,p->surface.width - x) * p->bpp/8; rows = BGFX_MIN(header.height, p->surface.height - y); dst_ptr = (uint8_t*)p->surface.buf; dst_ptr += y * p->surface.pitch + x * p->bpp/8; if (p->flags & BGFX_SURF_RGB) { for (row = 0; row < rows; row++) { bgfx_read(tbuf ,1,rowbytes,file_p); r_ptr = dst_ptr; for (i = 0; i < rowbytes; ++i) { uint32_t sr,sg,sb,sa,dr,dg,db,da,src_c; src_c = bgfx_clut8_to_rgb(p->palette.clut,tbuf[i]); sa = (src_c >> 24) & 0xFF; if (sa == 0xFF) { *((uint32_t*)r_ptr) = src_c; } else { sr = (src_c >> 16) & 0xFF; sg = (src_c >> 8) & 0xFF; sb = (src_c >> 0) & 0xFF; da = (*((uint32_t*)r_ptr) >> 24) & 0xFF; dr = (*((uint32_t*)r_ptr) >> 16) & 0xFF; dg = (*((uint32_t*)r_ptr) >> 8) & 0xFF; db = (*((uint32_t*)r_ptr) >> 0) & 0xFF; dr = (((sr * sa)/0xFF) & 0xFF) + ((((0xFF - sa) * dr)/0xFF) & 0xFF); dg = (((sg * sa)/0xFF) & 0xFF) + ((((0xFF - sa) * dg)/0xFF) & 0xFF); db = (((sb * sa)/0xFF) & 0xFF) + ((((0xFF - sa) * db)/0xFF) & 0xFF); *((uint32_t*)r_ptr) = (da << 24) | (dr << 16) | (dg << 8) | db; } r_ptr += p->bpp/8; } if (header.pitch > rowbytes) { bgfx_read(tbuf ,1,header.pitch - rowbytes,file_p); } dst_ptr += p->surface.pitch; } } else { for (row = 0; row < rows; row++) { bgfx_read(dst_ptr ,1,rowbytes,file_p); if (header.pitch > rowbytes) { bgfx_read(tbuf ,1,header.pitch - rowbytes,file_p); } dst_ptr += p->surface.pitch; } } } else { BGFX_TRACE(("Render - color key\n")); rowbytes = BGFX_MIN(header.width,(p->surface.width - x)) * p->bpp/8; rows = BGFX_MIN(header.height, (p->surface.height - y)); dst_ptr = (uint8_t*)p->surface.buf; dst_ptr += y * p->surface.pitch + x * p->bpp/8; if (p->flags & BGFX_SURF_RGB) { for (row = 0; row < rows; row++) { bgfx_read(tbuf ,1,rowbytes,file_p); r_ptr = dst_ptr; for (i = 0; i < rowbytes; ++i) { if (tbuf[i] != header.color_key) { uint32_t sr,sg,sb,sa,dr,dg,db,da,src_c; src_c = bgfx_clut8_to_rgb(p->palette.clut,tbuf[i]); sa = (src_c >> 24) & 0xFF; if (sa == 0xFF) { *((uint32_t*)r_ptr) = src_c; } else { sr = (src_c >> 16) & 0xFF; sg = (src_c >> 8) & 0xFF; sb = (src_c >> 0) & 0xFF; da = (*((uint32_t*)r_ptr) >> 24) & 0xFF; dr = (*((uint32_t*)r_ptr) >> 16) & 0xFF; dg = (*((uint32_t*)r_ptr) >> 8) & 0xFF; db = (*((uint32_t*)r_ptr) >> 0) & 0xFF; dr = (((sr * sa)/0xFF) & 0xFF) + ((((0xFF - sa) * dr)/0xFF) & 0xFF); dg = (((sg * sa)/0xFF) & 0xFF) + ((((0xFF - sa) * dg)/0xFF) & 0xFF); db = (((sb * sa)/0xFF) & 0xFF) + ((((0xFF - sa) * db)/0xFF) & 0xFF); *((uint32_t*)r_ptr) = (da << 24) | (dr << 16) | (dg << 8) | db; } } r_ptr += p->bpp/8; } if (header.pitch > rowbytes) { bgfx_read(tbuf ,1,header.pitch - rowbytes,file_p); } dst_ptr += p->surface.pitch; } } else { for (row = 0; row < rows; row++) { bgfx_read(dst_ptr ,1,rowbytes,file_p); if (header.pitch > rowbytes) { bgfx_read(tbuf ,1,header.pitch - rowbytes,file_p); } dst_ptr += p->surface.pitch; } } } } BGFX_TRACE(("Render - done\n")); bgfx_cacheflush(p->surface.buf,p->surface.pitch * p->surface.height); result = 0; return result; } /**************************************************************** * bgfx_blit * * INPUTS: p_src,p_dst - surface structure * x,y - destination coordinates * OUTPUTS: none * RETURNS: non-zero on error * FUNCTION: Blit between the two surfaces, only the destination can be RGB * ****************************************************************/ int bgfx_blit(bgfx_surf_p p_src, bgfx_surf_p p_dst, uint16_t x,uint16_t y) { uint8_t *dst,*src; uint16_t j,w,h,rowbytes; uint16_t i; uint8_t *tdst; BGFX_TRACE(("bgfx_blit x,y (%d,%d)\n",x,y)); if ((x > p_dst->surface.width) || (y > p_dst->surface.height)) { BGFX_DEBUG(("bgfx_blit x,y (%d,%d) outside destination (%d,%d)\n",x,y, p_dst->surface.width,p_dst->surface.height)); return -1; } w = p_src->surface.width; if (w > p_dst->surface.width - x) w = p_dst->surface.width - x; h = p_src->surface.height; if (h > p_dst->surface.height - y) h = p_dst->surface.height - y; src = (uint8_t*)p_src->surface.buf; dst = (uint8_t*)p_dst->surface.buf; dst += y * p_dst->surface.pitch + x * p_dst->bpp/8; if (p_dst->flags & BGFX_SURF_RGB) { for (j = 0; j < h; ++j) { tdst = dst; for (i = 0; i < w; ++i) { if (src[i] != 0xFF) *((uint32_t*)tdst) = bgfx_clut8_to_rgb(p_src->palette.clut,src[i]); tdst += p_dst->bpp/8; } dst += p_dst->surface.pitch; src += p_src->surface.pitch; } } else { rowbytes = BGFX_MIN(p_src->surface.width,p_dst->surface.width - x) * p_dst->bpp/8; for (j = 0; j < h; ++j) { BGFX_MEMCPY(dst,src,rowbytes); dst += p_dst->surface.pitch; src += p_src->surface.pitch; } } bgfx_cacheflush(p_dst->surface.buf,p_dst->surface.pitch * p_dst->surface.height); return 0; } /**************************************************************** * INPUTS: p_src,p_dst - source and destination buffer pointers * sx * dx * w - width * OUTPUTS: none * RETURNS: non-zero on error * FUNCTION: Blit a region of one surface to another (for 4 bpp ) * ****************************************************************/ static inline void bgfx_row_copy(unsigned char *src, unsigned char *dst, uint16_t sx,uint16_t dx,uint16_t w, int bpp) { if (bpp == 8) { BGFX_MEMCPY(dst,src,w); } else { unsigned int num_bytes = (w * 4)/8; int pix; if (sx & 1) { if (dx & 1) { *dst &= 0xF0; *dst |= (*src & 0xF); if (w & 1) { BGFX_MEMCPY(&dst[1],&src[1],num_bytes); } else { BGFX_MEMCPY(&dst[1],&src[1],num_bytes - 1); dst[num_bytes] &= 0x0F; dst[num_bytes] |= (src[num_bytes] & 0xF0); } } else { for (pix = 0; pix < w; ++pix) { if (pix & 1) { *dst &= 0xF0; *dst |= (*src & 0xF0) >> 4; dst++; } else { *dst &= 0x0F; *dst |= (*src & 0xF) << 4; src++; } } } } else { if (dx & 1) { for (pix = 0; pix < w; ++pix) { if (pix & 1) { *dst &= 0x0F; *dst |= (*src & 0xF) << 4; src++; } else { *dst &= 0xF0; *dst |= (*src & 0xF0) >> 4; dst++; } } } else { if (w & 1) { BGFX_MEMCPY(dst,src,num_bytes); dst[num_bytes] &= 0x0F; dst[num_bytes] |= (src[num_bytes] & 0xF0); } else { BGFX_MEMCPY(dst,src,num_bytes); } } } } } /**************************************************************** * INPUTS: p_src,p_dst - source and destination surface structures * sx,sy - source coordinates * dx,dy - destination coordinates * sw,sh - width and height of region * OUTPUTS: none * RETURNS: non-zero on error * FUNCTION: Blit a region of one surface to another * ****************************************************************/ int bgfx_blit_rect(bgfx_surf_p p_src, bgfx_surf_p p_dst, uint16_t sx,uint16_t sy, uint16_t dx,uint16_t dy, uint16_t sw,uint16_t sh) { uint8_t *dst,*src; uint16_t i,j,w,h; uint8_t *tdst; if ((dx >= p_dst->surface.width) || (dy >= p_dst->surface.height)) { BGFX_DEBUG(("bgfx_blit_rect dst_x,dst_y (%d,%d) outside destination (%d,%d)\n",dx,dy, p_dst->surface.width,p_dst->surface.height)); return -1; } if ((sx >= p_src->surface.width) || (sy >= p_src->surface.height)) { BGFX_DEBUG(("bgfx_blit_rect src_x,src_y (%d,%d) outside source (%d,%d)\n",sx,sy, p_src->surface.width,p_src->surface.height)); return -1; } src = (uint8_t*)p_src->surface.buf; src += (sy * p_src->surface.pitch) + ((sx * p_src->bpp)/8); dst = (uint8_t*)p_dst->surface.buf; dst += (dy * p_dst->surface.pitch) + ((dx * p_dst->bpp)/8); w = sw; if (sw >= (p_src->surface.width - sx)) w= p_src->surface.width - sx; if (w >= p_dst->surface.width - dx) w = p_dst->surface.width - dx; h = sh; if (sh >= (p_src->surface.height - sy)) h= p_src->surface.height - sy; if (h >= p_dst->surface.height - dy) h = p_dst->surface.height - dy; if (p_dst->flags & BGFX_SURF_RGB) { for (j = 0; j < h; ++j) { tdst = dst; for (i = 0; i < w; ++i) { if (src[i] != 0xFF) *((uint32_t*)tdst) = bgfx_clut8_to_rgb(p_src->palette.clut,src[i]); tdst += p_dst->bpp/8; } dst += p_dst->surface.pitch; src += p_src->surface.pitch; } } else { for (j = 0; j < h; ++j) { if (p_dst->bpp == 8) { for (i = 0; i < w; ++i) { if (p_src->palette.clut[src[i]] & 0xFF000000) { dst[i] = src[i]; } } } else { bgfx_row_copy(src,dst,sx,dx,w,p_dst->bpp); } dst += p_dst->surface.pitch; src += p_src->surface.pitch; } } bgfx_cacheflush(p_dst->surface.buf,p_dst->surface.pitch * p_dst->surface.height); return 0; }