package alternativa.engine3d.core {
import alternativa.engine3d.*;
import alternativa.types.Point3D;
import alternativa.types.Set;
import flash.geom.Matrix;
import flash.geom.Point;
use namespace alternativa3d;
/**
* Грань, образованная тремя или более вершинами. Грани являются составными частями полигональных объектов. Каждая грань
* содержит информацию об объекте и поверхности, которым она принадлежит. Для обеспечения возможности наложения
* текстуры на грань, первым трём её вершинам могут быть заданы UV-координаты, на основании которых расчитывается
* матрица трансформации текстуры.
*/
final public class Face {
// Операции
/**
* @private
* Расчёт глобальной нормали плоскости грани.
*/
alternativa3d var calculateNormalOperation:Operation = new Operation("calculateNormal", this, calculateNormal, Operation.FACE_CALCULATE_NORMAL);
/**
* @private
* Расчёт UV-координат (выполняется до трансформации, чтобы UV корректно разбились при построении BSP).
*/
alternativa3d var calculateUVOperation:Operation = new Operation("calculateUV", this, calculateUV, Operation.FACE_CALCULATE_UV);
/**
* @private
* Обновление примитива в сцене.
*/
alternativa3d var updatePrimitiveOperation:Operation = new Operation("updatePrimitive", this, updatePrimitive, Operation.FACE_UPDATE_PRIMITIVE);
/**
* @private
* Обновление материала.
*/
alternativa3d var updateMaterialOperation:Operation = new Operation("updateMaterial", this, updateMaterial, Operation.FACE_UPDATE_MATERIAL);
/**
* @private
* Расчёт UV для фрагментов (выполняется после трансформации, если её не было).
*/
alternativa3d var calculateFragmentsUVOperation:Operation = new Operation("calculateFragmentsUV", this, calculateFragmentsUV, Operation.FACE_CALCULATE_FRAGMENTS_UV);
/**
* @private
* Меш
*/
alternativa3d var _mesh:Mesh;
/**
* @private
* Поверхность
*/
alternativa3d var _surface:Surface;
/**
* @private
* Вершины грани
*/
alternativa3d var _vertices:Array;
/**
* @private
* Количество вершин
*/
alternativa3d var _verticesCount:uint;
/**
* @private
* Примитив
*/
alternativa3d var primitive:PolyPrimitive;
// UV-координаты
/**
* @private
*/
alternativa3d var _aUV:Point;
/**
* @private
*/
alternativa3d var _bUV:Point;
/**
* @private
*/
alternativa3d var _cUV:Point;
/**
* @private
* Коэффициенты базовой UV-матрицы
*/
alternativa3d var uvMatrixBase:Matrix;
/**
* @private
* UV Матрица перевода текстурных координат в изометрическую камеру.
*/
alternativa3d var uvMatrix:Matrix;
/**
* @private
* Нормаль плоскости
*/
alternativa3d var globalNormal:Point3D = new Point3D();
/**
* @private
* Смещение плоскости
*/
alternativa3d var globalOffset:Number;
/**
* Создание экземпляра грани.
*
* @param vertices массив объектов типа alternativa.engine3d.core.Vertex, задающий вершины грани в
* порядке обхода лицевой стороны грани против часовой стрелки.
*
* @see Vertex
*/
public function Face(vertices:Array) {
// Сохраняем вершины
_vertices = vertices;
_verticesCount = vertices.length;
// Создаём оригинальный примитив
primitive = PolyPrimitive.createPolyPrimitive();
primitive.face = this;
primitive.num = _verticesCount;
// Обрабатываем вершины
for (var i:uint = 0; i < _verticesCount; i++) {
var vertex:Vertex = vertices[i];
// Добавляем координаты вершины в примитив
primitive.points.push(vertex.globalCoords);
// Добавляем пустые UV-координаты в примитив
primitive.uvs.push(null);
// Добавляем вершину в грань
vertex.addToFace(this);
}
// Расчёт нормали
calculateNormalOperation.addSequel(updatePrimitiveOperation);
// Расчёт UV грани инициирует расчёт UV фрагментов и перерисовку
calculateUVOperation.addSequel(calculateFragmentsUVOperation);
calculateUVOperation.addSequel(updateMaterialOperation);
}
/**
* @private
* Расчёт нормали в глобальных координатах
*/
private function calculateNormal():void {
// Вектор AB
var vertex:Vertex = _vertices[0];
var av:Point3D = vertex.globalCoords;
vertex = _vertices[1];
var bv:Point3D = vertex.globalCoords;
var abx:Number = bv.x - av.x;
var aby:Number = bv.y - av.y;
var abz:Number = bv.z - av.z;
// Вектор AC
vertex = _vertices[2];
var cv:Point3D = vertex.globalCoords;
var acx:Number = cv.x - av.x;
var acy:Number = cv.y - av.y;
var acz:Number = cv.z - av.z;
// Перпендикуляр к плоскости
globalNormal.x = acz*aby - acy*abz;
globalNormal.y = acx*abz - acz*abx;
globalNormal.z = acy*abx - acx*aby;
// Нормализация перпендикуляра
globalNormal.normalize();
}
/**
* @private
* Расчитывает глобальное смещение плоскости грани.
* Помечает конечные примитивы на удаление, а базовый на добавление в сцене.
*/
private function updatePrimitive():void {
// Расчёт смещения
var vertex:Vertex = _vertices[0];
globalOffset = vertex.globalCoords.x*globalNormal.x + vertex.globalCoords.y*globalNormal.y + vertex.globalCoords.z*globalNormal.z;
removePrimitive(primitive);
primitive.mobility = _mesh.inheritedMobility;
_mesh._scene.addPrimitives.push(primitive);
}
/**
* @private
* Рекурсивно проходит по фрагментам примитива и отправляет конечные фрагменты на удаление из сцены
*/
private function removePrimitive(primitive:PolyPrimitive):void {
if (primitive.backFragment != null) {
removePrimitive(primitive.backFragment);
removePrimitive(primitive.frontFragment);
primitive.backFragment = null;
primitive.frontFragment = null;
if (primitive != this.primitive) {
primitive.parent = null;
primitive.sibling = null;
PolyPrimitive.destroyPolyPrimitive(primitive);
}
} else {
// Если примитив в BSP-дереве
if (primitive.node != null) {
// Удаление примитива
_mesh._scene.removeBSPPrimitive(primitive);
}
}
}
/**
* @private
* Пометка на перерисовку фрагментов грани.
*/
private function updateMaterial():void {
if (!updatePrimitiveOperation.queued) {
changePrimitive(primitive);
}
}
/**
* @private
* Рекурсивно проходит по фрагментам примитива и отправляет конечные фрагменты на перерисовку
*/
private function changePrimitive(primitive:PolyPrimitive):void {
if (primitive.backFragment != null) {
changePrimitive(primitive.backFragment);
changePrimitive(primitive.frontFragment);
} else {
_mesh._scene.changedPrimitives[primitive] = true;
}
}
/**
* @private
* Расчёт UV-матрицы на основании первых трёх UV-координат.
* Расчёт UV-координат для оставшихся точек.
*/
private function calculateUV():void {
var i:uint;
// Расчёт UV-матрицы
if (_aUV != null && _bUV != null && _cUV != null) {
var abu:Number = _bUV.x - _aUV.x;
var abv:Number = _bUV.y - _aUV.y;
var acu:Number = _cUV.x - _aUV.x;
var acv:Number = _cUV.y - _aUV.y;
var det:Number = abu*acv - abv*acu;
if (det != 0) {
if (uvMatrixBase == null) {
uvMatrixBase = new Matrix();
uvMatrix = new Matrix();
}
uvMatrixBase.a = acv/det;
uvMatrixBase.b = -abv/det;
uvMatrixBase.c = -acu/det;
uvMatrixBase.d = abu/det;
uvMatrixBase.tx = -(uvMatrixBase.a*_aUV.x + uvMatrixBase.c*_aUV.y);
uvMatrixBase.ty = -(uvMatrixBase.b*_aUV.x + uvMatrixBase.d*_aUV.y);
// Заполняем UV в базовом примитиве
primitive.uvs[0] = _aUV;
primitive.uvs[1] = _bUV;
primitive.uvs[2] = _cUV;
// Расчёт недостающих UV
if (_verticesCount > 3) {
var a:Point3D = primitive.points[0];
var b:Point3D = primitive.points[1];
var c:Point3D = primitive.points[2];
var ab1:Number;
var ab2:Number;
var ac1:Number;
var ac2:Number;
var ad1:Number;
var ad2:Number;
var abk:Number;
var ack:Number;
var uv:Point;
var point:Point3D;
// Выбор наиболее подходящих осей для расчёта
if (((globalNormal.x < 0) ? -globalNormal.x : globalNormal.x) > ((globalNormal.y < 0) ? -globalNormal.y : globalNormal.y)) {
if (((globalNormal.x < 0) ? -globalNormal.x : globalNormal.x) > ((globalNormal.z < 0) ? -globalNormal.z : globalNormal.z)) {
// Ось X
ab1 = b.y - a.y;
ab2 = b.z - a.z;
ac1 = c.y - a.y;
ac2 = c.z - a.z;
det = ab1*ac2 - ac1*ab2;
for (i = 3; i < _verticesCount; i++) {
point = primitive.points[i];
ad1 = point.y - a.y;
ad2 = point.z - a.z;
abk = (ad1*ac2 - ac1*ad2)/det;
ack = (ab1*ad2 - ad1*ab2)/det;
uv = primitive.uvs[i];
if (uv == null) {
uv = new Point();
primitive.uvs[i] = uv;
}
uv.x = _aUV.x + abu*abk + acu*ack;
uv.y = _aUV.y + abv*abk + acv*ack;
}
} else {
// Ось Z
ab1 = b.x - a.x;
ab2 = b.y - a.y;
ac1 = c.x - a.x;
ac2 = c.y - a.y;
det = ab1*ac2 - ac1*ab2;
for (i = 3; i < _verticesCount; i++) {
point = primitive.points[i];
ad1 = point.x - a.x;
ad2 = point.y - a.y;
abk = (ad1*ac2 - ac1*ad2)/det;
ack = (ab1*ad2 - ad1*ab2)/det;
uv = primitive.uvs[i];
if (uv == null) {
uv = new Point();
primitive.uvs[i] = uv;
}
uv.x = _aUV.x + abu*abk + acu*ack;
uv.y = _aUV.y + abv*abk + acv*ack;
}
}
} else {
if (((globalNormal.y < 0) ? -globalNormal.y : globalNormal.y) > ((globalNormal.z < 0) ? -globalNormal.z : globalNormal.z)) {
// Ось Y
ab1 = b.x - a.x;
ab2 = b.z - a.z;
ac1 = c.x - a.x;
ac2 = c.z - a.z;
det = ab1*ac2 - ac1*ab2;
for (i = 3; i < _verticesCount; i++) {
point = primitive.points[i];
ad1 = point.x - a.x;
ad2 = point.z - a.z;
abk = (ad1*ac2 - ac1*ad2)/det;
ack = (ab1*ad2 - ad1*ab2)/det;
uv = primitive.uvs[i];
if (uv == null) {
uv = new Point();
primitive.uvs[i] = uv;
}
uv.x = _aUV.x + abu*abk + acu*ack;
uv.y = _aUV.y + abv*abk + acv*ack;
}
} else {
// Ось Z
ab1 = b.x - a.x;
ab2 = b.y - a.y;
ac1 = c.x - a.x;
ac2 = c.y - a.y;
det = ab1*ac2 - ac1*ab2;
for (i = 3; i < _verticesCount; i++) {
point = primitive.points[i];
ad1 = point.x - a.x;
ad2 = point.y - a.y;
abk = (ad1*ac2 - ac1*ad2)/det;
ack = (ab1*ad2 - ad1*ab2)/det;
uv = primitive.uvs[i];
if (uv == null) {
uv = new Point();
primitive.uvs[i] = uv;
}
uv.x = _aUV.x + abu*abk + acu*ack;
uv.y = _aUV.y + abv*abk + acv*ack;
}
}
}
}
} else {
// Удаляем UV-матрицу
uvMatrixBase = null;
uvMatrix = null;
// Удаляем UV-координаты из базового примитива
for (i = 0; i < _verticesCount; i++) {
primitive.uvs[i] = null;
}
}
} else {
// Удаляем UV-матрицу
uvMatrixBase = null;
uvMatrix = null;
// Удаляем UV-координаты из базового примитива
for (i = 0; i < _verticesCount; i++) {
primitive.uvs[i] = null;
}
}
}
/**
* @private
* Расчёт UV-координат для фрагментов примитива, если не было трансформации
*/
private function calculateFragmentsUV():void {
// Если в этом цикле не было трансформации
if (!updatePrimitiveOperation.queued) {
if (uvMatrixBase != null) {
// Рассчитываем UV в примитиве
calculatePrimitiveUV(primitive);
} else {
// Удаляем UV в примитиве
removePrimitiveUV(primitive);
}
}
}
/**
* @private
* Расчёт UV для точек базового примитива.
*
* @param primitive
*/
private function calculatePrimitiveUV(primitive:PolyPrimitive):void {
if (primitive.backFragment != null) {
var points:Array = primitive.points;
var backPoints:Array = primitive.backFragment.points;
var frontPoints:Array = primitive.frontFragment.points;
var uvs:Array = primitive.uvs;
var backUVs:Array = primitive.backFragment.uvs;
var frontUVs:Array = primitive.frontFragment.uvs;
var index1:uint = 0;
var index2:uint = 0;
var point:Point3D;
var uv:Point;
var uv1:Point;
var uv2:Point;
var t:Number;
var firstSplit:Boolean = true;
for (var i:uint = 0; i < primitive.num; i++) {
var split:Boolean = true;
point = points[i];
if (point == frontPoints[index2]) {
if (frontUVs[index2] == null) {
frontUVs[index2] = uvs[i];
}
split = false;
index2++;
}
if (point == backPoints[index1]) {
if (backUVs[index1] == null) {
backUVs[index1] = uvs[i];
}
split = false;
index1++;
}
if (split) {
uv1 = uvs[(i == 0) ? (primitive.num - 1) : (i - 1)];
uv2 = uvs[i];
t = (firstSplit) ? primitive.splitTime1 : primitive.splitTime2;
uv = frontUVs[index2];
if (uv == null) {
uv = new Point(uv1.x + (uv2.x - uv1.x)*t, uv1.y + (uv2.y - uv1.y)*t);
frontUVs[index2] = uv;
backUVs[index1] = uv;
} else {
uv.x = uv1.x + (uv2.x - uv1.x)*t;
uv.y = uv1.y + (uv2.y - uv1.y)*t;
}
firstSplit = false;
index2++;
index1++;
if (point == frontPoints[index2]) {
if (frontUVs[index2] == null) {
frontUVs[index2] = uvs[i];
}
index2++;
}
if (point == backPoints[index1]) {
if (backUVs[index1] == null) {
backUVs[index1] = uvs[i];
}
index1++;
}
}
}
// Проверяем рассечение последнего ребра
if (index2 < primitive.frontFragment.num) {
uv1 = uvs[primitive.num - 1];
uv2 = uvs[0];
t = (firstSplit) ? primitive.splitTime1 : primitive.splitTime2;
uv = frontUVs[index2];
if (uv == null) {
uv = new Point(uv1.x + (uv2.x - uv1.x)*t, uv1.y + (uv2.y - uv1.y)*t);
frontUVs[index2] = uv;
backUVs[index1] = uv;
} else {
uv.x = uv1.x + (uv2.x - uv1.x)*t;
uv.y = uv1.y + (uv2.y - uv1.y)*t;
}
}
calculatePrimitiveUV(primitive.backFragment);
calculatePrimitiveUV(primitive.frontFragment);
}
}
/**
* @private
* Удаление UV в примитиве и его фрагментах
* @param primitive
*/
private function removePrimitiveUV(primitive:PolyPrimitive):void {
// Очищаем список UV
for (var i:uint = 0; i < primitive.num; i++) {
primitive.uvs[i] = null;
}
// Если есть фрагменты, удаляем UV в них
if (primitive.backFragment != null) {
removePrimitiveUV(primitive.backFragment);
removePrimitiveUV(primitive.frontFragment);
}
}
/**
* Массив вершин грани, представленных объектами класса alternativa.engine3d.core.Vertex.
*
* @see Vertex
*/
public function get vertices():Array {
return new Array().concat(_vertices);
}
/**
* Количество вершин грани.
*/
public function get verticesCount():uint {
return _verticesCount;
}
/**
* Полигональный объект, которому принадлежит грань.
*/
public function get mesh():Mesh {
return _mesh;
}
/**
* Поверхность, которой принадлежит грань.
*/
public function get surface():Surface {
return _surface;
}
/**
* Идентификатор грани в полигональном объекте. В случае, если грань не принадлежит ни одному объекту, идентификатор
* имеет значение null.
*/
public function get id():Object {
return (_mesh != null) ? _mesh.getFaceId(this) : null;
}
/**
* UV-координаты, соответствующие первой вершине грани.
*/
public function get aUV():Point {
return (_aUV != null) ? _aUV.clone() : null;
}
/**
* UV-координаты, соответствующие второй вершине грани.
*/
public function get bUV():Point {
return (_bUV != null) ? _bUV.clone() : null;
}
/**
* UV-координаты, соответствующие третьей вершине грани.
*/
public function get cUV():Point {
return (_cUV != null) ? _cUV.clone() : null;
}
/**
* @private
*/
public function set aUV(value:Point):void {
if (_aUV != null) {
if (value != null) {
if (!_aUV.equals(value)) {
_aUV.x = value.x;
_aUV.y = value.y;
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
} else {
_aUV = null;
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
} else {
if (value != null) {
_aUV = value.clone();
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
}
}
/**
* @private
*/
public function set bUV(value:Point):void {
if (_bUV != null) {
if (value != null) {
if (!_bUV.equals(value)) {
_bUV.x = value.x;
_bUV.y = value.y;
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
} else {
_bUV = null;
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
} else {
if (value != null) {
_bUV = value.clone();
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
}
}
/**
* @private
*/
public function set cUV(value:Point):void {
if (_cUV != null) {
if (value != null) {
if (!_cUV.equals(value)) {
_cUV.x = value.x;
_cUV.y = value.y;
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
} else {
_cUV = null;
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
} else {
if (value != null) {
_cUV = value.clone();
if (_mesh != null) {
_mesh.addOperationToScene(calculateUVOperation);
}
}
}
}
/**
* Нормаль в локальной системе координат.
*/
public function get normal():Point3D {
var res:Point3D = new Point3D();
var vertex:Vertex = _vertices[0];
var av:Point3D = vertex.coords;
vertex = _vertices[1];
var bv:Point3D = vertex.coords;
var abx:Number = bv.x - av.x;
var aby:Number = bv.y - av.y;
var abz:Number = bv.z - av.z;
vertex = _vertices[2];
var cv:Point3D = vertex.coords;
var acx:Number = cv.x - av.x;
var acy:Number = cv.y - av.y;
var acz:Number = cv.z - av.z;
res.x = acz*aby - acy*abz;
res.y = acx*abz - acz*abx;
res.z = acy*abx - acx*aby;
if (res.x != 0 || res.y != 0 || res.z != 0) {
var k:Number = Math.sqrt(res.x*res.x + res.y*res.y + res.z*res.z);
res.x /= k;
res.y /= k;
res.z /= k;
}
return res;
}
/**
* Расчёт UV-координат для произвольной точки в системе координат объекта, которому принадлежит грань.
*
* @param point точка в плоскости грани, для которой производится расчёт UV-координат
* @return UV-координаты заданной точки
*/
public function getUV(point:Point3D):Point {
return getUVFast(point, normal);
}
/**
* @private
* Расчёт UV-координат для произвольной точки в локальной системе координат без расчёта
* локальной нормали грани. Используется для оптимизации.
*
* @param point точка в плоскости грани, для которой производится расчёт UV-координат
* @param normal нормаль плоскости грани в локальной системе координат
* @return UV-координаты заданной точки
*/
alternativa3d function getUVFast(point:Point3D, normal:Point3D):Point {
if (_aUV == null || _bUV == null || _cUV == null) {
return null;
}
// Выбор наиболее длинной оси нормали
var dir:uint;
if (((normal.x < 0) ? -normal.x : normal.x) > ((normal.y < 0) ? -normal.y : normal.y)) {
if (((normal.x < 0) ? -normal.x : normal.x) > ((normal.z < 0) ? -normal.z : normal.z)) {
dir = 0;
} else {
dir = 2;
}
} else {
if (((normal.y < 0) ? -normal.y : normal.y) > ((normal.z < 0) ? -normal.z : normal.z)) {
dir = 1;
} else {
dir = 2;
}
}
// Расчёт соотношения по векторам AB и AC
var v:Vertex = _vertices[0];
var a:Point3D = v._coords;
v = _vertices[1];
var b:Point3D = v._coords;
v = _vertices[2];
var c:Point3D = v._coords;
var ab1:Number = (dir == 0) ? (b.y - a.y) : (b.x - a.x);
var ab2:Number = (dir == 2) ? (b.y - a.y) : (b.z - a.z);
var ac1:Number = (dir == 0) ? (c.y - a.y) : (c.x - a.x);
var ac2:Number = (dir == 2) ? (c.y - a.y) : (c.z - a.z);
var det:Number = ab1*ac2 - ac1*ab2;
var ad1:Number = (dir == 0) ? (point.y - a.y) : (point.x - a.x);
var ad2:Number = (dir == 2) ? (point.y - a.y) : (point.z - a.z);
var abk:Number = (ad1*ac2 - ac1*ad2)/det;
var ack:Number = (ab1*ad2 - ad1*ab2)/det;
// Интерполяция по UV первых точек
var abu:Number = _bUV.x - _aUV.x;
var abv:Number = _bUV.y - _aUV.y;
var acu:Number = _cUV.x - _aUV.x;
var acv:Number = _cUV.y - _aUV.y;
return new Point(_aUV.x + abu*abk + acu*ack, _aUV.y + abv*abk + acv*ack);
}
/**
* Множество граней, имеющих общие рёбра с текущей гранью.
*/
public function get edgeJoinedFaces():Set {
var res:Set = new Set(true);
// Перебираем точки грани
for (var i:uint = 0; i < _verticesCount; i++) {
var a:Vertex = _vertices[i];
var b:Vertex = _vertices[(i < _verticesCount - 1) ? (i + 1) : 0];
// Перебираем грани текущей точки
for (var key:* in a._faces) {
var face:Face = key;
// Если это другая грань и у неё также есть следующая точка
if (face != this && face._vertices.indexOf(b) >= 0) {
// Значит у граней общее ребро
res[face] = true;
}
}
}
return res;
}
/**
* @private
* Удаление всех вершин из грани.
* Очистка базового примитива.
*/
alternativa3d function removeVertices():void {
// Удалить вершины
for (var i:uint = 0; i < _verticesCount; i++) {
// Удаляем из списка
var vertex:Vertex = _vertices.pop();
// Удаляем координаты вершины из примитива
primitive.points.pop();
// Удаляем вершину из грани
vertex.removeFromFace(this);
}
// Обнуляем количество вершин
_verticesCount = 0;
}
/**
* @private
* Добавление грани на сцену
* @param scene
*/
alternativa3d function addToScene(scene:Scene3D):void {
// При добавлении на сцену рассчитываем плоскость и UV
scene.addOperation(calculateNormalOperation);
scene.addOperation(calculateUVOperation);
// Подписываем сцену на операции
updatePrimitiveOperation.addSequel(scene.calculateBSPOperation);
updateMaterialOperation.addSequel(scene.changePrimitivesOperation);
}
/**
* @private
* Удаление грани из сцены
* @param scene
*/
alternativa3d function removeFromScene(scene:Scene3D):void {
// Удаляем все операции из очереди
scene.removeOperation(calculateUVOperation);
scene.removeOperation(calculateFragmentsUVOperation);
scene.removeOperation(calculateNormalOperation);
scene.removeOperation(updatePrimitiveOperation);
scene.removeOperation(updateMaterialOperation);
// Удаляем примитивы из сцены
removePrimitive(primitive);
// Посылаем операцию сцены на расчёт BSP
scene.addOperation(scene.calculateBSPOperation);
// Отписываем сцену от операций
updatePrimitiveOperation.removeSequel(scene.calculateBSPOperation);
updateMaterialOperation.removeSequel(scene.changePrimitivesOperation);
}
/**
* @private
* Добавление грани в меш
* @param mesh
*/
alternativa3d function addToMesh(mesh:Mesh):void {
// Подписка на операции меша
mesh.changeCoordsOperation.addSequel(updatePrimitiveOperation);
mesh.changeRotationOrScaleOperation.addSequel(calculateNormalOperation);
mesh.calculateMobilityOperation.addSequel(updatePrimitiveOperation);
// Сохранить меш
_mesh = mesh;
}
/**
* @private
* Удаление грани из меша
* @param mesh
*/
alternativa3d function removeFromMesh(mesh:Mesh):void {
// Отписка от операций меша
mesh.changeCoordsOperation.removeSequel(updatePrimitiveOperation);
mesh.changeRotationOrScaleOperation.removeSequel(calculateNormalOperation);
mesh.calculateMobilityOperation.removeSequel(updatePrimitiveOperation);
// Удалить ссылку на меш
_mesh = null;
}
/**
* @private
* Добавление к поверхности
*
* @param surface
*/
alternativa3d function addToSurface(surface:Surface):void {
// Подписка поверхности на операции
surface.changeMaterialOperation.addSequel(updateMaterialOperation);
// Если при смене поверхности изменился материал
if (_mesh != null && (_surface != null && _surface._material != surface._material || _surface == null && surface._material != null)) {
// Отправляем сигнал смены материала
_mesh.addOperationToScene(updateMaterialOperation);
}
// Сохранить поверхность
_surface = surface;
}
/**
* @private
* Удаление из поверхности
*
* @param surface
*/
alternativa3d function removeFromSurface(surface:Surface):void {
// Отписка поверхности от операций
surface.changeMaterialOperation.removeSequel(updateMaterialOperation);
// Если был материал
if (surface._material != null) {
// Отправляем сигнал смены материала
_mesh.addOperationToScene(updateMaterialOperation);
}
// Удалить ссылку на поверхность
_surface = null;
}
/**
* Строковое представление объекта.
*
* @return строковое представление объекта
*/
public function toString():String {
var res:String = "[Face ID:" + id + ((_verticesCount > 0) ? " vertices:" : "");
for (var i:uint = 0; i < _verticesCount; i++) {
var vertex:Vertex = _vertices[i];
res += vertex.id + ((i < _verticesCount - 1) ? ", " : "");
}
res += "]";
return res;
}
}
}