Files
alternativa3d-archive/Alternativa3D5/5.4.1/alternativa/engine3d/core/Face.as
2024-10-05 12:11:16 +01:00

921 lines
30 KiB
ActionScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 массив объектов типа <code>alternativa.engine3d.core.Vertex</code>, задающий вершины грани в
* порядке обхода лицевой стороны грани против часовой стрелки.
*
* @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);
}
}
/**
* Массив вершин грани, представленных объектами класса <code>alternativa.engine3d.core.Vertex</code>.
*
* @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;
}
/**
* Идентификатор грани в полигональном объекте. В случае, если грань не принадлежит ни одному объекту, идентификатор
* имеет значение <code>null</code>.
*/
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;
}
}
}