text:
import {ChunkState, LayerChunkProgressInfo} from 'neuroglancer/chunk_manager/base';
import {Chunk, ChunkManager, ChunkSource} from 'neuroglancer/chunk_manager/frontend';
import {LayerView, VisibleLayerInfo} from 'neuroglancer/layer';
import {PerspectivePanel} from 'neuroglancer/perspective_view/panel';
import {PerspectiveViewRenderContext, PerspectiveViewRenderLayer} from 'neuroglancer/perspective_view/render_layer';
import {RenderLayer, ThreeDimensionalRenderLayerAttachmentState, update3dRenderLayerAttachment} from 'neuroglancer/renderlayer';
import {forEachVisibleSegment, getObjectKey} from 'neuroglancer/segmentation_display_state/base';
import {forEachVisibleSegmentToDraw, registerRedrawWhenSegmentationDisplayState3DChanged, SegmentationDisplayState3D, SegmentationLayerSharedObject} from 'neuroglancer/segmentation_display_state/frontend';
import {SKELETON_LAYER_RPC_ID, VertexAttributeInfo} from 'neuroglancer/skeleton/base';
import {SliceViewPanel} from 'neuroglancer/sliceview/panel';
import {SliceViewPanelRenderContext, SliceViewPanelRenderLayer} from 'neuroglancer/sliceview/renderlayer';
import {TrackableValue, WatchableValue} from 'neuroglancer/trackable_value';
import {DataType} from 'neuroglancer/util/data_type';
import {Borrowed, RefCounted} from 'neuroglancer/util/disposable';
import {mat4, vec3} from 'neuroglancer/util/geom';
import {verifyFinitePositiveFloat} from 'neuroglancer/util/json';
import {NullarySignal} from 'neuroglancer/util/signal';
import {CompoundTrackable, Trackable} from 'neuroglancer/util/trackable';
import {TrackableEnum} from 'neuroglancer/util/trackable_enum';
import {Buffer} from 'neuroglancer/webgl/buffer';
import {defineCircleShader, drawCircles, initializeCircleShader} from 'neuroglancer/webgl/circles';
import {glsl_COLORMAPS} from 'neuroglancer/webgl/colormaps';
import {GL} from 'neuroglancer/webgl/context';
import {makeTrackableFragmentMain, parameterizedEmitterDependentShaderGetter, shaderCodeWithLineDirective, WatchableShaderError} from 'neuroglancer/webgl/dynamic_shader';
import {defineLineShader, drawLines, initializeLineShader} from 'neuroglancer/webgl/lines';
import {ShaderBuilder, ShaderProgram, ShaderSamplerType} from 'neuroglancer/webgl/shader';
import {addControlsToBuilder, getFallbackBuilderState, parseShaderUiControls, setControlsInShader, ShaderControlsBuilderState, ShaderControlState} from 'neuroglancer/webgl/shader_ui_controls';
import {computeTextureFormat, getSamplerPrefixForDataType, OneDimensionalTextureAccessHelper, setOneDimensionalTextureData, TextureFormat} from 'neuroglancer/webgl/texture_access';
import {defineVertexId, VertexIdHelper} from 'neuroglancer/webgl/vertex_id';

const tempMat2 = mat4.create();

const DEFAULT_FRAGMENT_MAIN = `void main() {
  emitDefault();
}
`;

interface VertexAttributeRenderInfo extends VertexAttributeInfo {
  name: string;
  webglDataType: number;
  glslDataType: string;
}

const vertexAttributeSamplerSymbols: Symbol[] = [];

const vertexPositionTextureFormat = computeTextureFormat(new TextureFormat(), DataType.FLOAT32, 3);

class RenderHelper extends RefCounted {
  private textureAccessHelper = new OneDimensionalTextureAccessHelper('vertexData');
  private vertexIdHelper = this.registerDisposer(VertexIdHelper.get(this.gl));
  get vertexAttributes(): VertexAttributeRenderInfo[] {
    return this.base.vertexAttributes;
  }

  defineCommonShader(builder: ShaderBuilder) {
    defineVertexId(builder);
    builder.addUniform('highp vec4', 'uColor');
    builder.addUniform('highp mat4', 'uProjection');
    builder.addUniform('highp uint', 'uPickID');
  }

