@awayjs/renderer
Version:
Renderer for AwayJS
800 lines (655 loc) • 25.3 kB
text/typescript
import { Box, Matrix, Rectangle, Sphere, Vector3D } from '@awayjs/core';
import { AttributesBuffer, AttributesView, Byte4Attributes, Float1Attributes } from '@awayjs/stage';
import { View, PickingCollision, ContainerNode } from '@awayjs/view';
import { ElementsBase, THullImplId } from './ElementsBase';
const TMP_BBOX = new Box();
/**
* @class LineElements
*/
export class LineElements extends ElementsBase {
public static assetType: string = '[asset LineElements]';
private _positions: AttributesView;
private _thickness: Float1Attributes;
private _colors: Byte4Attributes;
private _thicknessScale: Vector3D = new Vector3D();
//used for hittesting geometry
public hitTestCache: Object = new Object();
public half_thickness: number = 5;
public scaleMode: LineScaleMode = LineScaleMode.HAIRLINE;
public dimension: number = 3;
public getThicknessScale(node: ContainerNode, strokeFlag: boolean): Vector3D {
if (!strokeFlag && this.scaleMode == LineScaleMode.HAIRLINE) {
this._thicknessScale.identity();
} else {
if (node)
this._thicknessScale.copyFrom(node.getMatrix3D().decompose()[2]);
else
this._thicknessScale.identity();
this._thicknessScale.x *= node.view.focalLength * node.view.pixelRatio / 1000;
this._thicknessScale.y *= node.view.focalLength / 1000;
if (this.scaleMode == LineScaleMode.NORMAL) {
this._thicknessScale.x = (!strokeFlag || this.half_thickness * this._thicknessScale.x > 0.5)
? this.half_thickness
: this._thicknessScale.x ? 0.5 / this._thicknessScale.x : 0;
this._thicknessScale.y = (!strokeFlag || this.half_thickness * this._thicknessScale.y > 0.5)
? this.half_thickness
: this._thicknessScale.y ? 0.5 / this._thicknessScale.y : 0;
} else if (this.scaleMode == LineScaleMode.HAIRLINE) {
this._thicknessScale.x = this._thicknessScale.x ? 0.5 / this._thicknessScale.x : 0;
this._thicknessScale.y = this._thicknessScale.y ? 0.5 / this._thicknessScale.y : 0;
}
}
return this._thicknessScale;
}
/**
*
* @returns {string}
*/
public get assetType(): string {
return LineElements.assetType;
}
/**
*
*/
public get positions(): AttributesView {
return this._positions;
}
/**
*
*/
public get thickness(): Float1Attributes {
return this._thickness;
}
/**
*
*/
public get colors(): Byte4Attributes {
if (!this._colors)
this.setColors(this._colors);
return this._colors;
}
/**
*
*/
constructor(concatenatedBuffer: AttributesBuffer = null) {
super(concatenatedBuffer);
this.dimension = Settings.LINE_BUFFER_DIM;
this._positions = new AttributesView(Float32Array, this.dimension * 2, concatenatedBuffer);
}
public prepareScale9(
bounds: Rectangle,
grid: Rectangle,
clone: boolean,
_emitUV?: boolean,
_uvMatrix?: Matrix
): LineElements {
return LineElementsUtils.prepareScale9(this, bounds, grid, clone);
}
public updateScale9(scaleX: number, scaleY: number) {
if (!this.scale9Indices) {
return;
}
LineElementsUtils.updateScale9(
this,
this.originalScale9Bounds,
scaleX,
scaleY,
false,
false
);
}
public getBoxBounds(
node: ContainerNode = null,
strokeFlag: boolean = false,
matrix3D: Matrix3D = null,
cache: Box = null,
target: Box = null,
count: number = 0,
offset: number = 0): Box
// eslint-disable-next-line brace-style
{
count = count || this._numElements || this._numVertices;
this._boundsRequests++;
if (
Settings.ENABLE_CONVEX_BOUNDS
&& this._boundsRequests > Settings.CONVEX_MIN_REQUIEST_FOR_BUILD
&& count > Settings.POINTS_COUNT_FOR_CONVEX
&& !this.isDynamic // diable for dynamic elements, beacause a reconstructed every frame
) {
if (
!this._convexHull
|| this._convexHull.count !== count// drop hull data, invalid
|| this._convexHull.offset !== offset // drop hull data, invalid
) {
this._convexHull = <THullImplId> ConvexHullUtils.fromAttribute(
this.positions,
this.indices,
3, // line elements has to many attirbutes, tick every 3
count,
offset
);
if (this._convexHull) {
this._convexHull.offset = offset;
this._convexHull.count = count;
console.debug(
'[Line] Build convex for:', this.id,
'vertex / hull', (count / this._convexHull.points.length) | 0);
}
}
if (this._convexHull) {
const tmp = TMP_BBOX;
tmp.identity();
const box = ConvexHullUtils.createBox(
this._convexHull,
matrix3D,
null,
tmp
);
LineElementsUtils.mergeThinkness(
box,
this.getThicknessScale(node, strokeFlag),
matrix3D
);
return tmp.union(target, target || cache);
}
}
return LineElementsUtils.getBoxBounds(
this.positions,
this.indices,
matrix3D,
this.getThicknessScale(node, strokeFlag),
cache,
target,
count,
offset);
}
public getSphereBounds(
center: Vector3D,
matrix3D: Matrix3D = null,
strokeFlag: boolean = false,
cache: Sphere = null,
target: Sphere = null,
count: number = 0,
offset: number = 0): Sphere
// eslint-disable-next-line brace-style
{
return LineElementsUtils.getSphereBounds(
this.positions, center, matrix3D, cache, target, count || this._numVertices, offset);
}
public hitTestPoint(
node: ContainerNode,
x: number, y: number, z: number,
box: Box,
count: number = 0,
offset: number = 0,
idx_count: number = 0,
idx_offset: number = 0): boolean
// eslint-disable-next-line brace-style
{
const scale: Vector3D = this.getThicknessScale(node, true);
const thickness: number = (scale.x + scale.y) / 2;//approx hack for now
return LineElementsUtils.hitTest(
x, y, 0, thickness, box, this, count || this._numElements || this._numVertices, offset);
}
/**
*
*/
public setPositions(array: Array<number>, offset?: number): void;
public setPositions(arrayBufferView: ArrayBufferView, offset?: number): void;
public setPositions(attributesView: AttributesView, offset?: number): void;
public setPositions(values: any, offset: number = 0): void {
const dimension = this.dimension * 2;
if (values instanceof AttributesView) {
this.clearVertices(this._positions);
this._positions = <AttributesView> values;
} else if (values) {
let i: number = 0;
let j: number = 0;
let index: number = 0;
const positions: Float32Array = new Float32Array(dimension * 4 * (values.length / 6));
const indices: Uint16Array = new Uint16Array(values.length);
//oders incoming startpos/endpos values to look like the following 6-dimensional attributes view:
//startpos x, y, z endpos x, y, z
//endpos x, y, z startpos x, y, z
//startpos x, y, z endpos x, y, z
//endpos x, y, z startpos x, y, z
while (i < values.length) {
if (index / dimension & 1) { //if number is odd, reverse the order of startpos/endpos
positions[index++] = values[i + 3];
positions[index++] = values[i + 4];
dimension === 6 && (positions[index++] = values[i + 5]);
positions[index++] = values[i];
positions[index++] = values[i + 1];
dimension === 6 && (positions[index++] = values[i + 2]);
} else {
positions[index++] = values[i];
positions[index++] = values[i + 1];
dimension === 6 && (positions[index++] = values[i + 2]);
positions[index++] = values[i + 3];
positions[index++] = values[i + 4];
dimension === 6 && (positions[index++] = values[i + 5]);
}
//index += 6;
if (++j == 4) {
const o: number = index / dimension - 4;
indices.set([o, o + 1, o + 2, o + 3, o + 2, o + 1], i);
j = 0;
i += 6;
}
}
this._positions.set(positions, offset * 4);
this.setIndices(indices, offset);
} else {
this.clearVertices(this._positions);
this._positions = new AttributesView(Float32Array, dimension, this._concatenatedBuffer);
}
this._numVertices = this._positions.count;
this.invalidateVertices(this._positions);
this._verticesDirty[this._positions.id] = false;
}
/**
* Updates the thickness.
*/
public setThickness(array: Array<number>, offset?: number);
public setThickness(float32Array: Float32Array, offset?: number);
public setThickness(float1Attributes: Float1Attributes, offset?: number);
public setThickness(values: any, offset: number = 0): void {
if (values instanceof Float1Attributes) {
this._thickness = <Float1Attributes> values;
} else if (values) {
if (!this._thickness)
this._thickness = new Float1Attributes(this._concatenatedBuffer);
let i: number = 0;
let j: number = 0;
let index: number = 0;
const thickness: Float32Array = new Float32Array(values.length * 4);
//oders incoming thickness values to look like the following 1-dimensional attributes view:
//thickness t
//thickness -t
//thickness -t
//thickness t
while (i < values.length) {
thickness[index] = (Math.floor(0.5 * index + 0.5) & 1) ? -values[i] : values[i];
if (++j == 4) {
j = 0;
i++;
}
index++;
}
this._thickness.set(thickness, offset * 4);
} else if (this._thickness) {
this._thickness.dispose();
this._thickness = null;
}
this.invalidateVertices(this._thickness);
this._verticesDirty[this._thickness.id] = false;
}
/**
*
*/
public setColors(array: Array<number>, offset?: number);
public setColors(float32Array: Float32Array, offset?: number);
public setColors(uint8Array: Uint8Array, offset?: number);
public setColors(byte4Attributes: Byte4Attributes, offset?: number);
public setColors(values: any, offset: number = 0): void {
if (values) {
if (values == this._colors)
return;
if (values instanceof Byte4Attributes) {
this.clearVertices(this._colors);
this._colors = <Byte4Attributes> values;
} else {
if (!this._colors)
this._colors = new Byte4Attributes(this._concatenatedBuffer);
let i: number = 0;
let j: number = 0;
let index: number = 0;
const colors: Uint8Array = new Uint8Array(values.length * 4);
while (i < values.length) {
if (index / 4 & 1) {
colors[index] = values[i + 4];
colors[index + 1] = values[i + 5];
colors[index + 2] = values[i + 6];
colors[index + 3] = values[i + 7];
} else {
colors[index] = values[i];
colors[index + 1] = values[i + 1];
colors[index + 2] = values[i + 2];
colors[index + 3] = values[i + 3];
}
if (++j == 4) {
j = 0;
i += 8;
}
index += 4;
}
this._colors.set(colors, offset * 4);
}
} else {
//auto-derive colors
this._colors = ElementsUtils.generateColors(
this.indices, this._colors, this._concatenatedBuffer, this._numVertices);
}
this.invalidateVertices(this._colors);
this._verticesDirty[this._colors.id] = false;
}
/**
*
*/
public dispose(): void {
super.dispose();
this._positions.dispose();
this._positions = null;
if (this._thickness) {
this._thickness.dispose();
this._thickness = null;
}
if (this._colors) {
this._colors.dispose();
this._colors = null;
}
}
/**
* Clones the current object
* @return An exact duplicate of the current object.
*/
public clone(): LineElements {
const clone: LineElements = new LineElements(
this._concatenatedBuffer ? this._concatenatedBuffer.clone() : null);
clone.setIndices(this.indices.clone());
clone.setPositions(this._positions.clone());
this._thickness && clone.setThickness(this._thickness.clone());
this._colors && clone.setColors(this._colors.clone());
return clone;
}
public testCollision(
collision: PickingCollision,
box: Box,
closestFlag: boolean,
material: IMaterial,
count: number,
offset: number = 0): boolean
// eslint-disable-next-line brace-style
{
//TODO: peform correct line collision calculations
const scale: Vector3D = this.getThicknessScale(collision.containerNode, true);
const thickness: number = (scale.x + scale.y) / 2;//approx hack for now
const rayEntryDistance: number = -collision.rayPosition.z / collision.rayDirection.z;
const position: Vector3D = new Vector3D(
collision.rayPosition.x + rayEntryDistance * collision.rayDirection.x,
collision.rayPosition.y + rayEntryDistance * collision.rayDirection.y);
//TODO use proper 3d testCollision method
if (LineElementsUtils.hitTest(position.x, position.y, 0, thickness, box, this, this._numElements, offset)) {
collision.rayEntryDistance = rayEntryDistance;
collision.position = position;
collision.normal = new Vector3D(0,0,1);
return true;
}
return false;
}
}
import { Matrix3D } from '@awayjs/core';
import {
ContextGLDrawMode,
IContextGL,
ContextGLProgramType,
Stage,
ShaderRegisterCache,
ShaderRegisterElement,
ShaderRegisterData,
IVao
} from '@awayjs/stage';
import { ElementsUtils } from '../utils/ElementsUtils';
import { IMaterial } from '../base/IMaterial';
import { _Stage_ElementsBase } from '../base/_Stage_ElementsBase';
import { _Render_RenderableBase } from '../base/_Render_RenderableBase';
import { ShaderBase } from '../base/ShaderBase';
import { _Render_ElementsBase } from '../base/_Render_ElementsBase';
import { RenderGroup } from '../RenderGroup';
import { LineElementsUtils } from '../utils/LineElementsUtils';
import { ConvexHullUtils } from '../utils/ConvexHullUtils';
import { Settings } from '../Settings';
import { LineScaleMode } from './LineScaleMode';
/**
*
* @class away.pool._Stage_LineElements
*/
export class _Stage_LineElements extends _Stage_ElementsBase {
private _scale: Vector3D = new Vector3D();
private _vao: IVao;
private _vaoIsInvalid: boolean = true;
public get lineElements(): LineElements {
return this._useWeak ? (<WeakRef<LineElements>> this._asset).deref() : <LineElements> this._asset;
}
public init(lineElements: LineElements, stage: Stage): void {
super.init(lineElements, stage);
this._vao = (stage.context.hasVao && Settings.ALLOW_VAO && !lineElements.isDynamic)
? stage.context.createVao()
: null;
}
public onInvalidate() {
super.onInvalidate();
this._vaoIsInvalid = true;
}
public onClear(): void {
super.onClear();
this._vaoIsInvalid = true;
if (this._vao) {
this._vao.dispose();
this._vao = null;
}
}
public transformMatrix(renderRenderable: _Render_RenderableBase, matrix: Matrix): Matrix {
const matrix3D: Matrix3D = new Matrix3D();
matrix3D.copyFrom(renderRenderable.entity.node.getMatrix3D());
matrix3D.append(renderRenderable.entity.renderer.view.projection.transform.inverseMatrix3D);
const offset: Vector3D = matrix3D.position.clone();
matrix3D.invert();
matrix3D.transpose();
const out: number[] = [];
matrix3D.deltaTransformVectors([matrix.a, matrix.c, 0, matrix.b, matrix.d, 0], out);
return new Matrix(out[0], out[3], out[1], out[4], matrix.tx - offset.x * out[0] - offset.y * out[1], matrix.ty - offset.x * out[3] - offset.y * out[4]);
}
public _setRenderState(renderRenderable: _Render_RenderableBase, shader: ShaderBase): void {
super._setRenderState(renderRenderable, shader);
const elements = <LineElements> this.elements;
const view: View = shader.view;
const renderElements = <_Render_LineElements> renderRenderable.entity
.renderer.getRenderElements(renderRenderable.stageElements.elements);
this._vao && this._vao.bind();
const lineElements: LineElements = this.lineElements;
if (!this._vao || this._vaoIsInvalid) {
if (shader.colorBufferIndex >= 0)
this.activateVertexBufferVO(shader.colorBufferIndex, lineElements.colors);
this.activateVertexBufferVO(0, lineElements.positions, elements.dimension);
this.activateVertexBufferVO(
renderElements.secondaryPositionIndex,
lineElements.positions,
elements.dimension,
elements.dimension * 2 * 2
);
this.activateVertexBufferVO(renderElements.thicknessIndex, lineElements.thickness);
if (shader.uvIndex >= 0) {
this.activateVertexBufferVO(shader.uvIndex, lineElements.positions, 2);
}
this._vaoIsInvalid = false;
}
const {
oMisc
} = renderElements.uOffsets;
const data: Float32Array = shader.vertexConstantData;
this._scale.copyFrom(renderRenderable.entity.node.getMatrix3D().decompose()[2]);
const scaleMode: LineScaleMode = lineElements.scaleMode;
const half_thickness: number = lineElements.half_thickness;
if (scaleMode == LineScaleMode.NORMAL) {
data[oMisc + 0] = (
// eslint-disable-next-line max-len
(half_thickness * this._scale.x / 1000 > 0.5 / (view.focalLength * view.pixelRatio))
? this._scale.x / 1000
: 0.5 / (half_thickness * view.focalLength * view.pixelRatio));
data[oMisc + 1] = (half_thickness * this._scale.y / 1000 > 0.5 / view.focalLength)
? this._scale.y / 1000
: 0.5 / (half_thickness * view.focalLength);
} else if (scaleMode == LineScaleMode.HAIRLINE) {
data[oMisc + 0] = 1 / (view.focalLength * view.pixelRatio);
data[oMisc + 1] = 1 / view.focalLength;
} else {
data[oMisc + 0] = 1 / Math.min(view.width, view.height);
data[oMisc + 1] = 1 / Math.min(view.width, view.height);
}
data[oMisc + 2] = view.projection.near;
}
public draw(renderRenderable: _Render_RenderableBase, shader: ShaderBase, count: number, offset: number): void {
const context: IContextGL = (<Stage> this._pool).context;
// projection matrix
shader.viewMatrix.copyFrom(shader.view.frustumMatrix3D, true);
const matrix3D: Matrix3D = Matrix3D.CALCULATION_MATRIX;
matrix3D.copyFrom(renderRenderable.entity.node.getMatrix3D());
matrix3D.append(shader.view.projection.transform.inverseMatrix3D);
shader.sceneMatrix.copyFrom(matrix3D, true);
context.setProgramConstantsFromArray(ContextGLProgramType.VERTEX, shader.vertexConstantData);
context.setProgramConstantsFromArray(ContextGLProgramType.FRAGMENT, shader.fragmentConstantData);
if (this._indices)
this.getIndexBufferGL().draw(ContextGLDrawMode.TRIANGLES, offset * 3, count * 3 || this.numIndices);
else
(<Stage> this._pool).context.drawVertices(ContextGLDrawMode.TRIANGLES, offset, count || this.numVertices);
this._vao && this._vao.unbind();
}
/**
* //TODO
*
* @param pool
* @param renderRenderable
* @param level
* @param indexOffset
* @returns {away.pool.LineSubSpriteRenderable}
* @protected
*/
public _pGetOverflowElements(): _Stage_ElementsBase {
return <_Stage_ElementsBase> (<Stage> this._pool).abstractions.getNewAbstraction(this.lineElements);
}
}
/**
* @class away.pool._Render_LineElements
*/
export class _Render_LineElements extends _Render_ElementsBase {
public secondaryPositionIndex: number = -1;
public thicknessIndex: number = -1;
public uOffsets = {
oMisc: 0,
};
public _includeDependencies(shader: ShaderBase): void {
//shader.colorDependencies++;
}
public _getVertexCode(
shader: ShaderBase, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string {
//get the projection coordinates
const position0: ShaderRegisterElement = (shader.globalPosDependencies > 0)
? sharedRegisters.globalPositionVertex
: sharedRegisters.animatedPosition;
const position1: ShaderRegisterElement = registerCache.getFreeVertexAttribute();
this.secondaryPositionIndex = position1.index;
const thickness: ShaderRegisterElement = registerCache.getFreeVertexAttribute();
this.thicknessIndex = thickness.index;
//reserving vertex constants for projection matrix
const viewMatrixReg: ShaderRegisterElement = registerCache.getFreeVertexConstant();
registerCache.getFreeVertexConstant();
registerCache.getFreeVertexConstant();
registerCache.getFreeVertexConstant();
shader.viewMatrixIndex = viewMatrixReg.index * 4;
const misc = registerCache.getFreeVertexConstant();
this.uOffsets.oMisc = misc.index * 4;
const sceneMatrixReg = registerCache.getFreeVertexConstant();
registerCache.getFreeVertexConstant();
registerCache.getFreeVertexConstant();
registerCache.getFreeVertexConstant();
shader.sceneMatrixIndex = sceneMatrixReg.index * 4;
const q0: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp();
registerCache.addVertexTempUsages(q0, 1);
const q1: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp();
registerCache.addVertexTempUsages(q1, 1);
const l: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp();
registerCache.addVertexTempUsages(l, 1);
const behind: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp();
registerCache.addVertexTempUsages(behind, 1);
const qclipped: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp();
registerCache.addVertexTempUsages(qclipped, 1);
const offset: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp();
registerCache.addVertexTempUsages(offset, 1);
// transform Q0 to eye space
let code: string = 'm44 ' + q0 + ', ' + position0 + ', ' + sceneMatrixReg + '\n' +
'm44 ' + q1 + ', ' + position1 + ', ' + sceneMatrixReg + '\n' + // transform Q1 to eye space
'sub ' + l + ', ' + q1 + ', ' + q0 + '\n' + // L = Q1 - Q0
// test if behind camera near plane
// if 0 - Q0.z < Camera.near then the point needs to be clipped
'slt ' + behind + '.x, ' + q0 + '.z, ' + misc + '.z\n' + // behind = ( 0 - Q0.z < -Camera.near ) ? 1 : 0
'sub ' + behind + '.y, #native( 1.0 )native#, ' + behind + '.x\n' + // !behind = 1 - behind
// p = point on the plane (0,0,-near)
// n = plane normal (0,0,-1)
// D = Q1 - Q0
// t = ( dot( n, ( p - Q0 ) ) / ( dot( n, d )
// solve for t where line crosses Camera.near
'add ' + offset + '.x, ' + q0 + '.z, ' + misc + '.z\n' + // Q0.z + ( -Camera.near )
'sub ' + offset + '.y, ' + q0 + '.z, ' + q1 + '.z\n' + // Q0.z - Q1.z
// fix divide by zero for horizontal lines
'seq ' + offset + '.z, ' + offset + '.y, #native( vec4(0.0) )native#\n' + // offset = (Q0.z - Q1.z)==0 ? 1 : 0
'add ' + offset + '.y, ' + offset + '.y, ' + offset + '.z\n' + // ( Q0.z - Q1.z ) + offset
'div ' + offset + '.z, ' + offset + '.x, ' + offset + '.y\n' + // t = ( Q0.z - near ) / ( Q0.z - Q1.z )
'mul ' + offset + '.xyz, ' + offset + '.zzz, ' + l + '.xyz\n' + // t(L)
'add ' + qclipped + '.xyz, ' + q0 + '.xyz, ' + offset + '.xyz\n' + // Qclipped = Q0 + t(L)
'mov ' + qclipped + '.w, #native( 1.0 )native#\n' + // Qclipped.w = 1
// If necessary, replace Q0 with new Qclipped
'mul ' + q0 + ', ' + q0 + ', ' + behind + '.yyyy\n' + // !behind * Q0
'mul ' + qclipped + ', ' + qclipped + ', ' + behind + '.xxxx\n' + // behind * Qclipped
'add ' + q0 + ', ' + q0 + ', ' + qclipped + '\n' + // newQ0 = Q0 + Qclipped
// calculate side vector for line
'nrm ' + l + '.xyz, ' + l + '.xyz\n' + // normalize( L )
'mov ' + behind + '.xyz, #native( vec4(0.0) )native#\n' + // D = normalize( Q1 )
'mov ' + behind + '.z, #native( 1.0 )native#\n' + // D.w = 1
'crs ' + qclipped + '.xyz, ' + l + ', ' + behind + '\n' + // S = L x D
'nrm ' + qclipped + '.xyz, ' + qclipped + '.xyz\n' + // normalize( S )
// face the side vector properly for the given point
'mul ' + qclipped + '.xyz, ' + qclipped + '.xyz, ' + thickness + '.xxx\n' + // S *= weight
'mov ' + qclipped + '.w, #native( 1.0 )native#\n' + // S.w = 1
// calculate the amount required to move at the point's distance to correspond to the line's pixel width
// scale the side vector by that amount
'mul ' + offset + '.x, ' + q0 + '.z, #native( -1.0 )native#\n' + // distance = dot( view )
'mul ' + qclipped + '.xyz, ' + qclipped + '.xyz, ' + offset + '.xxx\n' + // S.xyz *= pixelScaleFactor
'mul ' + qclipped + '.xyz, ' + qclipped + '.xyz, ' + misc + '.xy\n' + // distance *= vpsod
// add scaled side vector to Q0 and transform to clip space
'add ' + q0 + '.xyz, ' + q0 + '.xyz, ' + qclipped + '.xyz\n' + // Q0 + S
// transform Q0 to clip space
'm44 op, ' + q0 + ', ' + viewMatrixReg + '\n';
//Calculate the (possibly animated) UV coordinates.
if (shader.uvDependencies > 0) {
sharedRegisters.uvVarying = registerCache.getFreeVarying();
if (shader.usesUVTransform) {
// a, b, 0, tx
// c, d, 0, ty
const uvTransform1: ShaderRegisterElement = registerCache.getFreeVertexConstant();
const uvTransform2: ShaderRegisterElement = registerCache.getFreeVertexConstant();
shader.uvMatrixIndex = uvTransform1.index * 4;
code += 'dp4 ' + sharedRegisters.uvVarying + '.x, ' + q0 + ', ' + uvTransform1 + '\n' +
'dp4 ' + sharedRegisters.uvVarying + '.y, ' + q0 + ', ' + uvTransform2 + '\n' +
'mov ' + sharedRegisters.uvVarying + '.zw, ' + q0 + '.zw \n';
} else {
code += 'mov ' + sharedRegisters.uvVarying + ', ' + sharedRegisters.animatedUV + '\n';
}
}
registerCache.removeVertexTempUsage(q0);
registerCache.removeVertexTempUsage(q1);
registerCache.removeVertexTempUsage(l);
registerCache.removeVertexTempUsage(behind);
registerCache.removeVertexTempUsage(qclipped);
registerCache.removeVertexTempUsage(offset);
return code;
}
public _getFragmentCode(
shader: ShaderBase,
registerCache: ShaderRegisterCache,
sharedRegisters: ShaderRegisterData): string {
return '';
}
}
RenderGroup.registerElements(_Render_LineElements, LineElements);
Stage.registerAbstraction(_Stage_LineElements, LineElements);