static void setup_players(void) { n_players = 2; players = malloc(n_players * sizeof(player_t)); init_player(&players[0], mkcolor(255, 0, 0)); players[0].keydefs[0] = KEYDEF(3, 0x10000000) /* right */; players[0].keydefs[1] = KEYDEF(3, 0x40000000) /* up */; players[0].keydefs[2] = KEYDEF(3, 0x08000000) /* left */; players[0].keydefs[3] = KEYDEF(3, 0x20000000) /* down */; init_player(&players[1], mkcolor(0, 255, 0)); players[1].keydefs[0] = KEYDEF(0, 0x00000002) /* s */; players[1].keydefs[1] = KEYDEF(0, 0x00002000) /* w */; players[1].keydefs[2] = KEYDEF(0, 0x00000001) /* a */; players[1].keydefs[3] = KEYDEF(0, 0x00000040) /* z */; }
/* Transcribe one scanline from the GIF to the picogui bitmap */ void dither_transcribe_line(hwrdither d, GifFileType *f, int transparent_flag, int transparent_color) { pgcolor c; u8 pixel; GifColorType *color; int x; for (x=0;x<f->Image.Width;x++) { DGifGetPixel(f, &pixel); color = f->SColorMap->Colors + (pixel % f->SColorMap->ColorCount); if (transparent_flag) { c = mkcolora(pixel==transparent_color ? 0 : 127,color->Red,color->Green,color->Blue); } else { c = mkcolor(color->Red,color->Green,color->Blue); } vid->dither_store(d,c,PG_LGOP_NONE); } }
/* Transcribe one scanline from the GIF to the picogui bitmap */ void transcribe_line(hwrbitmap b, GifFileType *f, int y, int transparent_flag, int transparent_color) { pgcolor c; u8 pixel; GifColorType *color; int x; for (x=0;x<f->Image.Width;x++) { DGifGetPixel(f, &pixel); color = f->SColorMap->Colors + (pixel % f->SColorMap->ColorCount); if (transparent_flag) { c = mkcolora(pixel==transparent_color ? 0 : 127,color->Red,color->Green,color->Blue); } else { c = mkcolor(color->Red,color->Green,color->Blue); } vid->pixel(b,x,y,VID(color_pgtohwr)(c),PG_LGOP_NONE); } }
g_error jpeg_load(hwrbitmap *hbmp, const u8 *data, u32 datalen) { /* Convert from any of the pbmplus formats in binary or ascii */ struct stdbitmap **bmp = (struct stdbitmap **) hbmp; g_error e; int i,r,g,b,x,y; int pixels; int bytes; int scanline_bytes; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buffer; /* Output row buffer */ #ifdef CONFIG_DITHER hwrdither dither; #endif g_error efmt = mkerror(PG_ERRT_BADPARAM,48); if (!datalen) return efmt; /* get jpeg info */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, (unsigned char *) data, datalen); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); /* determine memory requirements */ pixels = cinfo.output_width * cinfo.output_height; bytes = pixels * cinfo.output_components; scanline_bytes = cinfo.output_components * cinfo.output_width; #if DEBUG printf(__FUNCTION__ "() image is %dx%dx%d (%d bytes), colorspace=%d\n", cinfo.output_width, cinfo.output_height, cinfo.output_components, bytes, cinfo.out_color_components); #endif /* Set up the bitmap */ e = vid->bitmap_new((hwrbitmap *)bmp,cinfo.output_width, cinfo.output_height,vid->bpp); errorcheck; #ifdef CONFIG_DITHER /* Start dithering */ e = vid->dither_start(&dither, *bmp, 0,0,0,cinfo.output_width,cinfo.output_height); errorcheck; #endif /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, scanline_bytes, 1); y = 0; while (cinfo.output_scanline < cinfo.output_height ) { jpeg_read_scanlines(&cinfo, buffer, 1); /* process scanline */ for (i=0,x=0;i<scanline_bytes;x++) { switch(cinfo.out_color_components) { case 3: r = (*buffer)[i++]; g = (*buffer)[i++]; b = (*buffer)[i++]; break; default: r = g = b = (*buffer)[i++]; } #ifdef CONFIG_DITHER vid->dither_store(dither, mkcolor(r,g,b), PG_LGOP_NONE); #else vid->pixel(*bmp,x,y,vid->color_pgtohwr(mkcolor(r,g,b)),PG_LGOP_NONE); #endif } y++; } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); #ifdef CONFIG_DITHER vid->dither_finish(dither); #endif return success; }
g_error load_custom_palette(const char *name) { int i; FILE *f; char linebuffer[256]; char *p; int r,g,b; if (name) { /* Load a gimp-format palette from file */ f = fopen(name,"r"); if (!f) return mkerror(PG_ERRT_IO,110); /* Can't open palette */ /* Zero unused entries */ memset(palette8_custom,0,sizeof(palette8_custom)); i = 0; while (fgets(linebuffer,sizeof(linebuffer)-1,f)) { linebuffer[sizeof(linebuffer)-1] = 0; /* Strip comments out */ p = strchr(linebuffer,'#'); if (p) *p = 0; /* Strip leading whitespace */ p = linebuffer; while (isspace(*p)) p++; /* If there's anything else, read in the palette entry */ if (*p) { sscanf(p, "%d %d %d", &r,&g,&b); palette8_custom[(i++)&0xFF] = mkcolor(r,g,b); } } fclose(f); } else { /* Load a default palette. * Grayscale is an easy fallback, but we can optionally include * a copy of the visibone2 palette from Gimp */ #ifdef CONFIG_PAL8_VISIBONE2 memcpy(palette8_custom,visibone2_palette,sizeof(palette8_custom)); #else for (i=0;i<256;i++) palette8_custom[i] = mkcolor(i,i,i); #endif } /* Now sort the palette by luminance so the AND/OR effects and such work */ qsort(palette8_custom, 256, sizeof(pgcolor), compare_luminance); /* Build the palette hash table if we're using one. * Note the extra care in bitshifting so that we really do get pure white, * rather than always truncating a bit or three */ #ifdef CONFIG_PAL8_LOOKUP_32K for (i=0;i<sizeof(palette_hash)/sizeof(palette_hash[0]);i++) { int r = i >> 10; int g = (i >> 5 ) & 0x1F; int b = i & 0x1F; palette_hash[i] = palette_lookup(mkcolor( (r >> 2) | (r << 3), (g >> 2) | (g << 3), (b >> 2) | (b << 3) )); } #endif #ifdef CONFIG_PAL8_LOOKUP_256K for (i=0;i<sizeof(palette_hash)/sizeof(palette_hash[0]);i++) { int r = i >> 12; int g = (i >> 6 ) & 0x3F; int b = i & 0x3F; palette_hash[i] = palette_lookup(mkcolor( (r >> 4) | (r << 2), (g >> 4) | (g << 2), (b >> 4) | (b << 2) )); } #endif return success; }
g_error png_load(hwrbitmap *hbmp, const u8 *data, u32 datalen) { png_structp png_ptr; png_infop info_ptr; struct datablock d; png_bytep *row_pointers; png_uint_32 width, height; int bit_depth,colortype,interlace; int x,y; u8 r,g,b,a; pgcolor c; png_bytep p; g_error e; png_colorp palette; int num_palette; png_colorp pp; png_bytep trans; int num_trans = 0; #ifdef CONFIG_DITHER hwrdither dither; #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return mkerror(PG_ERRT_IO, 68); /* Error initializing libpng */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return mkerror(PG_ERRT_IO, 68); /* Error initializing libpng */ } /* Set libpng error handler */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return mkerror(PG_ERRT_IO, 71); /* Error reading PNG */ } /* Set libpng read handler */ d.data = data; d.length = datalen; png_set_read_fn(png_ptr, &d, (png_rw_ptr) &png_user_read_data); /* Read the png into memory */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL); row_pointers = png_get_rows(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &colortype, &interlace, NULL, NULL); if (colortype == PNG_COLOR_TYPE_PALETTE) { png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); } if (interlace != PNG_INTERLACE_NONE) fprintf(stderr, "png loader: OOPS... interlaced image, will b0rk\n"); /* Allocate the picogui bitmap * * Important note: normally we create bitmaps at the display's * color depth, but if we have an alpha channel * we need room for ARGB colors. */ if (colortype == PNG_COLOR_TYPE_GRAY_ALPHA || colortype == PNG_COLOR_TYPE_RGB_ALPHA || num_trans) e = vid->bitmap_new(hbmp,width,height,32); else e = vid->bitmap_new(hbmp,width,height,vid->bpp); if (iserror(e)) png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); errorcheck; #ifdef CONFIG_DITHER /* Start dithering */ e = vid->dither_start(&dither, *hbmp, 0,0,0,width,height); errorcheck; #endif /* Transcribe it into a picogui bitmap. * This method is slow, but ensures compatibility */ for (y=0;y<height;y++) { p = row_pointers[y]; for (x=0;x<width;x++) { switch (colortype) { case PNG_COLOR_TYPE_GRAY: g = *(p++); c = mkcolor(g,g,g); break; case PNG_COLOR_TYPE_GRAY_ALPHA: g = *(p++); a = *(p++); c = mkcolora(a>>1,g,g,g); break; case PNG_COLOR_TYPE_PALETTE: pp = &palette[ (*p) % num_palette ]; if (*p < num_trans) c = mkcolora(trans[*p]>>1, pp->red, pp->green, pp->blue); else if (num_trans) c = mkcolora(0x7f, pp->red, pp->green, pp->blue); else c = mkcolor(pp->red, pp->green, pp->blue); p++; break; case PNG_COLOR_TYPE_RGB: r = *(p++); g = *(p++); b = *(p++); c = mkcolor(r,g,b); break; case PNG_COLOR_TYPE_RGB_ALPHA: r = *(p++); g = *(p++); b = *(p++); a = *(p++); c = mkcolora(a>>1,r,g,b); break; } #ifdef CONFIG_DITHER vid->dither_store(dither, c, PG_LGOP_NONE); #else vid->pixel(*hbmp,x,y,VID(color_pgtohwr)(c),PG_LGOP_NONE); #endif } }
/* Fillstyle interpreter- generates/refreshes a gropnode list */ g_error exec_fillstyle_inner(struct gropctxt *ctx,u16 state, u16 property) { g_error e; u32 fssize; /* Fillstyle size */ unsigned char *fs; /* Pointer to the actual fillstyle data */ unsigned char *p,*plimit; unsigned char op; int r,g,b; /* For color arithmetic */ struct widget *w; int stackframe = fsstkpos-4; /* Look up the fillstyle */ e = rdhandle((void**)&fs,PG_TYPE_FILLSTYLE,-1,theme_lookup(state,property)); errorcheck; if (!fs) { /* When our best just isn't good enough... */ if (property == PGTH_P_BACKDROP || property == PGTH_P_BORDER_FILL) return success; /* The default fillstyle, if no theme is loaded or no theme has defined the property*/ addgrop(ctx,PG_GROP_SETCOLOR); ctx->current->param[0] = VID(color_pgtohwr) (0x000000); switch (state) { case PGTH_O_BUTTON_ON: /* 2 borders */ addgropsz(ctx,PG_GROP_FRAME,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h); ctx->r.x += 1; ctx->r.y += 1; ctx->r.w -= 2; ctx->r.h -= 2; default: /* 1 border */ addgropsz(ctx,PG_GROP_FRAME,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h); ctx->r.x += 1; ctx->r.y += 1; ctx->r.w -= 2; ctx->r.h -= 2; case PGTH_O_LABEL_SCROLL: /* No border */ addgrop(ctx,PG_GROP_SETCOLOR); ctx->current->param[0] = VID(color_pgtohwr) (theme_lookup(state,PGTH_P_BGCOLOR)); addgropsz(ctx,PG_GROP_RECT,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h); } return success; } /* Process the opcodes */ fssize = *(((u32 *)fs)++); p = fs; plimit = fs+fssize; while (p<plimit) { op = *(p++); /* These must occur in MSB to LSB order! (see constants.h) */ if (op & PGTH_OPSIMPLE_GROP) { /* 1-byte gropnode */ e = fsgrop(ctx,op & (PGTH_OPSIMPLE_GROP-1)); errorcheck; } else if (op & PGTH_OPSIMPLE_LITERAL) { /* 1-byte literal */ fsstack[fsstkpos++] = op & (PGTH_OPSIMPLE_LITERAL-1); } else if (op & PGTH_OPSIMPLE_CMDCODE) { /* Command code */ switch (op) { case PGTH_OPCMD_LONGLITERAL: if ((plimit-p)<4) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsstack[fsstkpos++] = NEXTLONG; p += 4; break; case PGTH_OPCMD_LONGGROP: if ((plimit-p)<2) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ e = fsgrop(ctx,NEXTSHORT); p += 2; errorcheck; break; case PGTH_OPCMD_LONGGET: if (plimit<=p) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ e = fsget(*(p++)+stackframe); errorcheck; break; case PGTH_OPCMD_LONGSET: if (plimit<=p) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ e = fsset(*(p++)+stackframe); errorcheck; break; case PGTH_OPCMD_PROPERTY: if ((plimit-p)<4) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsa = NEXTSHORT; p += 2; fsb = NEXTSHORT; p += 2; fsstack[fsstkpos++] = theme_lookup(fsa,fsb); #ifdef CONFIG_ANIMATION /* If it depends on time or randomness, turn on the animated flag in the divnode */ if ((fsb==PGTH_P_TICKS || fsb==PGTH_P_RANDOM) && ctx->owner) ctx->owner->flags |= DIVNODE_ANIMATED; #endif break; case PGTH_OPCMD_LOCALPROP: if ((plimit-p)<2) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsa = NEXTSHORT; p += 2; #ifdef DEBUG_THEME printf("Local theme lookup, property %d\n",(int)fsa); #endif fsstack[fsstkpos++] = theme_lookup(state,fsa); #ifdef CONFIG_ANIMATION /* If it depends on time or randomness, turn on the animated flag in the divnode */ if ((fsa==PGTH_P_TICKS || fsa==PGTH_P_RANDOM) && ctx->owner) ctx->owner->flags |= DIVNODE_ANIMATED; #endif break; case PGTH_OPCMD_PLUS: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa + fsb; break; case PGTH_OPCMD_MINUS: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa - fsb; break; case PGTH_OPCMD_MULTIPLY: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa * fsb; break; case PGTH_OPCMD_SHIFTL: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa << fsb; break; case PGTH_OPCMD_SHIFTR: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa >> fsb; break; case PGTH_OPCMD_OR: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa | fsb; break; case PGTH_OPCMD_AND: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa & fsb; break; case PGTH_OPCMD_EQ: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa == fsb; break; case PGTH_OPCMD_LT: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa < fsb; break; case PGTH_OPCMD_GT: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa > fsb; break; case PGTH_OPCMD_LOGICAL_OR: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa || fsb; break; case PGTH_OPCMD_LOGICAL_AND: e = fspopargs(); errorcheck; fsstack[fsstkpos++] = fsa && fsb; break; case PGTH_OPCMD_LOGICAL_NOT: fsstack[fsstkpos-1] = !fsstack[fsstkpos-1]; break; case PGTH_OPCMD_DIVIDE: e = fspopargs(); errorcheck; if (fsb) fsstack[fsstkpos++] = fsa / fsb; else fsstack[fsstkpos++] = 0xFFFFFFFF; /* limit of fsa/fsb as fsb approaches 0 */ break; case PGTH_OPCMD_COLORADD: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r += getred(fsb); g += getgreen(fsb); b += getblue(fsb); if (r>255) r = 255; if (g>255) g = 255; if (b>255) b = 255; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_COLORSUB: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r -= getred(fsb); g -= getgreen(fsb); b -= getblue(fsb); if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_COLORDIV: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r = getred(fsb) ? (r/getred(fsb)) : 0xFF; /* Avoid divide by zero */ g = getgreen(fsb) ? (g/getgreen(fsb)) : 0xFF; b = getred(fsb) ? (b/getblue(fsb)) : 0xFF; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_COLORMULT: e = fspopargs(); errorcheck; r = getred(fsa); g = getgreen(fsa); b = getblue(fsa); r *= getred(fsb); g *= getgreen(fsb); b *= getblue(fsb); if (r>255) r = 255; if (g>255) g = 255; if (b>255) b = 255; fsstack[fsstkpos++] = mkcolor(r,g,b); break; case PGTH_OPCMD_QUESTIONCOLON: if (fsstkpos<3) return mkerror(PG_ERRT_BADPARAM,88); /* Stack underflow */ fsstkpos -= 2; fsstack[fsstkpos-1] = fsstack[fsstkpos+1] ? fsstack[fsstkpos] : fsstack[fsstkpos-1]; break; case PGTH_OPCMD_WIDGET: if (ctx->owner && ctx->owner->owner) fsstack[fsstkpos++] = hlookup(ctx->owner->owner,NULL); else fsstack[fsstkpos++] = 0; break; case PGTH_OPCMD_TRAVERSEWGT: if (fsstkpos<3) return mkerror(PG_ERRT_BADPARAM,88); /* Stack underflow */ fsstkpos -= 2; e = rdhandle((void**)&w, PG_TYPE_WIDGET, -1, fsstack[fsstkpos+1]); errorcheck; if (w) fsstack[fsstkpos-1] = hlookup(widget_traverse(w,fsstack[fsstkpos],fsstack[fsstkpos-1]),NULL); else fsstack[fsstkpos-1] = 0; break; case PGTH_OPCMD_GETWIDGET: e = fspopargs(); errorcheck; e = rdhandle((void**)&w, PG_TYPE_WIDGET, -1, fsa); errorcheck; if (w) fsstack[fsstkpos++] = widget_get(w,fsb); else fsstack[fsstkpos++] = 0; break; case PGTH_OPCMD_CALL: if ((plimit-p)<4) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsa = NEXTSHORT; p += 2; fsb = NEXTSHORT; p += 2; e = exec_fillstyle_inner(ctx,fsa,fsb); errorcheck; break; case PGTH_OPCMD_LOCALCALL: if ((plimit-p)<2) return mkerror(PG_ERRT_BADPARAM,91); /* Truncated opcode */ fsb = NEXTSHORT; p += 2; e = exec_fillstyle_inner(ctx,state,fsb); errorcheck; break; case PGTH_OPCMD_EXTENDED: /* extended command */ op = *(p++); switch (op) { case PGTH_EXCMD_SKIP_IF: if (!fsstack[--fsstkpos]) { --fsstkpos; break; } /* else proceed to EXCMD_SKIP */ case PGTH_EXCMD_SKIP: p += (s32)fsstack[--fsstkpos]; break; } break; } } else if (op & PGTH_OPSIMPLE_GET) { /* 1-byte get */ e = fsget((op & (PGTH_OPSIMPLE_GET-1)) + stackframe); errorcheck; } else { /* 1-byte set */ e = fsset(op + stackframe); errorcheck; } #ifdef DEBUG_THEME /* trace */ printf("FILLSTYLE --- Op: 0x%02X Stk:",op); for (fsa=0;fsa<fsstkpos;fsa++) printf(" %d",(int)fsstack[fsa]); printf("\n"); #endif /* check for stack over/underflow */ if (fsstkpos<0) return mkerror(PG_ERRT_BADPARAM,88); /* Stack underflow */ if (fsstkpos>=FSSTACKSIZE) return mkerror(PG_ERRT_BADPARAM,89); /* Stack overflow */ }