Commit d41c33e4 authored by Joel Martin's avatar Joel Martin

Add colour map support (non-true-color).

In colourMap mode there are 256 colours in a colour palette sent from
the server via the SetColourMapEntries message. This reduces the
bandwidth by about 1/4. However, appearance can be somewhat less than
ideal (pinks instead of gray, etc).

It also increases client side rendering performance especially on
firefox. Rendering a full 800x600 update takes about 950ms in
firefox on my system compared to about 1400ms. Round-trip time for
a full frame buffer update is even better on firefox (due to
performance of the flash WebSocket emulator). Reduced from about
1800ms to 1100ms on firefox (for 800x600 full update).
parent 507b473a
......@@ -14,6 +14,9 @@ var Canvas = {
prefer_js : false,
true_color : false,
colourMap : [],
c_x : 0,
c_y : 0,
c_wx : 0,
......@@ -74,7 +77,7 @@ ctxDisable: function (e) {
},
init: function (id, width, height, keyDown, keyUp,
init: function (id, width, height, true_color, keyDown, keyUp,
mouseDown, mouseUp, mouseMove, mouseWheel) {
console.log(">> Canvas.init");
......@@ -105,6 +108,8 @@ init: function (id, width, height, keyDown, keyUp,
Canvas.c_y = c.getPosition().y;
Canvas.c_wx = c.getSize().x;
Canvas.c_wy = c.getSize().y;
Canvas.true_color = true_color;
Canvas.colourMap = [];
if (! c.getContext) { return; }
Canvas.ctx = c.getContext('2d');
......@@ -147,21 +152,26 @@ stop: function () {
* gecko, Javascript array handling is much slower.
*/
getTile: function(x, y, width, height, color) {
var img, data, p, red, green, blue, j, i;
var img, data, p, rgb, red, green, blue, j, i;
img = {'x': x, 'y': y, 'width': width, 'height': height,
'data': []};
if (Canvas.prefer_js) {
data = img.data;
red = color[0];
green = color[1];
blue = color[2];
if (Canvas.true_color) {
rgb = color;
} else {
rgb = Canvas.colourMap[color[0]];
}
red = rgb[0];
green = rgb[1];
blue = rgb[2];
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
p = (i + (j * width) ) * 4;
img.data[p + 0] = red;
img.data[p + 1] = green;
img.data[p + 2] = blue;
//img.data[p + 3] = 255; // Set Alpha
data[p + 0] = red;
data[p + 1] = green;
data[p + 2] = blue;
//data[p + 3] = 255; // Set Alpha
}
}
} else {
......@@ -171,13 +181,18 @@ getTile: function(x, y, width, height, color) {
},
setTile: function(img, x, y, w, h, color) {
var data, p, red, green, blue, width, j, i;
var data, p, rgb, red, green, blue, width, j, i;
if (Canvas.prefer_js) {
data = img.data;
width = img.width;
red = color[0];
green = color[1];
blue = color[2];
if (Canvas.true_color) {
rgb = color;
} else {
rgb = Canvas.colourMap[color[0]];
}
red = rgb[0];
green = rgb[1];
blue = rgb[2];
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
p = (x + i + ((y + j) * width) ) * 4;
......@@ -208,20 +223,48 @@ rgbxImage: function(x, y, width, height, arr, offset) {
/* Old firefox and Opera don't support createImageData */
img = Canvas.ctx.getImageData(0, 0, width, height);
data = img.data;
for (i=0; i < (width * height * 4); i=i+4) {
j=i+offset;
for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
data[i + 0] = arr[j + 0];
data[i + 1] = arr[j + 1];
data[i + 2] = arr[j + 2];
data[i + 3] = 255; // Set Alpha
}
Canvas.ctx.putImageData(img, x, y);
},
cmapImage: function(x, y, width, height, arr, offset) {
var img, i, j, k, data, rgb, cmap;
img = Canvas.ctx.getImageData(0, 0, width, height);
data = img.data;
cmap = Canvas.colourMap;
//console.log("cmapImage x: " + x + ", y: " + y + "arr.slice(0,20): " + arr.slice(0,20));
for (i=0, j=offset; i < (width * height * 4); i=i+4, j++) {
rgb = cmap[arr[j]];
data[i + 0] = rgb[0];
data[i + 1] = rgb[1];
data[i + 2] = rgb[2];
data[i + 3] = 255; // Set Alpha
}
Canvas.ctx.putImageData(img, x, y);
},
blitImage: function(x, y, width, height, arr, offset) {
if (Canvas.true_color) {
Canvas.rgbxImage(x, y, width, height, arr, offset);
} else {
Canvas.cmapImage(x, y, width, height, arr, offset);
}
},
fillRect: function(x, y, width, height, color) {
var newStyle = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ")";
var rgb, newStyle;
if (Canvas.true_color) {
rgb = color;
} else {
rgb = Canvas.colourMap[color[0]];
}
if (newStyle !== Canvas.prevStyle) {
newStyle = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
Canvas.ctx.fillStyle = newStyle;
Canvas.prevStyle = newStyle;
}
......
......@@ -77,6 +77,10 @@ FBU : {
background : null
},
true_color : false,
fb_Bpp : 4,
fb_depth : 3,
// DOM objects
statusLine : null,
connectBtn : null,
......@@ -102,7 +106,6 @@ password : '',
fb_width : 0,
fb_height : 0,
fb_name : "",
fb_Bpp : 4,
rre_chunk : 100,
timing : {
......@@ -293,10 +296,18 @@ init_msg: function () {
name_length = RQ.shift32();
RFB.fb_name = RQ.shiftStr(name_length);
Canvas.init('VNC_canvas', RFB.fb_width, RFB.fb_height,
Canvas.init('VNC_canvas', RFB.fb_width, RFB.fb_height, RFB.true_color,
RFB.keyDown, RFB.keyUp, RFB.mouseDown, RFB.mouseUp,
RFB.mouseMove, RFB.mouseWheel);
if (RFB.true_color) {
RFB.fb_Bpp = 4;
RFB.fb_depth = 3;
} else {
RFB.fb_Bpp = 1;
RFB.fb_depth = 1;
}
response = RFB.pixelFormat();
response = response.concat(RFB.encodings());
response = response.concat(RFB.fbUpdateRequest(0));
......@@ -318,7 +329,8 @@ normal_msg: function () {
//console.log(">> normal_msg");
var RQ = RFB.RQ, FBU = RFB.FBU, now, fbu_rt_diff,
ret = true, msg_type, num_colours, msg;
ret = true, msg_type, msg,
c, first_colour, num_colours, red, green, blue;
if (FBU.rects > 0) {
msg_type = 0;
......@@ -414,11 +426,21 @@ normal_msg: function () {
break;
case 1: // SetColourMapEntries
console.log("SetColourMapEntries (unsupported)");
console.log("SetColourMapEntries");
RQ.shift8(); // Padding
RQ.shift16(); // First colour
first_colour = RQ.shift16(); // First colour
num_colours = RQ.shift16();
RQ.shiftBytes(num_colours * 6);
for (c=0; c < num_colours; c++) {
red = RQ.shift16();
//console.log("red before: " + red);
red = parseInt(red / 256, 10);
//console.log("red after: " + red);
green = parseInt(RQ.shift16() / 256, 10);
blue = parseInt(RQ.shift16() / 256, 10);
Canvas.colourMap[first_colour + c] = [red, green, blue];
}
console.log("Registered " + num_colours + " colourMap entries");
//console.log("colourMap: " + Canvas.colourMap);
break;
case 2: // Bell
console.log("Bell (unsupported)");
......@@ -477,7 +499,7 @@ display_raw: function () {
cur_y = FBU.y + (FBU.height - FBU.lines);
cur_height = Math.min(FBU.lines,
Math.floor(RQ.length/(FBU.width * RFB.fb_Bpp)));
Canvas.rgbxImage(FBU.x, cur_y, FBU.width, cur_height, RQ, 0);
Canvas.blitImage(FBU.x, cur_y, FBU.width, cur_height, RQ, 0);
RQ.shiftBytes(FBU.width * cur_height * RFB.fb_Bpp);
FBU.lines -= cur_height;
......@@ -629,7 +651,7 @@ display_hextile: function() {
Canvas.fillRect(x, y, w, h, FBU.background);
}
} else if (FBU.subencoding & 0x01) { // Raw
Canvas.rgbxImage(x, y, w, h, RQ, idx);
Canvas.blitImage(x, y, w, h, RQ, idx);
} else {
if (FBU.subencoding & 0x02) { // Background
FBU.background = RQ.slice(idx, idx + RFB.fb_Bpp);
......@@ -694,9 +716,9 @@ pixelFormat: function () {
arr.push8(0); // padding
arr.push8(RFB.fb_Bpp * 8); // bits-per-pixel
arr.push8(24); // depth
arr.push8(RFB.fb_depth * 8); // depth
arr.push8(0); // little-endian
arr.push8(1); // true-color
arr.push8(RFB.true_color); // true-color
arr.push16(255); // red-max
arr.push16(255); // green-max
......@@ -1187,7 +1209,7 @@ init_vars: function () {
},
connect: function (host, port, password, encrypt) {
connect: function (host, port, password, encrypt, true_color) {
console.log(">> connect");
RFB.host = (host !== undefined) ? host :
......@@ -1198,6 +1220,8 @@ connect: function (host, port, password, encrypt) {
$('VNC_password').value;
RFB.encrypt = (encrypt !== undefined) ? encrypt :
$('VNC_encrypt').checked;
RFB.true_color = (true_color !== undefined) ? true_color:
$('VNC_true_color').checked;
if ((!RFB.host) || (!RFB.port)) {
alert("Must set host and port");
return;
......@@ -1253,6 +1277,8 @@ load: function (target) {
html += ' type="password"></li>';
html += ' <li>Encrypt: <input id="VNC_encrypt"';
html += ' type="checkbox"></li>';
html += ' <li>True Color: <input id="VNC_true_color"';
html += ' type="checkbox" checked></li>';
html += ' <li><input id="VNC_connect_button" type="button"';
html += ' value="Loading" disabled></li>';
html += ' </ul>';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment