awayjs-display
Version:
AwayJS displaylist classes
647 lines (525 loc) • 18 kB
text/typescript
import {ElementsType} from "../graphics/ElementsType";
import {LineElements} from "../graphics/LineElements";
import {ElementsBase} from "../graphics/ElementsBase";
import {TriangleElements} from "../graphics/TriangleElements";
import {MaterialBase} from "../materials/MaterialBase";
import {PrimitivePrefabBase} from "../prefabs/PrimitivePrefabBase";
/**
* A Cube primitive prefab.
*/
export class PrimitiveCubePrefab extends PrimitivePrefabBase
{
private _width:number;
private _height:number;
private _depth:number;
private _tile6:boolean;
private _segmentsW:number;
private _segmentsH:number;
private _segmentsD:number;
/**
* Creates a new Cube object.
* @param width The size of the cube along its X-axis.
* @param height The size of the cube along its Y-axis.
* @param depth The size of the cube along its Z-axis.
* @param segmentsW The number of segments that make up the cube along the X-axis.
* @param segmentsH The number of segments that make up the cube along the Y-axis.
* @param segmentsD The number of segments that make up the cube along the Z-axis.
* @param tile6 The type of uv mapping to use. When true, a texture will be subdivided in a 2x3 grid, each used for a single face. When false, the entire image is mapped on each face.
*/
constructor(material:MaterialBase = null, elementsType:string = "triangle", width:number = 100, height:number = 100, depth:number = 100, segmentsW:number = 1, segmentsH:number = 1, segmentsD:number = 1, tile6:boolean = true)
{
super(material, elementsType);
this._width = width;
this._height = height;
this._depth = depth;
this._segmentsW = segmentsW;
this._segmentsH = segmentsH;
this._segmentsD = segmentsD;
this._tile6 = tile6;
}
/**
* The size of the cube along its X-axis.
*/
public get width():number
{
return this._width;
}
public set width(value:number)
{
this._width = value;
this._pInvalidatePrimitive();
}
/**
* The size of the cube along its Y-axis.
*/
public get height():number
{
return this._height;
}
public set height(value:number)
{
this._height = value;
this._pInvalidatePrimitive();
}
/**
* The size of the cube along its Z-axis.
*/
public get depth():number
{
return this._depth;
}
public set depth(value:number)
{
this._depth = value;
this._pInvalidatePrimitive();
}
/**
* The type of uv mapping to use. When false, the entire image is mapped on each face.
* When true, a texture will be subdivided in a 3x2 grid, each used for a single face.
* Reading the tiles from left to right, top to bottom they represent the faces of the
* cube in the following order: bottom, top, back, left, front, right. This creates
* several shared edges (between the top, front, left and right faces) which simplifies
* texture painting.
*/
public get tile6():boolean
{
return this._tile6;
}
public set tile6(value:boolean)
{
this._tile6 = value;
this._pInvalidatePrimitive();
}
/**
* The number of segments that make up the cube along the X-axis. Defaults to 1.
*/
public get segmentsW():number
{
return this._segmentsW;
}
public set segmentsW(value:number)
{
this._segmentsW = value;
this._pInvalidatePrimitive();
this._pInvalidateUVs();
}
/**
* The number of segments that make up the cube along the Y-axis. Defaults to 1.
*/
public get segmentsH():number
{
return this._segmentsH;
}
public set segmentsH(value:number)
{
this._segmentsH = value;
this._pInvalidatePrimitive();
this._pInvalidateUVs();
}
/**
* The number of segments that make up the cube along the Z-axis. Defaults to 1.
*/
public get segmentsD():number
{
return this._segmentsD;
}
public set segmentsD(value:number)
{
this._segmentsD = value;
this._pInvalidatePrimitive();
this._pInvalidateUVs();
}
/**
* @inheritDoc
*/
public _pBuildGraphics(target:ElementsBase, elementsType:string):void
{
var indices:Uint16Array;
var positions:ArrayBufferView;
var normals:Float32Array;
var tangents:Float32Array;
var stride:number;
var tl:number, tr:number, bl:number, br:number;
var i:number, j:number, inc:number = 0;
var vidx:number, fidx:number; // indices
var hw:number, hh:number, hd:number; // halves
var dw:number, dh:number, dd:number; // deltas
var outer_pos:number;
// half cube dimensions
hw = this._width/2;
hh = this._height/2;
hd = this._depth/2;
if (elementsType == ElementsType.TRIANGLE) {
var triangleGraphics:TriangleElements = <TriangleElements> target;
var numVertices:number = ((this._segmentsW + 1)*(this._segmentsH + 1) + (this._segmentsW + 1)*(this._segmentsD + 1) + (this._segmentsH + 1)*(this._segmentsD + 1))*2;
var numIndices:number = ((this._segmentsW*this._segmentsH + this._segmentsW*this._segmentsD + this._segmentsH*this._segmentsD)*12);
if (numVertices == triangleGraphics.numVertices && triangleGraphics.indices != null) {
triangleGraphics.invalidateIndices();
triangleGraphics.invalidateVertices(triangleGraphics.positions);
triangleGraphics.invalidateVertices(triangleGraphics.normals);
triangleGraphics.invalidateVertices(triangleGraphics.tangents);
} else {
triangleGraphics.setIndices(new Uint16Array(numIndices));
triangleGraphics.setPositions(new Float32Array(numVertices*3));
triangleGraphics.setNormals(new Float32Array(numVertices*3));
triangleGraphics.setTangents(new Float32Array(numVertices*3));
this._pInvalidateUVs();
}
indices = triangleGraphics.indices.get(triangleGraphics.numElements);
positions = triangleGraphics.positions.get(numVertices);
normals = triangleGraphics.normals.get(numVertices);
tangents = triangleGraphics.tangents.get(numVertices);
stride = triangleGraphics.concatenatedBuffer.stride/4;
vidx = 0;
fidx = 0;
// Segment dimensions
dw = this._width/this._segmentsW;
dh = this._height/this._segmentsH;
dd = this._depth/this._segmentsD;
for (i = 0; i <= this._segmentsW; i++) {
outer_pos = -hw + i*dw;
for (j = 0; j <= this._segmentsH; j++) {
// front
positions[vidx] = outer_pos;
positions[vidx + 1] = -hh + j*dh;
positions[vidx + 2] = -hd;
normals[vidx] = 0;
normals[vidx + 1] = 0;
normals[vidx + 2] = -1;
tangents[vidx] = 1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
// back
positions[vidx] = outer_pos;
positions[vidx + 1] = -hh + j*dh;
positions[vidx + 2] = hd;
normals[vidx] = 0;
normals[vidx + 1] = 0;
normals[vidx + 2] = 1;
tangents[vidx] = -1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
if (i && j) {
tl = 2*((i - 1)*(this._segmentsH + 1) + (j - 1));
tr = 2*(i*(this._segmentsH + 1) + (j - 1));
bl = tl + 2;
br = tr + 2;
indices[fidx++] = tl;
indices[fidx++] = bl;
indices[fidx++] = br;
indices[fidx++] = tl;
indices[fidx++] = br;
indices[fidx++] = tr;
indices[fidx++] = tr + 1;
indices[fidx++] = br + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tr + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tl + 1;
}
}
}
inc += 2*(this._segmentsW + 1)*(this._segmentsH + 1);
for (i = 0; i <= this._segmentsW; i++) {
outer_pos = -hw + i*dw;
for (j = 0; j <= this._segmentsD; j++) {
// top
positions[vidx] = outer_pos;
positions[vidx + 1] = hh;
positions[vidx + 2] = -hd + j*dd;
normals[vidx] = 0;
normals[vidx + 1] = 1;
normals[vidx + 2] = 0;
tangents[vidx] = 1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
// bottom
positions[vidx] = outer_pos;
positions[vidx + 1] = -hh;
positions[vidx + 2] = -hd + j*dd;
normals[vidx] = 0;
normals[vidx + 1] = -1;
normals[vidx + 2] = 0;
tangents[vidx] = 1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
if (i && j) {
tl = inc + 2*((i - 1)*(this._segmentsD + 1) + (j - 1));
tr = inc + 2*(i*(this._segmentsD + 1) + (j - 1));
bl = tl + 2;
br = tr + 2;
indices[fidx++] = tl;
indices[fidx++] = bl;
indices[fidx++] = br;
indices[fidx++] = tl;
indices[fidx++] = br;
indices[fidx++] = tr;
indices[fidx++] = tr + 1;
indices[fidx++] = br + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tr + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tl + 1;
}
}
}
inc += 2*(this._segmentsW + 1)*(this._segmentsD + 1);
for (i = 0; i <= this._segmentsD; i++) {
outer_pos = hd - i*dd;
for (j = 0; j <= this._segmentsH; j++) {
// left
positions[vidx] = -hw;
positions[vidx+1] = -hh + j*dh;
positions[vidx+2] = outer_pos;
normals[vidx] = -1;
normals[vidx+1] = 0;
normals[vidx+2] = 0;
tangents[vidx] = 0;
tangents[vidx+1] = 0;
tangents[vidx+2] = -1;
vidx += stride;
// right
positions[vidx] = hw;
positions[vidx+1] = -hh + j*dh;
positions[vidx+2] = outer_pos;
normals[vidx] = 1;
normals[vidx+1] = 0;
normals[vidx+2] = 0;
tangents[vidx] = 0;
tangents[vidx+1] = 0;
tangents[vidx+2] = 1;
vidx += stride;
if (i && j) {
tl = inc + 2*((i - 1)*(this._segmentsH + 1) + (j - 1));
tr = inc + 2*(i*(this._segmentsH + 1) + (j - 1));
bl = tl + 2;
br = tr + 2;
indices[fidx++] = tl;
indices[fidx++] = bl;
indices[fidx++] = br;
indices[fidx++] = tl;
indices[fidx++] = br;
indices[fidx++] = tr;
indices[fidx++] = tr + 1;
indices[fidx++] = br + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tr + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tl + 1;
}
}
}
} else if (elementsType == ElementsType.LINE) {
var lineGraphics:LineElements = <LineElements> target;
var numSegments:number = this._segmentsH*4 + this._segmentsW*4 + this._segmentsD*4;
var thickness:Float32Array;
positions = new Float32Array(numSegments*6);
thickness = new Float32Array(numSegments);
vidx = 0;
fidx = 0;
//front/back face
for (i = 0; i < this._segmentsH; ++i) {
positions[vidx++] = -hw;
positions[vidx++] = i*this._height/this._segmentsH - hh;
positions[vidx++] = -hd;
positions[vidx++] = hw;
positions[vidx++] = i*this._height/this._segmentsH - hh;
positions[vidx++] = -hd;
thickness[fidx++] = 1;
positions[vidx++] = -hw;
positions[vidx++] = hh - i*this._height/this._segmentsH;
positions[vidx++] = hd;
positions[vidx++] = hw;
positions[vidx++] = hh - i*this._height/this._segmentsH;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
for (i = 0; i < this._segmentsW; ++i) {
positions[vidx++] = i*this._width/this._segmentsW - hw;
positions[vidx++] = -hh;
positions[vidx++] = -hd;
positions[vidx++] = i*this._width/this._segmentsW - hw;
positions[vidx++] = hh;
positions[vidx++] = -hd;
thickness[fidx++] = 1;
positions[vidx++] = hw - i*this._width/this._segmentsW;
positions[vidx++] = -hh;
positions[vidx++] = hd;
positions[vidx++] = hw - i*this._width/this._segmentsW;
positions[vidx++] = hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
//left/right face
for (i = 0; i < this._segmentsH; ++i) {
positions[vidx++] = -hw;
positions[vidx++] = i*this._height/this._segmentsH - hh;
positions[vidx++] = -hd;
positions[vidx++] = -hw;
positions[vidx++] = i*this._height/this._segmentsH - hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
positions[vidx++] = hw;
positions[vidx++] = hh - i*this._height/this._segmentsH;
positions[vidx++] = -hd;
positions[vidx++] = hw;
positions[vidx++] = hh - i*this._height/this._segmentsH;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
for (i = 0; i < this._segmentsD; ++i) {
positions[vidx++] = hw;
positions[vidx++] = -hh;
positions[vidx++] = i*this._depth/this._segmentsD - hd;
positions[vidx++] = hw;
positions[vidx++] = hh;
positions[vidx++] = i*this._depth/this._segmentsD - hd;
thickness[fidx++] = 1;
positions[vidx++] = -hw;
positions[vidx++] = -hh;
positions[vidx++] = hd - i*this._depth/this._segmentsD;
positions[vidx++] = -hw;
positions[vidx++] = hh;
positions[vidx++] = hd - i*this._depth/this._segmentsD;
thickness[fidx++] = 1;
}
//top/bottom face
for (i = 0; i < this._segmentsD; ++i) {
positions[vidx++] = -hw;
positions[vidx++] = -hh;
positions[vidx++] = hd - i*this._depth/this._segmentsD;
positions[vidx++] = hw;
positions[vidx++] = -hh;
positions[vidx++] = hd - i*this._depth/this._segmentsD;
thickness[fidx++] = 1;
positions[vidx++] = -hw;
positions[vidx++] = hh;
positions[vidx++] = i*this._depth/this._segmentsD - hd;
positions[vidx++] = hw;
positions[vidx++] = hh;
positions[vidx++] = i*this._depth/this._segmentsD - hd;
thickness[fidx++] = 1;
}
for (i = 0; i < this._segmentsW; ++i) {
positions[vidx++] = hw - i*this._width/this._segmentsW;
positions[vidx++] = -hh;
positions[vidx++] = -hd;
positions[vidx++] = hw - i*this._width/this._segmentsW;
positions[vidx++] = -hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
positions[vidx++] = i*this._width/this._segmentsW - hw;
positions[vidx++] = hh;
positions[vidx++] = -hd;
positions[vidx++] = i*this._width/this._segmentsW - hw;
positions[vidx++] = hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
// build real data from raw data
lineGraphics.setPositions(positions);
lineGraphics.setThickness(thickness);
}
}
/**
* @inheritDoc
*/
public _pBuildUVs(target:ElementsBase, elementsType:string):void
{
var i:number, j:number, index:number;
var uvs:ArrayBufferView;
var stride:number;
var u_tile_dim:number, v_tile_dim:number;
var u_tile_step:number, v_tile_step:number;
var tl0u:number, tl0v:number;
var tl1u:number, tl1v:number;
var du:number, dv:number;
var numVertices:number;
if (elementsType == ElementsType.TRIANGLE) {
numVertices = ((this._segmentsW + 1)*(this._segmentsH + 1) + (this._segmentsW + 1)*(this._segmentsD + 1) + (this._segmentsH + 1)*(this._segmentsD + 1))*2;
var triangleGraphics:TriangleElements = <TriangleElements> target;
if (triangleGraphics.uvs && numVertices == triangleGraphics.numVertices) {
triangleGraphics.invalidateVertices(triangleGraphics.uvs);
} else {
triangleGraphics.setUVs(new Float32Array(numVertices*2));
}
uvs = triangleGraphics.uvs.get(numVertices);
stride = triangleGraphics.uvs.stride;
if (this._tile6) {
u_tile_dim = u_tile_step = 1/3;
v_tile_dim = v_tile_step = 1/2;
} else {
u_tile_dim = v_tile_dim = 1;
u_tile_step = v_tile_step = 0;
}
// Create planes two and two, the same way that they were
// constructed in the buildGraphics() function. First calculate
// the top-left UV coordinate for both planes, and then loop
// over the points, calculating the UVs from these numbers.
// When tile6 is true, the layout is as follows:
// .-----.-----.-----. (1,1)
// | Bot | T | Bak |
// |-----+-----+-----|
// | L | F | R |
// (0,0)'-----'-----'-----'
index = 0;
// FRONT / BACK
tl0u = 1*u_tile_step;
tl0v = 1*v_tile_step;
tl1u = 2*u_tile_step;
tl1v = 0*v_tile_step;
du = u_tile_dim/this._segmentsW;
dv = v_tile_dim/this._segmentsH;
for (i = 0; i <= this._segmentsW; i++) {
for (j = 0; j <= this._segmentsH; j++) {
uvs[index] = ( tl0u + i*du )*this._scaleU;
uvs[index + 1] = ( tl0v + (v_tile_dim - j*dv))*this._scaleV;
index += stride;
uvs[index] = ( tl1u + (u_tile_dim - i*du))*this._scaleU;
uvs[index + 1] = ( tl1v + (v_tile_dim - j*dv))*this._scaleV;
index += stride;
}
}
// TOP / BOTTOM
tl0u = 1*u_tile_step;
tl0v = 0*v_tile_step;
tl1u = 0*u_tile_step;
tl1v = 0*v_tile_step;
du = u_tile_dim/this._segmentsW;
dv = v_tile_dim/this._segmentsD;
for (i = 0; i <= this._segmentsW; i++) {
for (j = 0; j <= this._segmentsD; j++) {
uvs[index] = ( tl0u + i*du)*this._scaleU;
uvs[index + 1] = ( tl0v + (v_tile_dim - j*dv))*this._scaleV;
index += stride;
uvs[index] = ( tl1u + i*du)*this._scaleU;
uvs[index + 1] = ( tl1v + j*dv)*this._scaleV;
index += stride;
}
}
// LEFT / RIGHT
tl0u = 0*u_tile_step;
tl0v = 1*v_tile_step;
tl1u = 2*u_tile_step;
tl1v = 1*v_tile_step;
du = u_tile_dim/this._segmentsD;
dv = v_tile_dim/this._segmentsH;
for (i = 0; i <= this._segmentsD; i++) {
for (j = 0; j <= this._segmentsH; j++) {
uvs[index] = ( tl0u + i*du)*this._scaleU;
uvs[index + 1] = ( tl0v + (v_tile_dim - j*dv))*this._scaleV;
index += stride;
uvs[index] = ( tl1u + (u_tile_dim - i*du))*this._scaleU;
uvs[index + 1] = ( tl1v + (v_tile_dim - j*dv))*this._scaleV;
index += stride;
}
}
} else if (elementsType == ElementsType.LINE) {
//nothing to do here
}
}
}