849 lines
23 KiB
C
849 lines
23 KiB
C
|
|
/*
|
|
* Argyll Color Management System
|
|
* ChromeCast Display target patch window
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 8/9/14
|
|
*
|
|
* Copyright 2013, 2014 Graeme W. Gill
|
|
* All rights reserved.
|
|
*
|
|
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
|
|
* see the License.txt file for licencing details.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "copyright.h"
|
|
#include "aconfig.h"
|
|
#include "icc.h"
|
|
#include "numsup.h"
|
|
#include "cgats.h"
|
|
#include "conv.h"
|
|
#include "dispwin.h"
|
|
#include "conv.h"
|
|
#include "mongoose.h"
|
|
#include "ccast.h"
|
|
#include "ccwin.h"
|
|
#include "render.h"
|
|
|
|
#undef WRITE_PNG /* [und] Write each test patch to "ccwin.png" */
|
|
#undef CCTEST_PATTERN /* [und] Create dev. spatial test pattern */
|
|
#undef SEND_TEST_FILE /* [und] Send this file name to ChromeCast instead of pattern */
|
|
#undef DO_TIMING /* [und] Print rendering timing */
|
|
#undef DEBUG /* [und] */
|
|
|
|
#define DDITHER 1 /* 0 = no dither - quantize to PNG 8 bit RGB value */
|
|
/* [def] 1 = use error diffusion dithering with ccast quant model */
|
|
/* 2 = use crafted 4x4 dither cell */
|
|
|
|
#define VWIDTH 1920.0 /* Video stream and display size ? */
|
|
#define VHEIGHT 1080.0
|
|
|
|
/* Definitions for cctyp_1 */
|
|
#define IWIDTH 1280.0 /* This is the native still image framebuffer size for ChromeCasts */
|
|
#define IHEIGHT 720.0
|
|
|
|
/* 2K Definitions for cctyp_Ultra ? */
|
|
#define IWIDTH_H 1920.0
|
|
#define IHEIGHT_H 1080.0
|
|
|
|
/* 4K Definitions for cctyp_Ultra ? */
|
|
#define IWIDTH_U 3840.0
|
|
#define IHEIGHT_U 2160.0
|
|
|
|
//#define STANDALONE_TEST
|
|
|
|
#ifdef DEBUG
|
|
# pragma message("######### ccwin DEBUG is defined! ########")
|
|
#define errout g_log,0
|
|
# define debug2(xx) a1logd xx
|
|
# define debugr2(xx) a1logd xx
|
|
# define debugrr2(xx) a1logd xx
|
|
# define debugrr2l(lev, xx) a1logd xx
|
|
#else
|
|
#define errout g_log,0
|
|
# define debug2(xx) // Debug, args
|
|
# define debugr2(xx) if (p->ddebug) a1logd xx // Run ->ddebug, args
|
|
# define debugrr2(xx) if (callback_ddebug) a1logd xx // Run cback, args
|
|
# define debugrr2l(lev, xx) if (callback_ddebug >= lev) a1logd xx // Run cback >= lev, args
|
|
#endif
|
|
|
|
/* ================================================================== */
|
|
|
|
/* Chromwin context and (possible) web server */
|
|
typedef struct _chws {
|
|
int verb;
|
|
int ddebug;
|
|
|
|
int direct; /* End PNG directly, rather than using web server */
|
|
|
|
struct mg_context *mg; /* Mongoose context (if needed) */
|
|
char *ws_url; /* Web server URL for accessing server */
|
|
|
|
// double hoff, voff; /* Input position of test square */
|
|
double x, y; /* position of test square in pixels */
|
|
double w, h; /* size of test square in pixels */
|
|
double bg[3]; /* Background color */
|
|
int pno; /* Index to generate a sequence of URLs */
|
|
unsigned char *ibuf; /* Memory image of .png file */
|
|
size_t ilen;
|
|
|
|
ccast *cc; /* ChromeCast */
|
|
|
|
/* Set a whole screen sized png image */
|
|
int (*set)(struct _chws *p, unsigned char *ibuf, size_t ilen);
|
|
|
|
/* Update the test patch png image */
|
|
int (*update)(struct _chws *p, unsigned char *ibuf, size_t ilen, double *bg);
|
|
|
|
/* Destroy ourselves */
|
|
void (*del)(struct _chws *p);
|
|
|
|
} chws;
|
|
|
|
static void chws_del(chws *p) {
|
|
|
|
/* delete mongoose, if we are using it */
|
|
if (p->mg != NULL)
|
|
mg_stop(p->mg);
|
|
|
|
/* Delete ChromeCast */
|
|
if (p->cc != NULL)
|
|
p->cc->del(p->cc);
|
|
|
|
if (p->ibuf != NULL)
|
|
free(p->ibuf);
|
|
|
|
if (p->ws_url != NULL)
|
|
free(p->ws_url);
|
|
|
|
free(p);
|
|
}
|
|
|
|
/* Set a whole screen .png (size is assumed to be large enough) */
|
|
/* Return nz on error */
|
|
static int chws_set(chws *p, unsigned char *ibuf, size_t ilen) {
|
|
char url[200];
|
|
double bg[3] = { 0.0, 0.0, 0.0 };
|
|
|
|
debug2((errout,"\nUpdate png\n"));
|
|
|
|
if (p->ibuf != NULL)
|
|
free(p->ibuf);
|
|
|
|
p->ibuf = ibuf;
|
|
p->ilen = ilen;
|
|
|
|
/* Send the PNG swatch direct */
|
|
if (p->direct) {
|
|
double x, y, w, h;
|
|
/* Convert x,y,w,h to relative rather than pixel size */
|
|
|
|
debugr2((errout,"Got x %f y %f w %f h %f\n", p->x, p->y, p->w, p->h));
|
|
|
|
// Convert from quantized to direct loader parameters
|
|
x = 0.0;
|
|
y = 0.0;
|
|
w = 10.0; /* Scale */
|
|
h = 10.0 * 9.0/16.0;
|
|
|
|
debugr2((errout,"Sending direct x %f y %f w %f h %f\n", x, y, w, h));
|
|
|
|
if (p->cc->load(p->cc, NULL, p->ibuf, p->ilen, bg, x, y, w, h)) {
|
|
debugr2((errout,"ccwin_set direct load failed\n"));
|
|
return 1;
|
|
}
|
|
|
|
/* Using web server */
|
|
} else {
|
|
|
|
#ifdef SEND_TEST_FILE
|
|
sprintf(url, "%s%s",p->ws_url, SEND_TEST_FILE);
|
|
#else
|
|
sprintf(url, "%stpatch_%d.png",p->ws_url, ++p->pno);
|
|
#endif
|
|
if (p->cc->load(p->cc, url, NULL, 0, NULL, 0.0, 0.0, 0.0, 0.0)) {
|
|
debugr2((errout,"ccwin_set server load failed\n"));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Change the test patch .png being served */
|
|
/* Return nz on error */
|
|
static int chws_update(chws *p, unsigned char *ibuf, size_t ilen, double *bg) {
|
|
char url[200];
|
|
|
|
debug2((errout,"\nUpdate png\n"));
|
|
|
|
if (p->ibuf != NULL)
|
|
free(p->ibuf);
|
|
|
|
p->ibuf = ibuf;
|
|
p->ilen = ilen;
|
|
|
|
/* Send the PNG swatch direct */
|
|
if (p->direct) {
|
|
double x, y, w, h;
|
|
/* Convert x,y,w,h to relative rather than pixel size */
|
|
|
|
debugr2((errout,"Got x %f y %f w %f h %f\n", p->x, p->y, p->w, p->h));
|
|
|
|
// Convert from quantized to direct loader parameters
|
|
if (p->w < IWIDTH)
|
|
x = p->x/(IWIDTH - p->w);
|
|
else
|
|
x = 0.0;
|
|
if (p->h < IHEIGHT)
|
|
y = p->y/(IHEIGHT - p->h);
|
|
else
|
|
y = 0.0;
|
|
w = p->w/(0.1 * IWIDTH);
|
|
h = p->h/(0.1 * IWIDTH);
|
|
|
|
debugr2((errout,"Sending direct x %f y %f w %f h %f\n", x, y, w, h));
|
|
|
|
if (p->cc->load(p->cc, NULL, p->ibuf, p->ilen, bg, x, y, w, h)) {
|
|
debugr2((errout,"ccwin_update direct load failed\n"));
|
|
return 1;
|
|
}
|
|
|
|
/* Using web server */
|
|
} else {
|
|
|
|
#ifdef SEND_TEST_FILE
|
|
sprintf(url, "%s%s",p->ws_url, SEND_TEST_FILE);
|
|
#else
|
|
sprintf(url, "%stpatch_%d.png",p->ws_url, ++p->pno);
|
|
#endif
|
|
if (p->cc->load(p->cc, url, NULL, 0, NULL, 0.0, 0.0, 0.0, 0.0)) {
|
|
debugr2((errout,"ccwin_update server load failed\n"));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Web server event handler - return the current .png image */
|
|
static void *ccwin_ehandler(enum mg_event event,
|
|
struct mg_connection *conn) {
|
|
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
|
chws *p = (chws *)mg_get_user_data(conn);
|
|
char *cp;
|
|
char sbuf[200];
|
|
|
|
debugr2((errout,"ccwin_ehandler()\n"));
|
|
|
|
if (event != MG_NEW_REQUEST) {
|
|
return NULL;
|
|
}
|
|
|
|
debugr2((errout,"Event: uri = '%s'\n",request_info->uri));
|
|
|
|
#ifdef SEND_TEST_FILE
|
|
#pragma message("############################# ccwin.c SEND_TEST_FILE defined ! ##")
|
|
return NULL;
|
|
#endif
|
|
|
|
if (p->ibuf != NULL && p->ilen > 0
|
|
&& (cp = strrchr(request_info->uri, '.')) != NULL
|
|
&& strcmp(cp, ".png") == 0) {
|
|
|
|
debugr2((errout,"Event: Loading %s\n",request_info->uri));
|
|
|
|
debugr2((errout,"Returning current png size %d bytes\n",(int)p->ilen));
|
|
sprintf(sbuf,
|
|
"HTTP/1.1 200 OK\r\n"
|
|
"Content-Type: image/png\r\n"
|
|
"Content-Length: %d\r\n"
|
|
"\r\n"
|
|
,(int)p->ilen);
|
|
|
|
mg_write(conn, sbuf, strlen(sbuf));
|
|
mg_write(conn, p->ibuf, p->ilen);
|
|
|
|
} else {
|
|
debugr2((errout,"Bad request or png - returning 404\n"));
|
|
sprintf(sbuf,
|
|
"HTTP/1.0 404 Not Found\r\n"
|
|
"\r\n"
|
|
"<html><body><h1>Error 404 - Not Found</h1></body></html>");
|
|
|
|
mg_write(conn, sbuf, strlen(sbuf));
|
|
}
|
|
|
|
return "yes";
|
|
}
|
|
|
|
/* Change the patch display parameters. */
|
|
/* Optional - may be NULL */
|
|
static int ccwin_set_patch_win(
|
|
dispwin *p,
|
|
double hoff, double voff, /* Offset from c. in fraction of screen, -1.0 .. 1.0 */
|
|
double area, /* Patch area 0..1 */
|
|
dw_bg_type bge /* Background */
|
|
) {
|
|
chws *ws = (chws *)p->pcntx;
|
|
double width, height;
|
|
|
|
/* Set background color handling */
|
|
p->fullscreen = 1;
|
|
p->bge = bge;
|
|
|
|
if (area < 0.0)
|
|
area = 0.0;
|
|
else if (area > 1.0)
|
|
area = 1.0;
|
|
|
|
/* Can't do constant luma/power with larger than 50% area */
|
|
if (bge == dw_bg_cvideo
|
|
|| bge == dw_bg_clight) {
|
|
if (area > 0.5)
|
|
area = 0.5;
|
|
}
|
|
|
|
p->area = area;
|
|
|
|
if (area < (IHEIGHT * IHEIGHT)/(IWIDTH * IHEIGHT)) { // Not height limited
|
|
width = height = sqrt(area * IWIDTH * IHEIGHT)/IWIDTH;
|
|
|
|
} else {
|
|
height = IHEIGHT/IWIDTH;
|
|
width = area;
|
|
}
|
|
|
|
/* Setup window size and position */
|
|
/* The default size is 10% of the width */
|
|
ws->w = floor(width * IWIDTH + 0.5);
|
|
if (ws->w > IWIDTH)
|
|
ws->w = IWIDTH;
|
|
ws->h = floor(height * IWIDTH + 0.5);
|
|
if (ws->h > IHEIGHT)
|
|
ws->h = IHEIGHT;
|
|
|
|
ws->x = floor((hoff * 0.5 + 0.5) * (IWIDTH - ws->w) + 0.5);
|
|
ws->y = floor((voff * 0.5 + 0.5) * (IHEIGHT - ws->h) + 0.5);
|
|
|
|
// Make offset be on an even pixel boundary, so that we know
|
|
// the up-filter phase.
|
|
if (((int)ws->x) & 1)
|
|
ws->x++;
|
|
if (((int)ws->y) & 1)
|
|
ws->y++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
chws *new_chws(
|
|
ccast_id *cc_id, /* ChromeCast to open */
|
|
double width, double height, /* Width and height as % */
|
|
double hoff, double voff, /* Offset from center in fraction of screen, range -1.0 .. 1.0 */
|
|
int verb, int ddebug) {
|
|
chws *p;
|
|
const char *options[3];
|
|
char port[50];
|
|
int portno = 0; /* Port number allocated */
|
|
int forcedef = 0; /* Force default receiver app. */
|
|
|
|
if ((p = (chws *)calloc(sizeof(chws), 1)) == NULL) {
|
|
error("new_chws: calloc failed");
|
|
return NULL;
|
|
}
|
|
|
|
p->verb = verb;
|
|
p->ddebug = ddebug;
|
|
|
|
p->set = chws_set;
|
|
p->update = chws_update;
|
|
p->del = chws_del;
|
|
|
|
/* We make sure we round the test patch size and */
|
|
/* location to integer resolution so that we can know */
|
|
/* it's exact relationship to the upsampled pixel locations. */
|
|
|
|
/* Setup window size and position */
|
|
/* The default size is 10% of the width */
|
|
p->w = floor(width/100.0 * 0.1 * IWIDTH + 0.5);
|
|
if (p->w > IWIDTH)
|
|
p->w = IWIDTH;
|
|
p->h = floor(height/100.0 * 0.1 * IWIDTH + 0.5);
|
|
if (p->h > IHEIGHT)
|
|
p->h = IHEIGHT;
|
|
|
|
p->x = floor((hoff * 0.5 + 0.5) * (IWIDTH - p->w) + 0.5);
|
|
p->y = floor((voff * 0.5 + 0.5) * (IHEIGHT - p->h) + 0.5);
|
|
|
|
// Make offset be on an even pixel boundary, so that we know
|
|
// the up-filter phase.
|
|
if (((int)p->x) & 1)
|
|
p->x++;
|
|
if (((int)p->y) & 1)
|
|
p->y++;
|
|
|
|
if (verb) printf("Opening ChromeCast '%s'\n",cc_id->name);
|
|
|
|
#ifdef SEND_TEST_FILE
|
|
forcedef = 1;
|
|
#endif
|
|
|
|
/* Connect to the chrome cast */
|
|
if ((p->cc = new_ccast(cc_id, forcedef)) == NULL) {
|
|
debugr2((errout,"new_chws: new_ccast() failed\n"));
|
|
return NULL;
|
|
}
|
|
|
|
p->direct = p->cc->get_direct_send(p->cc);
|
|
|
|
if (!p->direct) {
|
|
/* Create a web server */
|
|
options[0] = "listening_ports";
|
|
// sprintf(port,"%d", 0); /* Use any available */
|
|
sprintf(port,"%d", 8081); /* Use fixed port for Linux firewall rule */
|
|
options[1] = port;
|
|
options[2] = NULL;
|
|
|
|
p->mg = mg_start(&ccwin_ehandler, (void *)p, options);
|
|
|
|
if ((p->ws_url = mg_get_url(p->mg)) == NULL) {
|
|
debugr2((errout, "mg_get_url() failed\n"));
|
|
chws_del(p);
|
|
return NULL;
|
|
}
|
|
if (p->ddebug)
|
|
printf("Created .png server at '%s'\n",p->ws_url);
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
/* ================================================================== */
|
|
|
|
/* Get RAMDAC values. ->del() when finished. */
|
|
/* Return NULL if not possible */
|
|
static ramdac *ccwin_get_ramdac(dispwin *p) {
|
|
debugr2((errout,"webdisp doesn't have a RAMDAC\n"));
|
|
return NULL;
|
|
}
|
|
|
|
/* Set the RAMDAC values. */
|
|
/* Return nz if not possible */
|
|
static int ccwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
|
|
debugr2((errout,"webdisp doesn't have a RAMDAC\n"));
|
|
return 1;
|
|
}
|
|
|
|
/* ----------------------------------------------- */
|
|
/* Install a display profile and make */
|
|
/* it the default for this display. */
|
|
/* Return nz if failed */
|
|
int ccwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
|
|
debugr2((errout,"webdisp doesn't support installing profiles\n"));
|
|
return 1;
|
|
}
|
|
|
|
/* Un-Install a display profile */
|
|
/* Return nz if failed, */
|
|
int ccwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
|
|
debugr2((errout,"webdisp doesn't support uninstalling profiles\n"));
|
|
return 1;
|
|
}
|
|
|
|
/* Get the currently installed display profile. */
|
|
/* Return NULL if failed. */
|
|
icmFile *ccwin_get_profile(dispwin *p, char *name, int mxlen) {
|
|
debugr2((errout,"webdisp doesn't support getting the current profile\n"));
|
|
return NULL;
|
|
}
|
|
|
|
/* ----------------------------------------------- */
|
|
|
|
/* Change the window color. */
|
|
/* Return 1 on error, 2 on window being closed */
|
|
/* inst_license, inst_licensenc, inst_tamper or inst_syscompat on licening problem */
|
|
static int ccwin_set_color(
|
|
dispwin *p,
|
|
double r, double g, double b /* Color values 0.0 - 1.0 */
|
|
) {
|
|
chws *ws = (chws *)p->pcntx;
|
|
int j;
|
|
double orgb[3]; /* Previous RGB value */
|
|
double kr, kf;
|
|
int update_delay = 0;
|
|
|
|
debugr2((errout, "ccwin_set_color called with %f %f %f\n",r,g,b));
|
|
|
|
if (p->nowin) {
|
|
debugr2((errout,"ccwin_set_color: nowin - give up\n"));
|
|
return 1;
|
|
}
|
|
|
|
orgb[0] = p->rgb[0]; p->rgb[0] = r;
|
|
orgb[1] = p->rgb[1]; p->rgb[1] = g;
|
|
orgb[2] = p->rgb[2]; p->rgb[2] = b;
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
if (p->rgb[j] < 0.0)
|
|
p->rgb[j] = 0.0;
|
|
else if (p->rgb[j] > 1.0)
|
|
p->rgb[j] = 1.0;
|
|
p->r_rgb[j] = p->s_rgb[j] = p->rgb[j];
|
|
if (p->out_tvenc) {
|
|
p->r_rgb[j] = p->s_rgb[j] = ((235.0 - 16.0) * p->s_rgb[j] + 16.0)/255.0;
|
|
|
|
/* For video encoding the extra bits of precision are created by bit shifting */
|
|
/* rather than scaling, so we need to scale the fp value to account for this. */
|
|
if (p->edepth > 8)
|
|
p->r_rgb[j] = (p->s_rgb[j] * 255 * (1 << (p->edepth - 8)))
|
|
/((1 << p->edepth) - 1.0);
|
|
}
|
|
}
|
|
|
|
/* This is probably not actually thread safe... */
|
|
p->ncix++;
|
|
|
|
#if DDITHER != 1
|
|
# pragma message("############################# ccwin.c DDITHER != 1 ##")
|
|
#endif
|
|
|
|
/* Turn the color into a png file */
|
|
{
|
|
/* We want a raster of IWIDTH x IHEIGHT pixels for web server, */
|
|
/* or p->w x p->h for PNG direct. */
|
|
render2d *rr;
|
|
prim2d *rct;
|
|
depth2d depth = bpc8_2d;
|
|
#if DDITHER == 1
|
|
int dither = 0x8002; /* 0x8002 = error diffuse FG only */
|
|
#elif DDITHER == 2
|
|
int dither = 0x4000; /* 0x4000 = no dither but don't average pixels */
|
|
/* so as to allow pattern to come through. */
|
|
#else
|
|
int dither = 0; /* Don't dither in renderer */
|
|
#endif
|
|
double hres = 1.0; /* Resoltion in pix/mm */
|
|
double vres = 1.0; /* Resoltion in pix/mm */
|
|
double iw, ih; /* Size of page in mm (pixels) */
|
|
color2d c;
|
|
unsigned char *ibuf; /* Memory image of .png file */
|
|
size_t ilen;
|
|
int rv;
|
|
#ifdef DO_TIMING
|
|
int stime;
|
|
#endif
|
|
|
|
if (ws->direct) {
|
|
iw = ws->w; /* Requested size */
|
|
ih = ws->h;
|
|
} else {
|
|
iw = IWIDTH;
|
|
ih = IHEIGHT; /* Size of page in mm */
|
|
}
|
|
|
|
/* Full screen background: */
|
|
if (p->fullscreen) {
|
|
if (p->bge == dw_bg_grey) {
|
|
ws->bg[0] = 0.2;
|
|
ws->bg[1] = 0.2;
|
|
ws->bg[2] = 0.2;
|
|
} else if (p->bge == dw_bg_cvideo) {
|
|
ws->bg[0] = p->area * (1.0 - r)/(1.0 - p->area);
|
|
ws->bg[1] = p->area * (1.0 - g)/(1.0 - p->area);
|
|
ws->bg[2] = p->area * (1.0 - b)/(1.0 - p->area);
|
|
|
|
} else if (p->bge == dw_bg_clight) {
|
|
double gamma = 2.3;
|
|
ws->bg[0] = pow(p->area * (1.0 - pow(r, gamma))/(1.0 - p->area), 1.0/gamma);
|
|
ws->bg[1] = pow(p->area * (1.0 - pow(g, gamma))/(1.0 - p->area), 1.0/gamma);
|
|
ws->bg[2] = pow(p->area * (1.0 - pow(b, gamma))/(1.0 - p->area), 1.0/gamma);
|
|
|
|
} else { /* Assume dw_bg_black */
|
|
ws->bg[0] = 0.0;
|
|
ws->bg[1] = 0.0;
|
|
ws->bg[2] = 0.0;
|
|
}
|
|
|
|
/* Use default dark gray background */
|
|
} else {
|
|
ws->bg[0] = 0.2;
|
|
ws->bg[1] = 0.2;
|
|
ws->bg[2] = 0.2;
|
|
}
|
|
|
|
debugr2((errout, "ccwin_set_color iw %f ih %f\n",iw,ih));
|
|
|
|
if ((rr = new_render2d(iw, ih, NULL, hres, vres, rgb_2d,
|
|
0, depth, dither,
|
|
#if DDITHER == 1
|
|
ccastQuant, NULL, 3.0/255.0
|
|
#else
|
|
NULL, NULL, 0.0
|
|
#endif
|
|
)) == NULL) {
|
|
a1loge(g_log, 1,"ccwin: new_render2d() failed\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Set the background color */
|
|
c[0] = ws->bg[0];
|
|
c[1] = ws->bg[1];
|
|
c[2] = ws->bg[2];
|
|
rr->set_defc(rr, c);
|
|
|
|
c[0] = p->r_rgb[0];
|
|
c[1] = p->r_rgb[1];
|
|
c[2] = p->r_rgb[2];
|
|
if (ws->direct)
|
|
rr->add(rr, rct = new_rect2d(rr, 0.0, 0.0, ws->w, ws->h, c));
|
|
else
|
|
rr->add(rr, rct = new_rect2d(rr, ws->x, ws->y, ws->w, ws->h, c));
|
|
|
|
#if DDITHER == 2 /* Use dither pattern */
|
|
{
|
|
double rgb[3];
|
|
double dpat[CCDITHSIZE][CCDITHSIZE][3];
|
|
double (*cpat)[MXPATSIZE][MXPATSIZE][TOTC2D];
|
|
int i, j;
|
|
|
|
/* Get a chrome cast dither pattern to match target color */
|
|
for (i = 0; i < 3; i++)
|
|
rgb[i] = p->r_rgb[i] * 255.0;
|
|
get_ccast_dith(dpat, rgb);
|
|
|
|
if ((cpat = malloc(sizeof(double) * MXPATSIZE * MXPATSIZE * TOTC2D)) == NULL) {
|
|
a1loge(g_log, 1, "ccwin: malloc of dither pattern failed\n");
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < CCDITHSIZE; i++) {
|
|
for (j = 0; j < CCDITHSIZE; j++) {
|
|
int k = (((int)IHEIGHT-2) - j) % CCDITHSIZE; /* Flip to origin bot left */
|
|
(*cpat)[i][k][0] = dpat[i][j][0]/255.0; /* (HEIGHT-2 is correct!) */
|
|
(*cpat)[i][k][1] = dpat[i][j][1]/255.0;
|
|
(*cpat)[i][k][2] = dpat[i][j][2]/255.0;
|
|
}
|
|
}
|
|
|
|
set_rect2d_dpat((rect2d *)rct, cpat, CCDITHSIZE, CCDITHSIZE);
|
|
}
|
|
#endif /* DDITHER == 2 */
|
|
|
|
#ifdef CCTEST_PATTERN
|
|
#pragma message("############################# ccwin.c TEST_PATTERN defined ! ##")
|
|
if (getenv("ARGYLL_CCAST_TEST_PATTERN") != NULL) {
|
|
verbose(0, "Writing test pattern to '%s'\n","testpattern.png");
|
|
if (r->write(r, "testpattern.png", 1, NULL, NULL, png_file)) {
|
|
a1loge(g_log, 1, "ccwin: render->write failed\n");
|
|
return 1;
|
|
}
|
|
}
|
|
#else /* !CCTEST_PATTERN */
|
|
# ifdef WRITE_PNG /* Write it to a file so that we can look at it */
|
|
# pragma message("############################# spectro/ccwin.c WRITE_PNG is enabled ######")
|
|
if (r->write(rr, "ccwin.png", 1, NULL, NULL, png_file)) {
|
|
a1loge(g_log, 1, "ccwin: render->write failed\n");
|
|
return 1;
|
|
}
|
|
# endif /* WRITE_PNG */
|
|
#endif /* !CCTEST_PATTERN */
|
|
|
|
|
|
#ifdef DO_TIMING
|
|
stime = msec_time();
|
|
#endif
|
|
|
|
rv = rr->write(rr, "MemoryBuf", 1, &ibuf, &ilen, png_mem);
|
|
|
|
|
|
if (rv) {
|
|
a1loge(g_log, 1, "ccwin: render->write failed\n");
|
|
return 1;
|
|
}
|
|
rr->del(rr);
|
|
#ifdef DO_TIMING
|
|
stime = msec_time() - stime;
|
|
printf("render->write took %d msec\n",stime);
|
|
#endif
|
|
if (ws->update(ws, ibuf, ilen, ws->bg)) {
|
|
a1loge(g_log, 1, "ccwin: color update failed\n");
|
|
return 1;
|
|
}
|
|
p->ccix = p->ncix;
|
|
}
|
|
|
|
|
|
/* If update is notified asyncronously ... */
|
|
while(p->ncix != p->ccix) {
|
|
msec_sleep(50);
|
|
}
|
|
//printf("#################################################################\n");
|
|
//printf("################# RGB update notified ################\n");
|
|
//printf("#################################################################\n");
|
|
|
|
/* Allow for display update & instrument delays */
|
|
update_delay = dispwin_compute_delay(p, orgb);
|
|
debugr2((errout, "ccwin_set_color delaying %d msec\n",update_delay));
|
|
msec_sleep(update_delay);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Set/unset the full screen background color flag */
|
|
/* Return nz on error */
|
|
static int ccwin_set_fc(dispwin *p, int fullscreen) {
|
|
p->fullscreen = fullscreen;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------- */
|
|
/* Set the shell set color callout */
|
|
void ccwin_set_callout(
|
|
dispwin *p,
|
|
char *callout
|
|
) {
|
|
debugr2((errout,"ccwin_set_callout called with '%s'\n",callout));
|
|
|
|
p->callout = strdup(callout);
|
|
}
|
|
|
|
/* ----------------------------------------------- */
|
|
/* Destroy ourselves */
|
|
static void ccwin_del(
|
|
dispwin *p
|
|
) {
|
|
chws *ws;
|
|
|
|
debugr2((errout,"ccwin_del called with %p\n",p));
|
|
|
|
if (p == NULL)
|
|
return;
|
|
|
|
ws = (chws *)p->pcntx;
|
|
|
|
if (ws != NULL)
|
|
ws->del(ws);
|
|
|
|
if (p->name != NULL)
|
|
free(p->name);
|
|
if (p->description != NULL)
|
|
free(p->description);
|
|
if (p->callout != NULL)
|
|
free(p->callout);
|
|
|
|
free(p);
|
|
}
|
|
|
|
/* ----------------------------------------------- */
|
|
|
|
/* Create a ChromeCast display test window, default grey */
|
|
dispwin *new_ccwin(
|
|
ccast_id *cc_id, /* ChromeCast to open */
|
|
double width, double height, /* Width and height in mm. (TV width assumed to b 1000mm) */
|
|
double hoff, double voff, /* Offset from center in fraction of screen, range -1.0 .. 1.0 */
|
|
int nowin, /* NZ if no window should be created - RAMDAC access only */
|
|
int native, /* X0 = use current per channel calibration curve */
|
|
/* X1 = set native linear output and use ramdac high precn. */
|
|
/* 0X = use current color management cLut (MadVR) */
|
|
/* 1X = disable color management cLUT (MadVR) */
|
|
int *noramdac, /* Return nz if no ramdac access. native is set to X0 */
|
|
int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */
|
|
double icalmax, /* Scale instrument calibration test values by this (0.0 .. 1.0) */
|
|
int out_tvenc, /* 1 = use RGB Video Level encoding */
|
|
int fullscreen, /* NZ if whole screen should be filled with black */
|
|
int noinitpatch, /* NZ if no initial test patch should be shown */
|
|
int verb, /* NZ for verbose prompts */
|
|
int ddebug /* >0 to print debug statements to stderr */
|
|
) {
|
|
dispwin *p = NULL;
|
|
char *cp;
|
|
chws *ws = NULL;
|
|
const char *options[3];
|
|
|
|
debug2((errout,"new_ccwin called\n"));
|
|
|
|
if ((p = (dispwin *)calloc(sizeof(dispwin), 1)) == NULL) {
|
|
debugr2((errout,"new_ccwin failed because malloc failed\n"));
|
|
return NULL;
|
|
}
|
|
|
|
/* !!!! Make changes in dispwin.c & madvrwin.c as well !!!! */
|
|
p->name = strdup("Web Window");
|
|
p->width = width;
|
|
p->height = height;
|
|
p->nowin = nowin;
|
|
p->native = native;
|
|
p->icalmax = icalmax;
|
|
p->out_tvenc = out_tvenc;
|
|
p->fullscreen = fullscreen;
|
|
p->ddebug = ddebug;
|
|
p->get_ramdac = ccwin_get_ramdac;
|
|
p->set_ramdac = ccwin_set_ramdac;
|
|
p->install_profile = ccwin_install_profile;
|
|
p->uninstall_profile = ccwin_uninstall_profile;
|
|
p->get_profile = ccwin_get_profile;
|
|
p->set_color = ccwin_set_color;
|
|
p->set_fc = ccwin_set_fc;
|
|
p->set_patch_win = ccwin_set_patch_win;
|
|
p->set_update_delay = dispwin_set_update_delay;
|
|
p->set_settling_delay = dispwin_set_settling_delay;
|
|
p->enable_update_delay = dispwin_enable_update_delay;
|
|
p->set_callout = ccwin_set_callout;
|
|
p->del = ccwin_del;
|
|
|
|
if (noramdac != NULL)
|
|
*noramdac = 1;
|
|
p->native &= ~1;
|
|
|
|
if (nocm != NULL)
|
|
*nocm = 1;
|
|
p->native &= ~2;
|
|
|
|
p->rgb[0] = p->rgb[1] = p->rgb[2] = 0.5 * icalmax; /* Set Grey as the initial test color */
|
|
|
|
dispwin_set_default_delays(p);
|
|
|
|
p->ncix = 1;
|
|
|
|
p->fdepth = 8; /* Assume this by API */
|
|
p->rdepth = p->fdepth; /* Assumed */
|
|
p->ndepth = p->rdepth; /* Assumed */
|
|
p->nent = 0; /* No ramdac */
|
|
p->edepth = 8; /* Assumed */
|
|
|
|
/* Basic object is initialised, so create connection to ChromeCast */
|
|
if ((ws = new_chws(cc_id, width, height, hoff, voff, verb, ddebug)) == NULL) {
|
|
debugr2((errout,"new_ccwin failed - new_chws() failed\n"));
|
|
p->del(p);
|
|
return NULL;
|
|
}
|
|
|
|
/* Extra delay ccast adds after confirming load */
|
|
p->extra_update_delay = ws->cc->get_load_delay(ws->cc) / 1000.0;
|
|
|
|
p->pcntx = (void *)ws;
|
|
|
|
/* Create a suitable description */
|
|
{
|
|
char buf[100];
|
|
sprintf(buf,"ChromeCast '%s'",cc_id->name);
|
|
p->description = strdup(buf);
|
|
}
|
|
|
|
// Set a default first color
|
|
if (!noinitpatch && ccwin_set_color(p, 128.0, 128.0, 128.0)) {
|
|
debugr2((errout,"new_ccwin failed because set_color() failed\n"));
|
|
p->del(p);
|
|
return NULL;
|
|
}
|
|
|
|
debugr2((errout,"new_ccwin: return successfully\n"));
|
|
|
|
return p;
|
|
}
|
|
|