diff --git a/src/js/libpannellum.js b/src/js/libpannellum.js index 662fb3c..128073a 100644 --- a/src/js/libpannellum.js +++ b/src/js/libpannellum.js @@ -294,18 +294,20 @@ function Renderer(container) { } // Make sure image isn't too big - var width = 0, maxWidth = 0; + var maxWidth = 0; if (imageType == 'equirectangular') { - width = Math.max(image.width, image.height); maxWidth = gl.getParameter(gl.MAX_TEXTURE_SIZE); + if (Math.max(image.width / 2, image.height) > maxWidth) { + console.log('Error: The image is too big; it\'s ' + image.width + 'px wide, '+ + 'but this device\'s maximum supported size is ' + (maxWidth * 2) + 'px.'); + throw {type: 'webgl size error', width: image.width, maxWidth: maxWidth * 2}; + } } else if (imageType == 'cubemap') { - width = cubeImgWidth; - maxWidth = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE); - } - if (width > maxWidth) { - console.log('Error: The image is too big; it\'s ' + width + 'px wide, '+ - 'but this device\'s maximum supported size is ' + maxWidth + 'px.'); - throw {type: 'webgl size error', width: width, maxWidth: maxWidth}; + if (cubeImgWidth > gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) { + console.log('Error: The image is too big; it\'s ' + width + 'px wide, '+ + 'but this device\'s maximum supported size is ' + maxWidth + 'px.'); + throw {type: 'webgl size error', width: width, maxWidth: maxWidth}; + } } // Store horizon pitch and roll if applicable @@ -414,8 +416,44 @@ function Renderer(container) { gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[0]); gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image[2]); } else { - // Upload image to the texture - gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); + if (image.width <= maxWidth) { + gl.uniform1i(gl.getUniformLocation(program, 'u_splitImage'), 0); + // Upload image to the texture + gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); + } else { + // Image needs to be split into two parts due to texture size limits + gl.uniform1i(gl.getUniformLocation(program, 'u_splitImage'), 1); + + // Draw image on canvas + var cropCanvas = document.createElement('canvas'); + cropCanvas.width = image.width; + cropCanvas.height = image.height; + var cropContext = cropCanvas.getContext('2d'); + cropContext.drawImage(image, 0, 0); + + // Upload first half of image to the texture + var cropImage = cropContext.getImageData(0, 0, image.width / 2, image.height); + gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, cropImage); + + // Create and bind texture for second half of image + program.texture2 = gl.createTexture(); + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(glBindType, program.texture2); + gl.uniform1i(gl.getUniformLocation(program, 'u_image1'), 1); + + // Upload second half of image to the texture + cropImage = cropContext.getImageData(image.width / 2, 0, image.width / 2, image.height); + gl.texImage2D(glBindType, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, cropImage); + + // Set parameters for rendering any size + gl.texParameteri(glBindType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(glBindType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(glBindType, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(glBindType, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + + // Reactive first texture unit + gl.activeTexture(gl.TEXTURE0); + } } // Set parameters for rendering any size @@ -1320,7 +1358,9 @@ var fragEquiCubeBase = [ 'const float PI = 3.14159265358979323846264;', // Texture -'uniform sampler2D u_image;', +'uniform sampler2D u_image0;', +'uniform sampler2D u_image1;', +'uniform bool u_splitImage;', 'uniform samplerCube u_imageCube;', // Coordinates passed in from vertex shader @@ -1365,8 +1405,17 @@ var fragEquirectangular = fragEquiCubeBase + [ // Map from [-1,1] to [0,1] and flip y-axis 'if(coord.x < -u_h || coord.x > u_h || coord.y < -u_v + u_vo || coord.y > u_v + u_vo)', 'gl_FragColor = u_backgroundColor;', - 'else', - 'gl_FragColor = texture2D(u_image, vec2((coord.x + u_h) / (u_h * 2.0), (-coord.y + u_v + u_vo) / (u_v * 2.0)));', + 'else {', + 'if(u_splitImage) {', + // Image was split into two textures to work around texture size limits + 'if(coord.x < 0.0)', + 'gl_FragColor = texture2D(u_image0, vec2((coord.x + u_h) / u_h, (-coord.y + u_v + u_vo) / (u_v * 2.0)));', + 'else', + 'gl_FragColor = texture2D(u_image1, vec2((coord.x + u_h) / u_h - 1.0, (-coord.y + u_v + u_vo) / (u_v * 2.0)));', + '} else {', + 'gl_FragColor = texture2D(u_image0, vec2((coord.x + u_h) / (u_h * 2.0), (-coord.y + u_v + u_vo) / (u_v * 2.0)));', + '}', + '}', '}' ].join('\n');