|
@@ -557,6 +557,7 @@
|
|
private _mustWipeVertexAttributes = false;
|
|
private _mustWipeVertexAttributes = false;
|
|
|
|
|
|
private _emptyTexture: WebGLTexture;
|
|
private _emptyTexture: WebGLTexture;
|
|
|
|
+ private _emptyCubeTexture: WebGLTexture;
|
|
|
|
|
|
// Hardware supported Compressed Textures
|
|
// Hardware supported Compressed Textures
|
|
private _texturesSupported = new Array<string>();
|
|
private _texturesSupported = new Array<string>();
|
|
@@ -578,6 +579,15 @@
|
|
|
|
|
|
return this._emptyTexture;
|
|
return this._emptyTexture;
|
|
}
|
|
}
|
|
|
|
+ public get emptyCubeTexture(): WebGLTexture {
|
|
|
|
+ if (!this._emptyCubeTexture) {
|
|
|
|
+ var faceData = new Uint8Array(4);
|
|
|
|
+ var cubeData = [faceData, faceData, faceData, faceData, faceData, faceData];
|
|
|
|
+ this._emptyCubeTexture = this.createRawCubeTexture(cubeData, 1, BABYLON.Engine.TEXTUREFORMAT_RGBA, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, false, false, BABYLON.Texture.NEAREST_SAMPLINGMODE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return this._emptyCubeTexture;
|
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
/**
|
|
* @constructor
|
|
* @constructor
|
|
@@ -3196,43 +3206,138 @@
|
|
texture._baseHeight = height;
|
|
texture._baseHeight = height;
|
|
}
|
|
}
|
|
|
|
|
|
- public createRawCubeTexture(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,
|
|
|
|
- callback: (ArrayBuffer: ArrayBuffer) => ArrayBufferView[],
|
|
|
|
- mipmmapGenerator: ((faces: ArrayBufferView[]) => ArrayBufferView[][]), onLoad: () => void = null, onError: () => void = null): WebGLTexture {
|
|
|
|
|
|
+ public updateRawCubeTexture(texture: WebGLTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: string = null, level = 0): void {
|
|
|
|
+ var gl = this._gl;
|
|
|
|
+ var textureType = this._getWebGLTextureType(type);
|
|
|
|
+ var internalFormat = this._getInternalFormat(format);
|
|
|
|
+ var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
|
|
+
|
|
|
|
+ var needConversion = false;
|
|
|
|
+ if (internalFormat === gl.RGB) {
|
|
|
|
+ internalFormat = gl.RGBA;
|
|
|
|
+ needConversion = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
|
|
|
|
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? 1 : (invertY ? 1 : 0));
|
|
|
|
+
|
|
|
|
+ if (texture._width % 4 !== 0) {
|
|
|
|
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var facesIndex = [
|
|
|
|
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
|
|
|
|
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ // Data are known to be in +X +Y +Z -X -Y -Z
|
|
|
|
+ for (let index = 0; index < facesIndex.length; index++) {
|
|
|
|
+ let faceData = data[index];
|
|
|
|
+
|
|
|
|
+ if (compression) {
|
|
|
|
+ gl.compressedTexImage2D(facesIndex[index], level, this.getCaps().s3tc[compression], texture._width, texture._height, 0, faceData);
|
|
|
|
+ } else {
|
|
|
|
+ if (needConversion) {
|
|
|
|
+ faceData = this._convertRGBtoRGBATextureData(faceData, texture._width, texture._height, type);
|
|
|
|
+ }
|
|
|
|
+ gl.texImage2D(facesIndex[index], level, internalSizedFomat, texture._width, texture._height, 0, internalFormat, textureType, faceData);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var isPot = (Tools.IsExponentOfTwo(texture._width) && Tools.IsExponentOfTwo(texture._height));
|
|
|
|
+ if (isPot && texture.generateMipMaps && level === 0) {
|
|
|
|
+ this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
|
|
|
|
+ }
|
|
|
|
+ this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
|
|
|
|
+
|
|
|
|
+ this.resetTextureCache();
|
|
|
|
+ texture.isReady = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public createRawCubeTexture(data: ArrayBufferView[], size: number, format: number, type: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: string = null): WebGLTexture {
|
|
var gl = this._gl;
|
|
var gl = this._gl;
|
|
var texture = gl.createTexture();
|
|
var texture = gl.createTexture();
|
|
- scene._addPendingData(texture);
|
|
|
|
texture.isCube = true;
|
|
texture.isCube = true;
|
|
texture.references = 1;
|
|
texture.references = 1;
|
|
- texture.url = url;
|
|
|
|
-
|
|
|
|
- var textureType = gl.UNSIGNED_BYTE;
|
|
|
|
- if (type === Engine.TEXTURETYPE_FLOAT) {
|
|
|
|
- textureType = gl.FLOAT;
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
+ var textureType = this._getWebGLTextureType(type);
|
|
var internalFormat = this._getInternalFormat(format);
|
|
var internalFormat = this._getInternalFormat(format);
|
|
|
|
+ var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
|
|
+
|
|
var needConversion = false;
|
|
var needConversion = false;
|
|
if (internalFormat === gl.RGB) {
|
|
if (internalFormat === gl.RGB) {
|
|
internalFormat = gl.RGBA;
|
|
internalFormat = gl.RGBA;
|
|
needConversion = true;
|
|
needConversion = true;
|
|
}
|
|
}
|
|
- var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
|
|
|
|
|
|
var width = size;
|
|
var width = size;
|
|
var height = width;
|
|
var height = width;
|
|
- var isPot = (Tools.IsExponentOfTwo(width) && Tools.IsExponentOfTwo(height));
|
|
|
|
|
|
|
|
texture._width = width;
|
|
texture._width = width;
|
|
texture._height = height;
|
|
texture._height = height;
|
|
|
|
|
|
|
|
+ // Double check on POT to generate Mips.
|
|
|
|
+ var isPot = (Tools.IsExponentOfTwo(texture._width) && Tools.IsExponentOfTwo(texture._height));
|
|
|
|
+ if (!isPot) {
|
|
|
|
+ generateMipMaps = false;
|
|
|
|
+ }
|
|
|
|
+ texture.generateMipMaps = generateMipMaps;
|
|
|
|
+
|
|
|
|
+ // Upload data if needed. The texture won t be ready until then.
|
|
|
|
+ if (data) {
|
|
|
|
+ this.updateRawCubeTexture(texture, data, format, type, invertY, compression);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture);
|
|
|
|
+
|
|
|
|
+ // Filters
|
|
|
|
+ if (data && generateMipMaps) {
|
|
|
|
+ this._gl.generateMipmap(this._gl.TEXTURE_CUBE_MAP);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (textureType === gl.FLOAT && !this._caps.textureFloatLinearFiltering) {
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
|
+ }
|
|
|
|
+ else if (textureType === Engine.HALF_FLOAT_OES && !this._caps.textureHalfFloatLinearFiltering) {
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ var filters = getSamplingParameters(samplingMode, generateMipMaps, gl);
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, filters.min);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
|
+ this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
|
|
+
|
|
|
|
+ this._loadedTexturesCache.push(texture);
|
|
|
|
+
|
|
|
|
+ return texture;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public createRawCubeTextureFromUrl(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,
|
|
|
|
+ callback: (ArrayBuffer: ArrayBuffer) => ArrayBufferView[],
|
|
|
|
+ mipmmapGenerator: ((faces: ArrayBufferView[]) => ArrayBufferView[][]),
|
|
|
|
+ onLoad: () => void = null,
|
|
|
|
+ onError: () => void = null,
|
|
|
|
+ samplingMode = Texture.TRILINEAR_SAMPLINGMODE,
|
|
|
|
+ invertY = false): WebGLTexture {
|
|
|
|
+
|
|
|
|
+ var gl = this._gl;
|
|
|
|
+ var texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode);
|
|
|
|
+ scene._addPendingData(texture);
|
|
|
|
+ texture.url = url;
|
|
|
|
+
|
|
var onerror = () => {
|
|
var onerror = () => {
|
|
scene._removePendingData(texture);
|
|
scene._removePendingData(texture);
|
|
if (onError) {
|
|
if (onError) {
|
|
onError();
|
|
onError();
|
|
}
|
|
}
|
|
};
|
|
};
|
|
-
|
|
|
|
|
|
+
|
|
var internalCallback = (data) => {
|
|
var internalCallback = (data) => {
|
|
var rgbeDataArrays = callback(data);
|
|
var rgbeDataArrays = callback(data);
|
|
|
|
|
|
@@ -3241,15 +3346,24 @@
|
|
gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
|
|
gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
|
|
];
|
|
];
|
|
|
|
|
|
- width = texture._width;
|
|
|
|
- height = texture._height;
|
|
|
|
- isPot = (Tools.IsExponentOfTwo(width) && Tools.IsExponentOfTwo(height));
|
|
|
|
|
|
+ var width = texture._width;
|
|
|
|
+ var height = texture._height;
|
|
|
|
+ if (mipmmapGenerator) {
|
|
|
|
|
|
- this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
|
|
|
|
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
|
|
|
|
|
|
+ // TODO Remove this once Proper CubeMap Blur... This has nothing to do in engine...
|
|
|
|
+ // I ll remove ASAP.
|
|
|
|
+ var textureType = this._getWebGLTextureType(type);
|
|
|
|
+ var internalFormat = this._getInternalFormat(format);
|
|
|
|
+ var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
|
|
|
|
|
|
- if (mipmmapGenerator) {
|
|
|
|
|
|
+ var needConversion = false;
|
|
|
|
+ if (internalFormat === gl.RGB) {
|
|
|
|
+ internalFormat = gl.RGBA;
|
|
|
|
+ needConversion = true;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
|
|
|
|
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
|
|
var arrayTemp: ArrayBufferView[] = [];
|
|
var arrayTemp: ArrayBufferView[] = [];
|
|
// Data are known to be in +X +Y +Z -X -Y -Z
|
|
// Data are known to be in +X +Y +Z -X -Y -Z
|
|
// mipmmapGenerator data is expected to be order in +X -X +Y -Y +Z -Z
|
|
// mipmmapGenerator data is expected to be order in +X -X +Y -Y +Z -Z
|
|
@@ -3274,45 +3388,15 @@
|
|
gl.texImage2D(facesIndex[mipIndex], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipFaceData);
|
|
gl.texImage2D(facesIndex[mipIndex], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipFaceData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- }
|
|
|
|
- else {
|
|
|
|
- // Data are known to be in +X +Y +Z -X -Y -Z
|
|
|
|
- for (let index = 0; index < facesIndex.length; index++) {
|
|
|
|
- let faceData = rgbeDataArrays[index];
|
|
|
|
- if (needConversion) {
|
|
|
|
- faceData = this._convertRGBtoRGBATextureData(faceData, width, height, type);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- gl.texImage2D(facesIndex[index], 0, internalSizedFomat, width, height, 0, internalFormat, textureType, faceData);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!noMipmap && isPot) {
|
|
|
|
- gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- noMipmap = true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
|
|
- if (textureType === gl.FLOAT && !this._caps.textureFloatLinearFiltering) {
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
|
- }
|
|
|
|
- else if (textureType === Engine.HALF_FLOAT_OES && !this._caps.textureHalfFloatLinearFiltering) {
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
|
|
|
+ this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, noMipmap ? gl.LINEAR : gl.LINEAR_MIPMAP_LINEAR);
|
|
|
|
|
|
+ texture.generateMipMaps = !noMipmap;
|
|
|
|
+ this.updateRawCubeTexture(texture, rgbeDataArrays, format, type, invertY);
|
|
}
|
|
}
|
|
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
|
|
- gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
|
- this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
|
|
|
|
-
|
|
|
|
texture.isReady = true;
|
|
texture.isReady = true;
|
|
-
|
|
|
|
this.resetTextureCache();
|
|
this.resetTextureCache();
|
|
scene._removePendingData(texture);
|
|
scene._removePendingData(texture);
|
|
|
|
|
|
@@ -3471,7 +3555,9 @@
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- var internalTexture = texture.isReady() ? texture.getInternalTexture() : this.emptyTexture;
|
|
|
|
|
|
+
|
|
|
|
+ var internalTexture = texture.isReady() ? texture.getInternalTexture() :
|
|
|
|
+ (texture.isCube ? this.emptyCubeTexture : this.emptyTexture);
|
|
|
|
|
|
if (this._activeTexturesCache[channel] === internalTexture) {
|
|
if (this._activeTexturesCache[channel] === internalTexture) {
|
|
return;
|
|
return;
|
|
@@ -3684,6 +3770,10 @@
|
|
this._releaseTexture(this._emptyTexture);
|
|
this._releaseTexture(this._emptyTexture);
|
|
this._emptyTexture = null;
|
|
this._emptyTexture = null;
|
|
}
|
|
}
|
|
|
|
+ if (this._emptyCubeTexture) {
|
|
|
|
+ this._releaseTexture(this._emptyCubeTexture);
|
|
|
|
+ this._emptyCubeTexture = null;
|
|
|
|
+ }
|
|
|
|
|
|
// Release scenes
|
|
// Release scenes
|
|
while (this.scenes.length) {
|
|
while (this.scenes.length) {
|