Files
alternativa3d-archive/Alternativa3D2/2.0/com/alternativagame/engine3d/object/.svn/text-base/Object3D.as.svn-base
2024-10-05 12:11:16 +01:00

476 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

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

package com.alternativagame.engine3d.object {
import com.alternativagame.engine3d.Math3D;
import com.alternativagame.engine3d.Matrix3D;
import com.alternativagame.engine3d.View3D;
import com.alternativagame.engine3d.engine3d;
import com.alternativagame.engine3d.object.light.Light3D;
import com.alternativagame.type.Set;
import com.alternativagame.type.Vector;
import flash.events.EventDispatcher;
import flash.geom.Matrix;
import flash.utils.Dictionary;
use namespace engine3d;
public class Object3D extends EventDispatcher {
use namespace engine3d;
// Название
private var _name:String;
// Инкремент количества объектов
private static var num:uint = 0;
// Флаг сплошного объекта
private var _solid:Boolean = false;
// Все объекты внутри солида
engine3d var solidObjects:Set;
// Все источники света внутри солида
engine3d var solidLights:Set;
// Вершина солида
engine3d var solidParent:Object3D;
// Ссылка на родителя
engine3d var parent:Object3D = null;
// Ссылка на камеру
engine3d var view:View3D = null;
// Флаг интерактивности
private var _interactive:Boolean = false;
// Смещение объекта относительно родителя
private var _x:Number = 0;
private var _y:Number = 0;
private var _z:Number = 0;
// Поворот объекта относительно родителя
private var _rotX:Number = 0;
private var _rotY:Number = 0;
private var _rotZ:Number = 0;
// Мастшаб объекта относительно родителя
private var _scaleX:Number = 1;
private var _scaleY:Number = 1;
private var _scaleZ:Number = 1;
// Списки дочерних объектов
private var _objects:Set;
// Глобальная трансформация
engine3d var transform:Matrix3D;
// Изменилась позиция объекта
engine3d var positionChanged:Boolean = true;
// Изменилась геометрия объекта (поворот, масштаб, параметры)
engine3d var geometryChanged:Boolean = true;
// Изменилось освещение объекта
engine3d var lightChanged:Set = new Set();
public function Object3D() {
_objects = new Set();
transform = new Matrix3D();
solidObjects = new Set();
solidLights = new Set();
solidParent = this;
solidObjects.add(this);
num++;
_name = "Object" + num;
}
// Пересчитать трансформацию объекта и его детей
engine3d function calculateTransform():void {
if (geometryChanged || positionChanged) { // Если позиция или геометрия изменилась
var topTransform:Matrix3D = (this === view.object) ? view.transformation : parent.transform;
// Если изменилась геометрия - Пересчитать трансформацию
if (geometryChanged) {
transform = Math3D.combineMatrix(topTransform, new Matrix3D(x, y, z, rotX, rotY, rotZ, scaleX, scaleY, scaleZ));
// Если изменилась только позиция - Скорректировать трансформацию
} else {
transform.d = topTransform.a*x + topTransform.b*y + topTransform.c*z + topTransform.d;
transform.h = topTransform.e*x + topTransform.f*y + topTransform.g*z + topTransform.h;
transform.l = topTransform.i*x + topTransform.j*y + topTransform.k*z + topTransform.l;
}
// Обновить скины
updateTransform();
// Сбрасываем флаги изменений
positionChanged = false;
geometryChanged = false;
}
// Расчитать трансформацию у дочерних объектов
for each (var object:Object3D in objects) {
object.calculateTransform();
}
}
// Пересчитать освещение объекта и его детей
engine3d function calculateLight():void {
// Обновить освещение
updateLight();
// Удалить источники света
clearLightChanged();
// Расчитать освещение у дочерних объектов
for each (var object:Object3D in objects) {
object.calculateLight();
}
}
// Обновиться после трансформации
protected function updateTransform():void {}
// Обновиться после освещения
protected function updateLight():void {}
// Добавить дочерний объект
public function attach(object:Object3D):void {
// Если объект был в другом объекте
if (object.parent != null) {
// Удалить его оттуда
object.parent.detach(object);
}
// Добавляем в список
objects.add(object);
// Указываем себя как родителя
object.setParent(this);
// Указываем камеру
object.setView(view);
}
// Удалить дочерний объект
public function detach(object:Object3D):void {
// Проверяем, есть ли у нас этот объект
if (objects.has(object)) {
// Убираем из списка
objects.remove(object);
// Удаляем ссылку на родителя
object.setParent(null);
// Удаляем ссылку на камеру
object.setView(null);
}
}
// Получить дочерний объект по имени
public function getObjectByName(name:String):Object3D {
var res:Object3D = null;
for each (var object:Object3D in objects) {
if (object.name == name) {
res = object;
break;
}
}
return res;
}
// Проверить освещение
protected function updateLightChanged():void {
// Собрать все источники внутри солида
for each (var light:Light3D in solidParent.solidLights) {
addLightChanged(light);
}
}
public function set name(value:String):void {
_name = value;
}
public function get name():String {
return _name;
}
public function get x():Number {
return _x;
}
public function get y():Number {
return _y;
}
public function get z():Number {
return _z;
}
public function get rotX():Number {
return _rotX;
}
public function get rotY():Number {
return _rotY;
}
public function get rotZ():Number {
return _rotZ;
}
public function get scaleX():Number {
return _scaleX;
}
public function get scaleY():Number {
return _scaleY;
}
public function get scaleZ():Number {
return _scaleZ;
}
public function set x(value:Number):void {
_x = value;
setPositionChanged();
}
public function set y(value:Number):void {
_y = value;
setPositionChanged();
}
public function set z(value:Number):void {
_z = value;
setPositionChanged();
}
public function set rotX(value:Number):void {
_rotX = value;
setGeometryChanged();
}
public function set rotY(value:Number):void {
_rotY = value;
setGeometryChanged();
}
public function set rotZ(value:Number):void {
_rotZ = value;
setGeometryChanged();
}
public function set scaleX(value:Number):void {
_scaleX = value;
setGeometryChanged();
}
public function set scaleY(value:Number):void {
_scaleY = value;
setGeometryChanged();
}
public function set scaleZ(value:Number):void {
_scaleZ = value;
setGeometryChanged();
}
public function get objects():Set {
return _objects;
}
public function set solid(value:Boolean):void {
// Сохранить солид
_solid = value;
var childSolid:Object3D;
if (value) {
// Если меня установили солидом, то разослать детям себя
childSolid = this;
} else {
// Если я теперь не солид, то разослать детям своего солидПарента
childSolid = solidParent;
}
// Рассылаем детям нового солидПарента
for each (var object:Object3D in objects) {
object.setSolidParent(childSolid);
}
// Пересчитать свет
clearLightChanged();
updateLightChanged();
}
public function get solid():Boolean {
return _solid;
}
engine3d function setSolidParent(value:Object3D):void {
// Забрали себя от старого solidParent
solidParent.solidObjects.remove(this);
// Добавили себя к новому solidParent
value.solidObjects.add(this);
// Если я не солид - установить этот солидПарент у дочерних объектов
if (!solid) {
for each (var object:Object3D in objects) {
object.setSolidParent(value);
}
}
solidParent = value;
}
// Установка новой камеры для объекта
engine3d function setView(value:View3D):void {
view = value;
// При снятии камеры сбросить флаги и очистить источники
if (value == null) {
geometryChanged = false;
positionChanged = false;
clearLightChanged();
// При назначении камеры установить флаги изменения и проверить свет
} else {
geometryChanged = true;
positionChanged = true;
updateLightChanged();
}
// Установить эту камеру у дочерних объектов
for each (var object:Object3D in objects) {
object.setView(value);
}
}
engine3d function setParent(value:Object3D):void {
// Если отцепили, то сам себе солидПарент
if (value == null) {
setSolidParent(this);
// Взять парентСолид у парента
} else {
setSolidParent(value.solid ? value : value.solidParent);
}
parent = value;
}
// Флаги геометрии
engine3d function setGeometryChanged():void {
if (!geometryChanged) {
updateLightChanged();
for each (var object:Object3D in objects) {
object.setGeometryChanged();
}
geometryChanged = true;
}
}
// Флаги позиции
engine3d function setPositionChanged():void {
if (!positionChanged) {
updateLightChanged();
for each (var object:Object3D in objects) {
object.setPositionChanged();
}
positionChanged = true;
}
}
// Добавить источник света
engine3d function addLightChanged(value:Light3D):void {
lightChanged.add(value);
}
// Убрать источники света
engine3d function clearLightChanged():void {
lightChanged = new Set();
}
// Флаг интерактивности
public function set interactive(value:Boolean):void {
_interactive = value;
}
public function get interactive():Boolean {
return _interactive;
}
// Координаты объекта в системе координат камеры
engine3d function get canvasCoords():Vector {
return (view != null) ? new Vector(transform.d, transform.h, transform.l) : null;
}
// Клон
public function clone():Object3D {
var res:Object3D = new Object3D();
cloneParams(res);
return res;
}
// Клонировать параметры
protected function cloneParams(object:*):void {
var obj:Object3D = Object3D(object);
obj.x = x;
obj.y = y;
obj.z = z;
obj.rotX = rotX;
obj.rotY = rotY;
obj.rotZ = rotZ;
obj.scaleX = scaleX;
obj.scaleY = scaleY;
obj.scaleZ = scaleZ;
obj.solid = solid;
obj.name = name;
obj.interactive = interactive;
for each (var child:Object3D in objects) {
obj.attach(child.clone());
}
}
// Получить ветку объектов от текущего до корневого
engine3d function getBranch():Array {
var res:Array = new Array();
var object:Object3D = this;
while (object != null) {
res.push(object);
object = object.parent;
}
return res;
}
// Получить локальные координаты внутри объекта из координат камеры
engine3d function canvasToLocal(coords:Vector):Vector {
var res:Vector = null;
if (view != null) {
// Формируем ветку объектов
var objectList:Array = getBranch();
// Перевести точку в мировые координаты
res = Math3D.vectorTransform(coords, view.inverseTransformation);
var object:Object3D;
var objectMatrix:Matrix3D;
// Перебираем список объектов с конца (с корневого объекта)
var i:int;
for (i = objectList.length - 1; i >= 0; i--) {
object = objectList[i];
// Трансформируем точку через матрицу в локальные координаты текущего объекта
res = Math3D.vectorTransform(res, object.inverseTransform);
}
}
return res;
}
// Расчёт обратной локальной трансформации текущего объекта
engine3d function get inverseTransform():Matrix3D {
var res:Matrix3D = new Matrix3D();
Math3D.translateMatrix(res, -_x, -_y, -_z);
Math3D.rotateZMatrix(res, -_rotZ);
Math3D.rotateYMatrix(res, -_rotY);
Math3D.rotateXMatrix(res, -_rotX);
Math3D.scaleMatrix(res, 1/_scaleX, 1/_scaleY, 1/_scaleZ);
return res;
}
}
}