mirror of
https://github.com/MapMakersAndProgrammers/alternativa3d-archive.git
synced 2025-10-26 01:49:05 -07:00
Add A3D6
This commit is contained in:
14
Alternativa3D6/6.0/alternativa/Alternativa3D.as
Normal file
14
Alternativa3D6/6.0/alternativa/Alternativa3D.as
Normal file
@@ -0,0 +1,14 @@
|
||||
package alternativa {
|
||||
|
||||
/**
|
||||
* Класс содержит информацию о версии библиотеки.
|
||||
* Также используется для интеграции библиотеки в среду разработки Adobe Flash.
|
||||
*/
|
||||
public class Alternativa3D {
|
||||
|
||||
/**
|
||||
* Версия библиотеки в формате: версия.подверсия.сборка
|
||||
*/
|
||||
public static const version:String = "6.0.0";
|
||||
}
|
||||
}
|
||||
3
Alternativa3D6/6.0/alternativa/engine3d/alternativa3d.as
Normal file
3
Alternativa3D6/6.0/alternativa/engine3d/alternativa3d.as
Normal file
@@ -0,0 +1,3 @@
|
||||
package alternativa.engine3d {
|
||||
public namespace alternativa3d = "http://alternativaplatform.com/en/alternativa3d";
|
||||
}
|
||||
564
Alternativa3D6/6.0/alternativa/engine3d/core/Camera3D.as
Normal file
564
Alternativa3D6/6.0/alternativa/engine3d/core/Camera3D.as
Normal file
@@ -0,0 +1,564 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.display.Canvas;
|
||||
import alternativa.engine3d.display.DisplayItem;
|
||||
import alternativa.engine3d.display.Skin;
|
||||
import alternativa.engine3d.display.View;
|
||||
import alternativa.engine3d.sorting.Node;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Set;
|
||||
import alternativa.utils.MathUtils;
|
||||
|
||||
import flash.display.DisplayObjectContainer;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Camera3D extends Object3D {
|
||||
|
||||
// Инкремент количества объектов
|
||||
private static var counter:uint = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Поле зрения
|
||||
*/
|
||||
alternativa3d var _fov:Number = MathUtils.DEG90;
|
||||
/**
|
||||
* @private
|
||||
* Фокусное расстояние
|
||||
*/
|
||||
alternativa3d var focalLength:Number;
|
||||
/**
|
||||
* @private
|
||||
* Перспективное искажение
|
||||
*/
|
||||
alternativa3d var focalDistortion:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Вид из камеры
|
||||
*/
|
||||
alternativa3d var _view:View;
|
||||
|
||||
//Половина ширины вьюпорта
|
||||
private var halfWidth:Number;
|
||||
|
||||
//Половина высоты вьюпорта
|
||||
private var halfHeight:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Режим отрисовки
|
||||
*/
|
||||
alternativa3d var _orthographic:Boolean = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Матрица перевода из системы координат камеры в глобальную
|
||||
*/
|
||||
alternativa3d var globalMatrix:Matrix3D = new Matrix3D();
|
||||
/**
|
||||
* @private
|
||||
* Матрица перевода из глобальной системы координат в систему камеры
|
||||
*/
|
||||
alternativa3d var inverseGlobalMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
// Масштаб
|
||||
alternativa3d var _zoom:Number = 1;
|
||||
|
||||
// Реестр отрисованных канвасов
|
||||
private var canvases:Dictionary = new Dictionary();
|
||||
|
||||
// Список канвасов на удаление
|
||||
private var canvasesToRemove:Set = new Set();
|
||||
|
||||
/**
|
||||
* Создание экземпляра камеры.
|
||||
*
|
||||
* @param name имя экземпляра
|
||||
*/
|
||||
public function Camera3D(name:String = null) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
override protected function transform():void {
|
||||
super.transform();
|
||||
// Если есть вьюпорт
|
||||
if (_view != null) {
|
||||
// Помечаем камеру на глобальную трансформацию
|
||||
_scene.camerasToRender[this] = true;
|
||||
}
|
||||
}
|
||||
|
||||
override protected function move():void {
|
||||
super.move();
|
||||
// Если есть вьюпорт
|
||||
if (_view != null) {
|
||||
// Помечаем камеру на глобальную трансформацию
|
||||
_scene.camerasToRender[this] = true;
|
||||
}
|
||||
}
|
||||
|
||||
alternativa3d function render():void {
|
||||
trace(this, "render");
|
||||
|
||||
// Если у пространства сцены есть материал
|
||||
if (_scene._space._material != null) {
|
||||
|
||||
// Расчитываем половины ширины и высоты вьюпорта
|
||||
halfWidth = _view._width*0.5;
|
||||
halfHeight = _view._height*0.5;
|
||||
|
||||
// Если перспектива
|
||||
if (!_orthographic) {
|
||||
// Вычисляем фокусное расстояние
|
||||
focalLength = Math.sqrt(halfWidth*halfWidth + halfHeight*halfHeight)/Math.tan(0.5*_fov);
|
||||
// Вычисляем минимальное (однопиксельное) искажение перспективной коррекции
|
||||
focalDistortion = 1/(focalLength*focalLength);
|
||||
}
|
||||
|
||||
// Расчитываем глобальную трансформацию
|
||||
globalMatrix.copy(spaceMatrix);
|
||||
globalMatrix.combine(space.globalMatrix);
|
||||
|
||||
// Расчитываем инверсную глобальную трансформацию
|
||||
inverseGlobalMatrix.copy(globalMatrix);
|
||||
inverseGlobalMatrix.invert();
|
||||
|
||||
// Создание канваса пространства сцены, если его ещё нет
|
||||
if (_view.canvas == null) {
|
||||
_view.canvas = Canvas.create();
|
||||
_view.addChild(_view.canvas);
|
||||
_view.canvas.x = halfWidth;
|
||||
_view.canvas.y = halfHeight;
|
||||
canvases[_scene._space] = _view.canvas;
|
||||
}
|
||||
|
||||
// Отрисовка пространства сцены
|
||||
renderSpace(_scene._space, _view.canvas);
|
||||
|
||||
} else {
|
||||
// Зачищаем канвас вьюпорта
|
||||
removeViewCanvas();
|
||||
}
|
||||
|
||||
// Снимаем пометки об отрисовке
|
||||
delete _scene.camerasToRender[this];
|
||||
}
|
||||
|
||||
private function renderSpace(space:Space, canvas:Canvas):void {
|
||||
trace("render space", space);
|
||||
|
||||
// Если пространство сцены
|
||||
if (space.space == null) {
|
||||
// Берём в качестве матриц пространства глобальные
|
||||
space.inverseCameraMatrix.copy(globalMatrix);
|
||||
space.cameraMatrix.copy(inverseGlobalMatrix);
|
||||
} else {
|
||||
// Считаем матрицу перевода из системы координат пространства в систему камеры
|
||||
space.cameraMatrix.copy(space.globalMatrix)
|
||||
space.cameraMatrix.combine(inverseGlobalMatrix);
|
||||
// Считаем матрицу перевода из системы координат камеры в систему пространства
|
||||
space.inverseCameraMatrix.copy(space.cameraMatrix);
|
||||
space.inverseCameraMatrix.invert();
|
||||
}
|
||||
|
||||
// Направление камеры в пространстве
|
||||
space.direction.x = space.inverseCameraMatrix.c;
|
||||
space.direction.y = space.inverseCameraMatrix.g;
|
||||
space.direction.z = space.inverseCameraMatrix.k;
|
||||
|
||||
// Расчёт направления и плоскостей отсечения в пространстве
|
||||
if (_orthographic) {
|
||||
// Масштабируем матрицу камеры
|
||||
space.cameraMatrix.scale(_zoom, _zoom, _zoom);
|
||||
// Расчёт плоскостей отсечения
|
||||
space.calculateOrthographicPlanes(halfWidth, halfHeight, _zoom)
|
||||
} else {
|
||||
// Нормализуем направление камеры
|
||||
space.direction.normalize();
|
||||
// Расчёт плоскостей отсечения
|
||||
space.calculatePerspectivePlanes(halfWidth, halfHeight, focalLength)
|
||||
}
|
||||
|
||||
// Отрисовка BSP-дерева
|
||||
/*if (space.root != null) {
|
||||
canvas.previousItem = null;
|
||||
canvas.currentItem = canvas.firstItem;
|
||||
renderNode(space.root, canvas);
|
||||
}*/
|
||||
|
||||
// Удаление помеченных канвасов
|
||||
for (var key:* in canvasesToRemove) {
|
||||
var c:Canvas = key;
|
||||
var parent:DisplayObjectContainer = c.parent;
|
||||
// Если есть объект перед канвасом
|
||||
if (c.previous != null) {
|
||||
// Устанавливаем ему ссылку на следующий
|
||||
c.previous.next = c.next;
|
||||
} else {
|
||||
// Устанавливаем первый объект в родительском канвасе
|
||||
(parent as Canvas).firstItem = c.next;
|
||||
}
|
||||
// Если после канваса есть канвас
|
||||
if (c.next is Canvas) {
|
||||
(c.next as Canvas).previous = c.previous;
|
||||
}
|
||||
// Удаляем из списка отображения
|
||||
parent.removeChild(c);
|
||||
// Отправляем на реиспользование
|
||||
Canvas.destroy(c);
|
||||
}
|
||||
|
||||
// Удаление лишних отрисовочных объектов
|
||||
if (canvas.previous != null) {
|
||||
// Обрываем список
|
||||
canvas.previous.next = null;
|
||||
}
|
||||
var item:DisplayItem = canvas.currentItem;
|
||||
while (item != null) {
|
||||
// Сохраняем следующий
|
||||
var next:DisplayItem = item.next;
|
||||
// Удаляем из канваса
|
||||
canvas.removeChild(item);
|
||||
// Удаляем
|
||||
(item is Skin) ? Skin.destroy(item as Skin) : Canvas.destroy(item as Canvas);
|
||||
// Следующий устанавливаем текущим
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
|
||||
private function renderNode(node:Node, container:Canvas):void {
|
||||
/*
|
||||
var primitives:Set;
|
||||
if (node is DistanceNode) {
|
||||
primitives = (node as DistanceNode).primitives;
|
||||
for (var key:* in primitives) {
|
||||
// Если точечный примитив грани
|
||||
if (key is FaceDistancePrimitive) {
|
||||
var face:Face = (key as FaceDistancePrimitive).face;
|
||||
var skin:Skin;
|
||||
// Пропускаем канвасы и помечаем их на удаление
|
||||
while (container.currentItem is Canvas) {
|
||||
// Помечаем на удаление
|
||||
canvasesToRemove[container.currentItem] = true;
|
||||
// Переключаемся на следующий объект
|
||||
container.previousItem = container.currentItem;
|
||||
container.currentItem = container.currentItem.next;
|
||||
}
|
||||
|
||||
// Если есть текущий объект
|
||||
if (container.currentItem != null) {
|
||||
// Берём текущий скин
|
||||
skin = container.currentItem as Skin;
|
||||
// Переключаемся на следующий объект
|
||||
container.previousItem = skin;
|
||||
container.currentItem = skin.next;
|
||||
} else {
|
||||
// Создаём новый скин
|
||||
skin = Skin.create();
|
||||
// Вставляем скин в конец
|
||||
container.addChild(skin);
|
||||
|
||||
// Обновление списка в текущем канвасе
|
||||
if (container.previousItem != null) {
|
||||
container.previousItem.next = skin;
|
||||
} else {
|
||||
container.firstItem = skin;
|
||||
}
|
||||
|
||||
// Переключаемся на следующий объект
|
||||
container.previousItem = skin;
|
||||
}
|
||||
|
||||
// Отрисовка скина
|
||||
// ...
|
||||
skin.graphics.beginFill(0xFFFF00, 0.3);
|
||||
skin.graphics.drawCircle(0, 0, Math.random()*100);
|
||||
|
||||
} else {
|
||||
// Если примитив объекта
|
||||
if (key is SpriteDistancePrimitive) {
|
||||
|
||||
} else {
|
||||
// Если примитив пространства
|
||||
var space:Space = (key as SpaceDistancePrimitive).space;
|
||||
var canvas:Canvas;
|
||||
|
||||
// Если канвас есть в реестре
|
||||
if ((canvas = canvases[space]) != null) {
|
||||
// Если канвасы не совпадают
|
||||
if (canvas != container.currentItem) {
|
||||
// Разорвать связи с соседними объектами
|
||||
// Если есть объект перед канвасом
|
||||
if (canvas.previous != null) {
|
||||
// Устанавливаем ему ссылку на следующий
|
||||
canvas.previous.next = canvas.next;
|
||||
} else {
|
||||
// Устанавливаем первый объект в родительском канвасе
|
||||
(canvas.parent as Canvas).firstItem = canvas.next;
|
||||
}
|
||||
// Если после канваса есть канвас
|
||||
if (canvas.next is Canvas) {
|
||||
(canvas.next as Canvas).previous = canvas.previous;
|
||||
}
|
||||
|
||||
// Создать новые связи
|
||||
// Установка связи со следующим объектом
|
||||
canvas.next = container.currentItem;
|
||||
// Установка связи с предыдущим объектом
|
||||
canvas.previous = container.previousItem;
|
||||
|
||||
// Обновление списка в текущем канвасе
|
||||
if (container.previousItem != null) {
|
||||
container.previousItem.next = canvas;
|
||||
} else {
|
||||
container.firstItem = canvas;
|
||||
}
|
||||
|
||||
// Если есть текущий объект
|
||||
if (container.currentItem != null) {
|
||||
// Вставляем канвас перед текущим объектом
|
||||
container.addChildAt(canvas, container.getChildIndex(container.currentItem));
|
||||
if (container.currentItem is Canvas) {
|
||||
(container.currentItem as Canvas).previous = canvas;
|
||||
}
|
||||
} else {
|
||||
// Вставляем канвас в конец
|
||||
container.addChild(canvas);
|
||||
}
|
||||
|
||||
// Переключаемся на следующий объект
|
||||
container.previousItem = canvas;
|
||||
|
||||
// Удалить канвас из списка на удаление
|
||||
delete canvasesToRemove[canvas];
|
||||
} else {
|
||||
// Переключаемся на следующий объект
|
||||
container.previousItem = canvas;
|
||||
container.currentItem = canvas.next;
|
||||
}
|
||||
} else {
|
||||
// Создаём новый канвас
|
||||
canvas = new Canvas();
|
||||
// Сохраняем его в реестр
|
||||
canvases[space] = canvas;
|
||||
|
||||
// Создать связи
|
||||
// Установка связи со следующим объектом
|
||||
canvas.next = container.currentItem;
|
||||
// Установка связи с предыдущим объектом
|
||||
canvas.previous = container.previousItem;
|
||||
|
||||
// Обновление списка в текущем канвасе
|
||||
if (container.previousItem != null) {
|
||||
container.previousItem.next = canvas;
|
||||
} else {
|
||||
container.firstItem = canvas;
|
||||
}
|
||||
|
||||
// Если есть текущий объект
|
||||
if (container.currentItem != null) {
|
||||
// Вставляем канвас перед текущим объектом
|
||||
container.addChildAt(canvas, container.getChildIndex(container.currentItem));
|
||||
if (container.currentItem is Canvas) {
|
||||
(container.currentItem as Canvas).previous = canvas;
|
||||
}
|
||||
} else {
|
||||
// Вставляем канвас в конец
|
||||
container.addChild(canvas);
|
||||
}
|
||||
|
||||
// Переключаемся на следующий объект
|
||||
container.previousItem = canvas;
|
||||
}
|
||||
|
||||
// Отрисовка пространства в канвас
|
||||
renderSpace(space, canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
alternativa3d function updateSpace(space:Space):void {
|
||||
trace(this, "updateSpace", space);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
alternativa3d function updateSpaceMaterial(space:Space):void {
|
||||
trace(this, "updateSpaceMaterial", space);
|
||||
|
||||
// Если канвас нарисован, перерисовать его
|
||||
var canvas:Canvas;
|
||||
if ((canvas = canvases[space]) != null) {
|
||||
space._material.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override protected function addToScene():void {
|
||||
super.addToScene();
|
||||
|
||||
// Добавляем камеру в реестр сцены
|
||||
if (_view != null) {
|
||||
_scene.cameras[this] = true;
|
||||
}
|
||||
}
|
||||
|
||||
override protected function removeFromScene():void {
|
||||
super.removeFromScene();
|
||||
|
||||
// Если у камеры есть вьюпорт
|
||||
if (_view != null) {
|
||||
|
||||
// Зачищаем канвас вьюпорта
|
||||
removeViewCanvas();
|
||||
|
||||
// Удаляем камеру из реестра сцены
|
||||
delete _scene.cameras[this];
|
||||
|
||||
// Удаляем все пометки в сцене
|
||||
delete _scene.camerasToRender[this];
|
||||
}
|
||||
}
|
||||
|
||||
private function removeViewCanvas():void {
|
||||
if (_view.canvas != null) {
|
||||
_view.removeChild(_view.canvas);
|
||||
Canvas.destroy(_view.canvas);
|
||||
_view.canvas = null;
|
||||
delete canvases[_scene._space];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Поле вывода, в котором происходит отрисовка камеры.
|
||||
*/
|
||||
public function get view():View {
|
||||
return _view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set view(value:View):void {
|
||||
if (value != _view) {
|
||||
// Если был вьюпорт
|
||||
if (_view != null) {
|
||||
// Зачищаем канвас вьюпорта
|
||||
removeViewCanvas();
|
||||
// Удалить в нём ссылку на камеру
|
||||
_view._camera = null;
|
||||
}
|
||||
// Если назначается вьюпорт
|
||||
if (value != null) {
|
||||
// Если у вьюпорта была камера
|
||||
if (value._camera != null) {
|
||||
// Отцепить от у неё вьюпорт
|
||||
value._camera.view = null;
|
||||
}
|
||||
// Сохранить во вьюпорте ссылку на камеру
|
||||
value._camera = this;
|
||||
// Если есть сцена
|
||||
if (_scene != null) {
|
||||
// Добавляем камеру в реестр сцены
|
||||
_scene.cameras[this] = true;
|
||||
// Помечаем камеру на отрисовку
|
||||
_scene.camerasToRender[this] = true;
|
||||
}
|
||||
} else {
|
||||
if (_scene != null) {
|
||||
// Удаляем камеру из реестра сцены
|
||||
delete _scene.cameras[this];
|
||||
}
|
||||
}
|
||||
// Сохраняем вьюпорт
|
||||
_view = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Включение режима аксонометрической проекции.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
public function get orthographic():Boolean {
|
||||
return _orthographic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set orthographic(value:Boolean):void {
|
||||
if (_orthographic != value) {
|
||||
// Отправляем сигнал об изменении типа камеры
|
||||
// ...
|
||||
// Сохраняем новое значение
|
||||
_orthographic = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Угол поля зрения в радианах в режиме перспективной проекции. При изменении FOV изменяется фокусное расстояние
|
||||
* камеры по формуле <code>f = d/tan(fov/2)</code>, где <code>d</code> является половиной диагонали поля вывода.
|
||||
* Угол зрения ограничен диапазоном 0-180 градусов.
|
||||
*/
|
||||
public function get fov():Number {
|
||||
return _fov;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set fov(value:Number):void {
|
||||
value = (value < 0) ? 0 : ((value > (Math.PI - 0.0001)) ? (Math.PI - 0.0001) : value);
|
||||
if (_fov != value) {
|
||||
// Если перспектива
|
||||
if (!_orthographic) {
|
||||
// Отправляем сигнал об изменении плоскостей отсечения
|
||||
// ...
|
||||
}
|
||||
// Сохраняем новое значение
|
||||
_fov = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Коэффициент увеличения изображения в режиме аксонометрической проекции.
|
||||
*/
|
||||
public function get zoom():Number {
|
||||
return _zoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set zoom(value:Number):void {
|
||||
value = (value < 0) ? 0 : value;
|
||||
if (_zoom != value) {
|
||||
// Если изометрия
|
||||
if (_orthographic) {
|
||||
// Отправляем сигнал об изменении zoom
|
||||
// ...
|
||||
}
|
||||
// Сохраняем новое значение
|
||||
_zoom = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function defaultName():String {
|
||||
return "camera" + ++counter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
483
Alternativa3D6/6.0/alternativa/engine3d/core/Face.as
Normal file
483
Alternativa3D6/6.0/alternativa/engine3d/core/Face.as
Normal file
@@ -0,0 +1,483 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.sorting.FaceDistancePrimitive;
|
||||
import alternativa.engine3d.sorting.FaceBSPPrimitive;
|
||||
import alternativa.types.Point3D;
|
||||
import alternativa.types.Set;
|
||||
import alternativa.engine3d.sorting.FaceNonePrimitive;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Грань, образованная тремя или более вершинами. Грани являются составными частями полигональных объектов. Каждая грань
|
||||
* содержит информацию об объекте и поверхности, которым она принадлежит. Для обеспечения возможности наложения
|
||||
* текстуры на грань, первым трём её вершинам могут быть заданы UV-координаты, на основании которых расчитывается
|
||||
* матрица трансформации текстуры.
|
||||
*/
|
||||
final public class Face {
|
||||
/**
|
||||
* @private
|
||||
* Меш
|
||||
*/
|
||||
alternativa3d var _mesh:Mesh;
|
||||
/**
|
||||
* @private
|
||||
* Поверхность
|
||||
*/
|
||||
alternativa3d var _surface:Surface;
|
||||
/**
|
||||
* @private
|
||||
* Вершины грани
|
||||
*/
|
||||
alternativa3d var _vertices:Array = new Array();
|
||||
/**
|
||||
* @private
|
||||
* Количество вершин
|
||||
*/
|
||||
alternativa3d var _verticesCount:uint;
|
||||
/**
|
||||
* @private
|
||||
* Нормаль плоскости в пространстве
|
||||
*/
|
||||
alternativa3d var spacePerpendicular:Point3D = new Point3D();
|
||||
/**
|
||||
* @private
|
||||
* Примитив грани
|
||||
*/
|
||||
alternativa3d var primitive:FaceNonePrimitive;
|
||||
alternativa3d var pointPrimitive:FaceDistancePrimitive;
|
||||
alternativa3d var polyPrimitive:FaceBSPPrimitive;
|
||||
|
||||
alternativa3d function calculatePerpendicular():void {
|
||||
trace(this, "- calculatePerpendicular");
|
||||
|
||||
// Вектор AB
|
||||
var vertex:Vertex = _vertices[0];
|
||||
var av:Point3D = vertex.spaceCoords;
|
||||
vertex = _vertices[1];
|
||||
var bv:Point3D = vertex.spaceCoords;
|
||||
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.spaceCoords;
|
||||
var acx:Number = cv.x - av.x;
|
||||
var acy:Number = cv.y - av.y;
|
||||
var acz:Number = cv.z - av.z;
|
||||
// Перпендикуляр к плоскости
|
||||
spacePerpendicular.x = acz*aby - acy*abz;
|
||||
spacePerpendicular.y = acx*abz - acz*abx;
|
||||
spacePerpendicular.z = acy*abx - acx*aby;
|
||||
|
||||
//TODO: проверить на нулевой перпендикуляр
|
||||
}
|
||||
|
||||
private function preparePointPrimitive():void {
|
||||
// Расчёт центра грани
|
||||
pointPrimitive.coords.x = 0;
|
||||
pointPrimitive.coords.y = 0;
|
||||
pointPrimitive.coords.z = 0;
|
||||
for each (var vertex:Vertex in _vertices) {
|
||||
pointPrimitive.coords.x += vertex.spaceCoords.x;
|
||||
pointPrimitive.coords.y += vertex.spaceCoords.y;
|
||||
pointPrimitive.coords.z += vertex.spaceCoords.z;
|
||||
}
|
||||
pointPrimitive.coords.x /= _verticesCount;
|
||||
pointPrimitive.coords.y /= _verticesCount;
|
||||
pointPrimitive.coords.z /= _verticesCount;
|
||||
}
|
||||
|
||||
private function preparePolyPrimitive():void {
|
||||
// Расчёт смещения плоскости
|
||||
|
||||
// Установка приоритета
|
||||
polyPrimitive.bspLevel = _surface._bspLevel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
alternativa3d function createPointPrimitive():void {
|
||||
trace(this, "- createPointPrimitive");
|
||||
|
||||
// Создание точечного примитива
|
||||
pointPrimitive = FaceDistancePrimitive.create();
|
||||
// Подготовка точечного примитива
|
||||
preparePointPrimitive();
|
||||
// Добавление примитива в уровень
|
||||
_surface._sortingLevel.distancePrimitivesToAdd.push(pointPrimitive);
|
||||
}
|
||||
|
||||
alternativa3d function createPolyPrimitive():void {
|
||||
trace(this, "- createPolyPrimitive");
|
||||
|
||||
// Создание полигонального примитива
|
||||
polyPrimitive = FaceBSPPrimitive.create();
|
||||
// Подготовка полигонального примитива
|
||||
preparePolyPrimitive();
|
||||
// Добавление примитива в уровень
|
||||
_surface._sortingLevel.bspPrimitivesToAdd.push(polyPrimitive);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
alternativa3d function updatePointPrimitive():void {
|
||||
trace(this, "- updatePointPrimitive");
|
||||
|
||||
// Удаляем примитив
|
||||
pointPrimitive.node.removePrimitive(pointPrimitive);
|
||||
// Подготовка точечного примитива
|
||||
preparePointPrimitive();
|
||||
// Добавление примитива в уровень
|
||||
_surface._sortingLevel.distancePrimitivesToAdd.push(pointPrimitive);
|
||||
}
|
||||
|
||||
alternativa3d function updatePolyPrimitive():void {
|
||||
trace(this, "- updatePolyPrimitive");
|
||||
|
||||
// Удаляем примитив
|
||||
polyPrimitive.node.removePrimitive(polyPrimitive);
|
||||
// Подготовка полигонального примитива
|
||||
preparePolyPrimitive();
|
||||
// Добавление примитива в уровень
|
||||
_surface._sortingLevel.bspPrimitivesToAdd.push(polyPrimitive);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
alternativa3d function redrawPointPrimitive():void {
|
||||
trace(this, "- redrawPointPrimitive");
|
||||
|
||||
// Помечаем примитив на перерисовку
|
||||
_surface._sortingLevel.changedPrimitives[pointPrimitive] = true;
|
||||
}
|
||||
|
||||
alternativa3d function redrawPolyPrimitive():void {
|
||||
trace(this, "- redrawPolyPrimitive");
|
||||
|
||||
_surface._sortingLevel.changedPrimitives[polyPrimitive] = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
alternativa3d function changePolyToPointPrimitive():void {
|
||||
trace(this, "- changePolyToPointPrimitive");
|
||||
|
||||
// Удаляем примитив
|
||||
polyPrimitive.node.removePrimitive(polyPrimitive);
|
||||
// Смена типа примитива с полигонального на точечный
|
||||
FaceBSPPrimitive.defer(polyPrimitive);
|
||||
polyPrimitive = null;
|
||||
pointPrimitive = FaceDistancePrimitive.create();
|
||||
// Подготовка точечного примитива
|
||||
preparePointPrimitive();
|
||||
// Добавление примитива в уровень
|
||||
_surface._sortingLevel.distancePrimitivesToAdd.push(pointPrimitive);
|
||||
}
|
||||
|
||||
alternativa3d function changePointToPolyPrimitive():void {
|
||||
trace(this, "- changePointToPolyPrimitive");
|
||||
|
||||
// Удаляем примитив
|
||||
pointPrimitive.node.removePrimitive(pointPrimitive);
|
||||
// Смена типа примитива с точечного на полигональный
|
||||
FaceDistancePrimitive.defer(pointPrimitive);
|
||||
pointPrimitive = null;
|
||||
polyPrimitive = FaceBSPPrimitive.create();
|
||||
// Подготовка полигонального примитива
|
||||
preparePolyPrimitive();
|
||||
// Добавление примитива в уровень
|
||||
_surface._sortingLevel.bspPrimitivesToAdd.push(polyPrimitive);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
alternativa3d function destroyPointPrimitive():void {
|
||||
trace(this, "- destroyPointPrimitive");
|
||||
|
||||
// Удаляем примитив
|
||||
pointPrimitive.node.removePrimitive(pointPrimitive);
|
||||
// Удаляем примитив
|
||||
FaceDistancePrimitive.defer(pointPrimitive);
|
||||
pointPrimitive = null;
|
||||
}
|
||||
|
||||
alternativa3d function destroyPolyPrimitive():void {
|
||||
trace(this, "- destroyPolyPrimitive");
|
||||
|
||||
// Удаляем примитив
|
||||
polyPrimitive.node.removePrimitive(polyPrimitive);
|
||||
// Разрушаем примитив
|
||||
FaceBSPPrimitive.defer(polyPrimitive);
|
||||
polyPrimitive = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
alternativa3d function updatePolyPrimitiveBSPLevel():void {
|
||||
trace(this, "- updatePolyPrimitiveBSPLevel");
|
||||
|
||||
// Удаляем примитив
|
||||
polyPrimitive.node.removePrimitive(polyPrimitive);
|
||||
// Обновляем приоритет примитива
|
||||
polyPrimitive.bspLevel = _surface._bspLevel;
|
||||
// Отправляем примитив на добавление в уровень
|
||||
_surface._sortingLevel.bspPrimitivesToAdd.push(polyPrimitive);
|
||||
}
|
||||
|
||||
alternativa3d function changeSurface():void {
|
||||
trace(this, "changeSurface");
|
||||
|
||||
// Если есть поверхность и материал
|
||||
if (_surface != null && _surface._material != null) {
|
||||
// Если BSP-сортировка
|
||||
if (_surface._sortingMode == 2) {
|
||||
// Если есть полигональный примитив
|
||||
if (polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (_mesh._scene.facesToTransform[this]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
calculatePerpendicular();
|
||||
// Обновление полигонального примитива
|
||||
updatePolyPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
} else {
|
||||
// Если изменилась мобильность
|
||||
if (polyPrimitive.bspLevel != _surface._bspLevel) {
|
||||
// Обновляем мобильность примитива
|
||||
updatePolyPrimitiveBSPLevel();
|
||||
} else {
|
||||
// Отправить полигональный примитив на перерисовку
|
||||
redrawPolyPrimitive();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если есть точечный примитив
|
||||
if (pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (_mesh._scene.facesToTransform[this]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
}
|
||||
// Смена типа примитива с точечного на полигональный
|
||||
changePointToPolyPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
calculatePerpendicular();
|
||||
// Создание полигонального примитива
|
||||
createPolyPrimitive();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если точечная сортировка
|
||||
if (_surface._sortingMode == 1) {
|
||||
// Если есть точечный примитив
|
||||
if (pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (_mesh._scene.facesToTransform[this]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
calculatePerpendicular();
|
||||
// Обновление точечного примитива
|
||||
updatePointPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
} else {
|
||||
// Отправить точечный примитив на перерисовку
|
||||
redrawPointPrimitive();
|
||||
}
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (_mesh._scene.facesToTransform[this]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
}
|
||||
// Смена типа примитива с полигонального на точечный
|
||||
changePolyToPointPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
calculatePerpendicular();
|
||||
// Создание точечного примитива
|
||||
createPointPrimitive();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если нет сортировки
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если был точечный примитив
|
||||
if (pointPrimitive != null) {
|
||||
// Удаляем точечный примитив
|
||||
destroyPointPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
} else {
|
||||
// Если был полигональный примитив
|
||||
if (polyPrimitive != null) {
|
||||
// Удаляем полигональный примитив
|
||||
destroyPolyPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Помечаем пространство на пересчёт
|
||||
_mesh._scene.spacesToCalculate[_mesh.space] = true;
|
||||
// Снимаем пометку на смену поверхности
|
||||
delete _mesh._scene.facesToChangeSurface[this];
|
||||
}
|
||||
|
||||
// Вызывается только при изменении координат хотя бы одной из вершин
|
||||
alternativa3d function transform():void {
|
||||
trace(this, "transform");
|
||||
|
||||
// Расчитываем перпендикуляр
|
||||
calculatePerpendicular();
|
||||
|
||||
if (pointPrimitive != null) {
|
||||
updatePointPrimitive();
|
||||
} else {
|
||||
updatePolyPrimitive();
|
||||
}
|
||||
|
||||
// Помечаем пространство на пересчёт
|
||||
_mesh._scene.spacesToCalculate[_mesh.space] = true;
|
||||
// Снимаем пометку на трансформацию
|
||||
delete _mesh._scene.facesToTransform[this];
|
||||
}
|
||||
|
||||
/**
|
||||
* Массив вершин грани, представленных объектами класса <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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Нормаль в локальной системе координат.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Множество граней, имеющих общие рёбра с текущей гранью.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление грани.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
1084
Alternativa3D6/6.0/alternativa/engine3d/core/Mesh.as
Normal file
1084
Alternativa3D6/6.0/alternativa/engine3d/core/Mesh.as
Normal file
File diff suppressed because it is too large
Load Diff
645
Alternativa3D6/6.0/alternativa/engine3d/core/Object3D.as
Normal file
645
Alternativa3D6/6.0/alternativa/engine3d/core/Object3D.as
Normal file
@@ -0,0 +1,645 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.errors.Object3DHierarchyError;
|
||||
import alternativa.engine3d.errors.Object3DNotFoundError;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
import alternativa.types.Set;
|
||||
import alternativa.utils.ObjectUtils;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый класс для объектов, находящихся в сцене. Класс реализует иерархию объектов сцены, а также содержит сведения
|
||||
* о трансформации объекта как единого целого.
|
||||
*
|
||||
* <p> Масштабирование, ориентация и положение объекта задаются в родительской системе координат. Результирующая
|
||||
* локальная трансформация является композицией операций масштабирования, поворотов объекта относительно осей
|
||||
* <code>X</code>, <code>Y</code>, <code>Z</code> и параллельного переноса центра объекта из начала координат.
|
||||
* Операции применяются в порядке их перечисления.
|
||||
*
|
||||
* <p> Глобальная трансформация (в системе координат корневого объекта сцены) является композицией трансформаций
|
||||
* самого объекта и всех его предков по иерархии объектов сцены.
|
||||
*/
|
||||
public class Object3D {
|
||||
|
||||
// Инкремент количества объектов
|
||||
private static var counter:uint = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Наименование
|
||||
*/
|
||||
alternativa3d var _name:String;
|
||||
/**
|
||||
* @private
|
||||
* Сцена
|
||||
*/
|
||||
alternativa3d var _scene:Scene3D;
|
||||
/**
|
||||
* @private
|
||||
* Родительский объект
|
||||
*/
|
||||
alternativa3d var _parent:Object3D;
|
||||
/**
|
||||
* @private
|
||||
* Дочерние объекты
|
||||
*/
|
||||
alternativa3d var _children:Set = new Set();
|
||||
/**
|
||||
* @private
|
||||
* Пространство
|
||||
*/
|
||||
alternativa3d var space:Space;
|
||||
/**
|
||||
* @private
|
||||
* Координаты объекта относительно родителя
|
||||
*/
|
||||
alternativa3d var _coords:Point3D = new Point3D();
|
||||
/**
|
||||
* @private
|
||||
* Поворот объекта по оси X относительно родителя. Угол измеряется в радианах.
|
||||
*/
|
||||
alternativa3d var _rotationX:Number = 0;
|
||||
/**
|
||||
* @private
|
||||
* Поворот объекта по оси Y относительно родителя. Угол измеряется в радианах.
|
||||
*/
|
||||
alternativa3d var _rotationY:Number = 0;
|
||||
/**
|
||||
* @private
|
||||
* Поворот объекта по оси Z относительно родителя. Угол измеряется в радианах.
|
||||
*/
|
||||
alternativa3d var _rotationZ:Number = 0;
|
||||
/**
|
||||
* @private
|
||||
* Мастшаб объекта по оси X относительно родителя
|
||||
*/
|
||||
alternativa3d var _scaleX:Number = 1;
|
||||
/**
|
||||
* @private
|
||||
* Мастшаб объекта по оси Y относительно родителя
|
||||
*/
|
||||
alternativa3d var _scaleY:Number = 1;
|
||||
/**
|
||||
* @private
|
||||
* Мастшаб объекта по оси Z относительно родителя
|
||||
*/
|
||||
alternativa3d var _scaleZ:Number = 1;
|
||||
/**
|
||||
* @private
|
||||
* Матрица перевода из локальной системы координат объекта в систему пространства
|
||||
*/
|
||||
alternativa3d var spaceMatrix:Matrix3D = new Matrix3D();
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param name имя экземпляра
|
||||
*/
|
||||
public function Object3D(name:String = null) {
|
||||
// Имя по-умолчанию
|
||||
_name = (name != null) ? name : defaultName();
|
||||
}
|
||||
|
||||
protected function transform():void {
|
||||
trace(this, "- transform");
|
||||
|
||||
// Если объект был в пространстве, помечаем пространство на пересчет
|
||||
//if (space != null) {
|
||||
// _scene.spacesToCalculate[space] = true;
|
||||
//}
|
||||
// Обновляем пространство
|
||||
space = (_parent is Space) ? Space(_parent) : _parent.space;
|
||||
// Помечаем пространство на пересчет
|
||||
//_scene.spacesToCalculate[space] = true;
|
||||
|
||||
// Локальная матрица трансформации
|
||||
spaceMatrix.toTransform(_coords.x, _coords.y, _coords.z, _rotationX, _rotationY, _rotationZ, _scaleX, _scaleY, _scaleZ);
|
||||
// Если родитель не является пространством
|
||||
if (!(_parent is Space)) {
|
||||
// Наследуем трансформацию у родителя
|
||||
spaceMatrix.combine(_parent.spaceMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
protected function move():void {
|
||||
trace("- move");
|
||||
|
||||
// Помечаем пространство на пересчет
|
||||
//_scene.spacesToCalculate[space] = true;
|
||||
|
||||
// Если родитель является пространством
|
||||
if (_parent is Space) {
|
||||
// Смещение равно локальным координатам
|
||||
spaceMatrix.d = _coords.x;
|
||||
spaceMatrix.h = _coords.y;
|
||||
spaceMatrix.l = _coords.z;
|
||||
} else {
|
||||
// Расчитываем новое смещение c учётом трансформации родителя
|
||||
var x:Number = _coords.x;
|
||||
var y:Number = _coords.y;
|
||||
var z:Number = _coords.z;
|
||||
var parentTransformation:Matrix3D = _parent.spaceMatrix;
|
||||
spaceMatrix.d = parentTransformation.a*x + parentTransformation.b*y + parentTransformation.c*z + parentTransformation.d;
|
||||
spaceMatrix.h = parentTransformation.e*x + parentTransformation.f*y + parentTransformation.g*z + parentTransformation.h;
|
||||
spaceMatrix.l = parentTransformation.i*x + parentTransformation.j*y + parentTransformation.k*z + parentTransformation.l;
|
||||
}
|
||||
}
|
||||
|
||||
alternativa3d function transformBranch():void {
|
||||
trace(this, "transformBranch");
|
||||
|
||||
// Трансформация
|
||||
transform();
|
||||
// Если объект не пространство, наследуем трансформацию
|
||||
if (!(this is Space)) {
|
||||
// Обрабатываем дочерние объекты
|
||||
for (var key:* in _children) {
|
||||
var child:Object3D = key;
|
||||
child.transformBranch();
|
||||
}
|
||||
}
|
||||
|
||||
// Снимаем отметки о перемещении, трансформации и мобильности
|
||||
delete _scene.objectsToTransform[this];
|
||||
delete _scene.objectsToMove[this];
|
||||
}
|
||||
|
||||
alternativa3d function moveBranch():void {
|
||||
trace(this, "moveBranch");
|
||||
|
||||
// Перемещение
|
||||
move();
|
||||
// Если объект не пространство, наследуем перемещение
|
||||
if (!(this is Space)) {
|
||||
// Обрабатываем дочерние объекты
|
||||
for (var key:* in _children) {
|
||||
var child:Object3D = key;
|
||||
_scene.objectsToTransform[child] ? child.transformBranch() : child.moveBranch();
|
||||
}
|
||||
}
|
||||
|
||||
// Снимаем отметку о перемещении
|
||||
delete _scene.objectsToMove[this];
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавление дочернего объекта. Добавляемый объект удаляется из списка детей предыдущего родителя.
|
||||
* Новой сценой дочернего объекта становится сцена родителя.
|
||||
*
|
||||
* @param child добавляемый объект
|
||||
*
|
||||
* @throws alternativa.engine3d.errors.Object3DHierarchyError нарушение иерархии объектов сцены
|
||||
*/
|
||||
public function addChild(child:Object3D):void {
|
||||
|
||||
// Проверка на null
|
||||
if (child == null) {
|
||||
throw new Object3DHierarchyError(null, this);
|
||||
}
|
||||
|
||||
// Проверка на наличие
|
||||
if (child._parent == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверка на добавление к самому себе
|
||||
if (child == this) {
|
||||
throw new Object3DHierarchyError(this, this);
|
||||
}
|
||||
|
||||
// Проверка на добавление родительского объекта
|
||||
if (child._scene == _scene) {
|
||||
// Если объект был в той же сцене, либо оба не были в сцене
|
||||
var parentObject:Object3D = _parent;
|
||||
while (parentObject != null) {
|
||||
if (child == parentObject) {
|
||||
throw new Object3DHierarchyError(child, this);
|
||||
return;
|
||||
}
|
||||
parentObject = parentObject._parent;
|
||||
}
|
||||
}
|
||||
|
||||
// Если объект был в другом объекте
|
||||
if (child._parent != null) {
|
||||
// Удалить его оттуда
|
||||
child._parent._children.remove(child);
|
||||
} else {
|
||||
// Если объект был корневым в сцене
|
||||
if (child._scene != null) {
|
||||
child._scene.space = null;
|
||||
}
|
||||
}
|
||||
// Добавляем в список
|
||||
_children.add(child);
|
||||
|
||||
// Указываем себя как родителя
|
||||
child._parent = this;
|
||||
|
||||
// Указываем сцену
|
||||
child.setScene(_scene);
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаление дочернего объекта.
|
||||
*
|
||||
* @param child удаляемый дочерний объект
|
||||
*
|
||||
* @throws alternativa.engine3d.errors.Object3DNotFoundError указанный объект не содержится в списке детей текущего объекта
|
||||
*/
|
||||
public function removeChild(child:Object3D):void {
|
||||
// Проверка на null
|
||||
if (child == null) {
|
||||
throw new Object3DNotFoundError(null, this);
|
||||
}
|
||||
// Проверка на наличие
|
||||
if (child._parent != this) {
|
||||
throw new Object3DNotFoundError(child, this);
|
||||
}
|
||||
// Убираем из списка
|
||||
_children.remove(child);
|
||||
// Удаляем ссылку на родителя
|
||||
child._parent = null;
|
||||
// Удаляем ссылку на сцену
|
||||
child.setScene(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Установка новой сцены для объекта.
|
||||
*
|
||||
* @param value сцена
|
||||
*/
|
||||
alternativa3d function setScene(value:Scene3D):void {
|
||||
if (_scene != value) {
|
||||
// Если была сцена
|
||||
if (_scene != null) {
|
||||
// Удалиться из сцены
|
||||
removeFromScene();
|
||||
}
|
||||
// Сохранить сцену
|
||||
_scene = value;
|
||||
// Если новая сцена
|
||||
if (value != null) {
|
||||
// Добавиться на сцену
|
||||
addToScene();
|
||||
}
|
||||
// Установить эту сцену у дочерних объектов
|
||||
for (var key:* in _children) {
|
||||
var object:Object3D = key;
|
||||
object.setScene(value);
|
||||
}
|
||||
} else {
|
||||
// При перемещении в пределах сцены пересчёт
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод вызывается при добавлении объекта на сцену. Наследники могут переопределять метод для выполнения
|
||||
* специфических действий.
|
||||
*/
|
||||
protected function addToScene():void {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод вызывается при удалении объекта со сцены. Наследники могут переопределять метод для выполнения
|
||||
* специфических действий.
|
||||
*/
|
||||
protected function removeFromScene():void {
|
||||
|
||||
/* // Если объект был в пространстве
|
||||
if (space != null) {
|
||||
// Помечаем пространство на пересчет
|
||||
_scene.spacesToCalculate[space] = true;
|
||||
// Удаляем ссылку на пространство
|
||||
space = null;
|
||||
}
|
||||
*/
|
||||
// Удаляем ссылку на пространство
|
||||
space = null;
|
||||
|
||||
// Удаляем все пометки в сцене
|
||||
delete _scene.objectsToTransform[this];
|
||||
delete _scene.objectsToMove[this];
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя объекта.
|
||||
*/
|
||||
public function get name():String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set name(value:String):void {
|
||||
_name = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сцена, которой принадлежит объект.
|
||||
*/
|
||||
public function get scene():Scene3D {
|
||||
return _scene;
|
||||
}
|
||||
|
||||
/**
|
||||
* Родительский объект.
|
||||
*/
|
||||
public function get parent():Object3D {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Набор дочерних объектов.
|
||||
*/
|
||||
public function get children():Set {
|
||||
return _children.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Координата X.
|
||||
*/
|
||||
public function get x():Number {
|
||||
return _coords.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Координата Y.
|
||||
*/
|
||||
public function get y():Number {
|
||||
return _coords.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Координата Z.
|
||||
*/
|
||||
public function get z():Number {
|
||||
return _coords.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set x(value:Number):void {
|
||||
if (_coords.x != value) {
|
||||
_coords.x = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToMove[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set y(value:Number):void {
|
||||
if (_coords.y != value) {
|
||||
_coords.y = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToMove[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set z(value:Number):void {
|
||||
if (_coords.z != value) {
|
||||
_coords.z = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToMove[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Координаты объекта.
|
||||
*/
|
||||
public function get coords():Point3D {
|
||||
return _coords.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set coords(value:Point3D):void {
|
||||
if (!_coords.equals(value)) {
|
||||
_coords.copy(value);
|
||||
if (_scene != null) {
|
||||
_scene.objectsToMove[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси X, заданный в радианах.
|
||||
*/
|
||||
public function get rotationX():Number {
|
||||
return _rotationX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси Y, заданный в радианах.
|
||||
*/
|
||||
public function get rotationY():Number {
|
||||
return _rotationY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси Z, заданный в радианах.
|
||||
*/
|
||||
public function get rotationZ():Number {
|
||||
return _rotationZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set rotationX(value:Number):void {
|
||||
if (_rotationX != value) {
|
||||
_rotationX = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set rotationY(value:Number):void {
|
||||
if (_rotationY != value) {
|
||||
_rotationY = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set rotationZ(value:Number):void {
|
||||
if (_rotationZ != value) {
|
||||
_rotationZ = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования вдоль оси X.
|
||||
*/
|
||||
public function get scaleX():Number {
|
||||
return _scaleX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования вдоль оси Y.
|
||||
*/
|
||||
public function get scaleY():Number {
|
||||
return _scaleY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования вдоль оси Z.
|
||||
*/
|
||||
public function get scaleZ():Number {
|
||||
return _scaleZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set scaleX(value:Number):void {
|
||||
if (_scaleX != value) {
|
||||
_scaleX = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set scaleY(value:Number):void {
|
||||
if (_scaleY != value) {
|
||||
_scaleY = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set scaleZ(value:Number):void {
|
||||
if (_scaleZ != value) {
|
||||
_scaleZ = value;
|
||||
if (_scene != null) {
|
||||
_scene.objectsToTransform[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*
|
||||
* @return строковое представление объекта
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[" + ObjectUtils.getClassName(this) + " " + _name + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя объекта по умолчанию.
|
||||
*
|
||||
* @return имя объекта по умолчанию
|
||||
*/
|
||||
protected function defaultName():String {
|
||||
return "object" + ++counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создание пустого объекта без какой-либо внутренней структуры. Например, если некоторый геометрический примитив при
|
||||
* своём создании формирует набор вершин, граней и поверхностей, то этот метод не должен создавать вершины, грани и
|
||||
* поверхности. Данный метод используется в методе clone() и должен быть переопределён в потомках для получения
|
||||
* правильного объекта.
|
||||
*
|
||||
* @return новый пустой объект
|
||||
*/
|
||||
protected function createEmptyObject():Object3D {
|
||||
return new Object3D();
|
||||
}
|
||||
|
||||
/**
|
||||
* Копирование свойств объекта-источника. Данный метод используется в методе clone() и должен быть переопределён в
|
||||
* потомках для получения правильного объекта. Каждый потомок должен в переопределённом методе копировать только те
|
||||
* свойства, которые добавлены к базовому классу именно в нём. Копирование унаследованных свойств выполняется
|
||||
* вызовом super.clonePropertiesFrom(source).
|
||||
*
|
||||
* @param source объект, свойства которого копируются
|
||||
*/
|
||||
protected function clonePropertiesFrom(source:Object3D):void {
|
||||
_name = source._name;
|
||||
_coords.x = source._coords.x;
|
||||
_coords.y = source._coords.y;
|
||||
_coords.z = source._coords.z;
|
||||
_rotationX = source._rotationX;
|
||||
_rotationY = source._rotationY;
|
||||
_rotationZ = source._rotationZ;
|
||||
_scaleX = source._scaleX;
|
||||
_scaleY = source._scaleY;
|
||||
_scaleZ = source._scaleZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Клонирование объекта. Для реализации собственного клонирования наследники должны переопределять методы
|
||||
* <code>createEmptyObject()</code> и <code>clonePropertiesFrom()</code>.
|
||||
*
|
||||
* @return клонированный экземпляр объекта
|
||||
*
|
||||
* @see #createEmptyObject()
|
||||
* @see #clonePropertiesFrom()
|
||||
*/
|
||||
public function clone():Object3D {
|
||||
var copy:Object3D = createEmptyObject();
|
||||
copy.clonePropertiesFrom(this);
|
||||
|
||||
// Клонирование детей
|
||||
for (var key:* in _children) {
|
||||
var child:Object3D = key;
|
||||
copy.addChild(child.clone());
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение дочернего объекта с заданным именем.
|
||||
*
|
||||
* @param name имя дочернего объекта
|
||||
* @return любой дочерний объект с заданным именем или <code>null</code> в случае отсутствия таких объектов
|
||||
*/
|
||||
public function getChildByName(name:String):Object3D {
|
||||
for (var key:* in _children) {
|
||||
var child:Object3D = key;
|
||||
if (child._name == name) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
405
Alternativa3D6/6.0/alternativa/engine3d/core/Scene3D.as
Normal file
405
Alternativa3D6/6.0/alternativa/engine3d/core/Scene3D.as
Normal file
@@ -0,0 +1,405 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.types.Set;
|
||||
import alternativa.utils.ObjectUtils;
|
||||
import alternativa.engine3d.sorting.SortingLevel;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Сцена является контейнером 3D-объектов, с которыми ведётся работа. Все взаимодействия объектов
|
||||
* происходят в пределах одной сцены. Класс обеспечивает работу системы сигналов и реализует алгоритм построения
|
||||
* BSP-дерева для содержимого сцены.
|
||||
*/
|
||||
public class Scene3D {
|
||||
|
||||
// Инкремент количества сцен
|
||||
private static var counter:uint = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Наименование
|
||||
*/
|
||||
alternativa3d var _name:String;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Пространство сцены
|
||||
*/
|
||||
alternativa3d var _space:Space;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Реестр камер сцены
|
||||
*/
|
||||
alternativa3d var cameras:Set = new Set();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Списки сигналов
|
||||
*/
|
||||
|
||||
|
||||
alternativa3d var objectsToTransform:Set = new Set();
|
||||
alternativa3d var objectsToMove:Set = new Set();
|
||||
// alternativa3d var verticesToMove:Set = new Set();
|
||||
alternativa3d var spacesToGlobalTransform:Set = new Set();
|
||||
|
||||
alternativa3d var spacesToChangeSortingMode:Set = new Set();
|
||||
alternativa3d var spacesToChangeSortingLevel:Set = new Set();
|
||||
alternativa3d var spacesToChangeMaterial:Set = new Set();
|
||||
/*
|
||||
alternativa3d var spritesToChangeSortingMode:Set = new Set();
|
||||
alternativa3d var spritesToChangeSortingLevel:Set = new Set();
|
||||
alternativa3d var spritesToChangeMaterial:Set = new Set();
|
||||
|
||||
alternativa3d var surfacesToChangeSortingMode:Set = new Set();
|
||||
alternativa3d var surfacesToChangeSortingLevel:Set = new Set();
|
||||
alternativa3d var surfacesToChangeMaterial:Set = new Set();
|
||||
alternativa3d var surfacesToChangeBSPLevel:Set = new Set();
|
||||
|
||||
alternativa3d var facesToChangeSurface:Set = new Set();
|
||||
alternativa3d var facesToTransform:Set = new Set();
|
||||
*/
|
||||
//alternativa3d var spacesToCalculate:Set = new Set();
|
||||
alternativa3d var levelsToCalculate:Set = new Set();
|
||||
|
||||
//alternativa3d var spacesToRender:Set = new Set();
|
||||
alternativa3d var spacesToUpdateMaterial:Set = new Set();
|
||||
|
||||
alternativa3d var camerasToRender:Set = new Set();
|
||||
|
||||
alternativa3d var levelsToClear:Set = new Set();
|
||||
|
||||
/**
|
||||
* Создание экземпляра сцены.
|
||||
*/
|
||||
public function Scene3D(name:String = null) {
|
||||
// Имя по-умолчанию
|
||||
_name = (name != null) ? name : defaultName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчёт сцены. Метод анализирует все изменения, произошедшие с момента предыдущего расчёта, формирует список
|
||||
* команд и исполняет их в необходимой последовательности. В результате расчёта происходит перерисовка во всех
|
||||
* областях вывода, к которым подключены находящиеся в сцене камеры.
|
||||
*/
|
||||
public function calculate():void {
|
||||
trace("----------------------------- calculate -------------------------------------");
|
||||
|
||||
var key:*;
|
||||
var object:Object3D;
|
||||
var method:Function;
|
||||
// var vertex:Vertex;
|
||||
// var face:Face;
|
||||
// var surface:Surface;
|
||||
// var sprite:Sprite3D;
|
||||
var space:Space;
|
||||
var level:SortingLevel;
|
||||
var camera:Camera3D;
|
||||
|
||||
// Трансформация объектов
|
||||
if (!objectsToTransform.isEmpty()) {
|
||||
trace("objectsToTransform:", objectsToTransform.length);
|
||||
}
|
||||
while ((object = objectsToTransform.peek()) != null) {
|
||||
// Ищем, нет ли выше в пространстве объектов на трансформацию или перемещение
|
||||
method = object.transformBranch;
|
||||
while ((object = object._parent) != null && !(object is Space)) {
|
||||
method = objectsToTransform[object] ? object.transformBranch : (objectsToMove[object] ? object.moveBranch : method);
|
||||
}
|
||||
method();
|
||||
}
|
||||
|
||||
// Перемещение объектов
|
||||
if (!objectsToMove.isEmpty()) {
|
||||
trace("objectsToMove:", objectsToMove.length);
|
||||
}
|
||||
while ((object = objectsToMove.peek()) != null) {
|
||||
// Ищем, нет ли выше в пространстве объектов на перемещение
|
||||
method = object.moveBranch;
|
||||
while ((object = object._parent) != null && !(object is Space)) {
|
||||
method = objectsToMove[object] ? object.moveBranch : method;
|
||||
}
|
||||
method();
|
||||
}
|
||||
/*
|
||||
// Перемещение вершин
|
||||
if (!verticesToMove.isEmpty()) {
|
||||
trace("verticesToMove:", verticesToMove.length);
|
||||
}
|
||||
for (key in verticesToMove) {
|
||||
vertex = key;
|
||||
vertex.move();
|
||||
}
|
||||
*/
|
||||
// Глобальная трансформация пространств
|
||||
if (!spacesToGlobalTransform.isEmpty()) {
|
||||
trace("spacesToGlobalTransform:", spacesToGlobalTransform.length);
|
||||
}
|
||||
while ((space = spacesToGlobalTransform.peek()) != null) {
|
||||
method = space.globalTransform;
|
||||
// Ищем, нет ли выше пространства на глобальную трансформацию
|
||||
while ((space = space.space) != null) {
|
||||
method = spacesToGlobalTransform[space] ? space.globalTransform : method;
|
||||
}
|
||||
method();
|
||||
}
|
||||
|
||||
// Изменение режима сортировки пространств
|
||||
if (!spacesToChangeSortingMode.isEmpty()) {
|
||||
trace("spacesToChangeSortingMode:", spacesToChangeSortingMode.length);
|
||||
}
|
||||
for (key in spacesToChangeSortingMode) {
|
||||
space = key;
|
||||
space.changeSortingMode();
|
||||
}
|
||||
|
||||
// Изменение уровней пространств
|
||||
if (!spacesToChangeSortingLevel.isEmpty()) {
|
||||
trace("spacesToChangeSortingLevel:", spacesToChangeSortingLevel.length);
|
||||
}
|
||||
for (key in spacesToChangeSortingLevel) {
|
||||
space = key;
|
||||
space.changeSortingLevel();
|
||||
}
|
||||
|
||||
// Изменение материалов пространств
|
||||
if (!spacesToChangeMaterial.isEmpty()) {
|
||||
trace("spacesToChangeMaterial:", spacesToChangeMaterial.length);
|
||||
}
|
||||
for (key in spacesToChangeMaterial) {
|
||||
space = key;
|
||||
space.changeMaterial();
|
||||
}
|
||||
/*
|
||||
// Изменение режима сортировки спрайтов
|
||||
if (!spritesToChangeSortingMode.isEmpty()) {
|
||||
trace("spritesToChangeSortingMode:", spritesToChangeSortingMode.length);
|
||||
}
|
||||
for (key in spritesToChangeSortingMode) {
|
||||
sprite = key;
|
||||
sprite.changeSortingMode();
|
||||
}
|
||||
|
||||
// Изменение уровней спрайтов
|
||||
if (!spritesToChangeSortingLevel.isEmpty()) {
|
||||
trace("spritesToChangeSortingLevel:", spritesToChangeSortingLevel.length);
|
||||
}
|
||||
for (key in spritesToChangeSortingLevel) {
|
||||
sprite = key;
|
||||
sprite.changeSortingLevel();
|
||||
}
|
||||
|
||||
// Изменение материалов спрайтов
|
||||
if (!spritesToChangeMaterial.isEmpty()) {
|
||||
trace("spritesToChangeMaterial:", spritesToChangeMaterial.length);
|
||||
}
|
||||
for (key in spritesToChangeMaterial) {
|
||||
sprite = key;
|
||||
sprite.changeMaterial();
|
||||
}
|
||||
|
||||
// Изменение режима сортировки поверхностей
|
||||
if (!surfacesToChangeSortingMode.isEmpty()) {
|
||||
trace("surfacesToChangeSortingMode:", surfacesToChangeSortingMode.length);
|
||||
}
|
||||
for (key in surfacesToChangeSortingMode) {
|
||||
surface = key;
|
||||
surface.changeSortingMode();
|
||||
}
|
||||
|
||||
// Изменение уровней поверхностей
|
||||
if (!surfacesToChangeSortingLevel.isEmpty()) {
|
||||
trace("surfacesToChangeSortingLevel:", surfacesToChangeSortingLevel.length);
|
||||
}
|
||||
for (key in surfacesToChangeSortingLevel) {
|
||||
surface = key;
|
||||
surface.changeSortingLevel();
|
||||
}
|
||||
|
||||
// Изменение материалов поверхностей
|
||||
if (!surfacesToChangeMaterial.isEmpty()) {
|
||||
trace("surfacesToChangeMaterial:", surfacesToChangeMaterial.length);
|
||||
}
|
||||
for (key in surfacesToChangeMaterial) {
|
||||
surface = key;
|
||||
surface.changeMaterial();
|
||||
}
|
||||
|
||||
// Изменение мобильности поверхностей
|
||||
if (!surfacesToChangeBSPLevel.isEmpty()) {
|
||||
trace("surfacesToChangeBSPLevel:", surfacesToChangeBSPLevel.length);
|
||||
}
|
||||
for (key in surfacesToChangeBSPLevel) {
|
||||
surface = key;
|
||||
surface.changeBSPLevel();
|
||||
}
|
||||
|
||||
// Изменение поверхности граней
|
||||
if (!facesToChangeSurface.isEmpty()) {
|
||||
trace("facesToChangeSurface:", facesToChangeSurface.length);
|
||||
}
|
||||
for (key in facesToChangeSurface) {
|
||||
face = key;
|
||||
face.changeSurface();
|
||||
}
|
||||
|
||||
// Трансформация граней
|
||||
if (!facesToTransform.isEmpty()) {
|
||||
trace("facesToTransform:", facesToTransform.length);
|
||||
}
|
||||
for (key in facesToTransform) {
|
||||
face = key;
|
||||
face.transform();
|
||||
}
|
||||
*/
|
||||
// Расчёт BSP пространств
|
||||
if (!levelsToCalculate.isEmpty()) {
|
||||
trace("levelsToCalculate:", levelsToCalculate.length);
|
||||
}
|
||||
for (key in levelsToCalculate) {
|
||||
level = key;
|
||||
level.calculate();
|
||||
}
|
||||
/*
|
||||
// Отрисовка пространств
|
||||
if (!spacesToRender.isEmpty()) {
|
||||
trace("spacesToRender:", spacesToRender.length);
|
||||
}
|
||||
while ((space = spacesToRender.peek()) != null) {
|
||||
var s:Space = space;
|
||||
// Ищем, нет ли выше пространства на отрисовку
|
||||
while ((space = space.space) != null) {
|
||||
s = spacesToRender[space] ? space : s;
|
||||
}
|
||||
// Отрисовка пространства
|
||||
s.render();
|
||||
}
|
||||
*/
|
||||
// Обновление материалов пространств
|
||||
if (!spacesToUpdateMaterial.isEmpty()) {
|
||||
trace("spacesToUpdateMaterial:", spacesToUpdateMaterial.length);
|
||||
}
|
||||
for (key in spacesToUpdateMaterial) {
|
||||
space = key;
|
||||
space.updateMaterial();
|
||||
}
|
||||
|
||||
|
||||
// Отрисовка камер
|
||||
if (!camerasToRender.isEmpty()) {
|
||||
trace("camerasToRender:", camerasToRender.length);
|
||||
}
|
||||
for (key in camerasToRender) {
|
||||
camera = key;
|
||||
camera.render();
|
||||
}
|
||||
|
||||
|
||||
// Очистка изменений уровней
|
||||
if (!levelsToClear.isEmpty()) {
|
||||
trace("levelsToClear:", levelsToClear.length);
|
||||
}
|
||||
for (key in levelsToClear) {
|
||||
level = key;
|
||||
level.clear();
|
||||
}
|
||||
|
||||
// Отложенное удаление примитивов в коллекторы
|
||||
//FaceNonePrimitive.destroyDeferred();
|
||||
//FaceDistancePrimitive.destroyDeferred();
|
||||
//FaceBSPPrimitive.destroyDeferred();
|
||||
//SpaceDistancePrimitive.destroyDeferred();
|
||||
//SpriteDistancePrimitive.destroyDeferred();
|
||||
|
||||
trace("-----------------------------------------------------------------------------");
|
||||
|
||||
}
|
||||
|
||||
public function hasChanges():Boolean {
|
||||
//return !objectsToLocate.isEmpty() || !objectsToChangeMobility.isEmpty() || !objectsToTransform.isEmpty() || !objectsToMove.isEmpty() || !verticesToMove.isEmpty() || !facesToChangeSurface.isEmpty() || !facesToTransform.isEmpty();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя сцены.
|
||||
*/
|
||||
public function get name():String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set name(value:String):void {
|
||||
_name = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Корневой объект сцены.
|
||||
*/
|
||||
public function get space():Space {
|
||||
return _space;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set space(value:Space):void {
|
||||
// Если ещё не является пространством сцены
|
||||
if (_space != value) {
|
||||
// Если у сцены было пространство
|
||||
if (_space != null) {
|
||||
// Удаляем у него ссылку на сцену
|
||||
_space.setScene(null);
|
||||
}
|
||||
|
||||
// Если устанавливаем пространство
|
||||
if (value != null) {
|
||||
// Если пространство было в другом объекте
|
||||
if (value._parent != null) {
|
||||
// Удалить его оттуда
|
||||
value._parent._children.remove(value);
|
||||
} else {
|
||||
// Если пространство было пространством в другой сцене
|
||||
if (value._scene != null) {
|
||||
value._scene.space = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Удаляем ссылку на родителя
|
||||
value._parent = null;
|
||||
// Указываем сцену
|
||||
value.setScene(this);
|
||||
// Если у пространства есть материал, помечаем его на обновление
|
||||
if (value._material != null) {
|
||||
spacesToUpdateMaterial[value] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Сохраняем пространство
|
||||
_space = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление сцены.
|
||||
*
|
||||
* @return строковое представление сцены
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[" + ObjectUtils.getClassName(this) + " " + _name + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя сцены по умолчанию.
|
||||
*
|
||||
* @return имя сцены по умолчанию
|
||||
*/
|
||||
protected function defaultName():String {
|
||||
return "scene" + ++counter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
700
Alternativa3D6/6.0/alternativa/engine3d/core/Space.as
Normal file
700
Alternativa3D6/6.0/alternativa/engine3d/core/Space.as
Normal file
@@ -0,0 +1,700 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.materials.SpaceMaterial;
|
||||
import alternativa.engine3d.sorting.DistanceNode;
|
||||
import alternativa.engine3d.sorting.SortingLevel;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
import alternativa.engine3d.errors.InvalidSortingModeError;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public final class Space extends Object3D {
|
||||
|
||||
// Инкремент количества пространств
|
||||
private static var counter:uint = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Режим сортировки
|
||||
*/
|
||||
alternativa3d var _sortingMode:uint = 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Материал
|
||||
*/
|
||||
alternativa3d var _material:SpaceMaterial;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Матрица перевода из локальной системы координат объекта в глобальную
|
||||
*/
|
||||
alternativa3d var globalMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Первый элемент списка уровней
|
||||
*/
|
||||
alternativa3d var firstLevel:SortingLevel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Номер уровня в пространстве
|
||||
*/
|
||||
private var sortingLevelIndex:int = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Ссылка на уровень в пространстве
|
||||
*/
|
||||
private var _sortingLevel:SortingLevel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Нода в которой находится спрайт
|
||||
*/
|
||||
alternativa3d var node:DistanceNode;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Вспомогательная матрица перевода из системы координат пространства в систему камеры
|
||||
*/
|
||||
alternativa3d var cameraMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Вспомогательная матрица перевода из системы координат камеры в систему пространства
|
||||
*/
|
||||
alternativa3d var inverseCameraMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
// Синус половинчатого угла обзора камеры
|
||||
alternativa3d var viewAngle:Number;
|
||||
|
||||
// Направление камеры
|
||||
alternativa3d var direction:Point3D = new Point3D(0, 0, 1);
|
||||
|
||||
// Плоскости отсечения
|
||||
alternativa3d var leftPlane:Point3D = new Point3D();
|
||||
alternativa3d var rightPlane:Point3D = new Point3D();
|
||||
alternativa3d var topPlane:Point3D = new Point3D();
|
||||
alternativa3d var bottomPlane:Point3D = new Point3D();
|
||||
alternativa3d var leftOffset:Number;
|
||||
alternativa3d var rightOffset:Number;
|
||||
alternativa3d var topOffset:Number;
|
||||
alternativa3d var bottomOffset:Number;
|
||||
|
||||
public function Space(name:String = null) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
override protected function transform():void {
|
||||
|
||||
if (_parent != null) {
|
||||
|
||||
super.transform();
|
||||
|
||||
if (_material != null) {
|
||||
if (_sortingLevel != null) {
|
||||
// Несортируемый
|
||||
if (_sortingMode == 0) {
|
||||
// Остался несортируемый
|
||||
|
||||
// Помечаем изменение в уровне
|
||||
_sortingLevel.changed[this] = true;
|
||||
_scene.levelsToClear[_sortingLevel] = true;
|
||||
|
||||
// Если изменился уровень
|
||||
if (_sortingLevel.space != space || _sortingLevel.index != sortingLevelIndex) {
|
||||
// Удаляем из старого уровня
|
||||
delete _sortingLevel.spaces[this];
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
// Добавляем в новый уровень
|
||||
_sortingLevel.spaces[this] = true;
|
||||
// Помечаем изменение в новом уровне
|
||||
_sortingLevel.changed[this] = true;
|
||||
_scene.levelsToClear[_sortingLevel] = true;
|
||||
}
|
||||
} else {
|
||||
// Изменился на сортируемый
|
||||
|
||||
// Удаляем из списка несортируемых пространств уровня
|
||||
delete _sortingLevel.spaces[this];
|
||||
// Помечаем изменение в уровне
|
||||
_sortingLevel.changed[this] = true;
|
||||
_scene.levelsToClear[_sortingLevel] = true;
|
||||
|
||||
// Если изменился уровень
|
||||
if (_sortingLevel.space != space || _sortingLevel.index != sortingLevelIndex) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
}
|
||||
|
||||
// Добавляем в список пространств на сортировку по дистанции
|
||||
_sortingLevel.spacesDistance[this] = true;
|
||||
_scene.levelsToCalculate[_sortingLevel] = true;
|
||||
// Удаляем ссылку на уровень
|
||||
_sortingLevel = null;
|
||||
}
|
||||
} else {
|
||||
if (node != null) {
|
||||
// Сортируемый
|
||||
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
// Нет в уровне
|
||||
|
||||
// Получаем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
|
||||
if (_sortingMode == 0) {
|
||||
// Появился несортируемый
|
||||
|
||||
// Добавляем в уровень
|
||||
_sortingLevel.spaces[this] = true;
|
||||
// Помечаем изменение в уровне
|
||||
_sortingLevel.changed[this] = true;
|
||||
_scene.levelsToClear[_sortingLevel] = true;
|
||||
|
||||
} else {
|
||||
// Появился сортируемый
|
||||
|
||||
// Добавляем в список пространств на сортировку по дистанции
|
||||
_sortingLevel.spacesDistance[this] = true;
|
||||
_scene.levelsToCalculate[_sortingLevel] = true;
|
||||
// Удаляем ссылку на уровень
|
||||
_sortingLevel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// Если есть примитив
|
||||
if (primitive != null) {
|
||||
// Если изменился уровень
|
||||
if (primitive.node.sortingLevel != _sortingLevel) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
}
|
||||
// Удаляем примитив
|
||||
primitive.node.removePrimitive(primitive);
|
||||
} else {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
// Создаём примитив
|
||||
primitive = SpaceDistancePrimitive.create();
|
||||
primitive.space = this;
|
||||
}
|
||||
|
||||
// Добавляем примитив в уровень
|
||||
_sortingLevel.distancePrimitivesToAdd.push(primitive);
|
||||
|
||||
// Устанавливаем координаты
|
||||
primitive.coords.x = spaceMatrix.d;
|
||||
primitive.coords.y = spaceMatrix.h;
|
||||
primitive.coords.z = spaceMatrix.l;
|
||||
*/
|
||||
// Помечаем пространство на глобальную трансформацию
|
||||
_scene.spacesToGlobalTransform[this] = true;
|
||||
|
||||
} else {
|
||||
// Если появился или изменился материал, помечаем на обновление материала
|
||||
if (_material != null && _scene.spacesToChangeMaterial[this]) {
|
||||
_scene.spacesToUpdateMaterial[this] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Снимаем пометки пространства
|
||||
delete _scene.spacesToChangeSortingMode[this];
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
}
|
||||
|
||||
override protected function move():void {
|
||||
super.move();
|
||||
/*
|
||||
// Если изменился уровень
|
||||
if (_sortingLevel.index != sortingLevelIndex) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
}
|
||||
|
||||
// Удаляем примитив
|
||||
primitive.node.removePrimitive(primitive);
|
||||
|
||||
// Добавляем примитив в уровень
|
||||
_sortingLevel.distancePrimitivesToAdd.push(primitive);
|
||||
|
||||
// Устанавливаем координаты
|
||||
primitive.coords.x = spaceMatrix.d;
|
||||
primitive.coords.y = spaceMatrix.h;
|
||||
primitive.coords.z = spaceMatrix.l;
|
||||
*/
|
||||
// Помечаем пространство на глобальную трансформацию
|
||||
_scene.spacesToGlobalTransform[this] = true;
|
||||
|
||||
// Снимаем пометки пространства
|
||||
delete _scene.spacesToChangeSortingMode[this];
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
}
|
||||
/*
|
||||
override alternativa3d function transformBranch():void {
|
||||
// Если не корневой объект
|
||||
if (_parent != null) {
|
||||
// Трансформируем дочернюю ветку
|
||||
super.transformBranch();
|
||||
} else {
|
||||
trace(this, "transformBranch sceneSpace");
|
||||
|
||||
|
||||
|
||||
|
||||
// Снимаем все отметки
|
||||
delete _scene.objectsToTransform[this];
|
||||
delete _scene.objectsToMove[this];
|
||||
delete _scene.spacesToChangeSortingMode[this];
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override alternativa3d function moveBranch():void {
|
||||
|
||||
// Если не корневой объект
|
||||
if (_parent != null) {
|
||||
super.moveBranch();
|
||||
} else {
|
||||
trace(this, "moveBranch sceneSpace");
|
||||
|
||||
// Снимаем отметку о перемещении
|
||||
delete _scene.objectsToMove[this];
|
||||
}
|
||||
}
|
||||
*/
|
||||
alternativa3d function changeSortingMode():void {
|
||||
trace(this, "changeSortingMode");
|
||||
|
||||
if (parent != null) {
|
||||
|
||||
// Снимаем пометку на смену материала
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
}
|
||||
|
||||
// Снимаем пометки пространства
|
||||
delete _scene.spacesToChangeSortingMode[this];
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeSortingLevel():void {
|
||||
trace(this, "changeSortingLevel");
|
||||
|
||||
if (parent != null) {
|
||||
/*
|
||||
// Если уровень изменился
|
||||
if (_sortingLevel.index != sortingLevelIndex) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
|
||||
// Удаляем примитив
|
||||
primitive.node.removePrimitive(primitive);
|
||||
|
||||
// Добавляем примитив в уровень
|
||||
_sortingLevel.distancePrimitivesToAdd.push(primitive);
|
||||
}
|
||||
*/
|
||||
// Снимаем пометку на смену материала
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
}
|
||||
// Снимаем пометки пространства
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeMaterial():void {
|
||||
trace(this, "changeMaterial");
|
||||
|
||||
// Если не корневое пространство
|
||||
if (parent != null) {
|
||||
|
||||
// Снимаем пометку на смену материала
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
} else {
|
||||
}
|
||||
}
|
||||
/*
|
||||
alternativa3d function render():void {
|
||||
trace(this, "render");
|
||||
|
||||
// Обрабатываем камеры не помеченные на полную отрисовку
|
||||
for (var key:* in _scene.cameras) {
|
||||
if (!_scene.camerasToRender[key]) {
|
||||
var camera:Camera3D = key;
|
||||
camera.updateSpaceMaterial(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Снимаем пометку об отрисовке пространства
|
||||
delete _scene.spacesToUpdate[this];
|
||||
}
|
||||
*/
|
||||
alternativa3d function updateMaterial():void {
|
||||
trace(this, "updateMaterial");
|
||||
|
||||
// Обрабатываем камеры не помеченные на полную отрисовку
|
||||
for (var key:* in _scene.cameras) {
|
||||
if (!_scene.camerasToRender[key]) {
|
||||
var camera:Camera3D = key;
|
||||
camera.updateSpaceMaterial(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Снимаем пометку об обновлении материала
|
||||
delete _scene.spacesToUpdateMaterial[this];
|
||||
}
|
||||
|
||||
alternativa3d function globalTransform():void {
|
||||
trace(this, "globalTransform");
|
||||
|
||||
// Расчитываем глобальную трансформацию
|
||||
globalMatrix.copy(spaceMatrix);
|
||||
globalMatrix.combine(space.globalMatrix);
|
||||
|
||||
// Вызвать глобальную трансформацию в дочерних пространствах
|
||||
globalTransformChildSpaces(this);
|
||||
|
||||
delete _scene.spacesToGlobalTransform[this];
|
||||
}
|
||||
|
||||
private function globalTransformChildSpaces(object:Object3D):void {
|
||||
// Обрабатываем дочерние объекты
|
||||
for (var key:* in object._children) {
|
||||
if (key is Space) {
|
||||
(key as Space).globalTransform();
|
||||
} else {
|
||||
// Если камера с вьюпортом, помечаем её на отрисовку
|
||||
if ((key is Camera3D) && (key as Camera3D)._view != null) {
|
||||
_scene.camerasToRender[key] = true;
|
||||
}
|
||||
globalTransformChildSpaces(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Расчёт плоскостей отсечения для ортографической камеры
|
||||
*/
|
||||
alternativa3d function calculateOrthographicPlanes(halfWidth:Number, halfHeight:Number, zoom:Number):void {
|
||||
var aw:Number = inverseCameraMatrix.a*halfWidth/zoom;
|
||||
var ew:Number = inverseCameraMatrix.e*halfWidth/zoom;
|
||||
var iw:Number = inverseCameraMatrix.i*halfWidth/zoom;
|
||||
var bh:Number = inverseCameraMatrix.b*halfHeight/zoom;
|
||||
var fh:Number = inverseCameraMatrix.f*halfHeight/zoom;
|
||||
var jh:Number = inverseCameraMatrix.j*halfHeight/zoom;
|
||||
|
||||
// Левая плоскость
|
||||
leftPlane.x = inverseCameraMatrix.f*inverseCameraMatrix.k - inverseCameraMatrix.j*inverseCameraMatrix.g;
|
||||
leftPlane.y = inverseCameraMatrix.j*inverseCameraMatrix.c - inverseCameraMatrix.b*inverseCameraMatrix.k;
|
||||
leftPlane.z = inverseCameraMatrix.b*inverseCameraMatrix.g - inverseCameraMatrix.f*inverseCameraMatrix.c;
|
||||
leftOffset = (inverseCameraMatrix.d - aw)*leftPlane.x + (inverseCameraMatrix.h - ew)*leftPlane.y + (inverseCameraMatrix.l - iw)*leftPlane.z;
|
||||
|
||||
// Правая плоскость
|
||||
rightPlane.x = -leftPlane.x;
|
||||
rightPlane.y = -leftPlane.y;
|
||||
rightPlane.z = -leftPlane.z;
|
||||
rightOffset = (inverseCameraMatrix.d + aw)*rightPlane.x + (inverseCameraMatrix.h + ew)*rightPlane.y + (inverseCameraMatrix.l + iw)*rightPlane.z;
|
||||
|
||||
// Верхняя плоскость
|
||||
topPlane.x = inverseCameraMatrix.g*inverseCameraMatrix.i - inverseCameraMatrix.k*inverseCameraMatrix.e;
|
||||
topPlane.y = inverseCameraMatrix.k*inverseCameraMatrix.a - inverseCameraMatrix.c*inverseCameraMatrix.i;
|
||||
topPlane.z = inverseCameraMatrix.c*inverseCameraMatrix.e - inverseCameraMatrix.g*inverseCameraMatrix.a;
|
||||
topOffset = (inverseCameraMatrix.d - bh)*topPlane.x + (inverseCameraMatrix.h - fh)*topPlane.y + (inverseCameraMatrix.l - jh)*topPlane.z;
|
||||
|
||||
// Нижняя плоскость
|
||||
bottomPlane.x = -topPlane.x;
|
||||
bottomPlane.y = -topPlane.y;
|
||||
bottomPlane.z = -topPlane.z;
|
||||
bottomOffset = (inverseCameraMatrix.d + bh)*bottomPlane.x + (inverseCameraMatrix.h + fh)*bottomPlane.y + (inverseCameraMatrix.l + jh)*bottomPlane.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Расчёт плоскостей отсечения для перспективной камеры
|
||||
*/
|
||||
alternativa3d function calculatePerspectivePlanes(halfWidth:Number, halfHeight:Number, focalLength:Number):void {
|
||||
var aw:Number = inverseCameraMatrix.a*halfWidth;
|
||||
var ew:Number = inverseCameraMatrix.e*halfWidth;
|
||||
var iw:Number = inverseCameraMatrix.i*halfWidth;
|
||||
var bh:Number = inverseCameraMatrix.b*halfHeight;
|
||||
var fh:Number = inverseCameraMatrix.f*halfHeight;
|
||||
var jh:Number = inverseCameraMatrix.j*halfHeight;
|
||||
|
||||
var cl:Number = inverseCameraMatrix.c*focalLength;
|
||||
var gl:Number = inverseCameraMatrix.g*focalLength;
|
||||
var kl:Number = inverseCameraMatrix.k*focalLength;
|
||||
|
||||
// Угловые вектора пирамиды видимости
|
||||
var leftTopX:Number = -aw - bh + cl;
|
||||
var leftTopY:Number = -ew - fh + gl;
|
||||
var leftTopZ:Number = -iw - jh + kl;
|
||||
var rightTopX:Number = aw - bh + cl;
|
||||
var rightTopY:Number = ew - fh + gl;
|
||||
var rightTopZ:Number = iw - jh + kl;
|
||||
var leftBottomX:Number = -aw + bh + cl;
|
||||
var leftBottomY:Number = -ew + fh + gl;
|
||||
var leftBottomZ:Number = -iw + jh + kl;
|
||||
var rightBottomX:Number = aw + bh + cl;
|
||||
var rightBottomY:Number = ew + fh + gl;
|
||||
var rightBottomZ:Number = iw + jh + kl;
|
||||
|
||||
// Левая плоскость
|
||||
leftPlane.x = leftBottomY*leftTopZ - leftBottomZ*leftTopY;
|
||||
leftPlane.y = leftBottomZ*leftTopX - leftBottomX*leftTopZ;
|
||||
leftPlane.z = leftBottomX*leftTopY - leftBottomY*leftTopX;
|
||||
leftOffset = inverseCameraMatrix.d*leftPlane.x + inverseCameraMatrix.h*leftPlane.y + inverseCameraMatrix.l*leftPlane.z;
|
||||
|
||||
// Правая плоскость
|
||||
rightPlane.x = rightTopY*rightBottomZ - rightTopZ*rightBottomY;
|
||||
rightPlane.y = rightTopZ*rightBottomX - rightTopX*rightBottomZ;
|
||||
rightPlane.z = rightTopX*rightBottomY - rightTopY*rightBottomX;
|
||||
rightOffset = inverseCameraMatrix.d*rightPlane.x + inverseCameraMatrix.h*rightPlane.y + inverseCameraMatrix.l*rightPlane.z;
|
||||
|
||||
// Верхняя плоскость
|
||||
topPlane.x = leftTopY*rightTopZ - leftTopZ*rightTopY;
|
||||
topPlane.y = leftTopZ*rightTopX - leftTopX*rightTopZ;
|
||||
topPlane.z = leftTopX*rightTopY - leftTopY*rightTopX;
|
||||
topOffset = inverseCameraMatrix.d*topPlane.x + inverseCameraMatrix.h*topPlane.y + inverseCameraMatrix.l*topPlane.z;
|
||||
|
||||
// Нижняя плоскость
|
||||
bottomPlane.x = rightBottomY*leftBottomZ - rightBottomZ*leftBottomY;
|
||||
bottomPlane.y = rightBottomZ*leftBottomX - rightBottomX*leftBottomZ;
|
||||
bottomPlane.z = rightBottomX*leftBottomY - rightBottomY*leftBottomX;
|
||||
bottomOffset = inverseCameraMatrix.d*bottomPlane.x + inverseCameraMatrix.h*bottomPlane.y + inverseCameraMatrix.l*bottomPlane.z;
|
||||
|
||||
// Расчёт угла конуса
|
||||
var length:Number = Math.sqrt(leftTopX*leftTopX + leftTopY*leftTopY + leftTopZ*leftTopZ);
|
||||
leftTopX /= length;
|
||||
leftTopY /= length;
|
||||
leftTopZ /= length;
|
||||
length = Math.sqrt(rightTopX*rightTopX + rightTopY*rightTopY + rightTopZ*rightTopZ);
|
||||
rightTopX /= length;
|
||||
rightTopY /= length;
|
||||
rightTopZ /= length;
|
||||
length = Math.sqrt(leftBottomX*leftBottomX + leftBottomY*leftBottomY + leftBottomZ*leftBottomZ);
|
||||
leftBottomX /= length;
|
||||
leftBottomY /= length;
|
||||
leftBottomZ /= length;
|
||||
length = Math.sqrt(rightBottomX*rightBottomX + rightBottomY*rightBottomY + rightBottomZ*rightBottomZ);
|
||||
rightBottomX /= length;
|
||||
rightBottomY /= length;
|
||||
rightBottomZ /= length;
|
||||
|
||||
viewAngle = leftTopX*direction.x + leftTopY*direction.y + leftTopZ*direction.z;
|
||||
var dot:Number = rightTopX*direction.x + rightTopY*direction.y + rightTopZ*direction.z;
|
||||
viewAngle = (dot < viewAngle) ? dot : viewAngle;
|
||||
dot = leftBottomX*direction.x + leftBottomY*direction.y + leftBottomZ*direction.z;
|
||||
viewAngle = (dot < viewAngle) ? dot : viewAngle;
|
||||
dot = rightBottomX*direction.x + rightBottomY*direction.y + rightBottomZ*direction.z;
|
||||
viewAngle = (dot < viewAngle) ? dot : viewAngle;
|
||||
|
||||
viewAngle = Math.sin(Math.acos(viewAngle));
|
||||
}
|
||||
|
||||
override protected function removeFromScene():void {
|
||||
|
||||
if (_sortingLevel != null) {
|
||||
// Удаляем пространства из уровня
|
||||
delete _sortingLevel.spaces[this];
|
||||
// Помечаем изменение в пространстве
|
||||
_sortingLevel.changed[this] = true;
|
||||
_scene.levelsToClear[_sortingLevel] = true;
|
||||
// Удаляем ссылку на уровень
|
||||
_sortingLevel = null;
|
||||
} else {
|
||||
if (node != null) {
|
||||
_scene.levelsToClear[_sortingLevel] = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Удаляем примитив
|
||||
if (primitive != null) {
|
||||
// Удаляем примитив из ноды
|
||||
primitive.node.removePrimitive(primitive);
|
||||
// Удаляем примитив
|
||||
SpaceDistancePrimitive.defer(primitive);
|
||||
primitive = null;
|
||||
}
|
||||
*/
|
||||
// Удаляем ссылку на уровень
|
||||
_sortingLevel = null;
|
||||
|
||||
super.removeFromScene();
|
||||
|
||||
// Удаляем все пометки в сцене
|
||||
delete _scene.spacesToGlobalTransform[this];
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
delete _scene.spacesToChangeMaterial[this];
|
||||
//delete _scene.spacesToUpdate[this];
|
||||
delete _scene.spacesToUpdateMaterial[this];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Получить уровень по индексу. Если уровня с таким индексом нет, он создаётся.
|
||||
*/
|
||||
alternativa3d function getSortingLevel(index:int):SortingLevel {
|
||||
var previous:SortingLevel = null;
|
||||
var current:SortingLevel = firstLevel;
|
||||
var level:SortingLevel;
|
||||
// Перебираем уровни
|
||||
while (true) {
|
||||
// Если есть текущий
|
||||
if (current != null) {
|
||||
// Если найден уровень с требуемым индексом
|
||||
if (current.index == index) {
|
||||
// Возвращаем его
|
||||
return current;
|
||||
} else {
|
||||
// Если найден уровень с большим индексом
|
||||
if (current.index > index) {
|
||||
// Создаём новый уровень
|
||||
level = new SortingLevel();
|
||||
level.space = this;
|
||||
level.index = index;
|
||||
if (previous != null) {
|
||||
previous.next = level;
|
||||
} else {
|
||||
firstLevel = level;
|
||||
}
|
||||
level.next = current;
|
||||
return level;
|
||||
} else {
|
||||
// Переключаемся на следующий уровень
|
||||
previous = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Создаём новый уровень
|
||||
level = new SortingLevel();
|
||||
level.space = this;
|
||||
level.index = index;
|
||||
if (previous != null) {
|
||||
previous.next = level;
|
||||
} else {
|
||||
firstLevel = level;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
}
|
||||
// null никогда не возвращается, т.к. возврат происходит из цикла
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Уровень сортировки.
|
||||
*/
|
||||
public function get sortingLevel():int {
|
||||
return sortingLevelIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set sortingLevel(value:int):void {
|
||||
if (sortingLevelIndex != value) {
|
||||
sortingLevelIndex = value;
|
||||
if (_scene != null) {
|
||||
_scene.spacesToChangeSortingLevel[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Режим сортировки пространства.
|
||||
*/
|
||||
public function get sortingMode():uint {
|
||||
return _sortingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set sortingMode(value:uint):void {
|
||||
if (value > 1) {
|
||||
throw new InvalidSortingModeError(value, this);
|
||||
}
|
||||
if (_sortingMode != value) {
|
||||
_sortingMode = value;
|
||||
if (_scene != null) {
|
||||
_scene.spacesToChangeSortingMode[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Материал пространства. При установке нового значения, устанавливаемый материал будет удалён из старого пространства.
|
||||
*/
|
||||
public function get material():SpaceMaterial {
|
||||
return _material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set material(value:SpaceMaterial):void {
|
||||
if (_material != value) {
|
||||
// Если был материал
|
||||
if (_material != null) {
|
||||
// Удалить материал
|
||||
_material._space = null;
|
||||
}
|
||||
// Если новый материал
|
||||
if (value != null) {
|
||||
// Если материал был в другом пространстве
|
||||
var oldSpace:Space = value._space;
|
||||
if (oldSpace != null) {
|
||||
// Удалить его оттуда
|
||||
oldSpace._material = null;
|
||||
// Если есть сцена, помечаем смену материала
|
||||
if (oldSpace._scene != null) {
|
||||
oldSpace._scene.spacesToChangeMaterial[oldSpace] = true;
|
||||
}
|
||||
|
||||
}
|
||||
// Добавить материал
|
||||
value._space = this;
|
||||
}
|
||||
// Если есть сцена, помечаем смену материала
|
||||
if (_scene != null) {
|
||||
_scene.spacesToChangeMaterial[this] = true;
|
||||
}
|
||||
// Сохраняем материал
|
||||
_material = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя пространства по умолчанию.
|
||||
*
|
||||
* @return имя пространства по умолчанию
|
||||
*/
|
||||
override protected function defaultName():String {
|
||||
return "space" + ++counter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
246
Alternativa3D6/6.0/alternativa/engine3d/core/Sprite3D.as
Normal file
246
Alternativa3D6/6.0/alternativa/engine3d/core/Sprite3D.as
Normal file
@@ -0,0 +1,246 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.sorting.SortingLevel;
|
||||
import alternativa.engine3d.sorting.SpriteDistancePrimitive;
|
||||
import alternativa.engine3d.materials.SpriteMaterial;
|
||||
import alternativa.engine3d.sorting.DistanceNode;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Sprite3D extends Object3D {
|
||||
|
||||
// Инкремент количества объектов
|
||||
private static var counter:uint = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Режим сортировки
|
||||
*/
|
||||
alternativa3d var _sortingMode:uint = 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Материал
|
||||
*/
|
||||
alternativa3d var _material:SpriteMaterial;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Номер уровня в пространстве
|
||||
*/
|
||||
private var sortingLevelIndex:int = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Ссылка на уровень в пространстве
|
||||
*/
|
||||
private var _sortingLevel:SortingLevel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Нода в которой находится спрайт
|
||||
*/
|
||||
alternativa3d var node:DistanceNode;
|
||||
|
||||
public function Sprite3D(name:String = null) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
override protected function transform():void {
|
||||
super.transform();
|
||||
|
||||
// Если есть примитив
|
||||
if (primitive != null) {
|
||||
// Если изменился уровень
|
||||
if (primitive.node.sortingLevel != _sortingLevel) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
}
|
||||
// Удаляем примитив
|
||||
primitive.node.removePrimitive(primitive);
|
||||
} else {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
// Создаём примитив
|
||||
primitive = SpriteDistancePrimitive.create();
|
||||
primitive.sprite = this;
|
||||
}
|
||||
|
||||
// Добавляем примитив в уровень
|
||||
_sortingLevel.distancePrimitivesToAdd.push(primitive);
|
||||
|
||||
// Устанавливаем координаты
|
||||
primitive.coords.x = spaceMatrix.d;
|
||||
primitive.coords.y = spaceMatrix.h;
|
||||
primitive.coords.z = spaceMatrix.l;
|
||||
|
||||
// Снимаем пометки о смене уровня и материала
|
||||
delete _scene.spritesToChangeSortingLevel[this];
|
||||
delete _scene.spritesToChangeMaterial[this];
|
||||
}
|
||||
|
||||
override protected function move():void {
|
||||
super.move();
|
||||
|
||||
// Если изменился уровень
|
||||
if (_sortingLevel.index != sortingLevelIndex) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
}
|
||||
|
||||
// Удаляем примитив
|
||||
primitive.node.removePrimitive(primitive);
|
||||
|
||||
// Добавляем примитив в уровень
|
||||
_sortingLevel.distancePrimitivesToAdd.push(primitive);
|
||||
|
||||
// Устанавливаем координаты
|
||||
primitive.coords.x = spaceMatrix.d;
|
||||
primitive.coords.y = spaceMatrix.h;
|
||||
primitive.coords.z = spaceMatrix.l;
|
||||
|
||||
// Снимаем пометки о смене уровня и материала
|
||||
delete _scene.spritesToChangeSortingLevel[this];
|
||||
delete _scene.spritesToChangeMaterial[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeSortingLevel():void {
|
||||
trace(this, "changeSortingLevel");
|
||||
|
||||
// Если уровень изменился
|
||||
if (_sortingLevel.index != sortingLevelIndex) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = space.getSortingLevel(sortingLevelIndex);
|
||||
|
||||
// Удаляем примитив
|
||||
primitive.node.removePrimitive(primitive);
|
||||
|
||||
// Добавляем примитив в уровень
|
||||
_sortingLevel.distancePrimitivesToAdd.push(primitive);
|
||||
}
|
||||
|
||||
// Снимаем пометку о смене уровня
|
||||
delete _scene.spacesToChangeSortingLevel[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeSortingMode():void {
|
||||
trace(this, "changeSortingMode");
|
||||
|
||||
}
|
||||
|
||||
alternativa3d function changeMaterial():void {
|
||||
trace(this, "changeMaterial");
|
||||
|
||||
}
|
||||
|
||||
override protected function removeFromScene(scene:Scene3D):void {
|
||||
super.removeFromScene(scene);
|
||||
|
||||
// Удаляем примитив
|
||||
if (primitive != null) {
|
||||
// Удаляем примитив из ноды
|
||||
primitive.node.removePrimitive(primitive);
|
||||
// Удаляем примитив
|
||||
SpriteDistancePrimitive.defer(primitive);
|
||||
primitive = null;
|
||||
}
|
||||
|
||||
// Удаляем ссылку на уровень
|
||||
_sortingLevel = null;
|
||||
|
||||
// Удаляем все пометки в сцене
|
||||
delete scene.spritesToChangeSortingLevel[this];
|
||||
delete scene.spritesToChangeMaterial[this];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Уровень сортировки.
|
||||
*/
|
||||
public function get sortingLevel():int {
|
||||
return sortingLevelIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set sortingLevel(value:int):void {
|
||||
if (sortingLevelIndex != value) {
|
||||
sortingLevelIndex = value;
|
||||
if (_scene != null) {
|
||||
_scene.spritesToChangeSortingLevel[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Режим сортировки спрайта.
|
||||
*/
|
||||
public function get sortingMode():uint {
|
||||
return _sortingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set sortingMode(value:uint):void {
|
||||
if (_sortingMode != value) {
|
||||
_sortingMode = value;
|
||||
if (_scene != null) {
|
||||
_scene.spritesToChangeSortingMode[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Материал спрайта. При установке нового значения, устанавливаемый материал будет удалён из старого спрайта.
|
||||
*/
|
||||
public function get material():SpriteMaterial {
|
||||
return _material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set material(value:SpriteMaterial):void {
|
||||
if (_material != value) {
|
||||
// Если был материал
|
||||
if (_material != null) {
|
||||
// Удалить материал
|
||||
_material._sprite = null;
|
||||
}
|
||||
// Если новый материал
|
||||
if (value != null) {
|
||||
// Если материал был в другом спрайте
|
||||
var oldSprite:Sprite3D = value._sprite;
|
||||
if (oldSprite != null) {
|
||||
// Удалить его оттуда
|
||||
oldSprite._material = null;
|
||||
// Если есть сцена, помечаем смену материала
|
||||
if (oldSprite._scene != null) {
|
||||
oldSprite._scene.spritesToChangeMaterial[oldSprite] = true;
|
||||
}
|
||||
|
||||
}
|
||||
// Добавить материал
|
||||
value._sprite = this;
|
||||
}
|
||||
// Если есть сцена, помечаем смену материала
|
||||
if (_scene != null) {
|
||||
_scene.spritesToChangeMaterial[this] = true;
|
||||
}
|
||||
// Сохраняем материал
|
||||
_material = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function defaultName():String {
|
||||
return "sprite" + ++counter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
788
Alternativa3D6/6.0/alternativa/engine3d/core/Surface.as
Normal file
788
Alternativa3D6/6.0/alternativa/engine3d/core/Surface.as
Normal file
@@ -0,0 +1,788 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.sorting.SortingLevel;
|
||||
import alternativa.engine3d.errors.FaceExistsError;
|
||||
import alternativa.engine3d.errors.FaceNotFoundError;
|
||||
import alternativa.engine3d.errors.InvalidIDError;
|
||||
import alternativa.engine3d.materials.SurfaceMaterial;
|
||||
import alternativa.types.Set;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Поверхность — набор граней, объединённых в группу. Поверхности используются для установки материалов,
|
||||
* визуализирующих грани объекта.
|
||||
*/
|
||||
public class Surface {
|
||||
/**
|
||||
* @private
|
||||
* Меш
|
||||
*/
|
||||
alternativa3d var _mesh:Mesh;
|
||||
/**
|
||||
* @private
|
||||
* Грани
|
||||
*/
|
||||
alternativa3d var _faces:Set = new Set();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Ссылка на уровень в пространстве
|
||||
*/
|
||||
alternativa3d var _sortingLevel:SortingLevel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Номер уровня в пространстве
|
||||
*/
|
||||
private var sortingLevelIndex:int = 0;
|
||||
/**
|
||||
* @private
|
||||
* Режим сортировки
|
||||
*/
|
||||
alternativa3d var _sortingMode:uint = 1;
|
||||
/**
|
||||
* @private
|
||||
* Материал
|
||||
*/
|
||||
alternativa3d var _material:SurfaceMaterial;
|
||||
/**
|
||||
* @private
|
||||
* Приоритет в BSP-дереве
|
||||
*/
|
||||
alternativa3d var _bspLevel:int = 0;
|
||||
|
||||
/**
|
||||
* Создание экземпляра поверхности.
|
||||
*/
|
||||
public function Surface() {}
|
||||
|
||||
|
||||
alternativa3d function changeSortingLevel():void {
|
||||
trace(this, "changeSortingLevel");
|
||||
|
||||
// Если уровень изменился
|
||||
if (_sortingLevel.index != sortingLevelIndex) {
|
||||
// Обновляем уровень
|
||||
_sortingLevel = _mesh.space.getSortingLevel(sortingLevelIndex);
|
||||
|
||||
|
||||
|
||||
|
||||
// Помечаем пространство на пересчёт
|
||||
_mesh._scene.spacesToCalculate[_mesh.space] = true;
|
||||
// Снимаем другие пометки поверхности
|
||||
delete _mesh._scene.surfacesToChangeSortingMode[this];
|
||||
delete _mesh._scene.surfacesToChangeMaterial[this];
|
||||
delete _mesh._scene.surfacesToChangeBSPLevel[this];
|
||||
}
|
||||
// Снимаем пометку о смене уровня
|
||||
delete _mesh._scene.surfacesToChangeSortingLevel[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeSortingMode():void {
|
||||
trace(this, "changeSortingMode");
|
||||
|
||||
var surfacesToChangeMaterial:Set = _mesh._scene.surfacesToChangeMaterial;
|
||||
var facesToChangeSurface:Set = _mesh._scene.facesToChangeSurface;
|
||||
var facesToTransform:Set = _mesh._scene.facesToTransform;
|
||||
|
||||
var key:*;
|
||||
var face:Face;
|
||||
// Если есть материал
|
||||
if (_material != null) {
|
||||
// Если BSP-сортировка
|
||||
if (_sortingMode == 2) {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Обновление полигонального примитива
|
||||
face.updatePolyPrimitive();
|
||||
// Снимаем все пометки грани
|
||||
delete facesToChangeSurface[face];
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если изменилась мобильность
|
||||
if (face.polyPrimitive.bspLevel != _bspLevel) {
|
||||
// Обновляем мобильность примитива
|
||||
face.updatePolyPrimitiveBSPLevel();
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
} else {
|
||||
// Если изменился материал поверхности или грань изменила поверхность
|
||||
if (surfacesToChangeMaterial[this] || facesToChangeSurface[face]) {
|
||||
// Отправить полигональный примитив на перерисовку
|
||||
face.redrawPolyPrimitive();
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
// Смена типа примитива с точечного на полигональный
|
||||
face.changePointToPolyPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Создание полигонального примитива
|
||||
face.createPolyPrimitive();
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если сортировка по расстоянию
|
||||
if (_sortingMode == 1) {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Обновление точечного примитива
|
||||
face.updatePointPrimitive();
|
||||
// Снимаем все пометки грани
|
||||
delete facesToChangeSurface[face];
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если изменился материал поверхности или грань изменила поверхность
|
||||
if (surfacesToChangeMaterial[this] || facesToChangeSurface[face]) {
|
||||
// Отправить точечный примитив на перерисовку
|
||||
face.redrawPointPrimitive();
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
// Смена типа примитива с полигонального на точечный
|
||||
face.changePolyToPointPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Создание точечного примитива
|
||||
face.createPointPrimitive();
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если нет сортировки
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Удаляем точечный примитив
|
||||
face.destroyPointPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Удаляем полигональный примитив
|
||||
face.destroyPolyPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
// Помечаем пространство на пересчёт
|
||||
_mesh._scene.spacesToCalculate[_mesh.space] = true;
|
||||
// Снимаем все пометки поверхности
|
||||
delete _mesh._scene.surfacesToChangeSortingMode[this];
|
||||
delete surfacesToChangeMaterial[this];
|
||||
delete _mesh._scene.surfacesToChangeBSPLevel[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeMaterial():void {
|
||||
trace(this, "changeMaterial");
|
||||
|
||||
var facesToChangeSurface:Set = _mesh._scene.facesToChangeSurface;
|
||||
var facesToTransform:Set = _mesh._scene.facesToTransform;
|
||||
|
||||
var key:*;
|
||||
var face:Face;
|
||||
// Если есть материал
|
||||
if (_material != null) {
|
||||
// Если BSP-сортировка
|
||||
if (_sortingMode == 2) {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Обновление точечного примитива
|
||||
face.updatePolyPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если изменилась мобильность
|
||||
if (face.polyPrimitive.bspLevel != _bspLevel) {
|
||||
// Обновляем мобильность примитива
|
||||
face.updatePolyPrimitiveBSPLevel();
|
||||
} else {
|
||||
// Отправить примитив на перерисовку
|
||||
face.redrawPolyPrimitive();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
// Смена типа примитива с полигонального на точечный
|
||||
face.changePointToPolyPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Создание точечного примитива
|
||||
face.createPolyPrimitive();
|
||||
}
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
} else {
|
||||
// Если сортировка по расстоянию
|
||||
if (_sortingMode == 1) {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Обновление точечного примитива
|
||||
face.updatePointPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Отправить примитив на перерисовку
|
||||
face.redrawPointPrimitive();
|
||||
}
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
// Смена типа примитива с полигонального на точечный
|
||||
face.changePolyToPointPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Создание точечного примитива
|
||||
face.createPointPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
} else {
|
||||
// Если нет сортировки
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Удаляем точечный примитив
|
||||
face.destroyPointPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Удаляем полигональный примитив
|
||||
face.destroyPolyPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
// Помечаем пространство на пересчёт
|
||||
_mesh._scene.spacesToCalculate[_mesh.space] = true;
|
||||
// Снимаем все пометки поверхности
|
||||
delete _mesh._scene.surfacesToChangeMaterial[this];
|
||||
delete _mesh._scene.surfacesToChangeBSPLevel[this];
|
||||
}
|
||||
|
||||
alternativa3d function changeBSPLevel():void {
|
||||
trace(this, "changeBSPLevel");
|
||||
|
||||
var facesToChangeSurface:Set = _mesh._scene.facesToChangeSurface;
|
||||
var facesToTransform:Set = _mesh._scene.facesToTransform;
|
||||
|
||||
var key:*;
|
||||
var face:Face;
|
||||
// Если есть материал
|
||||
if (_material != null) {
|
||||
// Если BSP-сортировка
|
||||
if (_sortingMode == 2) {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Обновление полигонального примитива
|
||||
face.updatePolyPrimitive();
|
||||
// Снимаем все пометки грани
|
||||
delete facesToChangeSurface[face];
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если изменилась мобильность
|
||||
if (face.polyPrimitive.bspLevel != _bspLevel) {
|
||||
// Обновляем мобильность примитива
|
||||
face.updatePolyPrimitiveBSPLevel();
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
} else {
|
||||
// Если грань изменила поверхность
|
||||
if (facesToChangeSurface[face]) {
|
||||
// Отправить полигональный примитив на перерисовку
|
||||
face.redrawPolyPrimitive();
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
// Смена типа примитива с точечного на полигональный
|
||||
face.changePointToPolyPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Создание полигонального примитива
|
||||
face.createPolyPrimitive();
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если сортировка по расстоянию
|
||||
if (_sortingMode == 1) {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Обновление точечного примитива
|
||||
face.updatePointPrimitive();
|
||||
// Снимаем все пометки грани
|
||||
delete facesToChangeSurface[face];
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если грань изменила поверхность
|
||||
if (facesToChangeSurface[face]) {
|
||||
// Отправить точечный примитив на перерисовку
|
||||
face.redrawPointPrimitive();
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Если грань помечена на трансформацию
|
||||
if (facesToTransform[face]) {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
// Смена типа примитива с полигонального на точечный
|
||||
face.changePolyToPointPrimitive();
|
||||
} else {
|
||||
// Расчитываем перпендикуляр грани
|
||||
face.calculatePerpendicular();
|
||||
// Создание точечного примитива
|
||||
face.createPointPrimitive();
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если нет сортировки
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Обрабатываем грани поверхности
|
||||
for (key in _faces) {
|
||||
face = key;
|
||||
// Если есть точечный примитив
|
||||
if (face.pointPrimitive != null) {
|
||||
// Удаляем точечный примитив
|
||||
face.destroyPointPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
} else {
|
||||
// Если есть полигональный примитив
|
||||
if (face.polyPrimitive != null) {
|
||||
// Удаляем полигональный примитив
|
||||
face.destroyPolyPrimitive();
|
||||
// Снимаем пометку на трансформацию
|
||||
delete facesToTransform[face];
|
||||
}
|
||||
}
|
||||
// Снимаем пометку грани на смену поверхности
|
||||
delete facesToChangeSurface[face];
|
||||
}
|
||||
}
|
||||
// Помечаем пространство на пересчёт
|
||||
_mesh._scene.spacesToCalculate[_mesh.space] = true;
|
||||
// Снимаем все пометки поверхности
|
||||
delete _mesh._scene.surfacesToChangeBSPLevel[this];
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавление грани в поверхность.
|
||||
*
|
||||
* @param face экземпляр класса <code>alternativa.engine3d.core.Face</code> или идентификатор грани полигонального объекта
|
||||
*
|
||||
* @throws alternativa.engine3d.errors.FaceNotFoundError грань не найдена в полигональном объекте содержащем поверхность
|
||||
* @throws alternativa.engine3d.errors.InvalidIDError указано недопустимое значение идентификатора
|
||||
* @throws alternativa.engine3d.errors.FaceExistsError поверхность уже содержит указанную грань
|
||||
*
|
||||
* @see Face
|
||||
*/
|
||||
public function addFace(face:Object):void {
|
||||
var byLink:Boolean = face is Face;
|
||||
|
||||
// Проверяем на нахождение поверхности в меше
|
||||
if (_mesh == null) {
|
||||
throw new FaceNotFoundError(face, this);
|
||||
}
|
||||
|
||||
// Проверяем на null
|
||||
if (face == null) {
|
||||
throw new FaceNotFoundError(null, this);
|
||||
}
|
||||
|
||||
// Проверяем наличие грани в меше
|
||||
if (byLink) {
|
||||
// Если удаляем по ссылке
|
||||
if (Face(face)._mesh != _mesh) {
|
||||
// Если грань не в меше
|
||||
throw new FaceNotFoundError(face, this);
|
||||
}
|
||||
} else {
|
||||
// Если удаляем по ID
|
||||
if (_mesh._faces[face] == undefined) {
|
||||
// Если нет грани с таким ID
|
||||
throw new FaceNotFoundError(face, this);
|
||||
} else {
|
||||
if (!(_mesh._faces[face] is Face)) {
|
||||
throw new InvalidIDError(face, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Находим грань
|
||||
var f:Face = byLink ? Face(face) : _mesh._faces[face];
|
||||
|
||||
// Проверяем наличие грани в поверхности
|
||||
if (_faces[f]) {
|
||||
// Если грань уже в поверхности
|
||||
throw new FaceExistsError(f, this);
|
||||
}
|
||||
|
||||
// Проверяем грань на нахождение в другой поверхности
|
||||
if (f._surface != null) {
|
||||
// Удаляем её из той поверхности
|
||||
delete f._surface._faces[f];
|
||||
}
|
||||
|
||||
// Добавляем грань в поверхность
|
||||
_faces[f] = true;
|
||||
// Указываем поверхность грани
|
||||
f._surface = this;
|
||||
|
||||
// Помечаем грань на смену поверхности
|
||||
if (_mesh != null && _mesh._scene != null) {
|
||||
_mesh._scene.facesToChangeSurface[f] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаление грани из поверхности.
|
||||
*
|
||||
* @param face экземпляр класса <code>alternativa.engine3d.core.Face</code> или идентификатор грани полигонального объекта
|
||||
*
|
||||
* @throws alternativa.engine3d.errors.FaceNotFoundError поверхность не содержит указанную грань
|
||||
* @throws alternativa.engine3d.errors.InvalidIDError указано недопустимое значение идентификатора
|
||||
*
|
||||
* @see Face
|
||||
*/
|
||||
public function removeFace(face:Object):void {
|
||||
var byLink:Boolean = face is Face;
|
||||
|
||||
// Проверяем на нахождение поверхности в меше
|
||||
if (_mesh == null) {
|
||||
throw new FaceNotFoundError(face, this);
|
||||
}
|
||||
|
||||
// Проверяем на null
|
||||
if (face == null) {
|
||||
throw new FaceNotFoundError(null, this);
|
||||
}
|
||||
|
||||
// Проверяем наличие грани в меше
|
||||
if (byLink) {
|
||||
// Если удаляем по ссылке
|
||||
if (Face(face)._mesh != _mesh) {
|
||||
// Если грань не в меше
|
||||
throw new FaceNotFoundError(face, this);
|
||||
}
|
||||
} else {
|
||||
// Если удаляем по ID
|
||||
if (_mesh._faces[face] == undefined) {
|
||||
// Если нет грани с таким ID
|
||||
throw new FaceNotFoundError(face, this);
|
||||
} else {
|
||||
if (!(_mesh._faces[face] is Face)) {
|
||||
throw new InvalidIDError(face, this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Находим грань
|
||||
var f:Face = byLink ? Face(face) : _mesh._faces[face];
|
||||
|
||||
// Проверяем наличие грани в поверхности
|
||||
if (!_faces[f]) {
|
||||
// Если грань не в поверхности
|
||||
throw new FaceNotFoundError(f, this);
|
||||
}
|
||||
|
||||
// Удаляем грань из поверхности
|
||||
delete _faces[f];
|
||||
// Удаляем ссылку на поверхность грани
|
||||
f._surface = null;
|
||||
|
||||
// Помечаем грань на смену поверхности
|
||||
if (_mesh != null && _mesh._scene != null) {
|
||||
_mesh._scene.facesToChangeSurface[f] = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Полигональный объект, которому принадлежит поверхность.
|
||||
*/
|
||||
public function get mesh():Mesh {
|
||||
return _mesh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Набор граней поверхности.
|
||||
*/
|
||||
public function get faces():Set {
|
||||
return _faces.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Уровень сортировки.
|
||||
*/
|
||||
public function get sortingLevel():int {
|
||||
return sortingLevelIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set sortingLevel(value:int):void {
|
||||
if (sortingLevelIndex != value) {
|
||||
sortingLevelIndex = value;
|
||||
if (_mesh != null && _mesh._scene != null) {
|
||||
_mesh._scene.surfacesToChangeSortingLevel[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Режим сортировки граней поверхности.
|
||||
*/
|
||||
public function get sortingMode():uint {
|
||||
return _sortingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set sortingMode(value:uint):void {
|
||||
if (_sortingMode != value) {
|
||||
_sortingMode = value;
|
||||
if (_mesh != null && _mesh._scene != null) {
|
||||
_mesh._scene.surfacesToChangeSortingMode[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Материал поверхности. При установке нового значения, устанавливаемый материал будет удалён из старой поверхности.
|
||||
*/
|
||||
public function get material():SurfaceMaterial {
|
||||
return _material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set material(value:SurfaceMaterial):void {
|
||||
if (_material != value) {
|
||||
// Если был материал
|
||||
if (_material != null) {
|
||||
// Удалить материал из поверхности
|
||||
_material._surface = null;
|
||||
}
|
||||
// Если новый материал
|
||||
if (value != null) {
|
||||
// Если материал был в другой поверхности
|
||||
var oldSurface:Surface = value._surface;
|
||||
if (oldSurface != null) {
|
||||
// Удалить его оттуда
|
||||
oldSurface._material = null;
|
||||
// Если есть сцена, помечаем смену материала
|
||||
if (oldSurface._mesh != null && oldSurface._mesh._scene != null) {
|
||||
oldSurface._mesh._scene.surfacesToChangeMaterial[oldSurface] = true;
|
||||
}
|
||||
|
||||
}
|
||||
// Добавить материал в поверхность
|
||||
value._surface = this;
|
||||
}
|
||||
// Если есть сцена, помечаем смену материала
|
||||
if (_mesh != null && _mesh._scene != null) {
|
||||
_mesh._scene.surfacesToChangeMaterial[this] = true;
|
||||
}
|
||||
// Сохраняем материал
|
||||
_material = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Приоритет BSP. Приоритет влияет на положение граней в BSP-дереве.
|
||||
*/
|
||||
public function get bspLevel():int {
|
||||
return _bspLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set bspLevel(value:int):void {
|
||||
if (_bspLevel != value) {
|
||||
_bspLevel = value;
|
||||
if (_mesh != null && _mesh._scene != null) {
|
||||
_mesh._scene.surfacesToChangeBSPLevel[this] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Идентификатор поверхности в полигональном объекте. Если поверхность не принадлежит ни одному объекту,
|
||||
* значение идентификатора равно <code>null</code>.
|
||||
*/
|
||||
public function get id():Object {
|
||||
return (_mesh != null) ? _mesh.getSurfaceId(this) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*
|
||||
* @return строковое представление объекта
|
||||
*/
|
||||
public function toString():String {
|
||||
var length:uint = _faces.length;
|
||||
var res:String = "[Surface ID:" + id + ((length > 0) ? " faces:" : "");
|
||||
var i:uint = 0;
|
||||
for (var key:* in _faces) {
|
||||
var face:Face = key;
|
||||
res += face.id + ((i < length - 1) ? ", " : "");
|
||||
i++;
|
||||
}
|
||||
res += "]";
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
174
Alternativa3D6/6.0/alternativa/engine3d/core/Vertex.as
Normal file
174
Alternativa3D6/6.0/alternativa/engine3d/core/Vertex.as
Normal file
@@ -0,0 +1,174 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.types.Matrix3D;
|
||||
import alternativa.types.Point3D;
|
||||
import alternativa.types.Set;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Вершина полигона в трёхмерном пространстве. Вершина хранит свои координаты, а также ссылки на
|
||||
* полигональный объект и грани этого объекта, которым она принадлежит.
|
||||
*/
|
||||
final public class Vertex {
|
||||
/**
|
||||
* @private
|
||||
* Меш
|
||||
*/
|
||||
alternativa3d var _mesh:Mesh;
|
||||
/**
|
||||
* @private
|
||||
* Координаты точки
|
||||
*/
|
||||
alternativa3d var _coords:Point3D = new Point3D();
|
||||
/**
|
||||
* @private
|
||||
* Грани
|
||||
*/
|
||||
alternativa3d var _faces:Set = new Set();
|
||||
/**
|
||||
* @private
|
||||
* Координаты в сцене
|
||||
*/
|
||||
alternativa3d var spaceCoords:Point3D = new Point3D();
|
||||
|
||||
/**
|
||||
* Создание экземпляра вершины.
|
||||
*
|
||||
* @param x координата вершины по оси X
|
||||
* @param y координата вершины по оси Y
|
||||
* @param z координата вершины по оси Z
|
||||
*/
|
||||
public function Vertex() {}
|
||||
|
||||
// Вызывается при изменении координат вершины, как вручную, так и при трансформации меша
|
||||
alternativa3d function move():void {
|
||||
trace(this, "move");
|
||||
|
||||
spaceCoords.copy(_coords);
|
||||
spaceCoords.transform(_mesh.spaceMatrix);
|
||||
|
||||
delete _mesh._scene.verticesToMove[this];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set x(value:Number):void {
|
||||
if (_coords.x != value) {
|
||||
_coords.x = value;
|
||||
markToMove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set y(value:Number):void {
|
||||
if (_coords.y != value) {
|
||||
_coords.y = value;
|
||||
markToMove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set z(value:Number):void {
|
||||
if (_coords.z != value) {
|
||||
_coords.z = value;
|
||||
markToMove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set coords(value:Point3D):void {
|
||||
if (!_coords.equals(value)) {
|
||||
_coords.copy(value);
|
||||
markToMove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавление сигнала об изменении координат вершины в сцену.
|
||||
* Также добавляются сигналы на трансформацию для зависимых видимых граней.
|
||||
*/
|
||||
private function markToMove():void {
|
||||
var scene:Scene3D;
|
||||
if (_mesh != null && (scene = _mesh._scene) != null) {
|
||||
// Пометка вершины на перемещение
|
||||
scene.verticesToMove[this] = true;
|
||||
for (var key:* in _faces) {
|
||||
var face:Face = key;
|
||||
if (face.pointPrimitive != null || face.polyPrimitive != null) {
|
||||
// Пометка зависимой грани, если у неё есть примитив
|
||||
scene.facesToTransform[face] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Координата вершины по оси X.
|
||||
*/
|
||||
public function get x():Number {
|
||||
return _coords.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Координата вершины по оси Y.
|
||||
*/
|
||||
public function get y():Number {
|
||||
return _coords.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Координата вершины по оси Z.
|
||||
*/
|
||||
public function get z():Number {
|
||||
return _coords.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Координаты вершины.
|
||||
*/
|
||||
public function get coords():Point3D {
|
||||
return _coords.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Полигональный объект, которому принадлежит вершина.
|
||||
*/
|
||||
public function get mesh():Mesh {
|
||||
return _mesh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Множество граней, которым принадлежит вершина. Каждый элемент множества является объектом класса
|
||||
* <code>altertnativa.engine3d.core.Face</code>.
|
||||
*
|
||||
* @see Face
|
||||
*/
|
||||
public function get faces():Set {
|
||||
return _faces.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Идентификатор вершины в полигональном объекте. Если вершина не принадлежит полигональному объекту, возвращается <code>null</code>.
|
||||
*/
|
||||
public function get id():Object {
|
||||
return (_mesh != null) ? _mesh.getVertexId(this) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*
|
||||
* @return строковое представление объекта
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[Vertex ID:" + id + " " + _coords.x.toFixed(2) + ", " + _coords.y.toFixed(2) + ", " + _coords.z.toFixed(2) + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Alternativa3D6/6.0/alternativa/engine3d/display/Canvas.as
Normal file
73
Alternativa3D6/6.0/alternativa/engine3d/display/Canvas.as
Normal file
@@ -0,0 +1,73 @@
|
||||
package alternativa.engine3d.display {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Space;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Canvas extends DisplayItem {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Пространство
|
||||
*/
|
||||
alternativa3d var space:Space;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Ссылка на предыдущий объект
|
||||
*/
|
||||
alternativa3d var previous:DisplayItem;
|
||||
|
||||
// Список отрисовочных объектов
|
||||
alternativa3d var firstItem:DisplayItem;
|
||||
alternativa3d var previousItem:DisplayItem;
|
||||
alternativa3d var currentItem:DisplayItem;
|
||||
|
||||
// Хранилище неиспользуемых канвасов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Создание полотна.
|
||||
*/
|
||||
static alternativa3d function create():Canvas {
|
||||
var canvas:Canvas;
|
||||
if ((canvas = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый канвас
|
||||
return new Canvas();
|
||||
}
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Удаление и зачистка канваса.
|
||||
*/
|
||||
static alternativa3d function destroy(canvas:Canvas):void {
|
||||
// Зачистка списка
|
||||
var item:DisplayItem = canvas.firstItem;
|
||||
while (item != null) {
|
||||
// Сохраняем следующий
|
||||
var next:DisplayItem = item.next;
|
||||
// Удаляем из канваса
|
||||
canvas.removeChild(item);
|
||||
// Удаляем
|
||||
(item is Skin) ? Skin.destroy(item as Skin) : Canvas.destroy(item as Canvas);
|
||||
// Следующий устанавливаем текущим
|
||||
item = next;
|
||||
}
|
||||
// Зачищаем ссылки
|
||||
canvas.next = null;
|
||||
canvas.previous = null;
|
||||
canvas.space = null;
|
||||
// Удаляем список
|
||||
canvas.firstItem = null;
|
||||
canvas.previousItem = null;
|
||||
canvas.currentItem = null;
|
||||
// Отправляем в хранилище
|
||||
collector.push(canvas);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package alternativa.engine3d.display {
|
||||
import alternativa.engine3d.*;
|
||||
|
||||
import flash.display.Sprite;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public class DisplayItem extends Sprite {
|
||||
/**
|
||||
* @private
|
||||
* Ссылка на следующий объект
|
||||
*/
|
||||
alternativa3d var next:DisplayItem;
|
||||
}
|
||||
}
|
||||
68
Alternativa3D6/6.0/alternativa/engine3d/display/Skin.as
Normal file
68
Alternativa3D6/6.0/alternativa/engine3d/display/Skin.as
Normal file
@@ -0,0 +1,68 @@
|
||||
package alternativa.engine3d.display {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.materials.Material;
|
||||
import alternativa.engine3d.sorting.Primitive;
|
||||
|
||||
import flash.display.Graphics;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Контейнер, используемый материалами для отрисовки примитивов.
|
||||
* Каждый примитив BSP-дерева рисуется в своём контейнере.
|
||||
*/
|
||||
public class Skin extends DisplayItem {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Графика скина (для быстрого доступа)
|
||||
*/
|
||||
alternativa3d var gfx:Graphics = graphics;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Примитив
|
||||
*/
|
||||
//alternativa3d var primitive:Primitive;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Материал, связанный со скином.
|
||||
*/
|
||||
alternativa3d var material:Material;
|
||||
|
||||
// Хранилище неиспользуемых скинов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Создание скина.
|
||||
*/
|
||||
static alternativa3d function create():Skin {
|
||||
var skin:Skin;
|
||||
if ((skin = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый скин
|
||||
return new Skin();
|
||||
}
|
||||
return skin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Удаление скина.
|
||||
*/
|
||||
static alternativa3d function destroy(skin:Skin):void {
|
||||
// Очистка скина
|
||||
if (skin.material != null) {
|
||||
skin.material.clear(skin);
|
||||
}
|
||||
// Зачищаем ссылки
|
||||
skin.next = null;
|
||||
//skin.primitive = null;
|
||||
skin.material = null;
|
||||
// Отправляем в хранилище
|
||||
collector.push(skin);
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Alternativa3D6/6.0/alternativa/engine3d/display/View.as
Normal file
117
Alternativa3D6/6.0/alternativa/engine3d/display/View.as
Normal file
@@ -0,0 +1,117 @@
|
||||
package alternativa.engine3d.display {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Camera3D;
|
||||
|
||||
import flash.display.Sprite;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Область для вывода изображения с камеры.
|
||||
*/
|
||||
public class View extends Sprite {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Область отрисовки пространства сцены
|
||||
*/
|
||||
alternativa3d var canvas:Canvas;
|
||||
|
||||
alternativa3d var _camera:Camera3D;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Ширина области вывода
|
||||
*/
|
||||
alternativa3d var _width:Number;
|
||||
/**
|
||||
* @private
|
||||
* Высота области вывода
|
||||
*/
|
||||
alternativa3d var _height:Number;
|
||||
|
||||
/**
|
||||
* Создание экземпляра области вывода.
|
||||
*
|
||||
* @param camera камера, изображение с которой должно выводиться
|
||||
* @param width ширина области вывода
|
||||
* @param height высота области вывода
|
||||
*/
|
||||
public function View(camera:Camera3D = null, width:Number = 0, height:Number = 0) {
|
||||
mouseChildren = false;
|
||||
tabChildren = false;
|
||||
|
||||
this.camera = camera;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Камера с которой ведётся отображение.
|
||||
*/
|
||||
public function get camera():Camera3D {
|
||||
return _camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set camera(value:Camera3D):void {
|
||||
if (value != _camera) {
|
||||
if (_camera != null) {
|
||||
_camera.view = null;
|
||||
}
|
||||
if (value != null) {
|
||||
value.view = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ширина области вывода в пикселях.
|
||||
*/
|
||||
override public function get width():Number {
|
||||
return _width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override public function set width(value:Number):void {
|
||||
if (_width != value) {
|
||||
_width = value;
|
||||
if (canvas != null) {
|
||||
canvas.x = _width*0.5;
|
||||
}
|
||||
if (_camera != null) {
|
||||
// Отправляем сигнал об изменении плоскостей отсечения
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Высота области вывода в пикселях.
|
||||
*/
|
||||
override public function get height():Number {
|
||||
return _height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override public function set height(value:Number):void {
|
||||
if (_height != value) {
|
||||
_height = value;
|
||||
if (canvas != null) {
|
||||
canvas.y = _height*0.5;
|
||||
}
|
||||
if (_camera != null) {
|
||||
// Отправляем сигнал об изменении плоскостей отсечения
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Базовый класс для ошибок 3d-engine.
|
||||
*/
|
||||
public class Alternativa3DError extends Error {
|
||||
|
||||
/**
|
||||
* Источник ошибки - объект в котором произошла ошибка.
|
||||
*/
|
||||
public var source:Object;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param message описание ошибки
|
||||
* @param source источник ошибки
|
||||
*/
|
||||
public function Alternativa3DError(message:String = "", source:Object = null) {
|
||||
super(message);
|
||||
this.source = source;
|
||||
this.name = "Alternativa3DError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Face;
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.utils.TextUtils;
|
||||
import alternativa.engine3d.core.Surface;
|
||||
|
||||
/**
|
||||
* Ошибка, возникающая при попытке добавить в какой-либо объект грань, уже содержащуюся в данном объекте.
|
||||
*/
|
||||
public class FaceExistsError extends ObjectExistsError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param face экземпляр или идентификатор грани, которая уже содержится в объекте
|
||||
* @param source источник ошибки
|
||||
*/
|
||||
public function FaceExistsError(face:Object = null, source:Object = null) {
|
||||
var message:String;
|
||||
if (source is Mesh) {
|
||||
message = "Mesh ";
|
||||
} else if (source is Surface) {
|
||||
message = "Surface ";
|
||||
}
|
||||
if (face is Face) {
|
||||
message += "%1. Face %2 already exists.";
|
||||
} else {
|
||||
message += "%1. Face with ID '%2' already exists.";
|
||||
}
|
||||
super(TextUtils.insertVars(message, source, face), face, source);
|
||||
this.name = "FaceExistsError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая недостаточное количество вершин для создания грани.
|
||||
* Для создания грани должно быть указано не менее трех вершин.
|
||||
*/
|
||||
public class FaceNeedMoreVerticesError extends Alternativa3DError {
|
||||
|
||||
/**
|
||||
* Количество переданных для создания грани вершин
|
||||
*/
|
||||
public var count:uint;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param mesh объект, в котором произошла ошибка
|
||||
* @param count количество вершин, переданное для создания грани
|
||||
*/
|
||||
public function FaceNeedMoreVerticesError(mesh:Mesh = null, count:uint = 0) {
|
||||
super(TextUtils.insertVars("Mesh %1. %2 vertices not enough for face creation.", mesh, count), mesh);
|
||||
this.count = count;
|
||||
this.name = "FaceNeedMoreVerticesError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Face;
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, возникающая, если грань не найдена в объекте.
|
||||
*/
|
||||
public class FaceNotFoundError extends ObjectNotFoundError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param face экземпляр или идентификатор грани
|
||||
* @param source объект, в котором произошла ошибка
|
||||
*/
|
||||
public function FaceNotFoundError(face:Object = null, source:Object = null) {
|
||||
var message:String;
|
||||
if (source is Mesh) {
|
||||
message = "Mesh ";
|
||||
} else {
|
||||
message = "Surface ";
|
||||
}
|
||||
if (face is Face) {
|
||||
message += "%1. Face %2 not found.";
|
||||
} else {
|
||||
message += "%1. Face with ID '%2' not found.";
|
||||
}
|
||||
super(TextUtils.insertVars(message, source, face), face, source);
|
||||
this.name = "FaceNotFoundError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package alternativa.engine3d.errors {
|
||||
import alternativa.utils.TextUtils;
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.engine3d.core.Surface;
|
||||
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что идентификатор зарезервирован и не может быть использован.
|
||||
*/
|
||||
public class InvalidIDError extends Engine3DError {
|
||||
/**
|
||||
* Зарезервированный идентификатор
|
||||
*/
|
||||
public var id:Object;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param id идентификатор
|
||||
* @param source объект, в котором произошла ошибка
|
||||
*/
|
||||
public function InvalidIDError(id:Object = null, source:Object = null) {
|
||||
var message:String;
|
||||
if (source is Mesh) {
|
||||
message = "Mesh %2. ";
|
||||
} else if (source is Surface) {
|
||||
message = "Surface %2. ";
|
||||
}
|
||||
super(TextUtils.insertVars(message + "ID %1 is reserved and cannot be used", [id, source]), source);
|
||||
this.id = id;
|
||||
this.name = "InvalidIDError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package alternativa.engine3d.errors {
|
||||
import alternativa.engine3d.core.Space;
|
||||
import alternativa.utils.TextUtils;
|
||||
import alternativa.engine3d.sorting.SortingMode;
|
||||
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что режим сортировки не может быть использован.
|
||||
*/
|
||||
public class InvalidSortingModeError extends Alternativa3DError {
|
||||
/**
|
||||
* Режим сортировки
|
||||
*/
|
||||
public var sortingMode:uint;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param sortingMode режим сортировки
|
||||
* @param source объект, в котором произошла ошибка
|
||||
*/
|
||||
public function InvalidSortingModeError(sortingMode:uint = 0, source:Object = null) {
|
||||
var message:String;
|
||||
if (source is Space) {
|
||||
message = "Space %2. ";
|
||||
} else {
|
||||
/*
|
||||
if (source is Sprite3D) {
|
||||
message = "Sprite3D %2. ";
|
||||
} else {
|
||||
if (source is Sprite3D) {
|
||||
message = "Surface %2. ";
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
super(TextUtils.insertVars(message + "Sorting mode %1 cannot be used", sortingMode, source));
|
||||
this.sortingMode = sortingMode;
|
||||
this.name = "InvalidSortingModeError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, связанная с нарушением иерархии объектов сцены.
|
||||
*/
|
||||
public class Object3DHierarchyError extends Alternativa3DError {
|
||||
|
||||
/**
|
||||
* Объект сцены, нарушающий иерархию
|
||||
*/
|
||||
public var object:Object3D;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param object объект, нарушающий иерархию
|
||||
* @param source источник ошибки
|
||||
*/
|
||||
public function Object3DHierarchyError(object:Object3D = null, source:Object3D = null) {
|
||||
super(TextUtils.insertVars("Object3D %1. Object %2 cannot be added", source, object), source);
|
||||
this.object = object;
|
||||
this.name = "Object3DHierarchyError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, возникающая, когда объект сцены не был найден в списке связанных с необходимым объектом сцены.
|
||||
*/
|
||||
public class Object3DNotFoundError extends ObjectNotFoundError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param object ненайденный объект сцены
|
||||
* @param source объект сцены, в котором произошла ошибка
|
||||
*/
|
||||
public function Object3DNotFoundError(object:Object3D = null, source:Object3D = null) {
|
||||
super(TextUtils.insertVars("Object3D %1. Object %2 not in child list", source, object), object, source);
|
||||
this.name = "Object3DNotFoundError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что объект уже присутствует в контейнере.
|
||||
*/
|
||||
public class ObjectExistsError extends Alternativa3DError {
|
||||
|
||||
/**
|
||||
* Экземпляр или идентификатор объекта, который уже присутствует в контейнере
|
||||
*/
|
||||
public var object:Object;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param message описание ошибки
|
||||
* @param object объект, который уже присутствует в контейнере
|
||||
* @param source объект, вызвавший ошибку
|
||||
*/
|
||||
public function ObjectExistsError(message:String = "", object:Object = null, source:Object = null) {
|
||||
super(message, source);
|
||||
this.object = object;
|
||||
this.name = "ObjectExistsError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
/**
|
||||
* Необходимый объект не был найден в контейнере.
|
||||
*/
|
||||
public class ObjectNotFoundError extends Alternativa3DError {
|
||||
|
||||
/**
|
||||
* Объект, который отсутствует в контейнере.
|
||||
*/
|
||||
public var object:Object;
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param message описание ошибки
|
||||
* @param object отсутствующий объект
|
||||
* @param source объект, вызвавший ошибку
|
||||
*/
|
||||
public function ObjectNotFoundError(message:String = "", object:Object = null, source:Object = null) {
|
||||
super(message, source);
|
||||
this.object = object;
|
||||
this.name = "ObjectNotFoundError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что поверхность уже присутствует в контейнере.
|
||||
*/
|
||||
public class SurfaceExistsError extends ObjectExistsError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param surface поверхность, которая уже присутствует в контейнере
|
||||
* @param mesh объект, вызвавший ошибку
|
||||
*/
|
||||
public function SurfaceExistsError(surface:Object = null, mesh:Mesh = null) {
|
||||
super(TextUtils.insertVars("Mesh %1. Surface with ID '%2' already exists.", mesh, surface), surface, mesh);
|
||||
this.name = "SurfaceExistsError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.engine3d.core.Surface;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что поверхность не найдена в контейнере.
|
||||
*/
|
||||
public class SurfaceNotFoundError extends ObjectNotFoundError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param surface поверхность, которая отсутствует в объекте
|
||||
* @param mesh объект, который вызвал ошибку
|
||||
*/
|
||||
public function SurfaceNotFoundError(surface:Object = null, mesh:Mesh = null) {
|
||||
if (mesh == null) {
|
||||
|
||||
}
|
||||
if (surface is Surface) {
|
||||
message = "Mesh %1. Surface %2 not found.";
|
||||
} else {
|
||||
message = "Mesh %1. Surface with ID '%2' not found.";
|
||||
}
|
||||
super(TextUtils.insertVars(message, mesh, surface), surface, mesh);
|
||||
this.name = "SurfaceNotFoundError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что вершина уже содержится в объекте.
|
||||
*/
|
||||
public class VertexExistsError extends ObjectExistsError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param vertex вершина, которая уже есть в объекте
|
||||
* @param mesh объект, вызвавший ошибку
|
||||
*/
|
||||
public function VertexExistsError(vertex:Object = null, mesh:Mesh = null) {
|
||||
super(TextUtils.insertVars("Mesh %1. Vertex with ID '%2' already exists.", mesh, vertex), vertex, mesh);
|
||||
this.name = "VertexExistsError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package alternativa.engine3d.errors {
|
||||
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.engine3d.core.Vertex;
|
||||
import alternativa.utils.TextUtils;
|
||||
|
||||
/**
|
||||
* Ошибка, обозначающая, что вершина не найдена в объекте.
|
||||
*/
|
||||
public class VertexNotFoundError extends ObjectNotFoundError {
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param vertex вершина, которая не найдена в объекте
|
||||
* @param mesh объект, вызвавший ошибку
|
||||
*/
|
||||
public function VertexNotFoundError(vertex:Object = null, mesh:Mesh = null) {
|
||||
if (vertex is Vertex) {
|
||||
message = "Mesh %1. Vertex %2 not found.";
|
||||
} else {
|
||||
message = "Mesh %1. Vertex with ID '%2' not found.";
|
||||
}
|
||||
super(TextUtils.insertVars(message, mesh, vertex), vertex, mesh);
|
||||
this.name = "VertexNotFoundError";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package alternativa.engine3d.materials {
|
||||
import alternativa.engine3d.*;
|
||||
import flash.display.BlendMode;
|
||||
import alternativa.engine3d.core.Space;
|
||||
import alternativa.engine3d.display.Skin;
|
||||
import alternativa.engine3d.core.Camera3D;
|
||||
import alternativa.engine3d.sorting.Primitive;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Материал, заполняющий полигон сплошной одноцветной заливкой.
|
||||
*/
|
||||
public class FillMaterial extends SurfaceMaterial {
|
||||
/**
|
||||
* @private
|
||||
* Цвет
|
||||
*/
|
||||
alternativa3d var _color:uint;
|
||||
|
||||
// Вспомогательные массивы точек для отрисовки
|
||||
private var points1:Array = new Array();
|
||||
private var points2:Array = new Array();
|
||||
|
||||
/**
|
||||
* Создание экземпляра класса.
|
||||
*
|
||||
* @param color цвет заливки
|
||||
* @param alpha коэффициент непрозрачности материала. Значение 1 соответствует полной непрозрачности, значение 0 соответствует полной прозрачности.
|
||||
* @param blendMode режим наложения цвета
|
||||
*/
|
||||
public function FillMaterial(color:uint, alpha:Number = 1, blendMode:String = BlendMode.NORMAL) {
|
||||
_color = color;
|
||||
_colorTransform.alphaMultiplier = alpha;
|
||||
_blendMode = blendMode;
|
||||
}
|
||||
|
||||
|
||||
alternativa3d function draw(space:Space, camera:Camera3D, skin:Skin, primitive:Primitive):Boolean {
|
||||
|
||||
/*var i:uint;
|
||||
var length:uint = primitive.num;
|
||||
var point:Point3D;
|
||||
|
||||
// Формируем список точек полигона
|
||||
for (i = 0; i < length; i++) {
|
||||
primitivePoint = primitive.points[i];
|
||||
point = points1[i];
|
||||
if (point == null) {
|
||||
points1[i] = new DrawPoint(primitivePoint.x, primitivePoint.y, primitivePoint.z);
|
||||
} else {
|
||||
point.x = primitivePoint.x;
|
||||
point.y = primitivePoint.y;
|
||||
point.z = primitivePoint.z;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function clip(length:uint, source:Array, target:Array, plane:Point3D, offset:Number):uint {
|
||||
var k:Number;
|
||||
var point:Point3D;
|
||||
var index:uint = 0;
|
||||
|
||||
var point1:Point3D = source[length - 1];
|
||||
var offset1:Number = plane.x*point1.x + plane.y*point1.y + plane.z*point1.z - offset;
|
||||
|
||||
for (var i:uint = 0; i < length; i++) {
|
||||
var point2:Point3D = source[i];
|
||||
var offset2:Number = plane.x*point2.x + plane.y*point2.y + plane.z*point2.z - offset;
|
||||
|
||||
if (offset2 > 0) {
|
||||
if (offset1 <= 0) {
|
||||
k = offset2/(offset2 - offset1);
|
||||
point = target[index];
|
||||
if (point == null) {
|
||||
point = new Point3D(point2.x - (point2.x - point1.x)*k, point2.y - (point2.y - point1.y)*k, point2.z - (point2.z - point1.z)*k);
|
||||
target[index] = point;
|
||||
} else {
|
||||
point.x = point2.x - (point2.x - point1.x)*k;
|
||||
point.y = point2.y - (point2.y - point1.y)*k;
|
||||
point.z = point2.z - (point2.z - point1.z)*k;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
point = target[index];
|
||||
if (point == null) {
|
||||
point = new Point3D(point2.x, point2.y, point2.z);
|
||||
target[index] = point;
|
||||
} else {
|
||||
point.x = point2.x;
|
||||
point.y = point2.y;
|
||||
point.z = point2.z;
|
||||
}
|
||||
index++;
|
||||
} else {
|
||||
if (offset1 > 0) {
|
||||
k = offset2/(offset2 - offset1);
|
||||
point = target[index];
|
||||
if (point == null) {
|
||||
point = new Point3D(point2.x - (point2.x - point1.x)*k, point2.y - (point2.y - point1.y)*k, point2.z - (point2.z - point1.z)*k);
|
||||
target[index] = point;
|
||||
} else {
|
||||
point.x = point2.x - (point2.x - point1.x)*k;
|
||||
point.y = point2.y - (point2.y - point1.y)*k;
|
||||
point.z = point2.z - (point2.z - point1.z)*k;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
offset1 = offset2;
|
||||
point1 = point2;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inheritDoc
|
||||
*/
|
||||
/*override alternativa3d function draw(camera:Camera3D, skin:Skin, length:uint, points:Array):void {
|
||||
skin.alpha = _alpha;
|
||||
skin.blendMode = _blendMode;
|
||||
|
||||
var i:uint;
|
||||
var point:DrawPoint;
|
||||
var gfx:Graphics = skin.gfx;
|
||||
|
||||
if (camera._orthographic) {
|
||||
gfx.beginFill(_color);
|
||||
if (_wireThickness >= 0) {
|
||||
gfx.lineStyle(_wireThickness, _wireColor);
|
||||
}
|
||||
point = points[0];
|
||||
gfx.moveTo(point.x, point.y);
|
||||
for (i = 1; i < length; i++) {
|
||||
point = points[i];
|
||||
gfx.lineTo(point.x, point.y);
|
||||
}
|
||||
if (_wireThickness >= 0) {
|
||||
point = points[0];
|
||||
gfx.lineTo(point.x, point.y);
|
||||
}
|
||||
} else {
|
||||
gfx.beginFill(_color);
|
||||
if (_wireThickness >= 0) {
|
||||
gfx.lineStyle(_wireThickness, _wireColor);
|
||||
}
|
||||
point = points[0];
|
||||
var perspective:Number = camera.focalLength/point.z;
|
||||
gfx.moveTo(point.x*perspective, point.y*perspective);
|
||||
for (i = 1; i < length; i++) {
|
||||
point = points[i];
|
||||
perspective = camera.focalLength/point.z;
|
||||
gfx.lineTo(point.x*perspective, point.y*perspective);
|
||||
}
|
||||
if (_wireThickness >= 0) {
|
||||
point = points[0];
|
||||
perspective = camera.focalLength/point.z;
|
||||
gfx.lineTo(point.x*perspective, point.y*perspective);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Цвет заливки.
|
||||
*/
|
||||
public function get color():uint {
|
||||
return _color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set color(value:uint):void {
|
||||
if (_color != value) {
|
||||
_color = value;
|
||||
markToChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function create():Material {
|
||||
return new FillMaterial(_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
169
Alternativa3D6/6.0/alternativa/engine3d/materials/Material.as
Normal file
169
Alternativa3D6/6.0/alternativa/engine3d/materials/Material.as
Normal file
@@ -0,0 +1,169 @@
|
||||
package alternativa.engine3d.materials {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.display.Skin;
|
||||
|
||||
import flash.display.BlendMode;
|
||||
import flash.geom.ColorTransform;
|
||||
import alternativa.engine3d.display.DisplayItem;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый класс для материалов.
|
||||
*/
|
||||
public class Material {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Видимость
|
||||
*/
|
||||
alternativa3d var _visible:Boolean = true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Режим наложения
|
||||
*/
|
||||
alternativa3d var _blendMode:String = BlendMode.NORMAL;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Трансформация цвета
|
||||
*/
|
||||
alternativa3d var _colorTransform:ColorTransform = new ColorTransform();
|
||||
|
||||
// Флаг трансформации цвета по умолчанию
|
||||
private var defaultColorTransform:Boolean = true;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Видимость.
|
||||
*/
|
||||
public function get visible():Boolean {
|
||||
return _visible;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set visible(value:Boolean):void {
|
||||
if (_visible != value) {
|
||||
_visible = value;
|
||||
markToChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Прозрачность.
|
||||
*/
|
||||
public function get alpha():Number {
|
||||
return _colorTransform.alphaMultiplier;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set alpha(value:Number):void {
|
||||
if (_colorTransform.alphaMultiplier != value) {
|
||||
_colorTransform.alphaMultiplier = value;
|
||||
markToChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Режим наложения.
|
||||
*/
|
||||
public function get blendMode():String {
|
||||
return _blendMode;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set blendMode(value:String):void {
|
||||
if (_blendMode != value) {
|
||||
_blendMode = value;
|
||||
markToChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Трансформация цвета.
|
||||
*/
|
||||
public function get colorTransform():ColorTransform {
|
||||
return new ColorTransform(_colorTransform.redMultiplier, _colorTransform.greenMultiplier, _colorTransform.blueMultiplier, _colorTransform.alphaMultiplier, _colorTransform.redOffset, _colorTransform.greenOffset, _colorTransform.blueOffset, _colorTransform.alphaOffset);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set colorTransform(value:ColorTransform):void {
|
||||
if (value == null) {
|
||||
throw new TypeError("Parameter colorTransform must be non-null.");
|
||||
}
|
||||
if (_colorTransform.redMultiplier != value.redMultiplier || _colorTransform.greenMultiplier != value.greenMultiplier || _colorTransform.blueMultiplier != value.blueMultiplier || _colorTransform.alphaMultiplier != value.alphaMultiplier || _colorTransform.redOffset != value.redOffset || _colorTransform.greenOffset != value.greenOffset || _colorTransform.blueOffset != value.blueOffset || _colorTransform.alphaOffset != value.alphaOffset) {
|
||||
_colorTransform.redMultiplier = value.redMultiplier;
|
||||
_colorTransform.greenMultiplier = value.greenMultiplier;
|
||||
_colorTransform.blueMultiplier = value.blueMultiplier;
|
||||
_colorTransform.alphaMultiplier = value.alphaMultiplier;
|
||||
_colorTransform.redOffset = value.redOffset;
|
||||
_colorTransform.greenOffset = value.greenOffset;
|
||||
_colorTransform.blueOffset = value.blueOffset;
|
||||
_colorTransform.alphaOffset = value.alphaOffset;
|
||||
defaultColorTransform = value.redMultiplier == 1 && value.greenMultiplier == 1 && value.blueMultiplier == 1 && value.redOffset == 0 && value.greenOffset == 0 && value.blueOffset == 0 && value.alphaOffset == 0;
|
||||
markToChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Отметить изменение материала.
|
||||
*/
|
||||
protected function markToChange():void {}
|
||||
|
||||
|
||||
alternativa3d function draw(item:DisplayItem):void {}
|
||||
|
||||
alternativa3d function clear(item:DisplayItem):void {}
|
||||
|
||||
/**
|
||||
* Клонирование объекта. При расширении класса, в наследниках должны быть переопределены вспомогательные
|
||||
* методы <code>create()</code> и <code>cloneProperties()</code>.
|
||||
* @return клон объекта
|
||||
* @see #create()
|
||||
* @see #cloneProperties()
|
||||
*/
|
||||
public function clone():Material {
|
||||
var res:Material = create();
|
||||
res.cloneProperties(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Вспомогательный для клонирования метод. Создание нового экземпляра, который выступит в качестве клона после копирования в него свойств.
|
||||
* Вызывается внутри метода <code>clone()</code>.
|
||||
* При переопределении метод должен перекрываться полностью.
|
||||
* @return новый материал
|
||||
* @see #clone()
|
||||
*/
|
||||
protected function create():Material {
|
||||
return new Material();
|
||||
}
|
||||
|
||||
/**
|
||||
* Вспомогательный для клонирования метод. Копирование свойств из другого объекта. Вызывается внутри метода <code>clone()</code>
|
||||
* объектом, который создан с помощью метода <code>create()</code>.
|
||||
* При переопределении нужно вызывать <code>super.cloneProperties()</code>.
|
||||
* @param source В качестве источника выступает клонируемый объект
|
||||
* @see #clone()
|
||||
* @see #create()
|
||||
*/
|
||||
protected function cloneProperties(source:Material):void {
|
||||
_visible = source._visible;
|
||||
_blendMode = source._blendMode;
|
||||
_colorTransform.redMultiplier = source._colorTransform.redMultiplier;
|
||||
_colorTransform.greenMultiplier = source._colorTransform.greenMultiplier;
|
||||
_colorTransform.blueMultiplier = source._colorTransform.blueMultiplier;
|
||||
_colorTransform.alphaMultiplier = source._colorTransform.alphaMultiplier;
|
||||
_colorTransform.redOffset = source._colorTransform.redOffset;
|
||||
_colorTransform.greenOffset = source._colorTransform.greenOffset;
|
||||
_colorTransform.blueOffset = source._colorTransform.blueOffset;
|
||||
_colorTransform.alphaOffset = source._colorTransform.alphaOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package alternativa.engine3d.materials {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Space;
|
||||
|
||||
import flash.filters.BitmapFilter;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый класс для материалов пространства.
|
||||
*/
|
||||
public class SpaceMaterial extends Material {
|
||||
/**
|
||||
* @private
|
||||
* Пространство
|
||||
*/
|
||||
alternativa3d var _space:Space;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Фильтры
|
||||
*/
|
||||
alternativa3d var _filters:Array = new Array();
|
||||
|
||||
/**
|
||||
* Фильтры.
|
||||
*/
|
||||
public function get filters():Array {
|
||||
return new Array().concat(_filters);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set filters(value:Array):void {
|
||||
var i:uint;
|
||||
var length:uint;
|
||||
length = _filters.length;
|
||||
for (i = 0; i < length; i++) {
|
||||
_filters.pop();
|
||||
}
|
||||
if (value != null) {
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (value[i] is BitmapFilter) {
|
||||
_filters.push(value[i]);
|
||||
} else {
|
||||
throw new ArgumentError("Parameter 0 is of the incorrect type. Should be type Filter.");
|
||||
}
|
||||
}
|
||||
}
|
||||
markToChange();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function markToChange():void {
|
||||
if (_space != null && _space._scene != null) {
|
||||
_space._scene.spacesToChangeMaterial[_space] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package alternativa.engine3d.materials {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Sprite3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый класс для материалов спрайтов.
|
||||
*/
|
||||
public class SpriteMaterial extends Material {
|
||||
/**
|
||||
* @private
|
||||
* Спрайт
|
||||
*/
|
||||
alternativa3d var _sprite:Sprite3D;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function markToChange():void {
|
||||
if (_sprite != null && _sprite._scene != null) {
|
||||
_sprite._scene.spritesToChangeMaterial[_sprite] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package alternativa.engine3d.materials {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Mesh;
|
||||
import alternativa.engine3d.core.Scene3D;
|
||||
import alternativa.engine3d.core.Surface;
|
||||
|
||||
import flash.display.BlendMode;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый класс для материалов поверхности.
|
||||
*/
|
||||
public class SurfaceMaterial extends Material {
|
||||
/**
|
||||
* @private
|
||||
* Поверхность
|
||||
*/
|
||||
alternativa3d var _surface:Surface;
|
||||
|
||||
/**
|
||||
* Поверхность материала.
|
||||
*/
|
||||
public function get surface():Surface {
|
||||
return _surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function markToChange():void {
|
||||
if (_surface != null && _surface._mesh != null && _surface._mesh._scene != null) {
|
||||
_surface._mesh._scene.surfacesToChangeMaterial[_surface] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Отсечение полигона плоскостью.
|
||||
*/
|
||||
protected function clip(length:uint, source:Array, target:Array, plane:Point3D, offset:Number):uint {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
Alternativa3D6/6.0/alternativa/engine3d/sorting/BSPNode.as
Normal file
49
Alternativa3D6/6.0/alternativa/engine3d/sorting/BSPNode.as
Normal file
@@ -0,0 +1,49 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class BSPNode extends Node {
|
||||
|
||||
// Дочерние полигональные ветки
|
||||
alternativa3d var frontBSP:BSPNode;
|
||||
alternativa3d var backBSP:BSPNode;
|
||||
|
||||
// Дочерние точечные ноды
|
||||
alternativa3d var frontDistance:DistanceNode;
|
||||
alternativa3d var backDistance:DistanceNode;
|
||||
|
||||
// Хранилище неиспользуемых нод
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
static alternativa3d function create():BSPNode {
|
||||
var node:BSPNode;
|
||||
if ((node = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новую ноду
|
||||
return new BSPNode();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static alternativa3d function destroy(node:BSPNode):void {
|
||||
// Удаляем ссылку на уровень
|
||||
node.sortingLevel = null;
|
||||
// Отправляем ноду в коллектор
|
||||
collector.push(node);
|
||||
}
|
||||
/*
|
||||
override alternativa3d function addBSPPrimitive(primitive:FaceBSPPrimitive):void {
|
||||
|
||||
}
|
||||
|
||||
override alternativa3d function addDistancePrimitive(primitive:DistancePrimitive):void {
|
||||
|
||||
}
|
||||
|
||||
alternativa3d function removePrimitive(primitive:FaceBSPPrimitive):void {
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.types.Set;
|
||||
import alternativa.engine3d.core.Space;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class DistanceNode extends Node {
|
||||
|
||||
// Список пространств
|
||||
alternativa3d var spaces:Set = new Set();
|
||||
// Список спрайтов
|
||||
alternativa3d var sprites:Set = new Set();
|
||||
// Список граней
|
||||
alternativa3d var faces:Set = new Set();
|
||||
|
||||
// Хранилище неиспользуемых нод
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
static alternativa3d function create():DistanceNode {
|
||||
var node:DistanceNode;
|
||||
if ((node = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новую ноду
|
||||
return new DistanceNode();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static alternativa3d function destroy(node:DistanceNode):void {
|
||||
// Удаляем ссылку на уровень
|
||||
node.sortingLevel = null;
|
||||
// Отправляем ноду в коллектор
|
||||
collector.push(node);
|
||||
}
|
||||
/*
|
||||
override alternativa3d function addDistancePrimitive(primitive:DistancePrimitive):void {
|
||||
// Пометка в уровне об изменении примитива
|
||||
sortingLevel.changedPrimitives[primitive] = true;
|
||||
// Устанавливаем связь примитива и ноды
|
||||
primitives[primitive] = true;
|
||||
primitive.node = this;
|
||||
}
|
||||
*/
|
||||
alternativa3d function removeSpace(space:Space):void {
|
||||
trace("removeSpace", sortingLevel, space);
|
||||
|
||||
// Пометка в уровне об изменении примитива
|
||||
sortingLevel.changed[space] = true;
|
||||
// Удаляем связь пространства и ноды
|
||||
space.node = null;
|
||||
delete spaces[space];
|
||||
// Если в ноде примитивов больше нет
|
||||
if (spaces.isEmpty() && sprites.isEmpty() && faces.isEmpty()) {
|
||||
// Если есть родительская нода
|
||||
if (parent != null) {
|
||||
// Удаляем связь ноды с родительской нодой
|
||||
if (parent.backDistance == this) {
|
||||
parent.backDistance = null;
|
||||
} else {
|
||||
parent.frontDistance = null;
|
||||
}
|
||||
parent = null;
|
||||
} else {
|
||||
// Удаляем корневую ноду из уровня
|
||||
sortingLevel.distanceNode = null;
|
||||
}
|
||||
// Отправляем ноду в коллектор
|
||||
destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.types.Point3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class DistancePrimitive extends Primitive {
|
||||
|
||||
// Нода
|
||||
alternativa3d var node:DistanceNode;
|
||||
|
||||
// Координаты в пространстве
|
||||
alternativa3d var coords:Point3D = new Point3D();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Face;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class FaceBSPPrimitive extends Primitive {
|
||||
|
||||
// Ссылка на грань
|
||||
alternativa3d var face:Face;
|
||||
|
||||
// Нода
|
||||
alternativa3d var node:BSPNode;
|
||||
|
||||
// Уровень в BSP
|
||||
alternativa3d var bspLevel:int;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():FaceBSPPrimitive {
|
||||
var primitive:FaceBSPPrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new FaceBSPPrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:FaceBSPPrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:FaceBSPPrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.face = null;
|
||||
primitive.node = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Face;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class FaceDistancePrimitive extends DistancePrimitive {
|
||||
|
||||
// Ссылка на грань
|
||||
alternativa3d var face:Face;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():FaceDistancePrimitive {
|
||||
var primitive:FaceDistancePrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new FaceDistancePrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:FaceDistancePrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:FaceDistancePrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.face = null;
|
||||
primitive.node = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Face;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class FaceNonePrimitive extends NonePrimitive {
|
||||
|
||||
// Ссылка на грань
|
||||
alternativa3d var face:Face;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():FaceNonePrimitive {
|
||||
var primitive:FaceNonePrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new FaceNonePrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:FaceNonePrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:FaceNonePrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.face = null;
|
||||
primitive.sortingLevel = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Alternativa3D6/6.0/alternativa/engine3d/sorting/Node.as
Normal file
17
Alternativa3D6/6.0/alternativa/engine3d/sorting/Node.as
Normal file
@@ -0,0 +1,17 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Space;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Node {
|
||||
|
||||
// Уровень
|
||||
alternativa3d var sortingLevel:SortingLevel;
|
||||
|
||||
// Родительская нода
|
||||
alternativa3d var parent:BSPNode;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class NonePrimitive extends Primitive {
|
||||
|
||||
// Уровень сортировки
|
||||
alternativa3d var sortingLevel:SortingLevel;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Primitive {}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Space;
|
||||
import alternativa.types.Set;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class SortingLevel {
|
||||
|
||||
// Порядковый номер
|
||||
alternativa3d var index:int;
|
||||
|
||||
// Пространство
|
||||
alternativa3d var space:Space;
|
||||
|
||||
// Следующий уровень
|
||||
alternativa3d var next:SortingLevel;
|
||||
|
||||
// Корневая нода дерева
|
||||
alternativa3d var bspNode:BSPNode;
|
||||
alternativa3d var distanceNode:DistanceNode;
|
||||
|
||||
// Список несортируемых пространств
|
||||
alternativa3d var spaces:Set = new Set();
|
||||
// Список пространств на сортировку по дистанции
|
||||
alternativa3d var spacesDistance:Set = new Set();
|
||||
|
||||
// Список несортируемых спрайтов
|
||||
alternativa3d var sprites:Set = new Set();
|
||||
// Список спрайтов на сортировку по дистанции
|
||||
alternativa3d var spritesDistance:Set = new Set();
|
||||
|
||||
// Список несортируемых граней
|
||||
alternativa3d var faces:Set = new Set();
|
||||
// Список граней на сортировку по дистанции
|
||||
alternativa3d var facesDistance:Set = new Set();
|
||||
// Список граней на сортировку по BSP
|
||||
alternativa3d var facesBSP:Array = new Array();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Список изменённых объектов
|
||||
*/
|
||||
alternativa3d var changed:Set = new Set();
|
||||
|
||||
alternativa3d function calculate():void {
|
||||
/*var polyPrimitive:FacePolyPrimitive;
|
||||
var pointPrimitive:PointPrimitive;
|
||||
|
||||
// Добавляем полигональные примитивы
|
||||
while ((polyPrimitive = polyPrimitivesToAdd.pop()) != null) {
|
||||
}
|
||||
|
||||
// Если есть точечные примитивы на добавление
|
||||
if (pointPrimitivesToAdd[0] != undefined) {
|
||||
|
||||
// Если корневого нода ещё нет, создаём
|
||||
if (root == null) {
|
||||
root = PointNode.create();
|
||||
root.space = this;
|
||||
}
|
||||
|
||||
// Встраиваем примитивы в дерево
|
||||
while ((pointPrimitive = pointPrimitivesToAdd.pop()) != null) {
|
||||
trace(pointPrimitive);
|
||||
root.addPointPrimitive(pointPrimitive);
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
// Если есть изменения, помечаем на очистку
|
||||
if (!changed.isEmpty()) {
|
||||
space._scene.levelsToClear[this] = true;
|
||||
}
|
||||
|
||||
delete space._scene.levelsToCalculate[this];
|
||||
}
|
||||
|
||||
alternativa3d function clear():void {
|
||||
trace(this, "clear");
|
||||
|
||||
delete space._scene.levelsToClear[this];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
public class SortingMode {
|
||||
|
||||
public static const NONE:uint = 0;
|
||||
public static const DISTANCE:uint = 1;
|
||||
public static const BSP:uint = 2;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Space;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class SpaceDistancePrimitive extends DistancePrimitive {
|
||||
|
||||
// Ссылка на пространство
|
||||
alternativa3d var space:Space;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():SpaceDistancePrimitive {
|
||||
var primitive:SpaceDistancePrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new SpaceDistancePrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:SpaceDistancePrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:SpaceDistancePrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.space = null;
|
||||
primitive.node = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Space;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class SpaceNonePrimitive extends NonePrimitive {
|
||||
|
||||
// Ссылка на пространство
|
||||
alternativa3d var space:Space;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():SpaceNonePrimitive {
|
||||
var primitive:SpaceNonePrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new SpaceNonePrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:SpaceNonePrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:SpaceNonePrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.space = null;
|
||||
primitive.sortingLevel = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Sprite3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class SpriteDistancePrimitive extends DistancePrimitive {
|
||||
|
||||
// Ссылка на спрайт
|
||||
alternativa3d var sprite:Sprite3D;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():SpriteDistancePrimitive {
|
||||
var primitive:SpriteDistancePrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new SpriteDistancePrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:SpriteDistancePrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:SpriteDistancePrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.sprite = null;
|
||||
primitive.node = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package alternativa.engine3d.sorting {
|
||||
|
||||
import alternativa.engine3d.*;
|
||||
import alternativa.engine3d.core.Sprite3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class SpriteNonePrimitive extends NonePrimitive {
|
||||
|
||||
// Ссылка на спрайт
|
||||
alternativa3d var sprite:Sprite3D;
|
||||
|
||||
// Хранилище неиспользуемых примитивов
|
||||
static private var collector:Array = new Array();
|
||||
|
||||
// Примитивы на отложенное удаление
|
||||
static private var deferred:Array = new Array();
|
||||
|
||||
static alternativa3d function create():SpriteNonePrimitive {
|
||||
var primitive:SpriteNonePrimitive;
|
||||
if ((primitive = collector.pop()) == null) {
|
||||
// Если коллектор пуст, создаём новый примитив
|
||||
return new SpriteNonePrimitive();
|
||||
}
|
||||
return primitive;
|
||||
}
|
||||
|
||||
static alternativa3d function defer(primitive:SpriteNonePrimitive):void {
|
||||
deferred.push(primitive);
|
||||
}
|
||||
|
||||
static alternativa3d function destroyDeferred():void {
|
||||
var primitive:SpriteNonePrimitive;
|
||||
while ((primitive = deferred.pop()) != null) {
|
||||
primitive.sprite = null;
|
||||
primitive.sortingLevel = null;
|
||||
collector.push(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user