Implementation
void uploadTexture(Map<String, dynamic> textureProperties, Texture texture, int slot) {
dynamic textureType = WebGL.TEXTURE_2D;
if (texture is DataArrayTexture) textureType = WebGL.TEXTURE_2D_ARRAY;
if (texture is Data3DTexture) textureType = WebGL.TEXTURE_3D;
final forceUpload = initTexture(textureProperties, texture);
final source = texture.source;
state.activeTexture(WebGL.TEXTURE0 + slot);
state.bindTexture(textureType, textureProperties["__webglTexture"]);
if (source.version != source.currentVersion || forceUpload) {
_gl.pixelStorei(WebGL.UNPACK_ALIGNMENT, texture.unpackAlignment);
if (kIsWeb) {
_gl.pixelStorei(WebGL.UNPACK_FLIP_Y_WEBGL, texture.flipY ? 1 : 0);
_gl.pixelStorei(WebGL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ? 1 : 0);
_gl.pixelStorei(WebGL.UNPACK_COLORSPACE_CONVERSION_WEBGL, WebGL.NONE);
}
//final needsPowerOfTwo = textureNeedsPowerOfTwo(texture) && isPowerOfTwo(texture.image) == false;
dynamic image = texture.image;//resizeImage(texture.image, needsPowerOfTwo, false, maxTextureSize);
image = verifyColorSpace(texture, image);
final bool supportsMips = isPowerOfTwo(image) || isWebGL2;
final int glFormat = utils.convert(texture.format, texture.encoding);
int glType = utils.convert(texture.type);
int glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.encoding, texture is VideoTexture);
setTextureParameters(textureType, texture, supportsMips);
dynamic mipmap;
final mipmaps = texture.mipmaps;
final useTexStorage = (isWebGL2 && texture is! VideoTexture);
final allocateMemory = (textureProperties["__version"] == null) || (forceUpload == true);
final levels = getMipLevels(texture, image, supportsMips);
if (texture is DepthTexture) {
glInternalFormat = WebGL.DEPTH_COMPONENT;
if (isWebGL2) {
if (texture.type == FloatType) {
glInternalFormat = WebGL.DEPTH_COMPONENT32F;
} else if (texture.type == UnsignedIntType) {
glInternalFormat = WebGL.DEPTH_COMPONENT24;
} else if (texture.type == UnsignedInt248Type) {
glInternalFormat = WebGL.DEPTH24_STENCIL8;
} else {
glInternalFormat = WebGL.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D
}
}
else {
if (texture.type == FloatType) {
console.error('WebGLRenderer: Floating point depth texture requires WebGL2.');
}
}
// validation checks for WebGL 1
if (texture.format == DepthFormat && glInternalFormat == WebGL.DEPTH_COMPONENT) {
// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
if (texture.type != UnsignedShortType && texture.type != UnsignedIntType) {
console.warning('three.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.');
texture.type = UnsignedIntType;
glType = utils.convert(texture.type);
}
}
if (texture.format == DepthStencilFormat && glInternalFormat == WebGL.DEPTH_COMPONENT) {
// Depth stencil textures need the DEPTH_STENCIL internal format
// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
glInternalFormat = WebGL.DEPTH_STENCIL;
// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
if (texture.type != UnsignedInt248Type) {
console.warning('WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.');
texture.type = UnsignedInt248Type;
glType = utils.convert(texture.type);
}
}
//
if (allocateMemory) {
if (useTexStorage) {
state.texStorage2D(WebGL.TEXTURE_2D, 1, glInternalFormat, image.width, image.height);
} else {
state.texImage2D(WebGL.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null);
}
}
}
else if (texture is DataTexture) {
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if (mipmaps.isNotEmpty && supportsMips) {
if (useTexStorage && allocateMemory) {
state.texStorage2D(WebGL.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height);
}
for (int i = 0, il = mipmaps.length; i < il; i++) {
mipmap = mipmaps[i];
if (useTexStorage) {
state.texSubImage2D(WebGL.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data);
} else {
state.texImage2D(WebGL.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data);
}
}
texture.generateMipmaps = false;
}
else {
if (useTexStorage) {
if (allocateMemory) {
state.texStorage2D(WebGL.TEXTURE_2D, levels, glInternalFormat, image.width.toInt(), image.height.toInt());
}
state.texSubImage2D(WebGL.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data);
}
else {
state.texImage2D(WebGL.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data);
}
}
}
else if (texture is CompressedTexture) {
if (useTexStorage && allocateMemory) {
state.texStorage2D(WebGL.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height);
}
for (int i = 0, il = mipmaps.length; i < il; i++) {
mipmap = mipmaps[i];
if (texture.format != RGBAFormat) {
if (glFormat > 0) {
if (useTexStorage) {
state.compressedTexSubImage2D(WebGL.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data);
} else {
state.compressedTexImage2D(WebGL.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data);
}
} else {
console.warning('WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()');
}
} else {
if (useTexStorage) {
state.texSubImage2D(WebGL.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data);
} else {
state.texImage2D(WebGL.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data);
}
}
}
}
else if (texture is DataArrayTexture) {
if (useTexStorage) {
if (allocateMemory) {
state.texStorage3D(WebGL.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth);
}
state.texSubImage3D(
WebGL.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data);
} else {
state.texImage3D(WebGL.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0,
glFormat, glType, image.data);
}
}
else if (texture is Data3DTexture) {
if (useTexStorage) {
if (allocateMemory) {
state.texStorage3D(WebGL.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth);
}
state.texSubImage3D(WebGL.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data);
} else {
state.texImage3D(WebGL.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat,glType, image.data);
}
}
else if (texture is FramebufferTexture) {
if (allocateMemory) {
if (useTexStorage) {
state.texStorage2D(WebGL.TEXTURE_2D, levels, glInternalFormat, image.width, image.height);
} else if (allocateMemory) {
int width = image.width, height = image.height;
for (int i = 0; i < levels; i++) {
state.texImage2D(WebGL.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null);
width >>= 1;
height >>= 1;
}
}
}
}
else {
// regular Texture (image, video, canvas)
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if (mipmaps.isNotEmpty && supportsMips) {
if (useTexStorage && allocateMemory) {
state.texStorage2D(WebGL.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height);
}
for (int i = 0, il = mipmaps.length; i < il; i++) {
mipmap = mipmaps[i];
if (useTexStorage) {
state.texSubImage2DIf(WebGL.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap);
}
else {
state.texImage2DIf(WebGL.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap);
}
}
texture.generateMipmaps = false;
}
else {
if (useTexStorage) {
if (allocateMemory) {
state.texStorage2D(WebGL.TEXTURE_2D, levels, glInternalFormat, image.width.toInt(), image.height.toInt());
}
state.texSubImage2DIf(WebGL.TEXTURE_2D, 0, 0, 0, glFormat, glType, image);
}
else {
state.texImage2DIf(WebGL.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image);
}
}
}
if (textureNeedsGenerateMipmaps(texture, supportsMips)) {
generateMipmap(textureType);
}
source.currentVersion = source.version;
if (texture.onUpdate != null) texture.onUpdate!(texture);
}
textureProperties["__version"] = texture.version;
}