mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-05 15:28:29 +08:00
Entity creation is now undoable. Fixed a bug that occurred when you started to translate an entity and then moved the cursor outside of the 3D-view.
This commit is contained in:
parent
a97b56cecc
commit
79b85fc859
@ -1,7 +1,6 @@
|
||||
import CameraControls from "camera-controls";
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
Camera,
|
||||
Clock,
|
||||
Color,
|
||||
Group,
|
||||
@ -34,8 +33,8 @@ export abstract class Renderer implements Disposable {
|
||||
this._debug = debug;
|
||||
}
|
||||
|
||||
readonly camera: Camera;
|
||||
readonly controls: CameraControls;
|
||||
abstract readonly camera: PerspectiveCamera | OrthographicCamera;
|
||||
readonly controls!: CameraControls;
|
||||
readonly scene = new Scene();
|
||||
readonly light_holder = new Group();
|
||||
|
||||
@ -44,23 +43,19 @@ export abstract class Renderer implements Disposable {
|
||||
private animation_frame_handle?: number = undefined;
|
||||
private light = new HemisphereLight(0xffffff, 0x505050, 1.2);
|
||||
private controls_clock = new Clock();
|
||||
private size = new Vector2();
|
||||
|
||||
protected constructor(camera: PerspectiveCamera | OrthographicCamera) {
|
||||
this.camera = camera;
|
||||
|
||||
protected constructor() {
|
||||
this.dom_element.tabIndex = 0;
|
||||
this.dom_element.addEventListener("mousedown", this.on_mouse_down);
|
||||
this.dom_element.style.outline = "none";
|
||||
|
||||
this.controls = new CameraControls(camera, this.renderer.domElement);
|
||||
this.controls.dampingFactor = 1;
|
||||
this.controls.draggingDampingFactor = 1;
|
||||
|
||||
this.scene.background = new Color(0x181818);
|
||||
this.light_holder.add(this.light);
|
||||
this.scene.add(this.light_holder);
|
||||
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
this.renderer.getSize(this.size);
|
||||
}
|
||||
|
||||
get dom_element(): HTMLElement {
|
||||
@ -68,15 +63,13 @@ export abstract class Renderer implements Disposable {
|
||||
}
|
||||
|
||||
set_size(width: number, height: number): void {
|
||||
this.size.set(width, height);
|
||||
this.renderer.setSize(width, height);
|
||||
this.schedule_render();
|
||||
}
|
||||
|
||||
pointer_pos_to_device_coords(e: MouseEvent): Vector2 {
|
||||
const coords = this.renderer.getSize(new Vector2());
|
||||
coords.width = (e.offsetX / coords.width) * 2 - 1;
|
||||
coords.height = (e.offsetY / coords.height) * -2 + 1;
|
||||
return coords;
|
||||
pointer_pos_to_device_coords(pos: Vector2): void {
|
||||
pos.set((pos.x / this.size.width) * 2 - 1, (pos.y / this.size.height) * -2 + 1);
|
||||
}
|
||||
|
||||
start_rendering(): void {
|
||||
@ -108,6 +101,16 @@ export abstract class Renderer implements Disposable {
|
||||
|
||||
dispose(): void {
|
||||
this.renderer.dispose();
|
||||
this.controls.dispose();
|
||||
}
|
||||
|
||||
protected init_camera_controls(): void {
|
||||
(this.controls as CameraControls) = new CameraControls(
|
||||
this.camera,
|
||||
this.renderer.domElement,
|
||||
);
|
||||
this.controls.dampingFactor = 1;
|
||||
this.controls.draggingDampingFactor = 1;
|
||||
}
|
||||
|
||||
protected render(): void {
|
||||
|
30
src/quest_editor/actions/CreateEntityAction.ts
Normal file
30
src/quest_editor/actions/CreateEntityAction.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Action } from "../../core/undo/Action";
|
||||
import { QuestEntityModel } from "../model/QuestEntityModel";
|
||||
import { entity_data } from "../../core/data_formats/parsing/quest/entities";
|
||||
import { quest_editor_store } from "../stores/QuestEditorStore";
|
||||
|
||||
export class CreateEntityAction implements Action {
|
||||
readonly description: string;
|
||||
|
||||
constructor(private entity: QuestEntityModel) {
|
||||
this.description = `Create ${entity_data(entity.type).name}`;
|
||||
}
|
||||
|
||||
undo(): void {
|
||||
const quest = quest_editor_store.current_quest.val;
|
||||
|
||||
if (quest) {
|
||||
quest.remove_entity(this.entity);
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void {
|
||||
const quest = quest_editor_store.current_quest.val;
|
||||
|
||||
if (quest) {
|
||||
quest.add_entity(this.entity);
|
||||
|
||||
quest_editor_store.set_selected_entity(this.entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import { area_store } from "../stores/AreaStore";
|
||||
import { ListProperty } from "../../core/observable/property/list/ListProperty";
|
||||
import { WritableListProperty } from "../../core/observable/property/list/WritableListProperty";
|
||||
import { QuestEntityModel } from "./QuestEntityModel";
|
||||
import { entity_type_to_string } from "../../core/data_formats/parsing/quest/entities";
|
||||
|
||||
const logger = Logger.get("quest_editor/model/QuestModel");
|
||||
|
||||
@ -111,6 +112,7 @@ export class QuestModel {
|
||||
private readonly _long_description: WritableProperty<string> = property("");
|
||||
private readonly _map_designations: WritableProperty<Map<number, number>>;
|
||||
private readonly _area_variants: WritableListProperty<AreaVariantModel> = list_property();
|
||||
private readonly _objects: WritableListProperty<QuestObjectModel>;
|
||||
private readonly _npcs: WritableListProperty<QuestNpcModel>;
|
||||
|
||||
constructor(
|
||||
@ -150,7 +152,8 @@ export class QuestModel {
|
||||
this.episode = episode;
|
||||
this._map_designations = property(map_designations);
|
||||
this.map_designations = this._map_designations;
|
||||
this.objects = list_property(undefined, ...objects);
|
||||
this._objects = list_property(undefined, ...objects);
|
||||
this.objects = this._objects;
|
||||
this._npcs = list_property(undefined, ...npcs);
|
||||
this.npcs = this._npcs;
|
||||
this.dat_unknowns = dat_unknowns;
|
||||
@ -179,15 +182,31 @@ export class QuestModel {
|
||||
this.map_designations.observe(this.update_area_variants);
|
||||
}
|
||||
|
||||
add_entity(entity: QuestEntityModel): void {
|
||||
if (entity instanceof QuestObjectModel) {
|
||||
this.add_object(entity);
|
||||
} else if (entity instanceof QuestNpcModel) {
|
||||
this.add_npc(entity);
|
||||
} else {
|
||||
throw new Error(`${entity_type_to_string(entity.type)} not supported.`);
|
||||
}
|
||||
}
|
||||
|
||||
add_object(object: QuestObjectModel): void {
|
||||
this._objects.push(object);
|
||||
}
|
||||
|
||||
add_npc(npc: QuestNpcModel): void {
|
||||
this._npcs.push(npc);
|
||||
}
|
||||
|
||||
remove_entity(entity: QuestEntityModel): void {
|
||||
if (entity instanceof QuestNpcModel) {
|
||||
if (entity instanceof QuestObjectModel) {
|
||||
this._objects.remove(entity);
|
||||
} else if (entity instanceof QuestNpcModel) {
|
||||
this._npcs.remove(entity);
|
||||
} else {
|
||||
// TODO: objects
|
||||
throw new Error(`${entity_type_to_string(entity.type)} not supported.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,8 @@ export class QuestEntityControls implements Disposable {
|
||||
* Iff defined, the user is transforming the selected entity.
|
||||
*/
|
||||
private pick?: Pick;
|
||||
private pointer_position = new Vector2(0, 0);
|
||||
private pointer_device_position = new Vector2(0, 0);
|
||||
private last_pointer_position = new Vector2(0, 0);
|
||||
private moved_since_last_mouse_down = false;
|
||||
private disposer = new Disposer();
|
||||
@ -82,8 +84,6 @@ export class QuestEntityControls implements Disposable {
|
||||
);
|
||||
|
||||
renderer.dom_element.addEventListener("mousedown", this.mousedown);
|
||||
renderer.dom_element.addEventListener("mousemove", this.mousemove);
|
||||
renderer.dom_element.addEventListener("mouseup", this.mouseup);
|
||||
add_entity_dnd_listener(renderer.dom_element, "dragenter", this.dragenter);
|
||||
add_entity_dnd_listener(renderer.dom_element, "dragover", this.dragover);
|
||||
add_entity_dnd_listener(renderer.dom_element, "dragleave", this.dragleave);
|
||||
@ -92,8 +92,8 @@ export class QuestEntityControls implements Disposable {
|
||||
|
||||
dispose(): void {
|
||||
this.renderer.dom_element.removeEventListener("mousedown", this.mousedown);
|
||||
this.renderer.dom_element.removeEventListener("mousemove", this.mousemove);
|
||||
this.renderer.dom_element.removeEventListener("mouseup", this.mouseup);
|
||||
document.removeEventListener("mousemove", this.doc_mousemove);
|
||||
document.removeEventListener("mouseup", this.doc_mouseup);
|
||||
remove_entity_dnd_listener(this.renderer.dom_element, "dragenter", this.dragenter);
|
||||
remove_entity_dnd_listener(this.renderer.dom_element, "dragover", this.dragover);
|
||||
remove_entity_dnd_listener(this.renderer.dom_element, "dragleave", this.dragleave);
|
||||
@ -120,9 +120,13 @@ export class QuestEntityControls implements Disposable {
|
||||
|
||||
private mousedown = (e: MouseEvent) => {
|
||||
this.process_event(e);
|
||||
|
||||
document.addEventListener("mouseup", this.doc_mouseup);
|
||||
document.addEventListener("mousemove", this.doc_mousemove);
|
||||
|
||||
this.stop_transforming();
|
||||
|
||||
const new_pick = this.pick_entity(this.renderer.pointer_pos_to_device_coords(e));
|
||||
const new_pick = this.pick_entity(this.pointer_device_position);
|
||||
|
||||
if (new_pick) {
|
||||
// Disable camera controls while the user is transforming an entity.
|
||||
@ -137,11 +141,9 @@ export class QuestEntityControls implements Disposable {
|
||||
this.renderer.schedule_render();
|
||||
};
|
||||
|
||||
private mousemove = (e: MouseEvent) => {
|
||||
private doc_mousemove = (e: MouseEvent) => {
|
||||
this.process_event(e);
|
||||
|
||||
const pointer_device_pos = this.renderer.pointer_pos_to_device_coords(e);
|
||||
|
||||
if (this.selected && this.pick) {
|
||||
if (this.moved_since_last_mouse_down) {
|
||||
// User is transforming selected entity.
|
||||
@ -151,7 +153,7 @@ export class QuestEntityControls implements Disposable {
|
||||
}
|
||||
} else {
|
||||
// User is hovering.
|
||||
const new_pick = this.pick_entity(pointer_device_pos);
|
||||
const new_pick = this.pick_entity(this.pointer_device_position);
|
||||
|
||||
if (this.mark_hovered(new_pick)) {
|
||||
this.renderer.schedule_render();
|
||||
@ -159,10 +161,12 @@ export class QuestEntityControls implements Disposable {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: deal with mouseup outside of 3D-view
|
||||
private mouseup = (e: MouseEvent) => {
|
||||
private doc_mouseup = (e: MouseEvent) => {
|
||||
this.process_event(e);
|
||||
|
||||
document.removeEventListener("mousemove", this.doc_mousemove);
|
||||
document.removeEventListener("mouseup", this.doc_mouseup);
|
||||
|
||||
if (!this.moved_since_last_mouse_down && !this.pick) {
|
||||
// If the user clicks on nothing, deselect the currently selected entity.
|
||||
this.deselect();
|
||||
@ -176,6 +180,8 @@ export class QuestEntityControls implements Disposable {
|
||||
};
|
||||
|
||||
private dragenter = (e: EntityDragEvent) => {
|
||||
this.process_event(e.event);
|
||||
|
||||
const area = quest_editor_store.current_area.val;
|
||||
const quest = quest_editor_store.current_quest.val;
|
||||
|
||||
@ -208,7 +214,7 @@ export class QuestEntityControls implements Disposable {
|
||||
);
|
||||
const grab_offset = new Vector3(0, 0, 0);
|
||||
const drag_adjust = new Vector3(0, 0, 0);
|
||||
this.translate_entity_horizontally(npc, e.event, grab_offset, drag_adjust);
|
||||
this.translate_entity_horizontally(npc, grab_offset, drag_adjust);
|
||||
quest.add_npc(npc);
|
||||
|
||||
quest_editor_store.set_selected_entity(npc);
|
||||
@ -224,6 +230,8 @@ export class QuestEntityControls implements Disposable {
|
||||
};
|
||||
|
||||
private dragover = (e: EntityDragEvent) => {
|
||||
this.process_event(e.event);
|
||||
|
||||
if (!quest_editor_store.current_area.val) return;
|
||||
|
||||
if (this.pick && this.pick.mode === PickMode.Creating) {
|
||||
@ -242,6 +250,8 @@ export class QuestEntityControls implements Disposable {
|
||||
};
|
||||
|
||||
private dragleave = (e: EntityDragEvent) => {
|
||||
this.process_event(e.event);
|
||||
|
||||
if (!quest_editor_store.current_area.val) return;
|
||||
|
||||
e.drag_element.style.display = "flex";
|
||||
@ -253,24 +263,31 @@ export class QuestEntityControls implements Disposable {
|
||||
}
|
||||
};
|
||||
|
||||
private drop = () => {
|
||||
// TODO: push onto undo stack.
|
||||
this.pick = undefined;
|
||||
private drop = (e: EntityDragEvent) => {
|
||||
this.process_event(e.event);
|
||||
|
||||
if (this.selected && this.pick && this.pick.mode === PickMode.Creating) {
|
||||
quest_editor_store.push_create_entity_action(this.selected.entity);
|
||||
|
||||
this.pick = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
private process_event(e: MouseEvent): void {
|
||||
const { left, top } = this.renderer.dom_element.getBoundingClientRect();
|
||||
this.pointer_position.set(e.clientX - left, e.clientY - top);
|
||||
this.pointer_device_position.copy(this.pointer_position);
|
||||
this.renderer.pointer_pos_to_device_coords(this.pointer_device_position);
|
||||
|
||||
if (e.type === "mousedown") {
|
||||
this.moved_since_last_mouse_down = false;
|
||||
} else {
|
||||
if (
|
||||
e.offsetX !== this.last_pointer_position.x ||
|
||||
e.offsetY !== this.last_pointer_position.y
|
||||
) {
|
||||
} else if (e.type === "mousemove" || e.type === "mouseup") {
|
||||
if (!this.pointer_position.equals(this.last_pointer_position)) {
|
||||
this.moved_since_last_mouse_down = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.last_pointer_position.set(e.offsetX, e.offsetY);
|
||||
this.last_pointer_position.copy(this.pointer_position);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,20 +347,10 @@ export class QuestEntityControls implements Disposable {
|
||||
private translate_entity(e: MouseEvent, selected: Highlighted, pick: Pick): void {
|
||||
if (e.shiftKey) {
|
||||
// Vertical movement.
|
||||
this.translate_entity_vertically(
|
||||
selected.entity,
|
||||
e,
|
||||
pick.drag_adjust,
|
||||
pick.grab_offset,
|
||||
);
|
||||
this.translate_entity_vertically(selected.entity, pick.drag_adjust, pick.grab_offset);
|
||||
} else {
|
||||
// Horizontal movement across the ground.
|
||||
this.translate_entity_horizontally(
|
||||
selected.entity,
|
||||
e,
|
||||
pick.drag_adjust,
|
||||
pick.grab_offset,
|
||||
);
|
||||
this.translate_entity_horizontally(selected.entity, pick.drag_adjust, pick.grab_offset);
|
||||
}
|
||||
|
||||
this.renderer.schedule_render();
|
||||
@ -351,15 +358,12 @@ export class QuestEntityControls implements Disposable {
|
||||
|
||||
private translate_entity_vertically(
|
||||
entity: QuestEntityModel,
|
||||
e: MouseEvent,
|
||||
drag_adjust: Vector3,
|
||||
grab_offset: Vector3,
|
||||
): void {
|
||||
const pointer_position = this.renderer.pointer_pos_to_device_coords(e);
|
||||
|
||||
// We intersect with a plane that's oriented toward the camera and that's coplanar with the
|
||||
// point where the entity was grabbed.
|
||||
this.raycaster.setFromCamera(pointer_position, this.renderer.camera);
|
||||
this.raycaster.setFromCamera(this.pointer_device_position, this.renderer.camera);
|
||||
const ray = this.raycaster.ray;
|
||||
|
||||
const negative_world_dir = this.renderer.camera.getWorldDirection(new Vector3()).negate();
|
||||
@ -386,14 +390,14 @@ export class QuestEntityControls implements Disposable {
|
||||
*/
|
||||
private translate_entity_horizontally(
|
||||
entity: QuestEntityModel,
|
||||
e: MouseEvent,
|
||||
drag_adjust: Vector3,
|
||||
grab_offset: Vector3,
|
||||
): void {
|
||||
const pointer_position = this.renderer.pointer_pos_to_device_coords(e);
|
||||
|
||||
// Cast ray adjusted for dragging entities.
|
||||
const { intersection, section } = this.pick_ground(pointer_position, drag_adjust);
|
||||
const { intersection, section } = this.pick_ground(
|
||||
this.pointer_device_position,
|
||||
drag_adjust,
|
||||
);
|
||||
|
||||
if (intersection) {
|
||||
entity.set_world_position(
|
||||
@ -410,7 +414,7 @@ export class QuestEntityControls implements Disposable {
|
||||
} else {
|
||||
// If the pointer is not over the ground, we translate the entity across the horizontal
|
||||
// plane in which the entity's origin lies.
|
||||
this.raycaster.setFromCamera(pointer_position, this.renderer.camera);
|
||||
this.raycaster.setFromCamera(this.pointer_device_position, this.renderer.camera);
|
||||
const ray = this.raycaster.ray;
|
||||
const plane = new Plane(
|
||||
new Vector3(0, 1, 0),
|
||||
|
@ -8,6 +8,13 @@ import { QuestEntityControls } from "./QuestEntityControls";
|
||||
import { EntityUserData } from "./conversion/entities";
|
||||
|
||||
export class QuestRenderer extends Renderer {
|
||||
private _collision_geometry = new Object3D();
|
||||
private _render_geometry = new Object3D();
|
||||
private _entity_models = new Object3D();
|
||||
private readonly disposer = new Disposer();
|
||||
private readonly entity_to_mesh = new Map<QuestEntityModel, Mesh>();
|
||||
private readonly entity_controls = this.disposer.add(new QuestEntityControls(this));
|
||||
|
||||
get debug(): boolean {
|
||||
return super.debug;
|
||||
}
|
||||
@ -20,7 +27,7 @@ export class QuestRenderer extends Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
private _collision_geometry = new Object3D();
|
||||
readonly camera = new PerspectiveCamera(60, 1, 10, 10000);
|
||||
|
||||
get collision_geometry(): Object3D {
|
||||
return this._collision_geometry;
|
||||
@ -32,8 +39,6 @@ export class QuestRenderer extends Renderer {
|
||||
this.scene.add(collision_geometry);
|
||||
}
|
||||
|
||||
private _render_geometry = new Object3D();
|
||||
|
||||
set render_geometry(render_geometry: Object3D) {
|
||||
this.scene.remove(this._render_geometry);
|
||||
this._render_geometry = render_geometry;
|
||||
@ -41,27 +46,24 @@ export class QuestRenderer extends Renderer {
|
||||
this.scene.add(render_geometry);
|
||||
}
|
||||
|
||||
private _entity_models = new Object3D();
|
||||
|
||||
get entity_models(): Object3D {
|
||||
return this._entity_models;
|
||||
}
|
||||
|
||||
private readonly disposer = new Disposer();
|
||||
private readonly perspective_camera: PerspectiveCamera;
|
||||
private readonly entity_to_mesh = new Map<QuestEntityModel, Mesh>();
|
||||
private readonly entity_controls = this.disposer.add(new QuestEntityControls(this));
|
||||
|
||||
constructor() {
|
||||
super(new PerspectiveCamera(60, 1, 10, 10000));
|
||||
|
||||
this.perspective_camera = this.camera as PerspectiveCamera;
|
||||
super();
|
||||
|
||||
this.disposer.add_all(
|
||||
new QuestModelManager(this),
|
||||
|
||||
quest_editor_store.debug.observe(({ value }) => (this.debug = value)),
|
||||
);
|
||||
|
||||
// Initialize camera-controls after QuestEntityControls to ensure correct order of event
|
||||
// listener registration. This is a fragile work-around for the fact that camera-controls
|
||||
// doesn't support intercepting pointer events.
|
||||
this.init_camera_controls();
|
||||
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@ -70,8 +72,8 @@ export class QuestRenderer extends Renderer {
|
||||
}
|
||||
|
||||
set_size(width: number, height: number): void {
|
||||
this.perspective_camera.aspect = width / height;
|
||||
this.perspective_camera.updateProjectionMatrix();
|
||||
this.camera.aspect = width / height;
|
||||
this.camera.updateProjectionMatrix();
|
||||
super.set_size(width, height);
|
||||
}
|
||||
|
||||
@ -99,6 +101,7 @@ export class QuestRenderer extends Renderer {
|
||||
const mesh = this.entity_to_mesh.get(entity);
|
||||
|
||||
if (mesh) {
|
||||
this.entity_to_mesh.delete(entity);
|
||||
this._entity_models.remove(mesh);
|
||||
this.schedule_render();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import { EditIdAction } from "../actions/EditIdAction";
|
||||
import { Episode } from "../../core/data_formats/parsing/quest/Episode";
|
||||
import { create_new_quest } from "./quest_creation";
|
||||
import Logger = require("js-logger");
|
||||
import { CreateEntityAction } from "../actions/CreateEntityAction";
|
||||
|
||||
const logger = Logger.get("quest_editor/gui/QuestEditorStore");
|
||||
|
||||
@ -269,6 +270,10 @@ export class QuestEditorStore implements Disposable {
|
||||
.redo();
|
||||
};
|
||||
|
||||
push_create_entity_action = (entity: QuestEntityModel) => {
|
||||
this.undo.push(new CreateEntityAction(entity));
|
||||
};
|
||||
|
||||
private async set_quest(quest?: QuestModel, filename?: string): Promise<void> {
|
||||
this.undo.reset();
|
||||
|
||||
|
@ -27,7 +27,6 @@ import { Disposer } from "../../core/observable/Disposer";
|
||||
import { ChangeEvent } from "../../core/observable/Observable";
|
||||
|
||||
export class Model3DRenderer extends Renderer implements Disposable {
|
||||
private readonly perspective_camera: PerspectiveCamera;
|
||||
private readonly disposer = new Disposer();
|
||||
private readonly clock = new Clock();
|
||||
private mesh?: Object3D;
|
||||
@ -39,10 +38,10 @@ export class Model3DRenderer extends Renderer implements Disposable {
|
||||
};
|
||||
private update_animation_time = true;
|
||||
|
||||
constructor() {
|
||||
super(new PerspectiveCamera(75, 1, 1, 200));
|
||||
readonly camera = new PerspectiveCamera(75, 1, 1, 200);
|
||||
|
||||
this.perspective_camera = this.camera as PerspectiveCamera;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.disposer.add_all(
|
||||
model_store.current_nj_data.observe(this.nj_data_or_xvm_changed),
|
||||
@ -53,11 +52,13 @@ export class Model3DRenderer extends Renderer implements Disposable {
|
||||
model_store.animation_frame_rate.observe(this.animation_frame_rate_changed),
|
||||
model_store.animation_frame.observe(this.animation_frame_changed),
|
||||
);
|
||||
|
||||
this.init_camera_controls();
|
||||
}
|
||||
|
||||
set_size(width: number, height: number): void {
|
||||
this.perspective_camera.aspect = width / height;
|
||||
this.perspective_camera.updateProjectionMatrix();
|
||||
this.camera.aspect = width / height;
|
||||
this.camera.updateProjectionMatrix();
|
||||
super.set_size(width, height);
|
||||
}
|
||||
|
||||
@ -71,7 +72,7 @@ export class Model3DRenderer extends Renderer implements Disposable {
|
||||
this.animation.mixer.update(this.clock.getDelta());
|
||||
}
|
||||
|
||||
this.light_holder.quaternion.copy(this.perspective_camera.quaternion);
|
||||
this.light_holder.quaternion.copy(this.camera.quaternion);
|
||||
super.render();
|
||||
|
||||
if (this.animation && !this.animation.action.paused) {
|
||||
|
@ -12,24 +12,19 @@ import { Renderer } from "../../core/rendering/Renderer";
|
||||
import { Disposer } from "../../core/observable/Disposer";
|
||||
import { Xvm } from "../../core/data_formats/parsing/ninja/texture";
|
||||
import { xvm_texture_to_texture } from "../../core/rendering/conversion/ninja_textures";
|
||||
import Logger = require("js-logger");
|
||||
import { texture_store } from "../stores/TextureStore";
|
||||
import Logger = require("js-logger");
|
||||
|
||||
const logger = Logger.get("viewer/rendering/TextureRenderer");
|
||||
|
||||
export class TextureRenderer extends Renderer implements Disposable {
|
||||
private readonly ortho_camera: OrthographicCamera;
|
||||
private readonly disposer = new Disposer();
|
||||
private readonly quad_meshes: Mesh[] = [];
|
||||
|
||||
readonly camera = new OrthographicCamera(-400, 400, 300, -300, 1, 10);
|
||||
|
||||
constructor() {
|
||||
super(new OrthographicCamera(-400, 400, 300, -300, 1, 10));
|
||||
|
||||
this.ortho_camera = this.camera as OrthographicCamera;
|
||||
this.controls.dollySpeed = -1;
|
||||
|
||||
this.controls.azimuthRotateSpeed = 0;
|
||||
this.controls.polarRotateSpeed = 0;
|
||||
super();
|
||||
|
||||
this.disposer.add_all(
|
||||
texture_store.current_xvm.observe(({ value: xvm }) => {
|
||||
@ -43,14 +38,19 @@ export class TextureRenderer extends Renderer implements Disposable {
|
||||
this.schedule_render();
|
||||
}),
|
||||
);
|
||||
|
||||
this.init_camera_controls();
|
||||
this.controls.dollySpeed = -1;
|
||||
this.controls.azimuthRotateSpeed = 0;
|
||||
this.controls.polarRotateSpeed = 0;
|
||||
}
|
||||
|
||||
set_size(width: number, height: number): void {
|
||||
this.ortho_camera.left = -Math.floor(width / 2);
|
||||
this.ortho_camera.right = Math.ceil(width / 2);
|
||||
this.ortho_camera.top = Math.floor(height / 2);
|
||||
this.ortho_camera.bottom = -Math.ceil(height / 2);
|
||||
this.ortho_camera.updateProjectionMatrix();
|
||||
this.camera.left = -Math.floor(width / 2);
|
||||
this.camera.right = Math.ceil(width / 2);
|
||||
this.camera.top = Math.floor(height / 2);
|
||||
this.camera.bottom = -Math.ceil(height / 2);
|
||||
this.camera.updateProjectionMatrix();
|
||||
super.set_size(width, height);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user