  edgeShaderGetter = parameterizedEmitterDependentShaderGetter(this, this.gl, {
    memoizeKey:
        {type: 'skeleton/SkeletonShaderManager/edge', vertexAttributes: this.vertexAttributes},
    fallbackParameters: this.base.fallbackShaderParameters,
    parameters: this.base.displayState.skeletonRenderingOptions.shaderControlState.builderState,
    shaderError: this.base.displayState.shaderError,
    defineShader:
        (builder: ShaderBuilder, shaderBuilderState: ShaderControlsBuilderState) => {
          if (shaderBuilderState.parseResult.errors.length !== 0) {
            throw new Error('Invalid UI control specification');
          }
          this.defineCommonShader(builder);
          this.defineAttributeAccess(builder);
          defineLineShader(builder);
          builder.addAttribute('highp uvec2', 'aVertexIndex');
          builder.addUniform('highp float', 'uLineWidth');
          let vertexMain = `
highp vec3 vertexA = readAttribute0(aVertexIndex.x);
highp vec3 vertexB = readAttribute0(aVertexIndex.y);
emitLine(uProjection, vertexA, vertexB, uLineWidth);
highp uint lineEndpointIndex = getLineEndpointIndex();
highp uint vertexIndex = aVertexIndex.x * lineEndpointIndex + aVertexIndex.y * (1u - lineEndpointIndex);
`;

          builder.addFragmentCode(`
vec4 segmentColor() {
  return uColor;
}
void emitRGB(vec3 color) {
  emit(vec4(color * uColor.a, uColor.a * getLineAlpha() * ${
              this.getCrossSectionFadeFactor()}), uPickID);
}
void emitDefault() {
  emit(vec4(uColor.rgb, uColor.a * getLineAlpha() * ${this.getCrossSectionFadeFactor()}), uPickID);
}
`);
          builder.addFragmentCode(glsl_COLORMAPS);
          const {vertexAttributes} = this;
          const numAttributes = vertexAttributes.length;
          for (let i = 1; i < numAttributes; ++i) {
            const info = vertexAttributes[i];
            builder.addVarying(`highp ${info.glslDataType}`, `vCustom${i}`);
            vertexMain += `vCustom${i} = readAttribute${i}(vertexIndex);\n`;
            builder.addFragmentCode(`#define ${info.name} vCustom${i}\n`);
          }
          builder.setVertexMain(vertexMain);
          addControlsToBuilder(shaderBuilderState, builder);
          builder.setFragmentMainFunction(
              shaderCodeWithLineDirective(shaderBuilderState.parseResult.code));
        },
  });

  nodeShaderGetter = parameterizedEmitterDependentShaderGetter(this, this.gl, {
    memoizeKey:
        {type: 'skeleton/SkeletonShaderManager/node', vertexAttributes: this.vertexAttributes},
    fallbackParameters: this.base.fallbackShaderParameters,
    parameters: this.base.displayState.skeletonRenderingOptions.shaderControlState.builderState,
    shaderError: this.base.displayState.shaderError,
    defineShader:
        (builder: ShaderBuilder, shaderBuilderState: ShaderControlsBuilderState) => {
          if (shaderBuilderState.parseResult.errors.length !== 0) {
            throw new Error('Invalid UI control specification');
          }
          this.defineCommonShader(builder);
          this.defineAttributeAccess(builder);
          defineCircleShader(builder, /*crossSectionFade=*/ this.targetIsSliceView);
          builder.addUniform('highp float', 'uNodeDiameter');
          let vertexMain = `
highp uint vertexIndex = uint(gl_InstanceID);
highp vec3 vertexPosition = readAttribute0(vertexIndex);
emitCircle(uProjection * vec4(vertexPosition, 1.0), uNodeDiameter, 0.0);
`;

          builder.addFragmentCode(`
vec4 segmentColor() {
  return uColor;
}
void emitRGBA(vec4 color) {
  vec4 borderColor = color;
  emit(getCircleColor(color, borderColor), uPickID);
}
void emitRGB(vec3 color) {
  emitRGBA(vec4(color, 1.0));
}
void emitDefault() {
  emitRGBA(uColor);
}
`);
          builder.addFragmentCode(glsl_COLORMAPS);
          const {vertexAttributes} = this;
          const numAttributes = vertexAttributes.length;
          for (let i = 1; i < numAttributes; ++i) {
            const info = vertexAttributes[i];
            builder.addVarying(`highp ${info.glslDataType}`, `vCustom${i}`);
            vertexMain += `vCustom${i} = readAttribute${i}(vertexIndex);\n`;
            builder.addFragmentCode(`#define ${info.name} vCustom${i}\n`);
          }
          builder.setVertexMain(vertexMain);
          addControlsToBuilder(shaderBuilderState, builder);
          builder.setFragmentMainFunction(
              shaderCodeWithLineDirective(shaderBuilderState.parseResult.code));
        },
  });

