mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-27 04:21:46 +08:00
Add face loop select
Fix outliner scrolling issue Fix #1043 keyframes can be created at invalid timecodes Fix #1040 Fix vertex snap issues (#1017) Add "Add Texture Mesh" to edit menu Change default animated texture FPS to 7 Fix #1012 Uv window does not refresh scale when changing project res
This commit is contained in:
parent
13a40283c8
commit
fd64786778
@ -728,7 +728,7 @@ class GeneralAnimator {
|
||||
}
|
||||
|
||||
keyframe.channel = channel;
|
||||
keyframe.time = time;
|
||||
keyframe.time = Timeline.snapTime(time);
|
||||
|
||||
this[channel].push(keyframe);
|
||||
keyframe.animator = this;
|
||||
|
@ -579,6 +579,7 @@ const MenuBar = {
|
||||
'add_group',
|
||||
'add_locator',
|
||||
'add_null_object',
|
||||
'add_texture_mesh',
|
||||
'_',
|
||||
'duplicate',
|
||||
'rename',
|
||||
|
@ -220,7 +220,7 @@ const Settings = {
|
||||
Canvas.updateRenderSides();
|
||||
}});
|
||||
new Setting('background_rendering', {category: 'preview', value: true});
|
||||
new Setting('texture_fps', {category: 'preview', value: 2, type: 'number', onChange() {
|
||||
new Setting('texture_fps', {category: 'preview', value: 7, type: 'number', onChange() {
|
||||
TextureAnimator.updateSpeed()
|
||||
}});
|
||||
new Setting('particle_tick_rate',{category: 'preview', value: 30, type: 'number', onChange() {
|
||||
|
@ -417,6 +417,7 @@ function setProjectResolution(width, height, modify_uv) {
|
||||
function updateProjectResolution() {
|
||||
if (Interface.Panels.uv) {
|
||||
UVEditor.vue.project_resolution.replace([Project.texture_width, Project.texture_height]);
|
||||
UVEditor.vue.updateSize()
|
||||
}
|
||||
if (Texture.selected) {
|
||||
// Update animated textures
|
||||
|
@ -50,7 +50,7 @@ class MeshFace extends Face {
|
||||
}
|
||||
invert() {
|
||||
if (this.vertices.length < 3) return this;
|
||||
[this.vertices[1], this.vertices[2]] = [this.vertices[2], this.vertices[1]];
|
||||
[this.vertices[0], this.vertices[1]] = [this.vertices[1], this.vertices[0]];
|
||||
}
|
||||
isSelected() {
|
||||
let selected_vertices = Project.selected_vertices[this.mesh.uuid];
|
||||
@ -86,6 +86,35 @@ class MeshFace extends Face {
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
getAdjacentFace(side_index = 0) {
|
||||
let vertices = this.getSortedVertices();
|
||||
side_index = side_index % this.vertices.length;
|
||||
let side_vertices = [
|
||||
vertices[side_index],
|
||||
vertices[side_index+1] || vertices[0]
|
||||
]
|
||||
for (let fkey in this.mesh.faces) {
|
||||
let face = this.mesh.faces[fkey];
|
||||
if (face === this) continue;
|
||||
if (face.vertices.includes(side_vertices[0]) && face.vertices.includes(side_vertices[1])) {
|
||||
let f_vertices = face.getSortedVertices();
|
||||
let index_a = f_vertices.indexOf(side_vertices[0]);
|
||||
let index_b = f_vertices.indexOf(side_vertices[1]);
|
||||
if (index_b - index_a == -1 || (index_b - index_a == f_vertices.length-1)) {
|
||||
return {
|
||||
face,
|
||||
index: index_b
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getFaceKey() {
|
||||
for (let fkey in this.mesh.faces) {
|
||||
if (this.mesh.faces[fkey] == this) return fkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
new Property(MeshFace, 'array', 'vertices', {default: 0});
|
||||
|
||||
@ -235,7 +264,8 @@ class Mesh extends OutlinerElement {
|
||||
el.uuid = this.uuid
|
||||
return el;
|
||||
}
|
||||
getSelectedVertices() {
|
||||
getSelectedVertices(make) {
|
||||
if (make && !Project.selected_vertices[this.uuid]) Project.selected_vertices[this.uuid] = [];
|
||||
return Project.selected_vertices[this.uuid] || [];
|
||||
}
|
||||
getSelectedFaces() {
|
||||
@ -546,9 +576,9 @@ new NodePreviewController(Mesh, {
|
||||
|
||||
let sorted_vertices = face.getSortedVertices();
|
||||
|
||||
indices.push(index_offset + 0);
|
||||
indices.push(index_offset + 1);
|
||||
indices.push(index_offset + 2);
|
||||
indices.push(face_indices[sorted_vertices[0]]);
|
||||
indices.push(face_indices[sorted_vertices[1]]);
|
||||
indices.push(face_indices[sorted_vertices[2]]);
|
||||
indices.push(face_indices[sorted_vertices[0]]);
|
||||
indices.push(face_indices[sorted_vertices[2]]);
|
||||
indices.push(face_indices[sorted_vertices[3]]);
|
||||
|
@ -1349,6 +1349,7 @@ Interface.definePanels(function() {
|
||||
list.scrollTop += (mouse_pos.y - (list_offset.top + list.clientHeight)) / 6 + 3;
|
||||
}
|
||||
}
|
||||
let scrollIntervalID;
|
||||
|
||||
function move(e2) {
|
||||
convertTouchEvent(e2);
|
||||
@ -1387,7 +1388,7 @@ Interface.definePanels(function() {
|
||||
}
|
||||
document.body.append(helper);
|
||||
|
||||
setInterval(scrollInterval, 1000/60)
|
||||
scrollIntervalID = setInterval(scrollInterval, 1000/60)
|
||||
}
|
||||
helper.style.left = `${e2.clientX}px`;
|
||||
helper.style.top = `${e2.clientY}px`;
|
||||
@ -1412,7 +1413,7 @@ Interface.definePanels(function() {
|
||||
}
|
||||
function off(e2) {
|
||||
if (helper) helper.remove();
|
||||
clearInterval(scrollInterval);
|
||||
clearInterval(scrollIntervalID);
|
||||
removeEventListeners(document, 'mousemove touchmove', move);
|
||||
removeEventListeners(document, 'mouseup touchend', off);
|
||||
$('.drag_hover').removeClass('drag_hover');
|
||||
|
@ -23,6 +23,22 @@ class TextureMesh extends OutlinerElement {
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
moveVector(arr, axis, update = true) {
|
||||
if (typeof arr == 'number') {
|
||||
var n = arr;
|
||||
arr = [0, 0, 0];
|
||||
arr[axis||0] = n;
|
||||
} else if (arr instanceof THREE.Vector3) {
|
||||
arr = arr.toArray();
|
||||
}
|
||||
arr.forEach((val, i) => {
|
||||
this.origin[i] += val;
|
||||
})
|
||||
if (update) {
|
||||
this.preview_controller.updateTransform(this);
|
||||
}
|
||||
TickUpdates.selection = true;
|
||||
}
|
||||
extend(object) {
|
||||
for (var key in TextureMesh.properties) {
|
||||
TextureMesh.properties[key].merge(this, object)
|
||||
|
@ -417,7 +417,8 @@ class Preview {
|
||||
element,
|
||||
intersects,
|
||||
intersect,
|
||||
vertex
|
||||
vertex,
|
||||
vertex_index: intersect.index,
|
||||
}
|
||||
} else if (intersect_object.type == 'LineSegments') {
|
||||
var element = OutlinerNode.uuids[intersect_object.parent.name];
|
||||
@ -733,13 +734,45 @@ class Preview {
|
||||
if (data.element instanceof Mesh && select_mode == 'face') {
|
||||
if (!data.element.selected) data.element.select(event);
|
||||
|
||||
if (!Project.selected_vertices[data.element.uuid]) {
|
||||
Project.selected_vertices[data.element.uuid] = [];
|
||||
let mesh = data.element;
|
||||
let selected_vertices = mesh.getSelectedVertices(true);
|
||||
|
||||
if (event.altKey || Pressing.overrides.alt) {
|
||||
|
||||
let mesh = data.element;
|
||||
let start_face = mesh.faces[data.face];
|
||||
if (!start_face) return;
|
||||
let processed_faces = [];
|
||||
function selectFace(face, index) {
|
||||
if (processed_faces.includes(face)) return;
|
||||
processed_faces.push(face);
|
||||
let next = face.getAdjacentFace(index);
|
||||
if (next) selectFace(next.face, next.index+2);
|
||||
|
||||
}
|
||||
|
||||
let face_test = start_face.getAdjacentFace(0);
|
||||
let index = (face_test && face_test.face.isSelected()) ? 1 : 0;
|
||||
selectFace(start_face, index);
|
||||
|
||||
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
|
||||
selected_vertices.empty();
|
||||
UVEditor.vue.selected_faces.empty();
|
||||
}
|
||||
|
||||
processed_faces.forEach(face => {
|
||||
Project.selected_vertices[data.element.uuid].safePush(...face.vertices);
|
||||
let fkey = face.getFaceKey();
|
||||
UVEditor.vue.selected_faces.push(fkey);
|
||||
});
|
||||
} else {
|
||||
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
|
||||
selected_vertices.empty();
|
||||
UVEditor.vue.selected_faces.empty();
|
||||
}
|
||||
Project.selected_vertices[data.element.uuid].safePush(...data.element.faces[data.face].vertices);
|
||||
UVEditor.vue.selected_faces.safePush(data.face);
|
||||
}
|
||||
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
|
||||
Project.selected_vertices[data.element.uuid].empty();
|
||||
}
|
||||
Project.selected_vertices[data.element.uuid].safePush(...data.element.faces[data.face].vertices);
|
||||
|
||||
} else {
|
||||
data.element.select(event)
|
||||
|
@ -226,20 +226,25 @@ const Vertexsnap = {
|
||||
}
|
||||
vectors.push([0, 0, 0]);
|
||||
|
||||
let points = new THREE.Points(new THREE.BufferGeometry(), Canvas.meshVertexMaterial);
|
||||
let points = new THREE.Points(new THREE.BufferGeometry(), new THREE.PointsMaterial().copy(Canvas.meshVertexMaterial));
|
||||
points.vertices = vectors;
|
||||
let vector_positions = [];
|
||||
vectors.forEach(vector => vector_positions.push(...vector));
|
||||
let vector_colors = [];
|
||||
vectors.forEach(vector => vector_colors.push(gizmo_colors.grid.r, gizmo_colors.grid.g, gizmo_colors.grid.b));
|
||||
points.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vector_positions), 3));
|
||||
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(new Array(vectors.length).fill(0), 1));
|
||||
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(new Float32Array(vector_colors), 3));
|
||||
points.material.transparent = true;
|
||||
mesh.vertex_points = points;
|
||||
mesh.outline.add(points);
|
||||
}
|
||||
mesh.vertex_points.visible = true;
|
||||
mesh.vertex_points.renderOrder = 900;
|
||||
|
||||
Vertexsnap.elements_with_vertex_gizmos.push(element)
|
||||
},
|
||||
clearVertexGizmos: function() {
|
||||
Project.model_3d.remove(Vertexsnap.line);
|
||||
Vertexsnap.elements_with_vertex_gizmos.forEach(element => {
|
||||
if (element.mesh.vertex_points) {
|
||||
element.mesh.vertex_points.visible = false;
|
||||
@ -263,13 +268,14 @@ const Vertexsnap = {
|
||||
let colors = [];
|
||||
for (let i = 0; i < points.geometry.attributes.position.count; i++) {
|
||||
let color;
|
||||
if (data && data.type == 'vertex' && data.intersect.index == i) {
|
||||
if (data && data.element == el && data.type == 'vertex' && data.vertex_index == i) {
|
||||
color = gizmo_colors.outline;
|
||||
} else {
|
||||
color = gizmo_colors.grid;
|
||||
}
|
||||
colors.push(color.r, color.g, color.b);
|
||||
}
|
||||
points.material.depthTest = !(data.element == el);
|
||||
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
||||
})
|
||||
}
|
||||
@ -309,7 +315,9 @@ const Vertexsnap = {
|
||||
if (Vertexsnap.step1) {
|
||||
Vertexsnap.step1 = false
|
||||
Vertexsnap.vertex_pos = Vertexsnap.getGlobalVertexPos(data.element, data.vertex);
|
||||
Vertexsnap.elements = Outliner.selected.slice()
|
||||
Vertexsnap.vertex_index = data.vertex_index;
|
||||
Vertexsnap.move_origin = typeof data.vertex !== 'string' && data.vertex.allEqual(0);
|
||||
Vertexsnap.elements = Outliner.selected.slice();
|
||||
Vertexsnap.clearVertexGizmos()
|
||||
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
|
||||
|
||||
@ -330,13 +338,13 @@ const Vertexsnap = {
|
||||
|
||||
let mode = BarItems.vertex_snap_mode.get()
|
||||
|
||||
if (Vertexsnap.vertex_id === 100) {
|
||||
if (Vertexsnap.move_origin) {
|
||||
|
||||
Vertexsnap.elements.forEach(function(element) {
|
||||
let vec = Vertexsnap.getGlobalVertexPos(data.element, data.vertex);
|
||||
|
||||
if (Format.bone_rig && element.parent instanceof Group && element.mesh.parent) {
|
||||
//element.mesh.parent.worldToLocal(vec);
|
||||
element.mesh.parent.worldToLocal(vec);
|
||||
}
|
||||
let vec_array = vec.toArray()
|
||||
vec_array.V3_add(element.parent.origin);
|
||||
@ -351,7 +359,7 @@ const Vertexsnap = {
|
||||
//Scale
|
||||
|
||||
var m;
|
||||
switch (Vertexsnap.vertex_id) {
|
||||
switch (Vertexsnap.vertex_index) {
|
||||
case 0: m=[ 1,1,1 ]; break;
|
||||
case 1: m=[ 1,1,0 ]; break;
|
||||
case 2: m=[ 1,0,1 ]; break;
|
||||
@ -361,6 +369,7 @@ const Vertexsnap = {
|
||||
case 6: m=[ 0,0,0 ]; break;
|
||||
case 7: m=[ 0,0,1 ]; break;
|
||||
}
|
||||
console.log()
|
||||
|
||||
Vertexsnap.elements.forEach(function(obj) {
|
||||
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).invert()
|
||||
@ -385,7 +394,7 @@ const Vertexsnap = {
|
||||
var q = obj.mesh.parent.getWorldQuaternion(new THREE.Quaternion()).invert();
|
||||
cube_pos.applyQuaternion(q);
|
||||
}
|
||||
if (Format.rotate_cubes) {
|
||||
if (obj instanceof Cube && Format.rotate_cubes) {
|
||||
obj.origin.V3_add(cube_pos);
|
||||
}
|
||||
var in_box = obj.moveVector(cube_pos.toArray());
|
||||
@ -646,7 +655,7 @@ function moveElementsInSpace(difference, axis) {
|
||||
}
|
||||
|
||||
} else if (space instanceof Group) {
|
||||
if (el.movable) el.from[axis] += difference;
|
||||
if (el.movable && el instanceof Mesh == false) el.from[axis] += difference;
|
||||
if (el.resizable && el.to) el.to[axis] += difference;
|
||||
if (el.rotatable && el instanceof Locator == false) el.origin[axis] += difference;
|
||||
} else {
|
||||
@ -677,7 +686,7 @@ function moveElementsInSpace(difference, axis) {
|
||||
}
|
||||
}
|
||||
|
||||
if (el.movable) el.from.V3_add(m.x, m.y, m.z);
|
||||
if (el.movable && el instanceof Mesh == false) el.from.V3_add(m.x, m.y, m.z);
|
||||
if (el.resizable && el.to) el.to.V3_add(m.x, m.y, m.z);
|
||||
if (move_origin) {
|
||||
if (el.rotatable && el instanceof Locator == false && el instanceof TextureMesh == false) el.origin.V3_add(m.x, m.y, m.z);
|
||||
|
Loading…
Reference in New Issue
Block a user