#include #include #include #include #include "sys.h" #include "video.h" #include "cfg.h" #include "png.h" /* Video variables */ static void *framebuffer0 = NULL; static void *framebuffer1 = NULL; static void *framebuffer = NULL; static int framebuffer_size; static GXRModeObj *vmode = NULL; static GXRModeObj vmode_non_wide; static int video_wide; void *bg_buf_rgba = NULL; void *bg_buf_ycbr = NULL; int con_inited = 0; void _Con_Clear(void); void Con_Init(u32 x, u32 y, u32 w, u32 h) { /* Create console in the framebuffer */ if (CFG.console_transparent) { CON_InitTr(vmode, x, y, w, h, CONSOLE_BG_COLOR); } else { CON_InitEx(vmode, x, y, w, h); } _Con_Clear(); con_inited = 1; } void _Con_Clear(void) { DefaultColor(); /* Clear console */ printf("\x1b[2J"); fflush(stdout); } void Con_Clear(void) { __console_flush(0); _Con_Clear(); } void Con_ClearLine(void) { s32 cols, rows; u32 cnt; printf("\r"); fflush(stdout); /* Get console metrics */ CON_GetMetrics(&cols, &rows); /* Erase line */ for (cnt = 1; cnt < cols; cnt++) { printf(" "); fflush(stdout); } printf("\r"); fflush(stdout); } void Con_FgColor(u32 color, u8 bold) { /* Set foreground color */ printf("\x1b[%u;%um", color + 30, bold); fflush(stdout); } void Con_BgColor(u32 color, u8 bold) { /* Set background color */ printf("\x1b[%u;%um", color + 40, bold); fflush(stdout); } void Con_SetPosition(int col, int row) { /* Move to specified pos */ printf("\x1b[%u;%uH", row, col); fflush(stdout); } void Con_FillRow(u32 row, u32 color, u8 bold) { s32 cols, rows; u32 cnt; /* Set color */ printf("\x1b[%u;%um", color + 40, bold); fflush(stdout); /* Get console metrics */ CON_GetMetrics(&cols, &rows); /* Save current row and col */ printf("\x1b[s"); fflush(stdout); /* Move to specified row */ printf("\x1b[%u;0H", row); fflush(stdout); /* Fill row */ for (cnt = 0; cnt < cols; cnt++) { printf(" "); fflush(stdout); } /* Load saved row and col */ printf("\x1b[u"); fflush(stdout); /* Set default color */ Con_BgColor(0, 0); Con_FgColor(7, 1); } void Video_Configure(GXRModeObj *rmode) { /* Configure the video subsystem */ VIDEO_Configure(rmode); /* Setup video */ VIDEO_SetBlack(FALSE); VIDEO_Flush(); VIDEO_WaitVSync(); if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); } // allocate a MAX size frambuffer, so that it // can accomodate all video mode changes void *Video_Allocate_MAX_Framebuffer(GXRModeObj *vmode, bool mem2) { int w, h; void *buf; w = vmode->fbWidth; h = MAX(vmode->xfbHeight, VI_MAX_HEIGHT_PAL); framebuffer_size = VIDEO_PadFramebufferWidth(w) * h * VI_DISPLAY_PIX_SZ; if (mem2) { buf = LARGE_memalign(32, framebuffer_size); } else { buf = memalign(32, framebuffer_size); } if (buf) { memset(buf, 0, framebuffer_size); DCFlushRange(buf, framebuffer_size); } return buf; } void Video_SetWide() { if (CFG.widescreen && video_wide) return; if (!CFG.widescreen && !video_wide) return; if (!vmode) return; // change required if (CFG.widescreen) { vmode->viWidth = 678; vmode->viXOrigin = ((VI_MAX_WIDTH_NTSC - 678) / 2); } else { *vmode = vmode_non_wide; } video_wide = CFG.widescreen; Video_Configure(vmode); } void Video_SetMode(void) { if (vmode) return; // already set?! /* Select preferred video mode */ vmode = VIDEO_GetPreferredMode(NULL); // save non-wide vmode vmode_non_wide = *vmode; // widescreen mode video_wide = CONF_GetAspectRatio(); if (video_wide) { vmode->viWidth = 678; vmode->viXOrigin = ((VI_MAX_WIDTH_NTSC - 678) / 2); } /* Allocate memory for the framebuffer */ //framebuffer0 = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode)); //framebuffer1 = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode)); framebuffer0 = MEM_K0_TO_K1(Video_Allocate_MAX_Framebuffer(vmode, true)); framebuffer1 = MEM_K0_TO_K1(Video_Allocate_MAX_Framebuffer(vmode, true)); framebuffer = framebuffer0; /* Clear the screen */ Video_Clear(COLOR_BLACK); // Set Next framebuffer VIDEO_SetNextFramebuffer(framebuffer); /* Configure the video subsystem */ Video_Configure(vmode); // VIDEO_WaitVSync This is necessary! // Otherwise the VIDEO_GetCurrentFramebuffer() // returns an invalid ptr before an actual vsync happens // so __console_flush can crash VIDEO_WaitVSync(); } void Video_Close() { void *fb = Video_Allocate_MAX_Framebuffer(vmode, false); VIDEO_SetBlack(TRUE); if (fb) { framebuffer = MEM_K0_TO_K1(fb); Video_Clear(COLOR_BLACK); VIDEO_SetNextFramebuffer(framebuffer); } VIDEO_Flush(); VIDEO_WaitVSync(); } void Video_Clear(s32 color) { VIDEO_ClearFrameBuffer(vmode, framebuffer, color); } void Video_DrawPng(IMGCTX ctx, PNGUPROP imgProp, u16 x, u16 y) { PNGU_DECODE_TO_COORDS_YCbYCr(ctx, x, y, imgProp.imgWidth, imgProp.imgHeight, vmode->fbWidth, vmode->xfbHeight, framebuffer); } GXRModeObj* _Video_GetVMode() { return vmode; } void* _Video_GetFB(int n) { switch(n) { case 0: return framebuffer0; case 1: return framebuffer1; } return framebuffer; } void _Video_SetFB(void *fb) { framebuffer = fb; } void _Video_SyncFB() { VIDEO_SetNextFramebuffer(framebuffer); VIDEO_Flush(); VIDEO_WaitVSync(); if (framebuffer != framebuffer0) { memcpy(framebuffer0, framebuffer, framebuffer_size); framebuffer = framebuffer0; VIDEO_SetNextFramebuffer(framebuffer); VIDEO_Flush(); VIDEO_WaitVSync(); } } void FgColor(int color) { Con_FgColor(color & 7, color > 7 ? 1 : 0); } void BgColor(int color) { Con_BgColor(color & 7, color > 7 ? 1 : 0); } void DefaultColor() { FgColor(CONSOLE_FG_COLOR); BgColor(CONSOLE_BG_COLOR); } #define BACKGROUND_WIDTH 640 #define BACKGROUND_HEIGHT 480 /** (from GRRLIB) * Make a PNG screenshot on the SD card. * @return True if every thing worked, false otherwise. */ bool ScreenShot(char *fname) { IMGCTX pngContext; int ErrorCode = -1; void *fb = VIDEO_GetCurrentFramebuffer(); if((pngContext = PNGU_SelectImageFromDevice(fname))) { ErrorCode = PNGU_EncodeFromYCbYCr(pngContext, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, fb, 0); PNGU_ReleaseImageContext(pngContext); } return !ErrorCode; } void Video_DrawBg() { //Video_DrawRGBA(0, 0, bg_buf_rgba, vmode->fbWidth, vmode->xfbHeight); //Video_DrawRGBA(0, 0, bg_buf_rgba, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); memcpy(framebuffer, bg_buf_ycbr, BACKGROUND_WIDTH * BACKGROUND_HEIGHT * 2); } int Video_AllocBg() { if (bg_buf_rgba == NULL) { bg_buf_rgba = LARGE_memalign(32, BACKGROUND_WIDTH * BACKGROUND_HEIGHT * 4); if (!bg_buf_rgba) return -1; } if (bg_buf_ycbr == NULL) { bg_buf_ycbr = LARGE_memalign(32, BACKGROUND_WIDTH * BACKGROUND_HEIGHT * 2); if (!bg_buf_ycbr) return -1; } return 0; } void Video_SaveBgRGBA() { RGBA_to_YCbYCr(bg_buf_ycbr, bg_buf_rgba, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); } s32 Video_SaveBg(void *img) { IMGCTX ctx = NULL; PNGUPROP imgProp; s32 ret; /* Select PNG data */ ctx = PNGU_SelectImageFromBuffer(img); if (!ctx) { ret = -1; goto out; } /* Get image properties */ ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) { ret = -1; goto out; } Video_AllocBg(); /* Decode image */ //PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, imgProp.imgWidth, imgProp.imgHeight, 255, // vmode->fbWidth, vmode->xfbHeight, bg_buf_rgba); PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, imgProp.imgWidth, imgProp.imgHeight, 255, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, bg_buf_rgba); Video_SaveBgRGBA(); /* Success */ ret = 0; out: /* Free memory */ if (ctx) PNGU_ReleaseImageContext(ctx); return ret; } void Video_GetBG(int x, int y, char *img, int width, int height) { int ix, iy; char *c, *bg; if (!bg_buf_rgba) return; c = img; for (iy=0; iyfbWidth * 4) + x*4; for (ix=0; ixfbWidth * 4) + x*4; for (ix=0; ixfbWidth / 2; for (iy=0; iy