  get gl(): GL {
    return this.base.gl;
  }

  constructor(public base: SkeletonLayer, public targetIsSliceView: boolean) {
    super();
  }

  defineAttributeAccess(builder: ShaderBuilder) {
    const {textureAccessHelper} = this;
    textureAccessHelper.defineShader(builder);
    const numAttributes = this.vertexAttributes.length;
    for (let j = vertexAttributeSamplerSymbols.length; j < numAttributes; ++j) {
      vertexAttributeSamplerSymbols[j] = Symbol(`SkeletonShader.vertexAttributeTextureUnit${j}`);
    }
    this.vertexAttributes.forEach((info, i) => {
      builder.addTextureSampler(
          `${getSamplerPrefixForDataType(info.dataType)}sampler2D` as ShaderSamplerType,
          `uVertexAttributeSampler${i}`, vertexAttributeSamplerSymbols[i]);
      builder.addVertexCode(textureAccessHelper.getAccessor(
          `readAttribute${i}`, `uVertexAttributeSampler${i}`, info.dataType, info.numComponents));
    });
  }

  getCrossSectionFadeFactor() {
    if (this.targetIsSliceView) {
      return `(clamp(1.0 - 2.0 * abs(0.5 - gl_FragCoord.z), 0.0, 1.0))`;
    } else {
      return `(1.0)`;
    }
  }

  beginLayer(
      gl: GL, shader: ShaderProgram,
      renderContext: SliceViewPanelRenderContext|PerspectiveViewRenderContext, modelMatrix: mat4) {
    const {viewProjectionMat} = renderContext.projectionParameters;
    let mat = mat4.multiply(tempMat2, viewProjectionMat, modelMatrix);
    gl.uniformMatrix4fv(shader.uniform('uProjection'), false, mat);
    this.vertexIdHelper.enable();
  }

  setColor(gl: GL, shader: ShaderProgram, color: vec3) {
    gl.uniform4fv(shader.uniform('uColor'), color);
  }

  setPickID(gl: GL, shader: ShaderProgram, pickID: number) {
    gl.uniform1ui(shader.uniform('uPickID'), pickID);
  }

  drawSkeleton(
      gl: GL, edgeShader: ShaderProgram, nodeShader: ShaderProgram|null,
      skeletonChunk: SkeletonChunk, projectionParameters: {width: number, height: number}) {
    const {vertexAttributes} = this;
    const numAttributes = vertexAttributes.length;
    const {vertexAttributeTextures} = skeletonChunk;
    for (let i = 0; i < numAttributes; ++i) {
      const textureUnit = WebGL2RenderingContext.TEXTURE0 +
          edgeShader.textureUnit(vertexAttributeSamplerSymbols[i]);
      gl.activeTexture(textureUnit);
      gl.bindTexture(WebGL2RenderingContext.TEXTURE_2D, vertexAttributeTextures[i]);
    }

    // Draw edges
    {
      edgeShader.bind();
      const aVertexIndex = edgeShader.attribute('aVertexIndex');
      skeletonChunk.indexBuffer.bindToVertexAttribI(
          aVertexIndex, 2, WebGL2RenderingContext.UNSIGNED_INT);
      gl.vertexAttribDivisor(aVertexIndex, 1);
      initializeLineShader(edgeShader, projectionParameters, this.targetIsSliceView ? 1.0 : 0.0);
      drawLines(gl, 1, skeletonChunk.numIndices / 2);
      gl.vertexAttribDivisor(aVertexIndex, 0);
      gl.disableVertexAttribArray(aVertexIndex);
    }

    if (nodeShader !== null) {
      nodeShader.bind();
      initializeCircleShader(
          nodeShader, projectionParameters,
          {featherWidthInPixels: this.targetIsSliceView ? 1.0 : 0.0});
      drawCircles(nodeShader.gl, 2, skeletonChunk.numVertices);
    }
  }

  endLayer(gl: GL, shader: ShaderProgram) {
    const {vertexAttributes} = this;
    const numAttributes = vertexAttributes.length;
    for (let i = 0; i < numAttributes; ++i) {
      let curTextureUnit =
          shader.textureUnit(vertexAttributeSamplerSymbols[i]) + WebGL2RenderingContext.TEXTURE0;
      gl.activeTexture(curTextureUnit);
      gl.bindTexture(gl.TEXTURE_2D, null);
    }
    this.vertexIdHelper.disable();
  }
}

export enum SkeletonRenderMode {
  LINES,
  LINES_AND_POINTS,
}

export class TrackableSkeletonRenderMode extends TrackableEnum<SkeletonRenderMode> {
  constructor(value: SkeletonRenderMode, defaultValue: SkeletonRenderMode = value) {
    super(SkeletonRenderMode, value, defaultValue);
  }
}

export class TrackableSkeletonLineWidth extends TrackableValue<number> {
  constructor(value: number, defaultValue: number = value) {
    super(value, verifyFinitePositiveFloat, defaultValue);
  }
}

export interface ViewSpecificSkeletonRenderingOptions {
  mode: TrackableSkeletonRenderMode;
  lineWidth: TrackableSkeletonLineWidth;
}

export class SkeletonRenderingOptions implements Trackable {
  private compound = new CompoundTrackable();
  get changed() {
    return this.compound.changed;
  }

  shader = makeTrackableFragmentMain(DEFAULT_FRAGMENT_MAIN);
  shaderControlState = new ShaderControlState(this.shader);
  params2d: ViewSpecificSkeletonRenderingOptions = {
    mode: new TrackableSkeletonRenderMode(SkeletonRenderMode.LINES_AND_POINTS),
    lineWidth: new TrackableSkeletonLineWidth(2),
  };
  params3d: ViewSpecificSkeletonRenderingOptions = {
    mode: new TrackableSkeletonRenderMode(SkeletonRenderMode.LINES),
    lineWidth: new TrackableSkeletonLineWidth(1),
  };

  constructor() {
    const {compound} = this;
    compound.add('shader', this.shader);
    compound.add('shaderControls', this.shaderControlState);
    compound.add('mode2d', this.params2d.mode);
    compound.add('lineWidth2d', this.params2d.lineWidth);
    compound.add('mode3d', this.params3d.mode);
    compound.add('lineWidth3d', this.params3d.lineWidth);
  }

  reset() {
    this.compound.reset();
  }

  restoreState(obj: any) {
    if (obj === undefined) return;
    this.compound.restoreState(obj);
  }

  toJSON(): any {
    const obj = this.compound.toJSON();
    for (const v of Object.values(obj)) {
      if (v !== undefined) return obj;
    }
    return undefined;
  }
}

export interface SkeletonLayerDisplayState extends SegmentationDisplayState3D {
  shaderError: WatchableShaderError;
  skeletonRenderingOptions: SkeletonRenderingOptions;
}

export class SkeletonLayer extends RefCounted {
  layerChunkProgressInfo = new LayerChunkProgressInfo();
  redrawNeeded = new NullarySignal();
  private sharedObject: SegmentationLayerSharedObject;
  vertexAttributes: VertexAttributeRenderInfo[];
  fallbackShaderParameters =
      new WatchableValue(getFallbackBuilderState(parseShaderUiControls(DEFAULT_FRAGMENT_MAIN)));

  get visibility() {
    return this.sharedObject.visibility;
  }

  constructor(
      public chunkManager: ChunkManager, public source: SkeletonSource,
      public displayState: SkeletonLayerDisplayState) {
    super();

    registerRedrawWhenSegmentationDisplayState3DChanged(displayState, this);
    this.displayState.shaderError.value = undefined;
    const {skeletonRenderingOptions: renderingOptions} = displayState;
    this.registerDisposer(renderingOptions.shader.changed.add(() => {
      this.displayState.shaderError.value = undefined;
      this.redrawNeeded.dispatch();
    }));
    let sharedObject = this.sharedObject = this.registerDisposer(
        new SegmentationLayerSharedObject(chunkManager, displayState, this.layerChunkProgressInfo));
    sharedObject.RPC_TYPE_ID = SKELETON_LAYER_RPC_ID;
    sharedObject.initializeCounterpartWithChunkManager({
      'source': source.addCounterpartRef(),
    });

    const vertexAttributes = this.vertexAttributes = [vertexPositionAttribute];

    for (let [name, info] of source.vertexAttributes) {
      vertexAttributes.push({
        name,
        dataType: info.dataType,
        numComponents: info.numComponents,
        webglDataType: getWebglDataType(info.dataType),
        glslDataType: info.numComponents > 1 ? `vec${info.numComponents}` : 'float',
      });
    }
  }

