ScriptedAmigaEmulator/sae/video.js
Rupert Hausberger 0c5b018866 update 0.7.0
2012-12-22 19:39:33 +01:00

245 lines
7.3 KiB
JavaScript

/**************************************************************************
* SAE - Scripted Amiga Emulator
*
* https://github.com/naTmeg/ScriptedAmigaEmulator
*
* ©2012 Rupert Hausberger
* Commercial use is prohibited.
*
**************************************************************************/
function Vide0() {
const vertexShader =
'attribute vec2 a_position;'+
'attribute vec2 a_texCoord;'+
'uniform vec2 u_resolution;'+
'varying vec2 v_texCoord;'+
'void main() {'+
'vec2 zeroToOne = a_position / u_resolution;'+
'vec2 zeroToTwo = zeroToOne * 2.0;'+
'vec2 clipSpace = zeroToTwo - 1.0;'+
'gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);'+
'v_texCoord = a_texCoord;'+
'}';
const fragmentShader =
'precision mediump float;'+
'uniform sampler2D u_image;'+
'varying vec2 v_texCoord;'+
'void main() {'+
'gl_FragColor = texture2D(u_image, v_texCoord);'+
'}';
const glParams = {
alpha: false,
stencil: false,
antialias: false
};
var width = 0;
var height = 0;
var size = 0;
var pixels = null;
var div = null;
var canvas = null;
var gl = null;
var video = null;
var open = false;
/*---------------------------------*/
function getShader(gl, id) {
var shader, source;
if (id == 'vertex') {
shader = gl.createShader(gl.VERTEX_SHADER);
source = vertexShader;
} else if (id == 'fragment') {
shader = gl.createShader(gl.FRAGMENT_SHADER);
source = fragmentShader;
}
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
Fatal(SAEE_Video_Shader_Error, gl.getShaderInfoLog(shader));
return shader;
}
function initGL() {
var vertexShader = getShader(gl, 'vertex');
var fragmentShader = getShader(gl, 'fragment');
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
Fatal(SAEE_Video_Shader_Error, 'Can\'t initialise the shaders for WebGL.');
gl.useProgram(program);
var positionLocation = gl.getAttribLocation(program, "a_position");
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, width, height);
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.viewport(0, 0, width, height);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.colorMask(true, true, true, false);
}
this.setup = function() {
if (!AMIGA.config.video.enabled) return;
if (open) this.cleanup();
width = AMIGA.config.video.scale ? VIDEO_WIDTH << 1 : VIDEO_WIDTH;
height = AMIGA.config.video.scale ? VIDEO_HEIGHT << 1 : VIDEO_WIDTH;
size = width * height;
//BUG.info('Video.init() %d x %d, %s mode', width, height, AMIGA.config.video.ntsc ? 'ntsc' : 'pal');
div = document.getElementById(AMIGA.config.video.id);
if (!div)
Fatal(SAEE_Video_ID_Not_Found, 'Video DIV-element not found. Check your code. (Malformed-DIV-name: '+AMIGA.config.video.id+')');
if ((canvas = document.createElement('canvas'))) {
canvas.width = width;
canvas.height = height;
} else {
if (confirm('Can\'t create a CANVAS-element. Continue without video-playback?'))
AMIGA.config.video.enabled = false;
else
Fatal(SAEE_Video_Canvas_Not_Supported, 'Can\'t create a CANVAS-element. Please update the browser.');
}
if (AMIGA.config.video.enabled) {
if ((gl = canvas.getContext('experimental-webgl', glParams) || canvas.getContext('webgl', glParams)))
initGL();
else
if (confirm('Can\'t initialise WebGL. Continue without video-playback?'))
AMIGA.config.video.enabled = false;
else
Fatal(SAEE_Video_WebGL_Not_Avail, 'Can\'t initialise WebGL. Is WebGL enabled in the browser-config?');
}
if (AMIGA.config.video.enabled) {
pixels = new Uint16Array(size);
for (var i = 0; i < size; i++) pixels[i] = 0;
}
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
canvas.onmousedown = function(e) { AMIGA.input.mouse.mousedown(e); }
canvas.onmouseup = function(e) { AMIGA.input.mouse.mouseup(e); }
canvas.onmouseover = function(e) { AMIGA.input.mouse.mouseover(e); }
canvas.onmouseout = function(e) { AMIGA.input.mouse.mouseout(e); }
canvas.onmousemove = function(e) { AMIGA.input.mouse.mousemove(e); }
}
canvas.oncontextmenu = function() { return false; }
video = document.createElement('div');
video.style.width = width + 'px';
video.style.height = height + 'px';
video.style.margin = 'auto';
video.style.webkitTouchCallout = 'none';
video.style.webkitUserSelect = 'none';
video.style.khtmlUserSelect = 'none';
video.style.mozUserSelect = 'none';
video.style.msUserSelect = 'none';
video.style.userSelect = 'none';
video.appendChild(canvas);
div.appendChild(video);
open = true;
}
this.cleanup = function() {
if (open) {
div.removeChild(video);
canvas = null;
pixels = null;
video = null;
open = false;
}
}
/*---------------------------------*/
this.hideCursor = function(hide) {
canvas.style.cursor = hide ? 'none' : 'auto';
}
this.clear_pixels = function () {
for (var i = 0; i < size; i++)
pixels[i] = 0;
}
this.drawpixel = function (x, y, rgb) {
pixels[y * width + x] = rgb;
}
this.draw2pixel = function (x, y, rgb) {
var ptr = y * width + x;
pixels[ptr] = pixels[ptr + 1] = rgb;
}
this.drawline = function (y, rgb) {
var ptr = y * width;
for (var i = 0; i < width; i++)
pixels[ptr++] = rgb;
}
this.drawline_from_to = function (x1, x2, y, rgb) {
var ptr = y * width + x1;
for (var i = 0; i < x2 - x1; i++)
pixels[ptr++] = rgb;
}
this.draw = function (rgb, scalex, scaley, colorOnly) {
var r = 0.0625 * (((rgb >> 11) & 31) >> 1);
var g = 0.0625 * (((rgb >> 5) & 63) >> 2);
var b = 0.0625 * ((rgb & 31) >> 1);
gl.viewport(0, 0, width, height);
gl.clearColor(r, g, b, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
if (!colorOnly) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_SHORT_5_6_5, pixels);
var s = AMIGA.config.video.scale ? 1 : 0;
var x1 = 0;
//var x2 = 0 + (width << (scalex ? (s+1) : s));
var x2 = 0 + (width << s);
var y1 = 0;
var y2 = 0 + (height << (scaley ? (s+1) : s));
//var y2 = 0 + (height << s);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1, x2, y1, x1, y2,
x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
}
}