/* Calculate a RGB palette out of VIC/VIC-II/TED colors (in ycbcr format), apply saturation, brightness, contrast, tint and gamma settings. this palette will be used for screenshots and by renderers if CRT emulation is disabled. */ static palette_t *video_calc_palette(struct video_canvas_s *canvas, const video_ycbcr_palette_t *p) { palette_t *prgb; unsigned int i; float sat, bri, con, gam, tin; video_resources_t *video_resources = &(canvas->videoconfig->video_resources); DBG(("video_calc_palette")); sat = ((float)(video_resources->color_saturation)) / 1000.0f; bri = ((float)(video_resources->color_brightness - 1000)) * (128.0f / 1000.0f); con = ((float)(video_resources->color_contrast)) / 1000.0f; gam = video_get_gamma(video_resources); tin = (((float)(video_resources->color_tint)) / (2000.0f / 50.0f)) - 25.0f; /* create RGB palette with the base colors of the video chip */ prgb = palette_create(p->num_entries, NULL); if (prgb == NULL) { return NULL; } for (i = 0; i < p->num_entries; i++) { video_convert_ycbcr_to_rgb(&p->entries[i], sat, bri, con, gam, tin, &prgb->entries[i]); } return prgb; }
/* Calculate a RGB palette out of VIC/VIC-II/TED colors (in ycbcr format), apply saturation, brightness, contrast, tint and gamma settings. this palette will be used for screenshots and by renderers if CRT emulation is disabled. */ static palette_t *video_calc_palette(struct video_canvas_s *canvas, const video_ycbcr_palette_t *p, int video) { palette_t *prgb; unsigned int i; float sat, bri, con, gam, tin; video_resources_t *video_resources = &(canvas->videoconfig->video_resources); DBG(("video_calc_palette")); sat = ((float)(video_resources->color_saturation)) / 1000.0f; bri = ((float)(video_resources->color_brightness - 1000)) * (128.0f / 1000.0f); con = ((float)(video_resources->color_contrast)) / 1000.0f; gam = video_get_gamma(video_resources, video); tin = (((float)(video_resources->color_tint)) / (2000.0f / 50.0f)) - 25.0f; /* create RGB palette with the base colors of the video chip */ prgb = palette_create(p->num_entries, NULL); if (prgb == NULL) { return NULL; } DBG((" sat:%d bri:%d con:%d gam:%d tin:%d", (int)sat, (int)bri, (int)con, (int)gam, (int)tin)); for (i = 0; i < p->num_entries; i++) { video_convert_renderer_to_rgb_gamma(&p->entries[i], sat, bri, con, gam, tin, &prgb->entries[i], video); DBG((" %2d: Y:%4d Cb:%4d Cr:%4d R:%3d G:%3d B:%3d", i, (int)p->entries[i].y, (int)p->entries[i].cb, (int)p->entries[i].cr, (int)prgb->entries[i].red, (int)prgb->entries[i].green, (int)prgb->entries[i].blue)); } return prgb; }
/* gammatable calculation */ static void video_calc_gammatable(video_resources_t *video_resources) { int i; float bri, con, gam, scn, v; double factor; DWORD vi; bri = ((float)(video_resources->color_brightness - 1000)) * (128.0f / 1000.0f); con = ((float)(video_resources->color_contrast )) / 1000.0f; gam = video_get_gamma(video_resources); scn = ((float)(video_resources->pal_scanlineshade)) / 1000.0f; factor = pow(255.0f, 1.0f - gam); for (i = 0; i < (256 * 3); i++) { v = video_gamma((float)(i - 256), factor, gam, bri, con); vi = (DWORD)v; if (vi > 255) { vi = 255; } gamma_red[i] = color_red[vi]; gamma_grn[i] = color_grn[vi]; gamma_blu[i] = color_blu[vi]; vi = (DWORD)(v * scn); if (vi > 255) { vi = 255; } gamma_red_fac[i * 2] = color_red[vi]; gamma_grn_fac[i * 2] = color_grn[vi]; gamma_blu_fac[i * 2] = color_blu[vi]; v = video_gamma((float)(i - 256) + 0.5f, factor, gam, bri, con); vi = (DWORD)(v * scn); if (vi > 255) { vi = 255; } gamma_red_fac[i * 2 + 1] = color_red[vi]; gamma_grn_fac[i * 2 + 1] = color_grn[vi]; gamma_blu_fac[i * 2 + 1] = color_blu[vi]; } }
static void video_calc_ycbcrtable(video_resources_t *video_resources, const video_ycbcr_palette_t *p, video_render_color_tables_t *color_tab) { video_ycbcr_color_t *primary; unsigned int i, lf, hf; float sat, tin, bri, con, gam; float yf, uf, vf; int y, u, v; double factor, len; lf = 64 * video_resources->pal_blur / 1000; hf = 255 - (lf << 1); sat = ((float)(video_resources->color_saturation)) * (256.0f / 1000.0f); tin = (((float)(video_resources->color_tint)) * (50.0f / 2000.0f)) - 25.0f; bri = ((float)(video_resources->color_brightness - 1000)) * (112.0f / 1000.0f); con = ((float)(video_resources->color_contrast )) / 1000.0f; gam = video_get_gamma(video_resources); factor = pow(256.0f, 1.0f - gam); for (i = 0; i < p->num_entries; i++) { SDWORD val; /* create primary table */ primary = &p->entries[i]; val = (SDWORD)(primary->y * 256.0f); color_tab->ytablel[i] = val * lf; color_tab->ytableh[i] = val * hf; color_tab->cbtable[i] = (SDWORD)((primary->cb) * sat); color_tab->cutable[i] = (SDWORD)(0.493111 * primary->cb * 256.0); /* tint, add to cr in odd lines */ val = (SDWORD)(tin); color_tab->crtable[i] = (SDWORD)((primary->cr + val) * sat); color_tab->cvtable[i] = (SDWORD)(0.877283 * (primary->cr + val) * 256.0); yf = (float)(video_gamma(primary->y, factor, gam, bri, con) * 224.0 / 256.0 + 16.5); uf = (float)(0.493111 * primary->cb * sat * con * 224.0 / 256.0 / 256.0 + 128.5); vf = (float)(0.877283 * (primary->cr + tin) * sat * con * 224.0 / 256.0 / 256.0 + 128.5); y = (int)yf; u = (int)uf; v = (int)vf; /* sanity check: cbtable and crtable must be kept in 16 bit range or we might get overflows in eg the CRT renderer */ len = sqrt(((double)color_tab->cbtable[i] * (double)color_tab->cbtable[i]) + ((double)color_tab->crtable[i] * (double)color_tab->crtable[i])); if (len >= (double)0x10000) { log_error(LOG_DEFAULT, "video_calc_ycbcrtable: color %d cbcr vector too long, use lower base saturation.", i); } if (y < 16) { y = 16; } else if (y > 240) { y = 240; } if (u < 16) { u = 16; } else if (u > 240) { u = 240; } if (v < 16) { v = 16; } else if (v > 240) { v = 240; } /* YCbCr to YUV, scale [0, 256] to [0, 255] */ color_tab->yuv_table[i] = (y << 16) | (u << 8) | v; } color_tab->yuv_updated = 0; }
/* called by video_color_update_palette, internal and external palette */ static void video_calc_ycbcrtable(video_resources_t *video_resources, const video_ycbcr_palette_t *p, video_render_color_tables_t *color_tab, int video) { video_ycbcr_color_t *primary; unsigned int i, lf, hf; float sat, tin, bri, con, gam; float yf, uf, vf; int y, u, v; double factor, len; #ifdef DEBUG_VIDEO palette_entry_t temp; #endif DBG(("video_calc_ycbcrtable")); lf = 64 * video_resources->pal_blur / 1000; hf = 255 - (lf << 1); sat = ((float)(video_resources->color_saturation)) * (256.0f / 1000.0f); tin = (((float)(video_resources->color_tint)) * (50.0f / 2000.0f)) - 25.0f; bri = ((float)(video_resources->color_brightness - 1000)) * (112.0f / 1000.0f); con = ((float)(video_resources->color_contrast )) / 1000.0f; gam = video_get_gamma(video_resources, video); factor = pow(256.0f, 1.0f - gam); DBG((" sat:%d bri:%d con:%d gam:%d tin:%d", (int)sat, (int)bri, (int)con, (int)gam, (int)tin)); for (i = 0; i < p->num_entries; i++) { SDWORD val; /* create primary table */ primary = &p->entries[i]; if (video) { val = (SDWORD)(primary->y * 256.0f); color_tab->ytablel[i] = val * lf; color_tab->ytableh[i] = val * hf; /* tint, add to cr in odd lines */ val = (SDWORD)(tin); color_tab->cbtable[i] = (SDWORD)((primary->cb) * sat); color_tab->crtable[i] = (SDWORD)((primary->cr + val) * sat); color_tab->cutable[i] = (SDWORD)(0.493111f * primary->cb * 256.0); /* convert Cb to U */ color_tab->cvtable[i] = (SDWORD)(0.877283f * (primary->cr + val) * 256.0); /* convert Cr to V */ } else { /* for NTSC use one bit less for the fraction in the tables to avoid integer overflows in the CRT renderer */ val = (SDWORD)(primary->y * 128.0f); color_tab->ytablel[i] = (val * lf); color_tab->ytableh[i] = (val * hf); /* FIXME: tint for NTSC */ val = (SDWORD)(tin); color_tab->cbtable[i] = (SDWORD)((primary->cb) * sat) >> 1; color_tab->crtable[i] = (SDWORD)((primary->cr + val) * sat) >> 1; /* FIXME: convert IQ to UV (used by YUV renderers) */ color_tab->cutable[i] = (SDWORD)(primary->cb * 256.0); color_tab->cvtable[i] = (SDWORD)((primary->cr + val) * 256.0); } #ifdef DEBUG_VIDEO video_convert_renderer_to_rgb(primary, &temp, video); DBG((" %2d 'Cb':%4d 'Cr':%4d 'Cr':%6d 'Cb':%6d R:%4d G:%4d B:%4d", i, (int)primary->cb, (int)primary->cr, (int)color_tab->cbtable[i], (int)color_tab->crtable[i], temp.red, temp.green, temp.blue )); #endif yf = (float)(video_gamma(primary->y, factor, gam, bri, con) * 224.0 / 256.0 + 16.5); if (video) { /* PAL: convert CbCr to UV */ uf = (float)(0.493111f * primary->cb * sat * con * 224.0 / 256.0 / 256.0 + 128.5); vf = (float)(0.877283f * (primary->cr + tin) * sat * con * 224.0 / 256.0 / 256.0 + 128.5); } else { /* FIXME: convert IQ to UV (used by YUV renderers) */ uf = (float)(0.493111f * primary->cb * sat * con * 224.0 / 256.0 / 256.0 + 128.5); vf = (float)(0.877283f * (primary->cr + tin) * sat * con * 224.0 / 256.0 / 256.0 + 128.5); } /* sanity check: cbtable and crtable must be kept in 16 bit range or we might get overflows in eg the CRT renderer */ /* FIXME: we need to check more and clamp the values accordingly - it is still possible to "overdrive" the renderer in NTSC mode */ len = sqrt(((double)color_tab->cbtable[i] * (double)color_tab->cbtable[i]) + ((double)color_tab->crtable[i] * (double)color_tab->crtable[i])); if (len >= (double)0x10000) { log_error(LOG_DEFAULT, "video_calc_ycbcrtable: color %d cbcr vector too long, use lower base saturation.", i); } y = (int)RMINMAX(yf, 16, 240); u = (int)RMINMAX(uf, 16, 240); v = (int)RMINMAX(vf, 16, 240); /* YCbCr to YUV, scale [0, 256] to [0, 255] (used by YUV renderers) */ color_tab->yuv_table[i] = (y << 16) | (u << 8) | v; } color_tab->yuv_updated = 0; }