  get gl() {
    return this.chunkManager.chunkQueueManager.gl;
  }

  draw(
      renderContext: SliceViewPanelRenderContext|PerspectiveViewRenderContext, layer: RenderLayer,
      renderHelper: RenderHelper, renderOptions: ViewSpecificSkeletonRenderingOptions,
      attachment: VisibleLayerInfo<LayerView, ThreeDimensionalRenderLayerAttachmentState>) {
    let lineWidth = renderOptions.lineWidth.value;
    const {gl, source, displayState} = this;
    if (displayState.objectAlpha.value <= 0.0) {
      // Skip drawing.
      return;
    }
    const modelMatrix = update3dRenderLayerAttachment(
        displayState.transform.value, renderContext.projectionParameters.displayDimensionRenderInfo,
        attachment);
    if (modelMatrix === undefined) return;
    let pointDiameter: number;
    if (renderOptions.mode.value === SkeletonRenderMode.LINES_AND_POINTS) {
      pointDiameter = Math.max(5, lineWidth * 2);
    } else {
      pointDiameter = lineWidth;
    }

    const edgeShaderResult = renderHelper.edgeShaderGetter(renderContext.emitter);
    const nodeShaderResult = renderHelper.nodeShaderGetter(renderContext.emitter);
    const {shader: edgeShader, parameters: edgeShaderParameters} = edgeShaderResult;
    const {shader: nodeShader, parameters: nodeShaderParameters} = nodeShaderResult;
    if (edgeShader === null || nodeShader === null) {
      // Shader error, skip drawing.
      return;
    }

    const {shaderControlState} = this.displayState.skeletonRenderingOptions;

    edgeShader.bind();
    renderHelper.beginLayer(gl, edgeShader, renderContext, modelMatrix);
    setControlsInShader(
        gl, edgeShader, shaderControlState, edgeShaderParameters.parseResult.controls);
    gl.uniform1f(edgeShader.uniform('uLineWidth'), lineWidth!);

    nodeShader.bind();
    renderHelper.beginLayer(gl, nodeShader, renderContext, modelMatrix);
    gl.uniform1f(nodeShader.uniform('uNodeDiameter'), pointDiameter);
    setControlsInShader(
        gl, nodeShader, shaderControlState, nodeShaderParameters.parseResult.controls);

    const skeletons = source.chunks;

    forEachVisibleSegmentToDraw(
        displayState, layer, renderContext.emitColor,
        renderContext.emitPickID ? renderContext.pickIDs : undefined,
        (objectId, color, pickIndex) => {
          const key = getObjectKey(objectId);
          const skeleton = skeletons.get(key);
          if (skeleton === undefined || skeleton.state !== ChunkState.GPU_MEMORY) {
            return;
          }
          if (color !== undefined) {
            edgeShader.bind();
            renderHelper.setColor(gl, edgeShader, <vec3><Float32Array>color);
            nodeShader.bind();
            renderHelper.setColor(gl, nodeShader, <vec3><Float32Array>color);
          }
          if (pickIndex !== undefined) {
            edgeShader.bind();
            renderHelper.setPickID(gl, edgeShader, pickIndex);
            nodeShader.bind();
            renderHelper.setPickID(gl, nodeShader, pickIndex);
          }
          renderHelper.drawSkeleton(
              gl, edgeShader, nodeShader, skeleton, renderContext.projectionParameters);
        });
    renderHelper.endLayer(gl, edgeShader);
  }

  isReady() {
    const {source, displayState} = this;
    if (displayState.objectAlpha.value <= 0.0) {
      // Skip drawing.
      return true;
    }

    const skeletons = source.chunks;

    let ready = true;

    forEachVisibleSegment(displayState.segmentationGroupState.value, objectId => {
      const key = getObjectKey(objectId);
      const skeleton = skeletons.get(key);
      if (skeleton === undefined || skeleton.state !== ChunkState.GPU_MEMORY) {
        ready = false;
        return;
      }
    });
    return ready;
  }
}

