mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-21 01:13:37 +08:00
Merge branch 'tiled-texture-view' into next
This commit is contained in:
commit
596ef01379
@ -2062,7 +2062,8 @@ span.controller_state_section_info {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
body[mode=paint] #uv_frame {
|
||||
body[mode=paint] #uv_frame,
|
||||
body[mode=paint] #uv_viewport.tiled_mode {
|
||||
cursor: crosshair;
|
||||
}
|
||||
#uv_frame > #texture_canvas_wrapper > canvas,
|
||||
@ -2076,6 +2077,16 @@ span.controller_state_section_info {
|
||||
object-fit: cover;
|
||||
object-position: 0 0;
|
||||
}
|
||||
#uv_frame > #texture_canvas_wrapper > canvas.overlay_canvas[overlay_mode=tiled] {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
margin-left: -100%;
|
||||
margin-top: -100%;
|
||||
}
|
||||
#uv_frame > #texture_canvas_wrapper > canvas.overlay_canvas[overlay_mode=onion_skin] {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
/* Fix in Firefox + iPadOS */
|
||||
#uv_frame_spacer {
|
||||
width: 1px;
|
||||
@ -2092,6 +2103,8 @@ span.controller_state_section_info {
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
object-position: 0 0;
|
||||
margin: -1px;
|
||||
border: 1px solid var(--color-grid);
|
||||
}
|
||||
#uv_texture_grid path {
|
||||
fill: none;
|
||||
|
@ -2262,6 +2262,8 @@ const BARS = {
|
||||
'color_erase_mode',
|
||||
'lock_alpha',
|
||||
'painting_grid',
|
||||
'image_tiled_view',
|
||||
'image_onion_skin_view',
|
||||
]
|
||||
})
|
||||
Toolbars.vertex_snap = new Toolbar({
|
||||
|
@ -249,7 +249,16 @@ const Painter = {
|
||||
|
||||
} else {
|
||||
texture.edit(canvas => {
|
||||
Painter.drawBrushLine(texture, x, y, event, new_face, uv)
|
||||
let is_line = true;
|
||||
if (BarItems.image_tiled_view.value == true && (Math.abs(Painter.current.x - x) > texture.width/2 || Math.abs(Painter.current.y - y) > texture.display_height/2)) {
|
||||
is_line = false;
|
||||
}
|
||||
if (is_line) {
|
||||
Painter.drawBrushLine(texture, x, y, event, new_face, uv);
|
||||
} else {
|
||||
Painter.current.x = Painter.current.y = 0
|
||||
Painter.useBrushlike(texture, x, y, event, uv)
|
||||
}
|
||||
}, {no_undo: true, use_cache: true});
|
||||
}
|
||||
Painter.current.x = x;
|
||||
@ -3050,12 +3059,37 @@ BARS.defineActions(function() {
|
||||
})
|
||||
|
||||
new Toggle('painting_grid', {
|
||||
icon: 'grid_on',
|
||||
icon: 'grid_3x3',
|
||||
category: 'view',
|
||||
condition: {modes: ['paint']},
|
||||
keybind: new Keybind({key: 'g'}),
|
||||
linked_setting: 'painting_grid'
|
||||
})
|
||||
new Toggle('image_tiled_view', {
|
||||
category: 'paint',
|
||||
icon: 'grid_view',
|
||||
onChange(value) {
|
||||
if (value && BarItems.image_onion_skin_view.value) {
|
||||
BarItems.image_onion_skin_view.set(false);
|
||||
}
|
||||
UVEditor.vue.overlay_canvas_mode = value ? 'tiled' : null;
|
||||
UVEditor.vue.updateTexture();
|
||||
UVEditor.updateOverlayCanvas();
|
||||
}
|
||||
})
|
||||
new Toggle('image_onion_skin_view', {
|
||||
category: 'paint',
|
||||
icon: 'animation',
|
||||
condition: () => Panels.textures.vue.maxFrameCount(),
|
||||
onChange(value) {
|
||||
if (value && BarItems.image_tiled_view.value) {
|
||||
BarItems.image_tiled_view.set(false);
|
||||
}
|
||||
UVEditor.vue.overlay_canvas_mode = value ? 'onion_skin' : null;
|
||||
UVEditor.vue.updateTexture();
|
||||
UVEditor.updateOverlayCanvas();
|
||||
}
|
||||
})
|
||||
|
||||
new NumSlider('slider_brush_size', {
|
||||
condition: () => (Toolbox && ((Toolbox.selected.brush?.size == true) || ['draw_shape_tool'].includes(Toolbox.selected.id))),
|
||||
|
@ -127,6 +127,7 @@ BARS.defineActions(function() {
|
||||
change: function(modify) {
|
||||
let slider_tex = getSliderTexture()
|
||||
if (!slider_tex) return;
|
||||
UVEditor.previous_animation_frame = slider_tex.currentFrame;
|
||||
slider_tex.currentFrame = (modify(slider_tex.currentFrame + slider_tex.frameCount) % slider_tex.frameCount) || 0;
|
||||
|
||||
let textures = Texture.all.filter(tex => tex.frameCount > 1);
|
||||
|
@ -206,6 +206,7 @@ class Texture {
|
||||
scope.canvas.width = scope.width;
|
||||
scope.canvas.height = scope.height;
|
||||
scope.ctx.drawImage(img, 0, 0);
|
||||
if (UVEditor.vue.texture == this) UVEditor.updateOverlayCanvas();
|
||||
}
|
||||
|
||||
if (this.flags.has('update_uv_size_from_resolution')) {
|
||||
@ -1745,6 +1746,7 @@ class Texture {
|
||||
this.source = this.canvas.toDataURL('image/png', 1);
|
||||
this.updateImageFromCanvas();
|
||||
}
|
||||
if (UVEditor.vue.texture == this) UVEditor.updateOverlayCanvas();
|
||||
}
|
||||
updateChangesAfterEdit() {
|
||||
if (this.layers_enabled) {
|
||||
@ -2645,12 +2647,15 @@ Interface.definePanels(function() {
|
||||
convertTouchEvent(e2);
|
||||
let pos = e2.clientX - timeline_offset;
|
||||
|
||||
let previous_frame = scope.currentFrame;
|
||||
scope.currentFrame = Math.clamp(Math.round((pos / timeline_width) * maxFrameCount), 0, maxFrameCount-1);
|
||||
if (previous_frame == scope.currentFrame) return;
|
||||
|
||||
let textures = Texture.all.filter(tex => tex.frameCount > 1);
|
||||
Texture.all.forEach(tex => {
|
||||
tex.currentFrame = (scope.currentFrame % tex.frameCount) || 0;
|
||||
})
|
||||
UVEditor.previous_animation_frame = previous_frame;
|
||||
TextureAnimator.update(textures);
|
||||
}
|
||||
function off(e3) {
|
||||
|
@ -7,6 +7,12 @@ const UVEditor = {
|
||||
panel: null,
|
||||
sliders: {},
|
||||
selected_element_faces: {},
|
||||
previous_animation_frame: 1,
|
||||
overlay_canvas: (() => {
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.classList.add('overlay_canvas');
|
||||
return canvas;
|
||||
})(),
|
||||
|
||||
get vue() {
|
||||
return this.panel.inside_vue;
|
||||
@ -60,6 +66,10 @@ const UVEditor = {
|
||||
if (tex) {
|
||||
if (tex.frameCount) result.y += (tex.height / tex.frameCount) * tex.currentFrame;
|
||||
if (!tex.frameCount && tex.ratio != tex.getUVWidth() / tex.getUVHeight()) result.y /= tex.ratio;
|
||||
if (BarItems.image_tiled_view.value == true) {
|
||||
result.x = (tex.width + result.x) % tex.width;
|
||||
result.y = (tex.display_height + result.y) % tex.display_height;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
@ -248,6 +258,30 @@ const UVEditor = {
|
||||
scrollTop: focus[1] + margin[1] - UVEditor.height / 2,
|
||||
}, 100)
|
||||
},
|
||||
|
||||
updateOverlayCanvas() {
|
||||
if (!Texture.selected) return;
|
||||
let canvas = UVEditor.overlay_canvas;
|
||||
let texture = Texture.selected;
|
||||
let ctx = canvas.getContext('2d');
|
||||
if (BarItems.image_tiled_view.value == true) {
|
||||
canvas.setAttribute('overlay_mode', 'tiled');
|
||||
canvas.width = texture.width * 3;
|
||||
canvas.height = texture.display_height * 3;
|
||||
for (let x = 0; x < 3; x++) {
|
||||
for (let y = 0; y < 3; y++) {
|
||||
ctx.drawImage(texture.canvas, x * texture.width, y * texture.display_height);
|
||||
}
|
||||
}
|
||||
} else if (BarItems.image_onion_skin_view.value == true) {
|
||||
canvas.setAttribute('overlay_mode', 'onion_skin');
|
||||
canvas.width = texture.width;
|
||||
canvas.height = texture.display_height;
|
||||
ctx.filter = `opacity(${45}%)`;
|
||||
let frame = Math.clamp(UVEditor.previous_animation_frame, 0, texture.frameCount-1);
|
||||
ctx.drawImage(texture.canvas, 0, frame * -texture.display_height);
|
||||
}
|
||||
},
|
||||
//Get
|
||||
get width() {
|
||||
return this.vue.width;
|
||||
@ -2105,6 +2139,7 @@ Interface.definePanels(function() {
|
||||
copy_brush_source: null,
|
||||
helper_lines: {x: -1, y: -1},
|
||||
brush_type: BarItems.brush_shape.value,
|
||||
overlay_canvas_mode: null,
|
||||
selection_rect: {
|
||||
pos_x: 0,
|
||||
pos_y: 0,
|
||||
@ -2316,12 +2351,19 @@ Interface.definePanels(function() {
|
||||
this.texture.canvas.style.objectFit = this.texture.frameCount > 1 ? 'cover' : 'fill';
|
||||
this.texture.canvas.style.imageRendering = this.texture.width < this.inner_width ? 'inherit' : 'auto';
|
||||
|
||||
UVEditor.updateOverlayCanvas();
|
||||
|
||||
Vue.nextTick(() => {
|
||||
let wrapper = this.$refs.texture_canvas_wrapper;
|
||||
if (!wrapper || wrapper.firstChild == this.texture.canvas) return;
|
||||
if (wrapper.firstChild) {
|
||||
let overlay_canvas_mode = this.overlay_canvas_mode;
|
||||
if (this.mode != 'paint') overlay_canvas_mode = null;
|
||||
if (!wrapper || (wrapper.firstChild == this.texture.canvas && !overlay_canvas_mode)) return;
|
||||
while (wrapper.firstChild) {
|
||||
wrapper.firstChild.remove();
|
||||
}
|
||||
if (UVEditor.overlay_canvas && overlay_canvas_mode) {
|
||||
wrapper.append(UVEditor.overlay_canvas);
|
||||
}
|
||||
wrapper.append(this.texture.canvas);
|
||||
})
|
||||
},
|
||||
@ -3941,6 +3983,7 @@ Interface.definePanels(function() {
|
||||
@mouseenter="onMouseEnter($event)"
|
||||
@mouseleave="onMouseLeave($event)"
|
||||
class="checkerboard_target"
|
||||
:class="{tiled_mode: overlay_canvas_mode == 'tiled'}"
|
||||
ref="viewport"
|
||||
v-if="!hidden && mode !== 'face_properties'"
|
||||
:style="{width: (width+8) + 'px', height: (height+8) + 'px', overflowX: (zoom > 1) ? 'scroll' : 'hidden', overflowY: (inner_height > height) ? 'scroll' : 'hidden'}"
|
||||
|
@ -1169,6 +1169,10 @@
|
||||
"action.mirror_painting.description": "Mirror your paint strokes to the other side of the model",
|
||||
"action.lock_alpha": "Lock Alpha Channel",
|
||||
"action.lock_alpha.description": "Lock the transparency of all pixels",
|
||||
"action.image_tiled_view": "Tiled View",
|
||||
"action.image_tiled_view.description": "Enable the tiled view in the 2D editor",
|
||||
"action.image_onion_skin_view": "Image Editor Onion Skin",
|
||||
"action.image_onion_skin_view.description": "Enable the onion skin view in the 2D editor",
|
||||
"action.slider_brush_size": "Size",
|
||||
"action.slider_brush_size.desc": "Radius of the brush in pixels",
|
||||
"action.slider_brush_opacity": "Opacity",
|
||||
|
Loading…
Reference in New Issue
Block a user