copyTextureToTexture method

void copyTextureToTexture(
  1. Texture srcTexture,
  2. Texture dstTexture, {
  3. dynamic srcRegion,
  4. dynamic dstPosition,
  5. int srcLevel = 0,
  6. dynamic dstLevel,
})

Implementation

void copyTextureToTexture(Texture srcTexture, Texture dstTexture, {srcRegion, dstPosition, int srcLevel = 0, dstLevel}) {
  if ( dstLevel == null ) {
    if ( srcLevel != 0 ) {
      dstLevel = srcLevel;
      srcLevel = 0;
    }
    else {
      dstLevel = 0;
    }
  }

  // gather the necessary dimensions to copy
  int width, height, depth, minX, minY, minZ;
  int dstX, dstY, dstZ;
  final image = srcTexture is CompressedTexture ? srcTexture.mipmaps[ dstLevel ] : srcTexture.image;
  if ( srcRegion != null ) {
    width = srcRegion.max.x - srcRegion.min.x;
    height = srcRegion.max.y - srcRegion.min.y;
    depth = srcRegion is BoundingBox ? (srcRegion.max.z - srcRegion.min.z).toInt() : 1;
    minX = srcRegion.min.x;
    minY = srcRegion.min.y;
    minZ = srcRegion is BoundingBox ? srcRegion.min.z.toInt() : 0;
  }
  else {
    final levelScale = math.pow( 2, - srcLevel );
    width = ( image.width * levelScale ).floor();
    height = ( image.height * levelScale ).floor();
    if ( srcTexture is DataArrayTexture ) {
      depth = image.depth;
    }
    else if ( srcTexture is Data3DTexture ) {
      depth = ( image.depth * levelScale ).floor();
    }
    else {
      depth = 1;
    }

    minX = 0;
    minY = 0;
    minZ = 0;
  }

  if ( dstPosition != null ) {
    dstX = dstPosition.x;
    dstY = dstPosition.y;
    dstZ = dstPosition.z;
  }
  else {
    dstX = 0;
    dstY = 0;
    dstZ = 0;
  }

  // Set up the destination target
  final glFormat = utils.convert( dstTexture.format );
  final glType = utils.convert( dstTexture.type );
  int glTarget = 0;

  if ( dstTexture is Data3DTexture ) {
    textures.setTexture3D( dstTexture, 0 );
    glTarget = WebGL.TEXTURE_3D;
  }
  else if ( dstTexture is DataArrayTexture || dstTexture is CompressedArrayTexture ) {
    textures.setTexture2DArray( dstTexture, 0 );
    glTarget = WebGL.TEXTURE_2D_ARRAY;
  }
  else {
    textures.setTexture2D( dstTexture, 0 );
    glTarget = WebGL.TEXTURE_2D;
  }
  // if(kIsWeb){
  //   _gl.pixelStorei( WebGL.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY?1:0 );
  //   _gl.pixelStorei( WebGL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha?1:0 );
  //   _gl.pixelStorei( WebGL.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
  // }

  // used for copying data from cpu
  final currentUnpackRowLen = _gl.getParameter( WebGL.UNPACK_ROW_LENGTH );
  final currentUnpackImageHeight = _gl.getParameter( WebGL.UNPACK_IMAGE_HEIGHT );
  final currentUnpackSkipPixels = _gl.getParameter( WebGL.UNPACK_SKIP_PIXELS );
  final currentUnpackSkipRows = _gl.getParameter( WebGL.UNPACK_SKIP_ROWS );
  final currentUnpackSkipImages = _gl.getParameter( WebGL.UNPACK_SKIP_IMAGES );

  _gl.pixelStorei( WebGL.UNPACK_ROW_LENGTH, image.width );
  _gl.pixelStorei( WebGL.UNPACK_IMAGE_HEIGHT, image.height );
  _gl.pixelStorei( WebGL.UNPACK_SKIP_PIXELS, minX );
  _gl.pixelStorei( WebGL.UNPACK_SKIP_ROWS, minY );
  _gl.pixelStorei( WebGL.UNPACK_SKIP_IMAGES, minZ );

  // set up the src texture
  final isSrc3D = srcTexture is DataArrayTexture || srcTexture is Data3DTexture;
  final isDst3D = dstTexture is DataArrayTexture || dstTexture is Data3DTexture;
  if ( srcTexture.isDepthTexture ) {

    final srcTextureProperties = properties.get( srcTexture );
    final dstTextureProperties = properties.get( dstTexture );
    final srcRenderTargetProperties = properties.get( srcTextureProperties['__renderTarget'] );
    final dstRenderTargetProperties = properties.get( dstTextureProperties['__renderTarget'] );
    state.bindFramebuffer( WebGL.READ_FRAMEBUFFER, srcRenderTargetProperties['__webglFramebuffer'] );
    state.bindFramebuffer( WebGL.DRAW_FRAMEBUFFER, dstRenderTargetProperties['__webglFramebuffer'] );

    for (int i = 0; i < depth; i ++ ) {
      // if the source or destination are a 3d target then a layer needs to be bound
      if ( isSrc3D ) {
        _gl.framebufferTextureLayer( WebGL.READ_FRAMEBUFFER, WebGL.COLOR_ATTACHMENT0, properties.get( srcTexture )['__webglTexture'], srcLevel, minZ + i );
        _gl.framebufferTextureLayer( WebGL.DRAW_FRAMEBUFFER, WebGL.COLOR_ATTACHMENT0, properties.get( dstTexture )['__webglTexture'], dstLevel, dstZ + i );
      }

      _gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, WebGL.DEPTH_BUFFER_BIT, WebGL.NEAREST );
    }

    state.bindFramebuffer( WebGL.READ_FRAMEBUFFER, null );
    state.bindFramebuffer( WebGL.DRAW_FRAMEBUFFER, null );

  }
  else if ( srcLevel != 0 || srcTexture.isRenderTargetTexture || properties.has( srcTexture ) ) {
    // get the appropriate frame buffers
    final srcTextureProperties = properties.get( srcTexture );
    final dstTextureProperties = properties.get( dstTexture );

    // bind the frame buffer targets
    state.bindFramebuffer( WebGL.READ_FRAMEBUFFER, _srcFramebuffer );
    state.bindFramebuffer( WebGL.DRAW_FRAMEBUFFER, _dstFramebuffer );

    for (int i = 0; i < depth; i ++ ) {

      // assign the correct layers and mip maps to the frame buffers
      if ( isSrc3D ) {
        _gl.framebufferTextureLayer( WebGL.READ_FRAMEBUFFER, WebGL.COLOR_ATTACHMENT0, srcTextureProperties['__webglTexture'], srcLevel, minZ + i );
      }
      else {
        _gl.framebufferTexture2D( WebGL.READ_FRAMEBUFFER, WebGL.COLOR_ATTACHMENT0, WebGL.TEXTURE_2D, srcTextureProperties['__webglTexture'], srcLevel );
      }

      if ( isDst3D ) {
        _gl.framebufferTextureLayer( WebGL.DRAW_FRAMEBUFFER, WebGL.COLOR_ATTACHMENT0, dstTextureProperties['__webglTexture'], dstLevel, dstZ + i );
      }
      else {
        _gl.framebufferTexture2D( WebGL.DRAW_FRAMEBUFFER, WebGL.COLOR_ATTACHMENT0, WebGL.TEXTURE_2D, dstTextureProperties['__webglTexture'], dstLevel );
      }

      // copy the data using the fastest function that can achieve the copy
      if ( srcLevel != 0 ) {
        _gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, WebGL.COLOR_BUFFER_BIT, WebGL.NEAREST );
      } else if ( isDst3D ) {
        _gl.copyTexSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ + i, minX, minY, width, height );
      } else {
        _gl.copyTexSubImage2D( glTarget, dstLevel, dstX, dstY, minX, minY, width, height );
      }
    }

    // unbind read, draw buffers
    state.bindFramebuffer( WebGL.READ_FRAMEBUFFER, null );
    state.bindFramebuffer( WebGL.DRAW_FRAMEBUFFER, null );
  }
  else {

    if ( isDst3D ) {
      // copy data into the 3d texture
      if ( srcTexture is DataTexture || srcTexture is Data3DTexture ) {
        _gl.texSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );
      }
      else if ( dstTexture is CompressedArrayTexture ) {
        _gl.compressedTexSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );
      }
      else {
        _gl.texSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image );
      }
    }
    else {
      // copy data into the 2d texture
      if ( srcTexture is DataTexture ) {
        _gl.texSubImage2D( WebGL.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data );
      }
      else if ( srcTexture.isCompressedTexture ) {
        _gl.compressedTexSubImage2D( WebGL.TEXTURE_2D, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data );
      }
      else {
        _gl.texSubImage2D( WebGL.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image );
      }
    }
  }

  // reset values
  _gl.pixelStorei( WebGL.UNPACK_ROW_LENGTH, currentUnpackRowLen );
  _gl.pixelStorei( WebGL.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
  _gl.pixelStorei( WebGL.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
  _gl.pixelStorei( WebGL.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
  _gl.pixelStorei( WebGL.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );

  // Generate mipmaps only when copying level 0
  if ( dstLevel == 0 && dstTexture.generateMipmaps ) {
    _gl.generateMipmap( glTarget );
  }

  state.unbindTexture();
}