export class PerspectiveViewSkeletonLayer extends PerspectiveViewRenderLayer {
  private renderHelper = this.registerDisposer(new RenderHelper(this.base, false));
  private renderOptions = this.base.displayState.skeletonRenderingOptions.params3d;
  constructor(public base: SkeletonLayer) {
    super();
    this.layerChunkProgressInfo = base.layerChunkProgressInfo;
    this.registerDisposer(base);
    this.registerDisposer(base.redrawNeeded.add(this.redrawNeeded.dispatch));
    const {renderOptions} = this;
    this.registerDisposer(renderOptions.mode.changed.add(this.redrawNeeded.dispatch));
    this.registerDisposer(renderOptions.lineWidth.changed.add(this.redrawNeeded.dispatch));
    this.registerDisposer(base.visibility.add(this.visibility));
  }
  get gl() {
    return this.base.gl;
  }

  get isTransparent() {
    return this.base.displayState.objectAlpha.value < 1.0;
  }

  draw(
      renderContext: PerspectiveViewRenderContext,
      attachment: VisibleLayerInfo<PerspectivePanel, ThreeDimensionalRenderLayerAttachmentState>) {
    if (!renderContext.emitColor && renderContext.alreadyEmittedPickID) {
      // No need for a separate pick ID pass.
      return;
    }
    this.base.draw(renderContext, this, this.renderHelper, this.renderOptions, attachment);
  }

  isReady() {
    return this.base.isReady();
  }
}

export class SliceViewPanelSkeletonLayer extends SliceViewPanelRenderLayer {
  private renderHelper = this.registerDisposer(new RenderHelper(this.base, true));
  private renderOptions = this.base.displayState.skeletonRenderingOptions.params2d;
  constructor(public base: SkeletonLayer) {
    super();
    this.layerChunkProgressInfo = base.layerChunkProgressInfo;
    this.registerDisposer(base);
    const {renderOptions} = this;
    this.registerDisposer(renderOptions.mode.changed.add(this.redrawNeeded.dispatch));
    this.registerDisposer(renderOptions.lineWidth.changed.add(this.redrawNeeded.dispatch));
    this.registerDisposer(base.redrawNeeded.add(this.redrawNeeded.dispatch));
    this.registerDisposer(base.visibility.add(this.visibility));
  }
  get gl() {
    return this.base.gl;
  }

  draw(
      renderContext: SliceViewPanelRenderContext,
      attachment: VisibleLayerInfo<SliceViewPanel, ThreeDimensionalRenderLayerAttachmentState>) {
    this.base.draw(renderContext, this, this.renderHelper, this.renderOptions, attachment);
  }

  isReady() {
    return this.base.isReady();
  }
}

function getWebglDataType(dataType: DataType) {
  switch (dataType) {
    case DataType.FLOAT32:
      return WebGL2RenderingContext.FLOAT;
    default:
      throw new Error(`Data type not supported by WebGL: ${DataType[dataType]}`);
  }
}

const vertexPositionAttribute: VertexAttributeRenderInfo = {
  dataType: DataType.FLOAT32,
  numComponents: 3,
  name: '',
  webglDataType: WebGL2RenderingContext.FLOAT,
  glslDataType: 'vec3',
};

export class SkeletonChunk extends Chunk {
  source: SkeletonSource;
  vertexAttributes: Uint8Array;
  indices: Uint32Array;
  indexBuffer: Buffer;
  numIndices: number;
  numVertices: number;
  vertexAttributeOffsets: Uint32Array;
  vertexAttributeTextures: (WebGLTexture|null)[];

  constructor(source: SkeletonSource, x: any) {
    super(source);
    this.vertexAttributes = x['vertexAttributes'];
    let indices = this.indices = x['indices'];
    this.numVertices = x['numVertices'];
    this.vertexAttributeOffsets = x['vertexAttributeOffsets'];
    this.numIndices = indices.length;
  }

