util.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /**
  2. * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { WebGLContext } from '../../mol-gl/webgl/context';
  7. import { createNullTexture, Texture } from '../../mol-gl/webgl/texture';
  8. import { ValueCell } from '../../mol-util';
  9. import { ValueSpec, AttributeSpec, UniformSpec, Values, TextureSpec } from '../../mol-gl/renderable/schema';
  10. import { Vec2 } from '../../mol-math/linear-algebra';
  11. import { ShaderCode } from '../shader-code';
  12. import { copy_frag } from '../shader/copy.frag';
  13. import { quad_vert } from '../shader/quad.vert';
  14. import { createComputeRenderItem } from '../webgl/render-item';
  15. import { ComputeRenderable, createComputeRenderable } from '../renderable';
  16. export const QuadPositions = new Float32Array([
  17. 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, // First triangle
  18. -1.0, -1.0, 1.0, -1.0, 1.0, 1.0 // Second triangle
  19. ]);
  20. export const QuadSchema = {
  21. drawCount: ValueSpec('number'),
  22. instanceCount: ValueSpec('number'),
  23. aPosition: AttributeSpec('float32', 2, 0),
  24. uQuadScale: UniformSpec('v2'),
  25. };
  26. export const QuadValues: Values<typeof QuadSchema> = {
  27. drawCount: ValueCell.create(6),
  28. instanceCount: ValueCell.create(1),
  29. aPosition: ValueCell.create(QuadPositions),
  30. uQuadScale: ValueCell.create(Vec2.create(1, 1)),
  31. };
  32. //
  33. const CopySchema = {
  34. ...QuadSchema,
  35. tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
  36. uTexSize: UniformSpec('v2'),
  37. };
  38. const CopyShaderCode = ShaderCode('copy', quad_vert, copy_frag);
  39. export type CopyRenderable = ComputeRenderable<Values<typeof CopySchema>>
  40. export function createCopyRenderable(ctx: WebGLContext, texture: Texture): CopyRenderable {
  41. const values: Values<typeof CopySchema> = {
  42. ...QuadValues,
  43. tColor: ValueCell.create(texture),
  44. uTexSize: ValueCell.create(Vec2.create(texture.getWidth(), texture.getHeight())),
  45. };
  46. const schema = { ...CopySchema };
  47. const renderItem = createComputeRenderItem(ctx, 'triangles', CopyShaderCode, schema, values);
  48. return createComputeRenderable(renderItem, values);
  49. }
  50. const SharedCopyName = 'shared-copy';
  51. export function getSharedCopyRenderable(ctx: WebGLContext, texture: Texture) {
  52. if (!ctx.namedComputeRenderables[SharedCopyName]) {
  53. ctx.namedComputeRenderables[SharedCopyName] = createCopyRenderable(ctx, createNullTexture());
  54. }
  55. const copy = ctx.namedComputeRenderables[SharedCopyName] as CopyRenderable;
  56. ValueCell.update(copy.values.tColor, texture);
  57. ValueCell.update(copy.values.uTexSize, Vec2.set(copy.values.uTexSize.ref.value, texture.getWidth(), texture.getHeight()));
  58. copy.update();
  59. return copy;
  60. }
  61. //
  62. const ReadTextureName = 'read-texture';
  63. const ReadAlphaTextureName = 'read-alpha-texture';
  64. export function readTexture(ctx: WebGLContext, texture: Texture) {
  65. const { gl, resources } = ctx;
  66. if (texture.type !== gl.UNSIGNED_BYTE) throw new Error('unsupported texture type');
  67. if (!ctx.namedFramebuffers[ReadTextureName]) {
  68. ctx.namedFramebuffers[ReadTextureName] = resources.framebuffer();
  69. }
  70. const framebuffer = ctx.namedFramebuffers[ReadTextureName];
  71. const width = texture.getWidth();
  72. const height = texture.getHeight();
  73. const array = new Uint8Array(width * height * 4);
  74. framebuffer.bind();
  75. texture.attachFramebuffer(framebuffer, 0);
  76. ctx.readPixels(0, 0, width, height, array);
  77. return { array, width, height };
  78. }
  79. export function readAlphaTexture(ctx: WebGLContext, texture: Texture) {
  80. const { gl, state, resources } = ctx;
  81. if (texture.type !== gl.UNSIGNED_BYTE) throw new Error('unsupported texture type');
  82. const width = texture.getWidth();
  83. const height = texture.getHeight();
  84. const copy = getSharedCopyRenderable(ctx, texture);
  85. state.currentRenderItemId = -1;
  86. if (!ctx.namedFramebuffers[ReadAlphaTextureName]) {
  87. ctx.namedFramebuffers[ReadAlphaTextureName] = resources.framebuffer();
  88. }
  89. const framebuffer = ctx.namedFramebuffers[ReadAlphaTextureName];
  90. framebuffer.bind();
  91. if (!ctx.namedTextures[ReadAlphaTextureName]) {
  92. ctx.namedTextures[ReadAlphaTextureName] = resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
  93. }
  94. const copyTex = ctx.namedTextures[ReadAlphaTextureName];
  95. copyTex.define(width, height);
  96. copyTex.attachFramebuffer(framebuffer, 0);
  97. state.disable(gl.CULL_FACE);
  98. state.enable(gl.BLEND);
  99. state.disable(gl.DEPTH_TEST);
  100. state.enable(gl.SCISSOR_TEST);
  101. state.depthMask(false);
  102. state.clearColor(0, 0, 0, 0);
  103. state.blendFunc(gl.ONE, gl.ONE);
  104. state.blendEquation(gl.FUNC_ADD);
  105. state.viewport(0, 0, width, height);
  106. state.scissor(0, 0, width, height);
  107. gl.clear(gl.COLOR_BUFFER_BIT);
  108. copy.render();
  109. const array = new Uint8Array(width * height * 4);
  110. ctx.readPixels(0, 0, width, height, array);
  111. return { array, width, height };
  112. }