  copyToGPU(gl: GL) {
    super.copyToGPU(gl);
    const {attributeTextureFormats} = this.source;
    const {vertexAttributes, vertexAttributeOffsets} = this;
    const vertexAttributeTextures: (WebGLTexture|null)[] = this.vertexAttributeTextures = [];
    for (let i = 0, numAttributes = vertexAttributeOffsets.length; i < numAttributes; ++i) {
      const texture = gl.createTexture();
      gl.bindTexture(WebGL2RenderingContext.TEXTURE_2D, texture);
      setOneDimensionalTextureData(
          gl, attributeTextureFormats[i],
          vertexAttributes.subarray(
              vertexAttributeOffsets[i],
              i + 1 !== numAttributes ? vertexAttributeOffsets[i + 1] : vertexAttributes.length));
      vertexAttributeTextures[i] = texture;
    }
    gl.bindTexture(WebGL2RenderingContext.TEXTURE_2D, null);
    this.indexBuffer = Buffer.fromData(
        gl, this.indices, WebGL2RenderingContext.ARRAY_BUFFER, WebGL2RenderingContext.STATIC_DRAW);
  }

  freeGPUMemory(gl: GL) {
    super.freeGPUMemory(gl);
    const {vertexAttributeTextures} = this;
    for (const texture of vertexAttributeTextures) {
      gl.deleteTexture(texture);
    }
    vertexAttributeTextures.length = 0;
    this.indexBuffer.dispose();
  }
}

const emptyVertexAttributes = new Map<string, VertexAttributeInfo>();

function getAttributeTextureFormats(vertexAttributes: Map<string, VertexAttributeInfo>):
    TextureFormat[] {
  const attributeTextureFormats: TextureFormat[] = [vertexPositionTextureFormat];
  for (const info of vertexAttributes.values()) {
    attributeTextureFormats.push(
        computeTextureFormat(new TextureFormat(), info.dataType, info.numComponents));
  }
  return attributeTextureFormats;
}

export interface SkeletonSourceOptions {}

export class SkeletonSource extends ChunkSource {
  private attributeTextureFormats_?: TextureFormat[];

  get attributeTextureFormats() {
    let attributeTextureFormats = this.attributeTextureFormats_;
    if (attributeTextureFormats === undefined) {
      attributeTextureFormats = this.attributeTextureFormats_ =
          getAttributeTextureFormats(this.vertexAttributes);
    }
    return attributeTextureFormats;
  }

  chunks: Map<string, SkeletonChunk>;
  getChunk(x: any) {
    return new SkeletonChunk(this, x);
  }

  constructor(chunkManager: Borrowed<ChunkManager>, options: SkeletonSourceOptions) {
    super(chunkManager, options);
  }

  get vertexAttributes(): Map<string, VertexAttributeInfo> {
    return emptyVertexAttributes;
  }
}

redpajama_set_name: RedPajamaGithub


It's awesome to see how Linden is taking shape in such a short time. Some new designers (Letitia and Lare) have made Linden their home. The Woodlady designs and produces various handmade products from recycled wood. Because of their environmental consciousness, with a strong focus on recycling and up-cycling, Woodlady embraces sustainable design. Upon request they manufacture custom made products, creatively transforming the products to complement a variety of interiors.
You can find them sharing space with the already famous Ceramic Factory in 4th Avenue Linden. Or find them on Facebook or twitter @woodladySA or hello@woodlady.co.za.


text:
Inspiring excellence.
Transforming lives.
Faculty Home Page
Faculty Booklet
Rated Researchers
Research at the UFS
Faculty Calendar
Department Home Page
Division Home Page
Astrophysics Research Facilities
Boyden Observatory and Science Centre
SAAO
HartRAO
ASSA (Bfn)
Friends of Boyden
Naval Hill Planetarium
Urgent Announcement
Visit our registration webpage for the 2021 Registration Information.
Faculty of Natural and Agricultural Sciences Home/
Physics Home/
Boyden Observatory Home
Boyden Observatory is situated 26 kilometres east of the city of Bloemfontein in South Africa. In addition to its role as an astronomical research station, Boyden Observatory also has a Science Education Centre, under the auspices of the University of the Free State and with the support of its donors and the Friends of Boyden.
Boyden is committed to bringing a high standard of scientific education and exposure to the public and youth. A Boyden Educational Assistant programme is in place, consisting partly of members from the Bloemfontein Centre of the Astronomical Society of Southern Africa (ASSA), which assures a high level of quality during presentations and telescope observations. The observatory has an active educational programme and is one of the most publically accessible observatories in the country, providing a memorable experience to all its visitors, including school groups from all backgrounds.
The observatory hosts frequent public events in the form of open evenings and a regular weekly event on selected Fridays. In addition, groups and schools can also visit Boyden on appointment during the week and weekends. Visitors can choose from a variety of digital presentations, ranging from topics such as human and robotic spaceflight, planetary exploration, astronomical themes for all age groups (e.g. The Solar System, Mars, Zoom Journey to the Stars etc.).
In addition to open evenings for the public, groups of people, organisations, and schools are welcome to arrange their own visits to Boyden. International amateur astronomers or tourists are also welcome to visit the observatory.
Elfrieda Lötter: Marketing Manager
E:lottere@ufs.ac.za
Apply Visit Donate Tenders Vacancies
© 2000 - 2020 UFS, Bloemfontein Terms and Conditions Privacy Policy
© 2000 - 2020 UFS, Bloemfontein

redpajama_set_name: RedPajamaCommonCrawl


Chinese New Year dinner with my family at Kota Kemuning last week.
A sumptuous dinner I can say! I forgot the name of the dishes, but thumbs up for every single dishes!
Overall, I feel the price is above average, there are two tables and the total amount of the bill is approximately RM1200++. Average of RM60 per pax.


text:
Q: "grew warmer" vs. "became warmer" Can "grew warmer" be used as a replacement for "became warmer" anywhere? I've started to think of the phrase "grew warmer" and it seems kind of strange. Things can become warm, but it sounds strange to say that some things grow warm. Like for an inanimate object that doesn't grow, how is it ok to say that it grows warm? Can someone explain this?

A: Both grew and became are perfectly acceptable.
Grew, as the past tense of grow, may be defined as:

To expand; gain; to increase by amount or degree.

While became, as the past tense of become, may be defined as:

To grow or come to be.

Grew may simply be considered the more figurative of the two.

A: "Grew" is perfectly fine here; it is simply metaphorical.

the kettle was boiling.

is perfectly fine. For the kettle to grow warm is also fine.

redpajama_set_name: RedPajamaStackExchange


John Hawkes, Logan Lerman and Sarah Bolger are set to star in End of Sentence, the feature debut from director Elfar Adalsteins.
Former House executive producer Katie Jacobs is taking the indie route with another medical drama project, Dr. Del, which she is producing with Nick Wechsler. John Hawkes is set to star in the pilot, developed and to be filmed without the backing of a studio.


This is super adorable - I love the light effects and the soft atmosphere!
Okay I'm jealous because this is really good. I've seen some of your other work and man it's awesome but this is my favorite.
A thought for the viewer. Are the girl and her companion denizens of this dreamlike realm with their slumber only adding to its richness?
Are their dreams filled with the wonderment that surrounds them or does their sleep contain images of the "magic" our own world. For what is commonplace to us may hold unyielding interest to them.
Perhaps they are dreamers from some other plane of existence. Their souls being provided with forms that are inaccessible in their own realm, but will inrich their experience in this world.
When they sleep here does the slumber return them their? Or does it simply replenish them so they may continue with the dream at hand?
Whether these questions I present to you hover close to the truth of the artwork or obstain from it entirely. Can only be answered by he or she that painted it.
Oops . Dont know were my mind was.
Very serene. Peaceful and wonderful to look at.


Hello people, we are happy to see your interest in our website and you have decided to click on this page. You will find everything related to Word Merge Daily Puzzle November 12 2016 Answers answers and solutions. The plot of it is very engaging and will hook you up for very long time. Our site offers all the answers of Word Merge Daily and we also have solutions of Spell n Link Answers.
This Word Merge Daily is an amazing game that you never want to leave it for a second. You can certainly get more solutions and relevant answers for your daily use. To get more solutions you need to use Word Merge Daily Puzzle November 12 2016 Answers, Word Merge Daily Puzzle November 12 2016 Answers, Word Bubbles November 30 2016 Answers and Word Trace Daily Puzzle November 29 2016 Answers. We appreciate your visit to our website and stay up to date to know more answers.


text:
from __future__ import unicode_literals

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('lexicon', '0105_auto_20160824_1309'),
    ]

    operations = [
        migrations.AddField(
            model_name='nexusexport',
            name='_constraintsData',
            field=models.BinaryField(null=True),
        ),
    ]