Compare commits

...

168 Commits

Author SHA1 Message Date
JannisX11
b549e4c060 v4.12.4 [ci-build] 2025-03-28 20:45:46 +01:00
JannisX11
6b8c51ca6b Fix #2731 Error dragging group to outliner end 2025-03-27 21:31:40 +01:00
JannisX11
91ceb36f42 Add Split RGB Channels into Layers 2025-03-27 21:25:20 +01:00
JannisX11
9624352b2a Generate PBR maps tweaks 2025-03-27 21:24:55 +01:00
JannisX11
ae5378c7d1 Add setting to pick combined color 2025-03-27 20:17:22 +01:00
JannisX11
deb6927d50 Support for editing subsurface scattering in texture sets 2025-03-26 23:07:19 +01:00
JannisX11
46c20d5297 Add new skin variants for cow, pig, chicken, magmacube 2025-03-26 20:54:46 +01:00
JannisX11
72c3725a10 Fix height map blurry when converted to different pbr channel 2025-03-25 00:05:33 +01:00
JannisX11
bb80e4f928 Auto-load texture_sets when opening bedrock model
Improve texture set and pbr map name generation
2025-03-24 23:22:40 +01:00
JannisX11
4e5898bdd3 Fix #2378 Face properties selection issue 2025-03-23 14:38:19 +01:00
JannisX11
c15bbd1f77 Fix PBR action conditions
Fix context menu not closing when selecting texture
2025-03-23 13:42:38 +01:00
JannisX11
34dcf0a601 FIx #2604 "Keep Multi Texture Occupancy" doesn't work for mirrored UV 2025-03-23 13:20:48 +01:00
JannisX11
c4fd308f73 When generating PBR MER map, combine into existing MER texture as Add layer
Fix MER map not updating when editing layers
2025-03-22 23:34:21 +01:00
JannisX11
acdb41af74 Fix issue with loading animation controllers 2025-03-22 15:11:10 +01:00
JannisX11
c515592598 Fix #2723 Multiple images in the same imare project can overwrite each other on save 2025-03-19 23:28:38 +01:00
JannisX11
7c29703b3c Rename bone binding item slot 2025-03-19 23:09:49 +01:00
JannisX11
b0f9bc9dc1 Fix issues with generating MER map from existing texture
Fix MER map display issues
Materials can no longer be created from textures that are already in a material
2025-03-19 20:33:32 +01:00
JannisX11
e36c119082 FIx #2720 Open Parent & Adopt Textures still does an action when dismissing dialog 2025-03-16 23:23:03 +01:00
JannisX11
095ed3ef76 Merge branch 'master' into patch 2025-03-16 23:07:48 +01:00
JannisX11
834a97c47e Remove unused field 2025-02-27 23:26:18 +01:00
JannisX11
1289d43eea JSON exporter improvements
Move to new file
Improve performance
Fix #2688 NaN is exported to JSON as NaN
2025-02-22 13:44:11 +01:00
JannisX11
a49f6494a8 Update webapp deploy config 2025-02-19 23:18:44 +01:00
JannisX11
690430ac68 v4.12.3 [ci-build] 2025-02-19 23:03:54 +01:00
JannisX11
717aed5517 Update lang files 2025-02-19 22:57:59 +01:00
JannisX11
73f4fe2cf7 Convert vertex snap amend edit ignore axis into one line 2025-02-19 22:04:22 +01:00
JannisX11
b22df10302 Merge branch 'patch' 2025-02-19 21:55:24 +01:00
JannisX11
8b81761068 Fix #1851 default actions cannot be removed from toolbars in some cases 2025-02-16 23:35:32 +01:00
JannisX11
b7d2dba3e8 Add experimental fix for bbmodel file extensions on android 2025-02-16 21:59:12 +01:00
JannisX11
41faa51738 Fix texture not updating when moving cube in per group texture format 2025-02-16 19:01:31 +01:00
JannisX11
a21c60c589 Fix #2644 selecting collections with invalid state can lock interface 2025-02-16 18:56:10 +01:00
JannisX11
824000b509 Fix edit session issue with undo selections enabled 2025-02-14 20:22:39 +01:00
JannisX11
43297d58cd Fix edit sessions not snycing correctly 2025-02-14 20:19:07 +01:00
JannisX11
e93ba41176 Fix face directions when extruding edge loop
Fix amend edit not working when extruding edges
2025-02-09 15:06:31 +01:00
JannisX11
65862e5747 Fix graph editor limit value not applying 2025-02-09 14:13:59 +01:00
JannisX11
458a8bf7f2 Change form linked ratio to update ratio when enabling link 2025-02-09 14:13:40 +01:00
JannisX11
c51a420178 Make sure selection is valid after mirror modeling mesh 2025-02-09 14:12:57 +01:00
JannisX11
dd4fbd9bfd Ignroe box UV when determining format version for bedrock geo 2025-02-09 13:40:14 +01:00
JannisX11
71b0bd77ea Fix #1334 Mesh wireframes sometimes do not update 2025-02-06 22:59:07 +01:00
JannisX11
2c0d8f11b3 Fix #2665 tiny numbers not rounded in minified bbmodel 2025-02-05 00:30:36 +01:00
JannisX11
e7dd11e6d9 Limit height of placeholder variable buttons list 2025-02-04 21:26:19 +01:00
JannisX11
03d640c569 Fix per group texture not being saved in custom formats 2025-02-02 00:16:09 +01:00
JannisX11
7953f13112 Fix #2661 dragging multiple groups in outliner can causes recursive structure 2025-02-01 14:52:20 +01:00
JannisX11
d207e00cae Add V3_set support vor three vectors 2025-01-31 21:41:28 +01:00
JannisX11
b9b3a1afa3 Fix material instances in face properties editor not applying to all cubes 2025-01-30 20:32:01 +01:00
JannisX11
65bf903fef Make minimum reference image size scale with zoom level 2025-01-30 20:11:19 +01:00
JannisX11
a26bf1c17f Add creaking skin preset 2025-01-30 01:07:07 +01:00
JannisX11
d766cd1678 Fix issue where undoing a selection of a deleted element would create invalid state
Make tool config API match type
2025-01-30 01:06:48 +01:00
JannisX11
368efc7c82 Update Readme 2025-01-21 20:30:27 +01:00
JannisX11
774ef189e1 Fix missing certificate identifier 2025-01-20 18:59:04 +01:00
JannisX11
0b99ed8787 v4.12.2 [ci-build] 2025-01-20 18:48:34 +01:00
JannisX11
5e51f95352 Update languages 2025-01-20 18:27:16 +01:00
JannisX11
75d5c59a9a Mirror modeling fix 2025-01-20 18:20:47 +01:00
JannisX11
8f0d81c5a3 Bluesky link on start screen
Remove console logs
2025-01-20 17:53:10 +01:00
JannisX11
213fd7fa40 Merge branch 'patch' 2025-01-20 12:57:11 +01:00
JannisX11
4c63e657ae Fix issues with retargeting animations
Fix animation undo issues
2025-01-20 12:56:50 +01:00
JannisX11
fac8535b21
Merge pull request #2646 from Nestorboy/fix-java-brush-matrix
Fixed Java brush matrix
2025-01-20 12:19:49 +01:00
JannisX11
545b052dee Improve molang handling and export 2025-01-20 11:53:27 +01:00
JannisX11
09bbf45c5f Revamp how undo tracks selections in regular edits 2025-01-19 17:50:40 +01:00
JannisX11
a11651b3ab Fix move tool not working with multi selected groups in some cases 2025-01-19 17:33:25 +01:00
JannisX11
f438cbb816 Fix select-all not multi-selecting root groups 2025-01-19 17:32:48 +01:00
JannisX11
2a5bd7cf07 Fix e-16 numbers in molang strings 2025-01-18 21:34:07 +01:00
Nestorboy
ee80888e71 Fix java block/item brush matrix
Since we're applying the brush matrix directly, we need to factor in the parent matrices too, since the brush is parented to the scene. By using the parent matrix instead, we make it account for all translations, rotations and scaling.
2025-01-17 01:52:56 +01:00
Nestorboy
97f6382e8a Revert "Fix brush outline offset in java block/item models"
This reverts commit 3039c281d22f0539afe0c1084f33a72a8a0ee847.
2025-01-17 01:47:26 +01:00
JannisX11
89bea015b1 Fix rounding errors being imported into molang fields 2025-01-16 23:29:25 +01:00
JannisX11
f1d3243f0f v4.12.1 [ci-build] 2025-01-16 16:01:59 +01:00
JannisX11
3039c281d2 Fix brush outline offset in java block/item models 2025-01-16 14:30:48 +01:00
JannisX11
54838b65b1 Turned gamepad controls off by default 2025-01-16 14:27:32 +01:00
JannisX11
8208382ccd Fix referencing selected collections fails without project 2025-01-16 14:26:02 +01:00
JannisX11
fc66268c64 Fix #2641 drag+dropping unselected groups in outliner moves selection instead
Fix dragging groups and elements at the same time not working
2025-01-16 14:11:57 +01:00
JannisX11
22d3497ce3 Fix invisible texture issue by disabling bleed fix setting 2025-01-16 14:02:42 +01:00
JannisX11
7488b73f9b Add setting to disable gamepad controls 2025-01-16 13:45:06 +01:00
JannisX11
3d88d91bf0 Fix issue with importing JEM models 2025-01-16 13:33:23 +01:00
JannisX11
d9b72a218d v4.12.0 [ci-build] 2025-01-15 16:19:43 +01:00
JannisX11
d61ae83ab8 v4.12.0 Remove config key [ci-build] 2025-01-15 14:54:47 +01:00
JannisX11
885991a565 v4.12.0 [ci-build] electron-builder next 2025-01-15 14:45:00 +01:00
JannisX11
724eea36a1 v4.12.0 electron builder upgrade [ci-build] 2025-01-15 13:40:39 +01:00
JannisX11
e620783bb0 v4.12.0 notarize upgrade [ci-build] 2025-01-15 13:32:32 +01:00
JannisX11
4ffe74f86c v4.12.0 [ci-build] 2025-01-15 12:52:17 +01:00
JannisX11
39ff9b053a Selection system fixes 2025-01-15 12:50:01 +01:00
JannisX11
7b328cabbf Fix #2626 Preview scenes geometry renders pitchblack with shading disabled 2025-01-15 12:38:59 +01:00
JannisX11
8253256d09 Optimize splash screen images 2025-01-14 21:34:31 +01:00
JannisX11
5a56af019e 4.12 start screen 2025-01-14 21:31:06 +01:00
JannisX11
86b75f066a Update languages 2025-01-14 19:16:28 +01:00
JannisX11
777565eb6c Merge branch 'next' 2025-01-14 19:11:04 +01:00
JannisX11
c45cc65286 Fix issue when deleting nested multi selected groups 2025-01-14 15:11:18 +01:00
JannisX11
2627c9a86c 4.12 update screen 2025-01-14 14:39:43 +01:00
JannisX11
83d173e01f Fix skin poses not loading 2025-01-11 22:10:09 +01:00
JannisX11
bf148732e3 v4.12.0-beta.3 2025-01-11 21:42:54 +01:00
JannisX11
e4457ba114 Fix range selecting elements in outliner not working 2025-01-11 14:10:05 +01:00
JannisX11
47c662fb68 Upgrade electron to fix context menu issue on macos 2025-01-11 14:09:40 +01:00
JannisX11
7d1600be60 Fix beta page netlify logo 2025-01-11 14:00:33 +01:00
JannisX11
32d7f3597c Fix JPM exporter issues
Fix Group Elements not working with group multi selection
2025-01-11 13:51:42 +01:00
JannisX11
e049f2cf9c Fix #2631 Magic wand and color selection changes are not saved 2025-01-10 22:22:02 +01:00
JannisX11
72be1f3ffb Fix #2628 keyframe shared actions apply to animation instead 2025-01-08 00:15:38 +01:00
JannisX11
915c15da9d FIx #2627 Cannot select UV faces of a cube with Per-Face UV mode in viewport 2025-01-08 00:09:36 +01:00
JannisX11
787cdd671e Fix #2629 undoing group duplication creates broken objects 2025-01-07 23:49:51 +01:00
JannisX11
5cbccc98f3
Merge pull request #2625 from Nestorboy/fix-brush-offset
Fixed brush outline in rotated group
2025-01-07 23:42:40 +01:00
JannisX11
f437b04a24 Fix PBR maps not unapplying when setting uniform value
UV drag onStart event
2025-01-06 19:32:31 +01:00
JannisX11
a74c79ac28 Make all panels togglable
Rearrange View menu to make Panels menu more accessible
2025-01-06 19:31:49 +01:00
JannisX11
f0f06041d7 Add selection tolerance setting 2025-01-05 20:21:24 +01:00
JannisX11
cd81dc8bc2 Fix Move Texture with UV issue
Fix box UV template generator issue
Fix box UV mirror icon error
2025-01-05 20:15:16 +01:00
JannisX11
3c674e6cfa Fix #2623 Paint Bucket broken in 3D view with an active selection area 2025-01-05 18:18:40 +01:00
JannisX11
94ac808090 Fix group multi selection issues 2025-01-05 16:50:34 +01:00
JannisX11
68dbf7585d Move mesh tools to new menu 2025-01-05 16:36:44 +01:00
JannisX11
697b2b43be Fix collections not getting exported 2025-01-04 23:44:15 +01:00
JannisX11
078d4910fb Enable collections in animate mode
Fix collection multi selection
Fix group+element multi selection issue
2025-01-04 23:39:32 +01:00
JannisX11
dd9cd1798e Delete modifier to keep edges or vertices 2025-01-04 15:50:59 +01:00
JannisX11
afad90cf85 Make proportional editing option always visible 2025-01-04 15:35:53 +01:00
Nestorboy
af39d3ba49 Applied brush world z offset later
• Fixed the brush outline offset when working with rotated elements in rotated groups.
2025-01-03 21:48:33 +01:00
JannisX11
c1d35e4dd6 Add num slider form type
Change some amend edit sliders back to num sliders
2025-01-02 23:00:24 +01:00
JannisX11
5ca1cd86c1 Add outliner toggle support for material and other icons
Fix console error when hovering over cubes while mesh selected with knife tool
2025-01-01 23:42:52 +01:00
JannisX11
ee0818495d v4.12.0-beta.2 [ci-build] 2024-12-31 14:47:47 +01:00
JannisX11
cd7a7e55c0 Goat horn tooting reference
Closes #2248
2024-12-31 14:44:51 +01:00
JannisX11
6896b3571d Fix animation controller vue updating issue 2024-12-31 00:30:52 +01:00
JannisX11
bbbfecb28a Fix animation controller issues 2024-12-30 23:37:36 +01:00
JannisX11
929c6df161 Add gamepad navigation 2024-12-30 22:48:20 +01:00
JannisX11
3156382ae0 Fix X-ray outlines not working on meshes 2024-12-30 22:03:31 +01:00
JannisX11
edd3e92c74 JPM update refactor 2024-12-30 19:02:16 +01:00
JannisX11
85f0db0cb7 Group multi selection fixes 2024-12-30 18:52:27 +01:00
JannisX11
10ba7d995b Merge branch 'next' of https://github.com/JannisX11/blockbench into next 2024-12-30 17:53:44 +01:00
JannisX11
c756e75c33 Optional modifiers: Add inverted option for all options 2024-12-30 17:52:24 +01:00
JannisX11
946d7f4c64 Center on Selection: Optional zoom modifier
Closes #1447
2024-12-30 00:39:10 +01:00
Jannis
ce01e8bde4 Fix #2603 cannot select custom macOS app to edit images externally 2024-12-29 19:04:44 +01:00
JannisX11
1afe9f4130 Merge branch 'next' of https://github.com/JannisX11/blockbench into next 2024-12-29 15:14:42 +01:00
JannisX11
1867b79aec Refactor undo system 2024-12-29 15:14:11 +01:00
JannisX11
bcfbee2aac Save mode in undo 2024-12-29 15:09:52 +01:00
JannisX11
2a3f817b88 Finish undo selections 2024-12-29 15:04:17 +01:00
JannisX11
a3420e9309 Selection undo improvements 2024-12-28 22:15:12 +01:00
JannisX11
36871858da Merge branch 'next' into undo-selections 2024-12-28 13:42:49 +01:00
JannisX11
ead7caa716
Merge pull request #2599 from jasonjgardner/fix/pbr-reflections
Fix PBR Reflections
2024-12-28 01:15:47 +01:00
JannisX11
4792e3725c Fix reflections not updating when loading cubemap first time
Remove reduntant scene environment code
2024-12-28 01:14:24 +01:00
JannisX11
b4a9be49fb Fix lasso selection overflow 2024-12-28 00:28:35 +01:00
JannisX11
0c94c659f8 Lasso selection tool 2024-12-27 22:20:05 +01:00
JannisX11
ac2b38ff51 Fix #2605 Blockbench closes after using enter key with extrude tool 2024-12-27 18:47:03 +01:00
JannisX11
42d0aec873 Finish UV optional mirror modeling 2024-12-27 14:21:01 +01:00
JannisX11
f6070dd7bd Option in template generator to disable UV mirroring (#2218) 2024-12-23 15:00:37 +01:00
JannisX11
c6f6179cef Mirror modeling option to not mirror UV
Closes #2218
2024-12-23 14:47:39 +01:00
JannisX11
8c1c7b6ce9 Merge branch 'next' into uv-optional-mirror-modeling 2024-12-23 14:33:33 +01:00
Jason Gardner
85f4eab039 chore: Fix comment typos 2024-12-23 06:50:56 -06:00
Jason Gardner
b881106fb6 Fix MER processing
Updated MER processing logic to:
- Use green channel as a mask instead of value
- Add roughness multiplier when MER is present
2024-12-23 06:35:41 -06:00
Jason Gardner
bc2d642246 Fix normal scale
Corrected normal scale once more to match DirectX style.
2024-12-23 05:54:26 -06:00
JannisX11
90f210c1c2 Fix #2592 Fit to frame property in bedrock display settings is not supported
Bedrock display settings now only export modified slots
2024-12-23 00:18:09 +01:00
Jason Gardner
ca808cd02d chore: Remove old lines 2024-12-22 14:15:02 -06:00
Jason Gardner
180a691bc5 envMap requires active preview scene to load 2024-12-22 14:13:53 -06:00
Jason Gardner
ba15f2e251 Fix: Do not modify Y normal scale 2024-12-22 13:17:24 -06:00
Jason Gardner
201bfd0a7d Fix PBR cubemap appearance in reflections. 2024-12-22 13:02:15 -06:00
JannisX11
3e37689c16 Fix #2593 bedrock block GUI display preset incorrect 2024-12-22 12:43:06 +01:00
JannisX11
e571275c68 Fix #2594 add support for "." and "-" in bedrock bone names
Add format property node_name_regex
2024-12-22 12:37:48 +01:00
JannisX11
f1fb415879 Fix #2590 animation molang properties are stored as numbers 2024-12-22 11:39:01 +01:00
JannisX11
b317dca17b
Merge pull request #2416 from lynrayy/master
Add 'Overlay' blend mode for brush and layers
2024-12-22 00:42:45 +01:00
JannisX11
42718c184b UV navigator now visible when scrolling all the way to the left 2024-12-21 19:48:13 +01:00
JannisX11
0db5881da9 Option to get alt tri normal for face 2024-12-21 18:59:41 +01:00
JannisX11
0602e600f5
Merge pull request #2595 from Nestorboy/fix-3d-brush-group 2024-12-21 00:37:46 +01:00
JannisX11
e027c9066a Fix group multi selection issues 2024-12-20 23:44:31 +01:00
Nestorboy
d16319426e Fixed brush matrix when using groups with a rotation and translation 2024-12-20 21:08:31 +01:00
JannisX11
1e51e3f0c2 Keep bones in timeline when switching animation
Closes #1480
2024-12-20 16:06:39 +01:00
JannisX11
0ce96f7c5b Fix bone selection issue in animation mode 2024-12-20 15:35:19 +01:00
JannisX11
6ab6bd9800 Fix image format Ctrl+S shortcut functionality 2024-12-20 15:34:38 +01:00
JannisX11
5e3f819a62 Move materials to static properties
Fix collections panel visible in 2D editor
Fix generate PBR map not working correctly when no material exists
2024-12-20 14:58:06 +01:00
JannisX11
da9e7a0227 Fix group multi selection issues 2024-12-20 14:40:14 +01:00
JannisX11
88a1dbafe2 Fix plugin loader issue
Fix multi select group API issue
2024-12-20 12:47:35 +01:00
JannisX11
3ed74ef095 Fix not being able to move elements 2024-12-19 19:11:51 +01:00
JannisX11
aad6434fa4 Disable CI cache 2024-12-19 18:00:02 +01:00
JannisX11
c695e26782 WIP selection undo system 2024-12-07 23:21:52 +01:00
JannisX11
7deb76ab43 Remove bluesky PSA 2024-11-30 00:10:29 +01:00
JannisX11
9cc89be4de Add Bluesky PSA 2024-11-20 22:38:42 +01:00
JannisX11
5ce93c2104 WIP optional UV in mirror modeling 2024-08-19 20:54:52 +02:00
Lynrayy
e108675736 Add 'Overlay' blend mode for brush and layers 2024-07-10 00:05:38 +03:00
103 changed files with 8847 additions and 5567 deletions

View File

@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Build
@ -29,10 +29,10 @@ jobs:
npm install
npm run prepublish
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
uses: actions/deploy-pages@v4

View File

@ -23,10 +23,6 @@ jobs:
- sudo apt-get install rpm
- electron-builder --publish=onTagOrDraft
cache:
directories:
- node_modules
install:
- npm install

View File

@ -1,9 +1,9 @@
# Blockbench
Blockbench is a free, modern model editor for low-poly and boxy models with pixel art textures.
Blockbench is a free and open source model editor for low-poly models with pixel art textures.
Models can be exported into standardized formats, to be shared, rendered, 3D-printed, or used in game engines. There are also multiple dedicated formats for Minecraft Java and Bedrock Edition with format-specific features.
Blockbench features a modern and intuitive UI, plugin support and innovative features. It is the industry standard for creating custom 3D models for the Minecraft Marketplace.
Blockbench features a modern and beginner friendly interface, but also offers lots of customization and advanced features for experienced 3D artists. Plugins can extend the functionality of the program even further.
Website and download: [blockbench.net](https://www.blockbench.net)
@ -27,6 +27,8 @@ To launch Blockbench from source, you can clone the repository, navigate to the
* Install [NodeJS](https://nodejs.org/en/).
* Then install all dependencies via
`npm install`
* Bundle the code via
`npm run bundle`
* Finally, launch Blockbench using
`npm run dev`
@ -34,7 +36,7 @@ To launch Blockbench from source, you can clone the repository, navigate to the
## Plugins
Blockbench supports Javascript-based plugins. Learn more about creating plugins on [https://www.blockbench.net/wiki/api/index](https://www.blockbench.net/wiki/api/index).
Blockbench supports Javascript-based plugins. Learn more about creating plugins on [https://www.blockbench.net/wiki/docs/plugin](https://www.blockbench.net/wiki/docs/plugin).

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="147" height="40">
<defs>
<radialGradient id="a" cy="0%" r="100.11%" fx="50%" fy="0%" gradientTransform="matrix(0 .9989 -1.152 0 .5 -.5)">
<stop offset="0%" stop-color="#20C6B7"/>
<stop offset="100%" stop-color="#4D9ABF"/>
</radialGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<path fill="#FFF" d="M53.37 12.978l.123 2.198c1.403-1.7 3.245-2.55 5.525-2.55 3.951 0 5.962 2.268 6.032 6.804v12.568H60.79V19.676c0-1.207-.26-2.1-.78-2.681-.52-.58-1.371-.87-2.552-.87-1.719 0-3 .78-3.84 2.338v13.535h-4.262v-19.02h4.016zM77.748 32.35c-2.7 0-4.89-.852-6.567-2.557-1.678-1.705-2.517-3.976-2.517-6.812v-.527c0-1.898.365-3.595 1.096-5.089.73-1.494 1.757-2.657 3.078-3.49 1.321-.831 2.794-1.247 4.42-1.247 2.583 0 4.58.826 5.988 2.478 1.41 1.653 2.114 3.99 2.114 7.014v1.723h-12.4c.13 1.57.652 2.812 1.57 3.726.918.914 2.073 1.371 3.464 1.371 1.952 0 3.542-.79 4.77-2.373l2.297 2.198c-.76 1.136-1.774 2.018-3.042 2.645-1.269.627-2.692.94-4.27.94zm-.508-16.294c-1.17 0-2.113.41-2.832 1.23-.72.82-1.178 1.963-1.377 3.428h8.12v-.317c-.094-1.43-.474-2.51-1.14-3.243-.667-.732-1.59-1.098-2.771-1.098zm16.765-7.7v4.623h3.35v3.164h-3.35V26.76c0 .726.144 1.25.43 1.573.286.322.798.483 1.535.483a6.55 6.55 0 0 0 1.49-.176v3.305c-.97.27-1.905.404-2.806.404-3.273 0-4.91-1.81-4.91-5.431V16.142H86.62v-3.164h3.122V8.355h4.261zm11.137 23.643h-4.262v-27h4.262v27zm9.172 0h-4.262v-19.02h4.262v19.02zm-4.525-23.96c0-.655.207-1.2.622-1.634.416-.433 1.009-.65 1.78-.65.772 0 1.368.217 1.79.65.42.434.63.979.63 1.635 0 .644-.21 1.18-.63 1.608-.422.428-1.018.642-1.79.642-.771 0-1.364-.214-1.78-.642-.415-.427-.622-.964-.622-1.608zm10.663 23.96V16.142h-2.894v-3.164h2.894v-1.74c0-2.11.584-3.738 1.753-4.887 1.17-1.148 2.806-1.722 4.91-1.722.749 0 1.544.105 2.386.316l-.105 3.34a8.375 8.375 0 0 0-1.631-.14c-2.035 0-3.052 1.048-3.052 3.146v1.687h3.858v3.164h-3.858v15.856h-4.261zm17.87-6.117l3.858-12.903h4.542l-7.54 21.903c-1.158 3.199-3.122 4.799-5.893 4.799-.62 0-1.304-.106-2.052-.317v-3.305l.807.053c1.075 0 1.885-.196 2.429-.589.543-.392.973-1.051 1.289-1.977l.613-1.635-6.664-18.932h4.595l4.016 12.903z"/>
<path fill="url(#a)" fill-rule="nonzero" d="M28.589 14.135l-.014-.006c-.008-.003-.016-.006-.023-.013a.11.11 0 0 1-.028-.093l.773-4.726 3.625 3.626-3.77 1.604a.083.083 0 0 1-.033.006h-.015c-.005-.003-.01-.007-.02-.017a1.716 1.716 0 0 0-.495-.381zm5.258-.288l3.876 3.876c.805.806 1.208 1.208 1.355 1.674.022.069.04.138.054.209l-9.263-3.923a.728.728 0 0 0-.015-.006c-.037-.015-.08-.032-.08-.07 0-.038.044-.056.081-.071l.012-.005 3.98-1.684zm5.127 7.003c-.2.376-.59.766-1.25 1.427l-4.37 4.369-5.652-1.177-.03-.006c-.05-.008-.103-.017-.103-.062a1.706 1.706 0 0 0-.655-1.193c-.023-.023-.017-.059-.01-.092 0-.005 0-.01.002-.014l1.063-6.526.004-.022c.006-.05.015-.108.06-.108a1.73 1.73 0 0 0 1.16-.665c.009-.01.015-.021.027-.027.032-.015.07 0 .103.014l9.65 4.082zm-6.625 6.801l-7.186 7.186 1.23-7.56.002-.01c.001-.01.003-.02.006-.029.01-.024.036-.034.061-.044l.012-.005a1.85 1.85 0 0 0 .695-.517c.024-.028.053-.055.09-.06a.09.09 0 0 1 .029 0l5.06 1.04zm-8.707 8.707l-.81.81-8.955-12.942a.424.424 0 0 0-.01-.014c-.014-.019-.029-.038-.026-.06 0-.016.011-.03.022-.042l.01-.013c.027-.04.05-.08.075-.123l.02-.035.003-.003c.014-.024.027-.047.051-.06.021-.01.05-.006.073-.001l9.921 2.046a.164.164 0 0 1 .076.033c.013.013.016.027.019.043a1.757 1.757 0 0 0 1.028 1.175c.028.014.016.045.003.078a.238.238 0 0 0-.015.045c-.125.76-1.197 7.298-1.485 9.063zm-1.692 1.691c-.597.591-.949.904-1.347 1.03a2 2 0 0 1-1.206 0c-.466-.148-.869-.55-1.674-1.356L8.73 28.73l2.349-3.643c.011-.018.022-.034.04-.047.025-.018.061-.01.091 0a2.434 2.434 0 0 0 1.638-.083c.027-.01.054-.017.075.002a.19.19 0 0 1 .028.032L21.95 38.05zM7.863 27.863L5.8 25.8l4.074-1.738a.084.084 0 0 1 .033-.007c.034 0 .054.034.072.065a2.91 2.91 0 0 0 .13.184l.013.016c.012.017.004.034-.008.05l-2.25 3.493zm-2.976-2.976l-2.61-2.61c-.444-.444-.766-.766-.99-1.043l7.936 1.646a.84.84 0 0 0 .03.005c.049.008.103.017.103.063 0 .05-.059.073-.109.092l-.023.01-4.337 1.837zM.831 19.892a2 2 0 0 1 .09-.495c.148-.466.55-.868 1.356-1.674l3.34-3.34a2175.525 2175.525 0 0 0 4.626 6.687c.027.036.057.076.026.106-.146.161-.292.337-.395.528a.16.16 0 0 1-.05.062c-.013.008-.027.005-.042.002H9.78L.831 19.891zm5.68-6.403L11 8.998c.423.185 1.96.834 3.333 1.414 1.04.44 1.988.84 2.286.97.03.012.057.024.07.054.008.018.004.041 0 .06a2.003 2.003 0 0 0 .523 1.828c.03.03 0 .073-.026.11l-.014.021-4.56 7.063c-.012.02-.023.037-.043.05-.024.015-.058.008-.086.001a2.274 2.274 0 0 0-.543-.074c-.164 0-.342.03-.522.063h-.001c-.02.003-.038.007-.054-.005a.21.21 0 0 1-.045-.051l-4.808-7.013zm5.398-5.398l5.814-5.814c.805-.805 1.208-1.208 1.674-1.355a2 2 0 0 1 1.206 0c.466.147.869.55 1.674 1.355l1.26 1.26-4.135 6.404a.155.155 0 0 1-.041.048c-.025.017-.06.01-.09 0a2.097 2.097 0 0 0-1.92.37c-.027.028-.067.012-.101-.003-.54-.235-4.74-2.01-5.341-2.265zm12.506-3.676l3.818 3.818-.92 5.698v.015a.135.135 0 0 1-.008.038c-.01.02-.03.024-.05.03a1.83 1.83 0 0 0-.548.273.154.154 0 0 0-.02.017c-.011.012-.022.023-.04.025a.114.114 0 0 1-.043-.007l-5.818-2.472-.011-.005c-.037-.015-.081-.033-.081-.071a2.198 2.198 0 0 0-.31-.915c-.028-.046-.059-.094-.035-.141l4.066-6.303zm-3.932 8.606l5.454 2.31c.03.014.063.027.076.058a.106.106 0 0 1 0 .057c-.016.08-.03.171-.03.263v.153c0 .038-.039.054-.075.069l-.011.004c-.864.369-12.13 5.173-12.147 5.173-.017 0-.035 0-.052-.017-.03-.03 0-.072.027-.11a.76.76 0 0 0 .014-.02l4.482-6.94.008-.012c.026-.042.056-.089.104-.089l.045.007c.102.014.192.027.283.027.68 0 1.31-.331 1.69-.897a.16.16 0 0 1 .034-.04c.027-.02.067-.01.098.004zm-6.246 9.185l12.28-5.237s.018 0 .035.017c.067.067.124.112.179.154l.027.017c.025.014.05.03.052.056 0 .01 0 .016-.002.025L25.756 23.7l-.004.026c-.007.05-.014.107-.061.107a1.729 1.729 0 0 0-1.373.847l-.005.008c-.014.023-.027.045-.05.057-.021.01-.048.006-.07.001l-9.793-2.02c-.01-.002-.152-.519-.163-.52z" transform="translate(-.702)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 226 KiB

BIN
assets/splash_art/4.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
content/collections.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
content/lasso.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@ -1,29 +1,38 @@
{
"new_version": {
"color": "var(--color-bright_ui)",
"text_color": "var(--color-bright_ui_text)",
"color": "var(--color-dark)",
"layout": "vertical",
"insert_after": "splash_screen",
"text": [
{"text": "Welcome to Blockbench 4.11", "type": "h3"},
{"text": "The Texture Group Update!", "type": "h1"},
{"text": "Check out the [full changelog](https://github.com/JannisX11/blockbench/releases/tag/v4.11.0)!"}
{"text": "Welcome to Blockbench 4.12", "type": "h3"},
{"text": "The Collection & Selection Update!", "type": "h1"},
{"text": "Check out the [full changelog](https://github.com/JannisX11/blockbench/releases/tag/v4.12.0)!"}
],
"features": [
{
"image": "https://web.blockbench.net/content/texture_groups.png",
"title": "Texture Groups",
"text": "Organize your textures with groups!"
"image": "https://web.blockbench.net/content/pbr.png",
"title": "PBR Editing + Preview",
"text": "Create, edit, and view physically based materials"
},
{
"image": "https://web.blockbench.net/content/tiled_view.png",
"title": "Onion Skin and Tiled View",
"text": "Use onion skinning on animated textures or create tiled textures."
"image": "https://web.blockbench.net/content/collections.png",
"title": "Collections",
"text": "A new way to organize your model!"
},
{
"image": "https://web.blockbench.net/content/cube_knife.png",
"title": "Knife Tool for Cubes",
"text": "Use the knife tool to cut cubes and speed up your workflow!"
"image": "https://web.blockbench.net/content/lasso.png",
"title": "Lasso Selection Tool",
"text": "Select free-form shapes in the 2D Editor"
},
{
"image": "https://web.blockbench.net/content/group_multi_select.png",
"title": "Group Multi Selection",
"text": "You can finally select multiple groups at once!"
},
{
"image": "https://web.blockbench.net/content/rotation_snap.png",
"title": "Rotation Snap",
"text": "It's vertex snap, but for rotations!"
}
]
}

BIN
content/pbr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

BIN
content/rotation_snap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -387,6 +387,9 @@
flex-grow: 1;
padding: 3px 5px;
}
.form_bar > .nslide_tool {
flex-grow: 1;
}
.dialog_form_description {
margin-left: auto;
padding-top: 8px;
@ -1982,7 +1985,7 @@
cursor: pointer;
border: 2px solid transparent;
display: flex;
justify-content: space-between;
gap: 5px;
}
#edit_history_list ul li.current {
border-color: var(--color-accent);
@ -2009,6 +2012,9 @@
#edit_history_list .edit_history_time {
color: var(--color-subtle_text);
}
#edit_history_list > ul > li label {
margin-right: auto;
}
#edit_history_list ul li.selected .edit_history_time {
color: inherit;
}

View File

@ -1218,6 +1218,10 @@
}
/* Placeholders */
ul#placeholder_buttons {
max-height: 32%;
overflow: auto;
}
#placeholder_buttons li {
padding: 0px 8px;
height: 30px;
@ -2031,6 +2035,7 @@ span.controller_state_section_info {
.controller_state_connection_wrapper_top,
.controller_state_connection_wrapper_bottom {
height: calc(20px + var(--max-layer) * 10px);
min-height: calc(20px + var(--max-layer) * 10px);
position: relative;
}
.controller_state_connection {
@ -2376,6 +2381,33 @@ span.controller_state_section_info {
stroke-dashoffset: -10px;
}
}
#texture_selection_polygon {
position: absolute;
pointer-events: none;
width: calc(100% + 2px);
height: calc(100% + 2px);
top: -1px;
left: -1px;
object-fit: cover;
object-position: 0 0;
}
#texture_selection_polygon path {
fill: none;
stroke-width: 2px;
stroke: var(--color-light);
stroke-dasharray: 5px 3px;
stroke-dashoffset: 0;
animation: selection-outline-shift 700ms linear infinite;
animation-timing-function: steps(3, end);
}
#texture_selection_polygon circle {
fill: var(--color-ui);
stroke-width: 1;
stroke: var(--color-border);
}
#texture_selection_polygon circle.closed {
fill: var(--color-accent);
}
.face_properties_toggle {
width: 32px;

View File

@ -221,6 +221,7 @@
padding-right: 15px;
padding-left: 100px;
background: linear-gradient(90deg, rgba(3,86,112,0) 0%, rgba(0,10,22,0.63) 34%, rgba(0,9,20,0.72) 45%);
color: #d5d5d5;
position: absolute;
}
#start_screen div.start_screen_right {
@ -240,15 +241,17 @@
#start_screen i.start_screen_close_button:not(:hover) {
opacity: 0.8;
}
#start_screen section.vertical .start_screen_right {
box-shadow: 0 0 40px rgba(0, 0, 0, 0.4);
}
#start_screen section.vertical.bright_ui .start_screen_right {
box-shadow: 0 0 14px #00103030;
}
#start_screen .start_screen_features {
display: flex;
flex-wrap: wrap;
flex-wrap: wrap-reverse;
box-sizing: border-box;
padding: 12px;
background: #00004006;
}
#start_screen .start_screen_features > li {
width: 30%;
@ -260,6 +263,10 @@
margin: 7px;
padding: 7px;
}
#start_screen .start_screen_features > li:nth-child(1),
#start_screen .start_screen_features > li:nth-child(2) {
order: 1;
}
#start_screen .start_screen_features > li > * {
max-width: 100%;
font-weight: 300;
@ -268,6 +275,7 @@
}
#start_screen .start_screen_features > li > img {
border-radius: 5px;
-webkit-user-drag: none;
}
#start_screen .start_screen_features > li > h3 {
font-size: 1.4em;

View File

@ -1228,7 +1228,7 @@
width: fit-content;
z-index: 3;
}
#amend_edit_menu > form {
#amend_edit_menu > div.form {
background-color: var(--color-ui);
padding: 2px 10px;
}

View File

@ -98,6 +98,7 @@
<script src="js/util/array_util.js"></script>
<script src="js/util/event_system.js"></script>
<script src="js/util/property.js"></script>
<script src="js/util/json.js"></script>
<script src="js/interface/menu.js"></script>
<script src="js/interface/actions.js"></script>
<script src="js/interface/themes.js"></script>

View File

@ -133,8 +133,8 @@ class Animation extends AnimationItem {
copy.animators = {}
for (var uuid in this.animators) {
let ba = this.animators[uuid]
var kfs = ba.keyframes
if ((kfs && kfs.length) || ba.rotation_global) {
let kfs = ba.keyframes
if ((kfs && kfs.length) || ba.rotation_global || !save) {
let ba_copy = copy.animators[uuid] = {
name: ba.name,
type: ba.type,
@ -160,10 +160,10 @@ class Animation extends AnimationItem {
if (this.length) ani_tag.animation_length = Math.roundTo(this.length, 4);
if (this.override) ani_tag.override_previous_animation = true;
if (this.anim_time_update) ani_tag.anim_time_update = this.anim_time_update.replace(/\n/g, '');
if (this.blend_weight) ani_tag.blend_weight = this.blend_weight.replace(/\n/g, '');
if (this.start_delay) ani_tag.start_delay = this.start_delay.replace(/\n/g, '');
if (this.loop_delay && ani_tag.loop) ani_tag.loop_delay = this.loop_delay.replace(/\n/g, '');
if (this.anim_time_update) ani_tag.anim_time_update = exportMolang(this.anim_time_update);
if (this.blend_weight) ani_tag.blend_weight = exportMolang(this.blend_weight);
if (this.start_delay) ani_tag.start_delay = exportMolang(this.start_delay);
if (this.loop_delay && ani_tag.loop) ani_tag.loop_delay = exportMolang(this.loop_delay);
ani_tag.bones = {};
for (var uuid in this.animators) {
@ -433,14 +433,19 @@ class Animation extends AnimationItem {
return this;
}
select() {
var scope = this;
Prop.active_panel = 'animations';
let previous_animation = Animation.selected;
if (this == Animation.selected) return;
var selected_bone = Group.first_selected;
AnimationItem.all.forEach((a) => {
a.selected = false;
if (a.playing == true) a.playing = false;
})
let animator_keys = previous_animation && Object.keys(previous_animation.animators);
let selected_animator_key;
let timeline_animator_keys = previous_animation && Timeline.animators.map(a => {
let key = animator_keys.find(key => previous_animation.animators[key] == a);
if (a.selected) selected_animator_key = key;
return key;
});
Timeline.clear();
Timeline.vue._data.markers = this.markers;
Timeline.vue._data.animation_length = this.length;
@ -453,15 +458,21 @@ class Animation extends AnimationItem {
BarItems.slider_animation_length.update();
Group.all.forEach(group => {
scope.getBoneAnimator(group);
this.getBoneAnimator(group);
})
Outliner.elements.forEach(element => {
if (!element.constructor.animator) return;
scope.getBoneAnimator(element);
this.getBoneAnimator(element);
})
if (selected_bone) {
selected_bone.select();
if (timeline_animator_keys) {
timeline_animator_keys.forEachReverse(key => {
let animator = this.animators[key];
if (animator) {
animator.addToTimeline();
if (selected_animator_key == key) animator.select(false);
}
});
}
if (Modes.animate) {
Animator.preview();
@ -470,6 +481,12 @@ class Animation extends AnimationItem {
Blockbench.dispatchEvent('select_animation', {animation: this})
return this;
}
clickSelect() {
Undo.initSelection();
Prop.active_panel = 'animations';
this.select();
Undo.finishSelection('Select animation')
}
setLength(len = this.length) {
this.length = 0;
this.length = limitNumber(len, this.getMaxLength(), 1e4);
@ -1752,12 +1769,17 @@ BARS.defineActions(function() {
temp_animators[target_uuid] = new animator.constructor(target_uuid, animation);
copyAnimator(temp_animators[target_uuid], target_animator);
}
let tempsave_current_animator = !temp_animators[animator.uuid];
if (tempsave_current_animator) {
temp_animators[animator.uuid] = new animator.constructor(animator.uuid, animation);
copyAnimator(temp_animators[animator.uuid], animator);
}
copyAnimator(target_animator, temp_animators[animator.uuid] ?? animator);
// Reset animator
if (!temp_animators[animator.uuid]) {
temp_animators[animator.uuid] = new animator.constructor(animator.uuid, animation);
copyAnimator(temp_animators[animator.uuid], animator);
if (tempsave_current_animator) {
resetAnimator(animator)
}
}
@ -2110,8 +2132,8 @@ Interface.definePanels(function() {
v-bind:class="{ selected: animation.selected }"
v-bind:anim_id="animation.uuid"
class="animation"
v-on:click.stop="animation.select()"
v-on:dblclick.stop="animation.propertiesDialog()"
@click.stop="animation.clickSelect()"
@dblclick.stop="animation.propertiesDialog()"
:key="animation.uuid"
@contextmenu.prevent.stop="animation.showContextMenu($event)"
>

View File

@ -2,6 +2,8 @@ class AnimationControllerState {
constructor(controller, data = 0) {
this.controller = controller;
this.uuid = guid();
this.transitions = [];
this.animations = [];
for (let key in AnimationControllerState.properties) {
AnimationControllerState.properties[key].reset(this);
@ -39,60 +41,63 @@ class AnimationControllerState {
}
}
if (data.animations instanceof Array) {
let previous_animations = this.animations.slice();
this.animations.empty();
data.animations.forEach(a => {
let animation;
let animation = previous_animations.find(a1 => a1.uuid == a.uuid) ?? {
uuid: guid(),
key: '',
animation: '',
blend_value: ''
};
if (typeof a == 'object' && typeof a.uuid == 'string' && a.uuid.length == 36) {
// Internal
animation = {
uuid: a.uuid || guid(),
key: a.key || '',
animation: a.animation || '',// UUID
blend_value: a.blend_value || ''
};
Object.assign(animation, a);
} else if (typeof a == 'object' || typeof a == 'string') {
// Bedrock
let key = typeof a == 'object' ? Object.keys(a)[0] : a;
let anim_match = Animation.all.find(anim => anim.getShortName() == key);
animation = {
uuid: guid(),
Object.assign(animation, {
key: key || '',
animation: anim_match ? anim_match.uuid : '',// UUID
blend_value: (typeof a == 'object' && a[key]) || ''
};
});
}
this.animations.push(animation);
})
}
if (data.transitions instanceof Array) {
let previous_transitions = this.transitions.slice();
this.transitions.empty();
data.transitions.forEach(a => {
let transition;
let transition = previous_transitions.find(t1 => t1.uuid == a.uuid) ?? {
uuid: guid(),
target: '',
condition: ''
};
this.transitions.push(transition);
if (typeof a == 'object' && typeof a.uuid == 'string' && a.uuid.length == 36) {
// Internal
transition = {
uuid: a.uuid || guid(),
target: a.target || '',
condition: a.condition || ''
};
Object.assign(transition, a);
} else if (typeof a == 'object') {
// Bedrock
let key = Object.keys(a)[0];
let state_match = this.controller.states.find(state => state !== this && state.name == key);
transition = {
uuid: guid(),
Object.assign(transition, {
target: state_match ? state_match.uuid : '',
condition: a[key] || ''
};
});
if (!state_match) {
setTimeout(() => {
// Delay to after loading controller so that all states can be found
let state_match = this.controller.states.find(state => state !== this && state.name == key);
if (state_match) transition.target = state_match.uuid;
if (state_match) {
let updated_transition = this.transitions.find(t => t.uuid == transition.uuid) ?? transitions;
updated_transition.target = state_match.uuid;
}
}, 0);
}
}
this.transitions.push(transition);
})
}
if (data.particles instanceof Array) {
@ -1040,7 +1045,6 @@ class AnimationController extends AnimationItem {
return this;
}
select() {
Prop.active_panel = 'animations';
if (this == AnimationController.selected) return;
if (Timeline.playing) Timeline.pause()
AnimationItem.all.forEach((a) => {
@ -1061,6 +1065,11 @@ class AnimationController extends AnimationItem {
}
return this;
}
clickSelect() {
Undo.initSelection();
this.select();
Undo.finishSelection('Select animation')
}
createUniqueName(arr) {
var scope = this;
var others = AnimationController.all.slice();
@ -1499,6 +1508,7 @@ Interface.definePanels(() => {
'_',
{id: 'remove', name: 'generic.remove', icon: 'clear', click() {
Undo.initEdit({animation_controller_state: state});
animation = state.animations.find(t => t.uuid == animation.uuid);
state.animations.remove(animation);
Undo.finishEdit('Remove animation from controller state');
}}
@ -1522,6 +1532,7 @@ Interface.definePanels(() => {
'_',
{id: 'remove', name: 'generic.remove', icon: 'clear', click() {
Undo.initEdit({animation_controller_state: state});
transition = state.transitions.find(t => t.uuid == transition.uuid);
state.transitions.remove(transition);
Undo.finishEdit('Remove transition from controller state');
}}
@ -2007,13 +2018,13 @@ Interface.definePanels(() => {
<div class="text_button" @click.stop="addAnimationButton(state, $event)"><i class="icon fa fa-plus"></i></div>
</div>
<ul v-if="!state.fold.animations" v-sortable="{onUpdate(event) {sortAnimation(state, event)}, animation: 160, handle: '.controller_item_drag_handle'}">
<li v-for="animation in state.animations" :key="animation.uuid" class="controller_animation">
<li v-for="(animation, i) in state.animations" :key="animation.uuid" class="controller_animation">
<div class="controller_item_drag_handle"></div>
<div class="tool" title="" @click="openAnimationMenu(state, animation, $event.target)"><i class="material-icons">movie</i></div>
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="animation.key">
<div class="tool" title="" @click="openAnimationMenu(state, state.animations[i], $event.target)"><i class="material-icons">movie</i></div>
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="state.animations[i].key">
<vue-prism-editor
class="molang_input animation_controller_text_input tab_target"
v-model="animation.blend_value"
v-model="state.animations[i].blend_value"
language="molang"
:autocomplete="autocomplete"
:placeholder="'${tl('animation_controllers.state.condition')}'"
@ -2040,24 +2051,24 @@ Interface.definePanels(() => {
</div>
</div>
<ul v-if="!state.fold.particles">
<li v-for="particle in state.particles" :key="particle.uuid" class="controller_particle" @contextmenu="openParticleMenu(state, particle, $event)">
<li v-for="(particle, i) in state.particles" :key="particle.uuid" class="controller_particle" @contextmenu="openParticleMenu(state, state.particles[i], $event)">
<div class="bar flex">
<label>${tl('data.effect')}</label>
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="particle.effect">
<div class="tool" title="${tl('timeline.select_particle_file')}" @click="changeParticleFile(state, particle)">
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="state.particles[i].effect">
<div class="tool" title="${tl('timeline.select_particle_file')}" @click="changeParticleFile(state, state.particles[i])">
<i class="material-icons">upload_file</i>
</div>
</div>
<div class="bar flex">
<label>${tl('data.locator')}</label>
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="particle.locator" list="locator_suggestion_list" @focus="updateLocatorSuggestionList()">
<input type="checkbox" v-model="particle.bind_to_actor" title="${tl('timeline.bind_to_actor')}">
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="state.particles[i].locator" list="locator_suggestion_list" @focus="updateLocatorSuggestionList()">
<input type="checkbox" v-model="state.particles[i].bind_to_actor" title="${tl('timeline.bind_to_actor')}">
</div>
<div class="bar flex">
<label>${tl('timeline.pre_effect_script')}</label>
<vue-prism-editor
class="molang_input animation_controller_text_input tab_target"
v-model="particle.script"
v-model="state.particles[i].script"
language="molang"
:autocomplete="autocomplete"
:ignoreTabKey="true"
@ -2084,11 +2095,11 @@ Interface.definePanels(() => {
</div>
</div>
<ul v-if="!state.fold.sounds">
<li v-for="sound in state.sounds" :key="sound.uuid" class="controller_sound" @contextmenu="openSoundMenu(state, sound, $event)">
<li v-for="(sound, i) in state.sounds" :key="sound.uuid" class="controller_sound" @contextmenu="openSoundMenu(state, state.sounds[i], $event)">
<div class="bar flex">
<label>${tl('data.effect')}</label>
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="sound.effect">
<div class="tool" title="${tl('timeline.select_sound_file')}" @click="changeSoundFile(state, sound)">
<input type="text" class="dark_bordered tab_target animation_controller_text_input" v-model="state.sounds[i].effect">
<div class="tool" title="${tl('timeline.select_sound_file')}" @click="changeSoundFile(state, state.sounds[i])">
<i class="material-icons">upload_file</i>
</div>
</div>
@ -2138,12 +2149,12 @@ Interface.definePanels(() => {
</div>
<template v-if="!state.fold.transitions">
<ul v-sortable="{onUpdate(event) {sortTransition(state, event)}, animation: 160, handle: '.controller_item_drag_handle'}">
<li v-for="transition in state.transitions" :key="transition.uuid" :uuid="transition.uuid" class="controller_transition">
<li v-for="(transition, i) in state.transitions" :key="transition.uuid" :uuid="transition.uuid" class="controller_transition"">
<div class="controller_item_drag_handle" :style="{'--color-marker': connections.colors[transition.uuid]}"></div>
<bb-select @click="openTransitionMenu(state, transition, $event)">{{ getStateName(transition.target) }}</bb-select>
<bb-select @click="openTransitionMenu(state, state.transitions[i], $event)">{{ getStateName(state.transitions[i].target) }}</bb-select>
<vue-prism-editor
class="molang_input animation_controller_text_input tab_target"
v-model="transition.condition"
v-model="state.transitions[i].condition"
language="molang"
:autocomplete="autocomplete"
:ignoreTabKey="true"
@ -2224,7 +2235,7 @@ Interface.definePanels(() => {
if (val != molang_edit_value) {
Undo.finishEdit('Edit animation controller molang');
} else {
Undo.cancelEdit();
Undo.cancelEdit(false);
}
}
})

View File

@ -1470,8 +1470,8 @@ Interface.definePanels(function() {
<ul id="placeholder_buttons">
<li v-for="button in buttons" :key="button.id" :class="{placeholder_slider: button.type == 'slider'}" @click="button.type == 'impulse' && changeButtonValue(button, $event)" :buttontype="button.type">
<i v-if="button.type == 'impulse'" class="material-icons">play_arrow</i>
<input v-if="button.type == 'toggle'" type="checkbox" class="tab_target" :value="button.value == 1" @change="changeButtonValue(button, $event)" :id="'placeholder_button_'+button.id">
<numeric-input v-if="button.type == 'slider'" class="dark_bordered tab_target" :step="button.step" :min="button.min" :max="button.max" v-model="button.value" @input="changeButtonValue(button, $event)" />
<input v-if="button.type == 'toggle'" type="checkbox" :value="button.value == 1" @change="changeButtonValue(button, $event)" :id="'placeholder_button_'+button.id">
<numeric-input v-if="button.type == 'slider'" :step="button.step" :min="button.min" :max="button.max" v-model="button.value" @input="changeButtonValue(button, $event)" />
<label :for="'placeholder_button_'+button.id" @mousedown="slideButton(button, $event)" @touchstart="slideButton(button, $event)">{{ button.id }}</label>
</li>
</ul>

View File

@ -94,11 +94,8 @@ class Keyframe {
data_point = this.data_points[data_point];
if (!data_point || !data_point[axis]) {
return this.transform ? 0 : '';
} else if (!isNaN(data_point[axis])) {
let num = parseFloat(data_point[axis]);
return isNaN(num) ? 0 : num;
} else {
return data_point[axis]
return exportMolang(data_point[axis])
}
}
calc(axis, data_point = 0) {
@ -113,6 +110,7 @@ class Keyframe {
}
set(axis, value, data_point = 0) {
if (data_point) data_point = Math.clamp(data_point, 0, this.data_points.length-1);
if (typeof value == 'number') value = Math.roundTo(value, 10).toString();
if (this.data_points[data_point]) {
if (this.uniform) {
this.data_points[data_point].x = value;
@ -435,13 +433,20 @@ class Keyframe {
}
Timeline.selected.safePush(this);
if (Timeline.selected.length == 1 && Timeline.selected[0].animator.selected == false) {
Timeline.selected[0].animator.select()
Timeline.selected[0].animator.select();
}
this.selected = true
this.selected = true;
TickUpdates.keyframe_selection = true;
if (this.transform) Timeline.vue.graph_editor_channel = this.channel;
return this;
}
clickSelect(event) {
Undo.initSelection({timeline: true});
this.select(event);
var select_tool = true;
Timeline.selected.forEach(kf => {
if (kf.channel != this.channel) select_tool = false;
@ -453,7 +458,7 @@ class Keyframe {
case 'scale': BarItems.resize_tool.select(); break;
}
}
return this;
Undo.finishSelection('Select keyframe')
}
callPlayhead() {
Timeline.setTime(this.time)

View File

@ -104,6 +104,7 @@ const Timeline = {
if (e.shiftKey || Pressing.overrides.shift) {
Timeline.selector.selected_before = Timeline.selected.slice();
}
Undo.initSelection({timeline: true});
},
move(e) {
var R = Timeline.selector;
@ -204,6 +205,7 @@ const Timeline = {
if (settings.canvas_unselect.value) {
Timeline.selected.empty();
updateKeyframeSelection();
Undo.finishSelection('Unselect keyframes');
}
Timeline.vue.clickGraphEditor(e);
return false;
@ -215,6 +217,7 @@ const Timeline = {
.css('width', 0)
.css('height', 0)
.hide();
Undo.finishSelection('Select keyframes');
}
},
},
@ -928,7 +931,7 @@ Interface.definePanels(() => {
let padding = 16;
let min_size = 2.4;
let unit_size = Math.clamp(max-min, min_size, 1e4);
let unit_size = Math.clamp(max-min, min_size, Timeline.graph_editor_limit);
this.graph_size = (clientHeight - 2*padding) / unit_size;
let blend = Math.clamp(1 - (max-min) / min_size, 0, 1)
this.graph_offset = clientHeight - padding + (this.graph_size * (min - unit_size/2 * blend ) );
@ -1039,6 +1042,7 @@ Interface.definePanels(() => {
selectChannel(animator, channel) {
if (this.graph_editor_channel == channel && animator.selected) return;
if (!animator.channels[channel].transform) return;
Undo.initSelection();
if (!animator.selected) animator.select();
// Select keyframe in new channel
if (animator[channel].length && Keyframe.selected.length > 0) {
@ -1053,6 +1057,7 @@ Interface.definePanels(() => {
}
}
this.graph_editor_channel = channel;
Undo.finishSelection('Select animation channel');
},
getColor(index) {
if (index == -1 || index == undefined) return;
@ -1099,6 +1104,7 @@ Interface.definePanels(() => {
}
} else if (distance > 6) {
active = true;
Undo.initSelection();
}
} else {
if (e2) e2.preventDefault();
@ -1151,6 +1157,7 @@ Interface.definePanels(() => {
if (Timeline.animators[index] == animator) return;
Timeline.animators.remove(animator);
Timeline.animators.splice(index, 0, animator);
Undo.finishSelection('Rearrange animators in timeline');
}
}
@ -1672,13 +1679,13 @@ Interface.definePanels(() => {
</div>
<div id="timeline_body" ref="timeline_body" @scroll="updateScroll($event)">
<div id="timeline_body_inner" v-bind:style="{width: (size*length + head_width)+'px'}" @contextmenu.stop="Timeline.showMenu($event)">
<li v-for="animator in animators" class="animator" :class="{selected: animator.selected, boneless: animator.constructor.name == 'BoneAnimator' && !animator.group}" :uuid="animator.uuid" v-on:click="animator.select();">
<li v-for="animator in animators" class="animator" :class="{selected: animator.selected, boneless: animator.constructor.name == 'BoneAnimator' && !animator.group}" :uuid="animator.uuid" v-on:click="animator.clickSelect();">
<div class="animator_head_bar">
<div class="channel_head" v-bind:style="{left: '0px', width: head_width+'px'}" v-on:dblclick.stop="toggleAnimator(animator)" @contextmenu.stop="animator.showContextMenu($event)">
<div class="text_button" v-on:click.stop="toggleAnimator(animator)">
<i class="icon-open-state fa" v-bind:class="{'fa-angle-right': !animator.expanded, 'fa-angle-down': animator.expanded}"></i>
</div>
<span v-on:click.stop="animator.select();" @mousedown="dragAnimator(animator, $event)" @touchstart="dragAnimator(animator, $event)">{{animator.name}}</span>
<span v-on:click.stop="animator.clickSelect();" @mousedown="dragAnimator(animator, $event)" @touchstart="dragAnimator(animator, $event)">{{animator.name}}</span>
<div class="text_button" v-on:click.stop="removeAnimator(animator)">
<i class="material-icons">remove</i>
</div>
@ -1738,7 +1745,7 @@ Interface.definePanels(() => {
class="keyframe"
v-bind:class="{[keyframe.channel]: true, selected: keyframe.selected, has_expressions: keyframe.has_expressions}"
v-bind:id="keyframe.uuid"
v-on:click.stop="keyframe.select($event)"
v-on:click.stop="keyframe.clickSelect($event)"
v-on:dblclick="keyframe.callPlayhead()"
:title="tl('timeline.'+keyframe.channel)"
@mousedown="dragKeyframes(keyframe, $event)" @touchstart="dragKeyframes(keyframe, $event)"
@ -1796,7 +1803,7 @@ Interface.definePanels(() => {
class="keyframe graph_keyframe"
v-bind:class="[keyframe.channel, keyframe.selected?'selected':'']"
v-bind:id="keyframe.uuid"
v-on:click.stop="keyframe.select($event)"
v-on:click.stop="keyframe.clickSelect($event)"
v-on:dblclick="keyframe.callPlayhead()"
:title="trimFloatNumber(keyframe.time, 2) + ' ⨉ ' + trimFloatNumber(keyframe.display_value || 0)"
@mousedown="dragKeyframes(keyframe, $event)" @touchstart="dragKeyframes(keyframe, $event)"

View File

@ -29,9 +29,18 @@ class GeneralAnimator {
})
return this;
}
addToTimeline() {
clickSelect() {
Undo.initSelection();
this.select();
Undo.finishSelection('Select animator');
}
addToTimeline(end_of_list = false) {
if (!Timeline.animators.includes(this)) {
Timeline.animators.splice(0, 0, this);
if (end_of_list == true) {
Timeline.animators.push(this);
} else {
Timeline.animators.splice(0, 0, this);
}
}
for (let channel in this.channels) {
if (!this[channel]) this[channel] = [];
@ -230,7 +239,7 @@ class BoneAnimator extends GeneralAnimator {
}
super.select();
if (this[Toolbox.selected.animation_channel] && (Timeline.selected.length == 0 || Timeline.selected[0].animator != this)) {
if (this[Toolbox.selected.animation_channel] && (Timeline.selected.length == 0 || Timeline.selected[0].animator != this) && !Blockbench.hasFlag('loading_selection_save')) {
var nearest;
this[Toolbox.selected.animation_channel].forEach(kf => {
if (Math.abs(kf.time - Timeline.time) < 0.002) {

View File

@ -85,7 +85,7 @@ const Clipbench = {
}
if (Modes.edit && p == 'preview') {
let options = [];
if (Clipbench.elements.length || Clipbench.group) {
if (Clipbench.elements.length || Clipbench.groups) {
options.push(Clipbench.types.outliner);
}
if (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length && Clipbench.vertices) {
@ -153,7 +153,7 @@ const Clipbench = {
case 'face':
UVEditor.copy(event);
if (Prop.active_panel == 'uv') {
Clipbench.group = undefined;
Clipbench.groups = undefined;
Clipbench.elements = [];
}
break;
@ -223,12 +223,12 @@ const Clipbench = {
},
setGroups(groups) {
if (!groups || !groups.length) {
Clipbench.group = undefined
Clipbench.groups = undefined
return;
}
Clipbench.groups = groups.map(g => group.getSaveCopy())
Clipbench.groups = groups.map(group => group.getSaveCopy())
if (isApp) {
clipboard.writeHTML(JSON.stringify({type: 'groups', content: Clipbench.group}))
clipboard.writeHTML(JSON.stringify({type: 'groups', content: Clipbench.groups}))
}
},
setElements(arr) {
@ -320,15 +320,15 @@ const Clipbench = {
try {
var data = JSON.parse(raw)
if (data.type === 'elements' && data.content) {
Clipbench.group = undefined;
Clipbench.groups = undefined;
Clipbench.elements = data.content;
} else if (data.type === 'group' && data.content) {
Clipbench.group = data.content;
Clipbench.groups = data.content;
Clipbench.elements = [];
}
} catch (err) {}
}
if (Clipbench.group) {
if (Clipbench.groups) {
function iterate(obj, parent) {
if (obj.children) {
let copy = new Group(obj).addTo(parent).init();
@ -350,8 +350,10 @@ const Clipbench = {
return copy;
}
}
let copy = iterate(Clipbench.group, target);
copy.select();
for (let group_template of Clipbench.groups) {
let copy = iterate(group_template, target);
copy.multiSelect();
}
} else if (Clipbench.elements && Clipbench.elements.length) {
let elements = [];

View File

@ -288,7 +288,7 @@ async function updateRecentProjectThumbnail() {
}
}
function loadDataFromModelMemory() {
let project = Project.getProjectMemory();
let project = Project && Project.getProjectMemory();
if (!project) return;
if (project.textures) {
@ -346,6 +346,7 @@ function changeImageEditor(texture, not_found) {
type: 'file',
file_type: 'Program',
extensions: app_file_extension[Blockbench.platform],
readtype: 'none',
description: 'message.image_editor.exe',
condition: result => result.editor == 'other'
}

View File

@ -9,6 +9,7 @@ const DisplayMode = {};
class DisplaySlot {
constructor(id, data) {
this.slot_id = id;
this.default()
if (data) this.extend(data)
}
@ -19,6 +20,7 @@ class DisplaySlot {
this.rotation_pivot = [0, 0, 0];
this.scale_pivot = [0, 0, 0];
this.mirror = [false, false, false]
this.fit_to_frame = false;
return this;
}
copy() {
@ -51,6 +53,32 @@ class DisplaySlot {
return build;
}
}
exportBedrock() {
let has_data = !this.rotation.allEqual(0)
|| !this.translation.allEqual(0)
|| !this.scale.allEqual(1)
|| !this.mirror.allEqual(false)
|| !this.rotation_pivot.allEqual(0)
|| !this.scale_pivot.allEqual(0);
if (!has_data) return;
let build = {
rotation: this.rotation.slice(),
translation: this.translation.slice(),
scale: this.scale.slice(),
rotation_pivot: this.rotation_pivot,
scale_pivot: this.scale_pivot,
}
if (this.slot_id == 'gui') {
build.fit_to_frame = this.fit_to_frame;
}
if (!this.mirror.allEqual(false)) {
for (let i = 0; i < 3; i++) {
build.scale[i] *= this.mirror[i] ? -1 : 1;
}
}
return build;
}
extend(data) {
if (!data) return this;
for (var i = 0; i < 3; i++) {
@ -63,6 +91,7 @@ class DisplaySlot {
this.scale[i] = Math.abs(this.scale[i])
if (data.scale && data.scale[i] < 0) this.mirror[i] = true;
}
if (typeof data.fit_to_frame == 'boolean') this.fit_to_frame = data.fit_to_frame;
this.update()
return this;
}
@ -373,6 +402,13 @@ class refModel {
0.8, 0.8, 0.8)
}
break;
case 'tooting':
this.updateBasePosition = function() {
var side = display_slot.includes('left') ? -1 : 1;
//setDisplayArea(side*-0.6, 19.8, 23.8, 31.5, side*22, -11, 1, 1, 1)
setDisplayArea(side == 1 ? -2.7 : 2.1, 20.1, Format.id.includes('bedrock') ? 24.5 : 25.6, 36, side*21.5, side*-12, 1, 1, 1)
}
break;
}
}
buildModel(things, texture, texture_res = [16, 16]) {
@ -488,6 +524,7 @@ class refModel {
case 'crossbow':
case 'bow':
case 'eating':
case 'tooting':
case 'monitor': this.buildMonitor(); break;
case 'block': this.buildBlock(); break;
case 'frame': this.buildFrame(); break;
@ -1222,6 +1259,7 @@ window.displayReferenceObjects = {
bow: new refModel('bow', {icon: 'icon-bow'}),
crossbow: new refModel('crossbow', {icon: 'icon-crossbow'}),
eating: new refModel('eating', {icon: 'fa-apple-whole'}),
tooting: new refModel('tooting', {icon: 'fa-bullhorn'}),
block: new refModel('block', {icon: 'fa-cube'}),
frame: new refModel('frame', {icon: 'filter_frames'}),
frame_invisible: new refModel('frame_invisible', {icon: 'visibility_off'}),
@ -1419,13 +1457,16 @@ DisplayMode.applyPreset = function(preset, all) {
Undo.initEdit({display_slots: slots})
slots.forEach(function(sl) {
if (!Project.display_settings[sl]) {
Project.display_settings[sl] = new DisplaySlot()
Project.display_settings[sl] = new DisplaySlot(sl)
}
let preset_values = preset.areas[sl];
if (preset_values) {
if (!preset_values.rotation_pivot) Project.display_settings[sl].rotation_pivot.replace([0, 0, 0]);
if (!preset_values.scale_pivot) Project.display_settings[sl].scale_pivot.replace([0, 0, 0]);
Project.display_settings[sl].extend(preset.areas[sl]);
if (preset.id == 'block' && Format.id == 'bedrock_block' && sl == 'gui') {
Project.display_settings[sl].rotation[1] = 45;
}
}
})
DisplayMode.updateDisplayBase()
@ -1434,7 +1475,7 @@ DisplayMode.applyPreset = function(preset, all) {
DisplayMode.loadJSON = function(data) {
for (var slot in data) {
if (displayReferenceObjects.slots.includes(slot)) {
Project.display_settings[slot] = new DisplaySlot().extend(data[slot])
Project.display_settings[slot] = new DisplaySlot(slot).extend(data[slot])
}
}
}
@ -1495,7 +1536,7 @@ function loadDisp(key) { //Loads The Menu and slider values, common for all Radi
display_preview.camPers.setFocalLength(45)
if (Project.display_settings[key] == undefined) {
Project.display_settings[key] = new DisplaySlot()
Project.display_settings[key] = new DisplaySlot(key)
}
display_preview.force_locked_angle = false;
DisplayMode.vue._data.slot = Project.display_settings[key]
@ -1541,7 +1582,7 @@ DisplayMode.loadFirstRight = function() { //Loader
})
display_preview.controls.enabled = false
if (display_preview.orbit_gizmo) display_preview.orbit_gizmo.hide();
displayReferenceObjects.bar(['monitor', 'bow', 'crossbow', 'eating']);
displayReferenceObjects.bar(['monitor', 'bow', 'crossbow', 'tooting', 'eating']);
$('.single_canvas_wrapper').append('<div id="display_crosshair"></div>')
}
DisplayMode.loadFirstLeft = function() { //Loader
@ -1553,7 +1594,7 @@ DisplayMode.loadFirstLeft = function() { //Loader
})
display_preview.controls.enabled = false
if (display_preview.orbit_gizmo) display_preview.orbit_gizmo.hide();
displayReferenceObjects.bar(['monitor', 'bow', 'crossbow', 'eating']);
displayReferenceObjects.bar(['monitor', 'bow', 'crossbow', 'tooting', 'eating']);
$('.single_canvas_wrapper').append('<div id="display_crosshair"></div>')
}
DisplayMode.loadHead = function() { //Loader
@ -1916,7 +1957,7 @@ Interface.definePanels(function() {
axes: [0, 1, 2],
reference_model: 'player',
pose_angle: 0,
slot: new DisplaySlot(),
slot: new DisplaySlot(''),
allow_mirroring: Settings.get('allow_display_slot_mirror')
}},
watch: {
@ -1984,14 +2025,20 @@ Interface.definePanels(function() {
DisplayMode.slot.update()
Undo.finishEdit('Mirror display setting')
},
start: (axis, channel) => {
start: () => {
Undo.initEdit({display_slots: [display_slot]});
Interface.addSuggestedModifierKey('shift', 'modifier_actions.uniform_scaling');
},
save: (axis, channel) => {
save: () => {
Undo.finishEdit('Change display setting');
Interface.removeSuggestedModifierKey('shift', 'modifier_actions.uniform_scaling');
},
toggleFitToFrame() {
Undo.initEdit({display_slots: [display_slot]});
this.slot.fit_to_frame = !this.slot.fit_to_frame;
Undo.finishEdit('Change display setting fit-to-frame property');
Interface.removeSuggestedModifierKey('shift', 'modifier_actions.uniform_scaling');
},
showMirroringSetting() {
Settings.openDialog({search_term: tl('settings.allow_display_slot_mirror')});
},
@ -2071,6 +2118,10 @@ Interface.definePanels(function() {
value="0" @input="change(axis, 'scale')" @mousedown="start(axis, 'scale')" @change="save(axis, 'scale')">
<numeric-input class="tool disp_text" v-model.number="slot.scale[axis]" :min="0" :max="4" :step="0.01" @input="change(axis, 'scale')" @focusout="focusout(axis, 'scale');save()" @mousedown="start()" />
</div>
<div class="bar" v-if="isBedrockStyle() && slot.slot_id == 'gui'" @click="toggleFitToFrame()">
<input type="checkbox" :checked="slot.fit_to_frame == true">
<label style="padding-top: 3px;">Fit to Frame</label>
</div>
<template v-if="reference_model == 'player'">
<div class="bar display_slot_section_bar">

View File

@ -128,6 +128,16 @@ Object.assign(Blockbench, {
var errant;
var i = 0;
if (isApp) {
if (options.readtype == 'none') {
let results = files.map(file => {
return {
name: pathToName(file, true),
path: file
}
})
cb(results);
return results;
}
while (index < files.length) {
(function() {
var this_i = index;
@ -176,7 +186,7 @@ Object.assign(Blockbench, {
try {
data = fs.readFileSync(file, readtype == 'text' ? 'utf8' : undefined);
} catch(err) {
console.log(err)
console.error(err)
if (!errant && options.errorbox !== false) {
Blockbench.showMessageBox({
translateKey: 'file_not_found',
@ -300,7 +310,13 @@ Object.assign(Blockbench, {
saveAs(blob, file_name)
} else {
var blob = new Blob([options.content], {type: "text/plain;charset=utf-8"});
let type = 'text/plain;charset=utf-8';
if (file_name.endsWith('json')) {
type = 'application/json;charset=utf-8';
} else if (file_name.endsWith('bbmodel')) {
type = 'model/vnd.blockbench.bbmodel';
}
var blob = new Blob([options.content], {type});
saveAs(blob, file_name, {autoBOM: true})
}

View File

@ -1534,17 +1534,21 @@ class Toolbar {
}
}
}
/**
* Builds the toolbar from data
* @param {object} data Data used to build the toolbar
* @param {boolean} force If true, customization data will be ignored. Used when resetting toolbar
*/
build(data, force) {
var scope = this;
//Items
this.children.length = 0;
var items = data.children
if (!force && BARS.stored[scope.id] && typeof BARS.stored[scope.id] === 'object') {
items = BARS.stored[scope.id]
if (!force && BARS.stored[this.id] && typeof BARS.stored[this.id] === 'object') {
items = BARS.stored[this.id];
if (data.children) {
// Add new actions to existing toolbars
// Add new actions (newly added via bb update) to existing toolbars
data.children.forEach((key, index) => {
if (typeof key == 'string' && key.length > 1 && !items.includes(key) && !Keybinds.stored[key] && BarItems[key]) {
if (typeof key == 'string' && key.length > 1 && !items.includes(key) && !Keybinds.stored[key] && BARS.stored._known?.includes(key) == false && BarItems[key]) {
// Figure out best index based on item before. Otherwise use index from original array
let prev_index = items.indexOf(data.children[index-1]);
if (prev_index != -1) index = prev_index+1;
@ -1554,7 +1558,7 @@ class Toolbar {
}
}
if (items && items instanceof Array) {
var content = $(scope.node).find('div.content')
var content = $(this.node).find('div.content')
content.children().detach()
for (var itemPosition = 0; itemPosition < items.length; itemPosition++) {
let item = items[itemPosition];
@ -1566,7 +1570,10 @@ class Toolbar {
continue;
}
if (typeof item == 'string') item = BarItems[item]
if (typeof item == 'string') {
BARS.stored._known?.safePush(item);
item = BarItems[item];
}
if (item) {
item.pushToolbar(this);
@ -1581,8 +1588,8 @@ class Toolbar {
}
}
}
$(scope.node).toggleClass('no_wrap', this.no_wrap)
$(scope.node).toggleClass('vertical', this.vertical)
$(this.node).toggleClass('no_wrap', this.no_wrap)
$(this.node).toggleClass('vertical', this.vertical)
if (data.default_place) {
this.toPlace(this.id)
}
@ -1748,7 +1755,10 @@ class Toolbar {
}
})
BARS.stored[this.id] = arr;
if (arr.equals(this.default_children)) {
let identical_to_default = this.default_children.length == arr.length && this.default_children.allAre((item, i) => {
return arr[i] == item || (typeof arr[i] == 'string' && arr[i].startsWith(item));
})
if (identical_to_default) {
delete BARS.stored[this.id];
}
// Temporary fix
@ -1779,7 +1789,9 @@ Toolbar.prototype.menu = new Menu([
])
const BARS = {
stored: {},
stored: {
_known: []
},
editing_bar: undefined,
action_definers: [],
condition: Condition,
@ -2145,6 +2157,9 @@ const BARS = {
stored = JSON.parse(stored)
if (typeof stored === 'object') {
BARS.stored = stored;
if (!BARS.stored._known) {
BARS.stored._known = [];
}
}
}
@ -2266,9 +2281,6 @@ const BARS = {
}
})
}
Blockbench.onUpdateTo('4.4.0-beta.0', () => {
delete BARS.stored.brush;
})
Toolbars.brush = new Toolbar({
id: 'brush',
no_wrap: true,

View File

@ -535,6 +535,8 @@ window.MessageBox = class MessageBox extends Dialog {
super(options.id, options);
this.options = options;
if (!options.buttons) this.buttons = ['dialog.ok'];
this.cancelIndex = Math.min(this.buttons.length-1, this.cancelIndex);
this.confirmIndex = Math.min(this.buttons.length-1, this.confirmIndex);
this.callback = callback;
}
close(button, result, event) {
@ -687,6 +689,17 @@ window.ToolConfig = class ToolConfig extends Dialog {
}
save() {
localStorage.setItem(`tool_config.${this.id}`, JSON.stringify(this.options));
return this;
}
changeOptions(options) {
for (let key in options) {
this.options[key] = options[key];
}
if (this.form) {
this.form.setValues(options);
}
this.save();
return this;
}
close(button, event) {
this.save();
@ -703,6 +716,7 @@ window.ToolConfig = class ToolConfig extends Dialog {
this.object.style.top = (anchor_position.top+anchor.offsetHeight) + 'px';
this.object.style.left = Math.clamp(anchor_position.left - 30, 0, window.innerWidth-this.object.clientWidth - (this.title ? 0 : 30)) + 'px';
}
return this;
}
build() {
if (this.object) this.object.remove();

View File

@ -4,7 +4,7 @@ class InputForm extends EventSystem {
this.uuid = guid();
this.form_config = form_config;
this.form_data = {};
this.node = Interface.createElement('form', {class: 'form'});
this.node = Interface.createElement('div', {class: 'form'});
this.max_label_width = 0;
this.uses_wide_inputs = false;
@ -284,6 +284,29 @@ class InputForm extends EventSystem {
scope.updateValues();
})
break;
case 'num_slider':
let getInterval = input_config.getInterval;
if (input_config.interval_type == 'position') getInterval = getSpatialInterval;
if (input_config.interval_type == 'rotation') getInterval = getRotationInterval;
let slider = new NumSlider({
id: 'form_slider_'+form_id,
private: true,
onChange: () => {
scope.updateValues();
},
getInterval,
settings: {
default: input_config.value || 0,
min: input_config.min,
max: input_config.max,
step: input_config.step||1,
},
});
bar.append(slider.node);
slider.update();
data.slider = slider;
break;
case 'vector':
@ -325,8 +348,9 @@ class InputForm extends EventSystem {
linked_ratio_toggle.addEventListener('click', event => {
data.linked_ratio = !data.linked_ratio;
if (data.linked_ratio) {
updateInputs(vector_inputs[0]);
scope.updateValues();
initial_value = vector_inputs.map(v => v.value);
// updateInputs(vector_inputs[0]);
// scope.updateValues();
}
updateState();
})
@ -487,7 +511,6 @@ class InputForm extends EventSystem {
for (let form_id in this.form_config) {
let data = this.form_data[form_id];
let input_config = this.form_config[form_id];
console.log(form_id, values[form_id])
if (values[form_id] != undefined && typeof input_config == 'object' && data.bar) {
let value = values[form_id];
switch (input_config.type) {
@ -523,6 +546,9 @@ class InputForm extends EventSystem {
case 'number': case 'range':
data.bar.find('input').val(value);
break;
case 'num_slider':
data.slider.setValue(value);
break;
case 'vector':
for (let i = 0; i < (input_config.dimensions || 3); i++) {
data.bar.find(`input#${form_id}_${i}`).val(value[i])
@ -532,7 +558,6 @@ class InputForm extends EventSystem {
data.colorpicker.set(value);
break;
case 'checkbox':
console.log(data.bar.find('input'), value)
data.bar.find('input').prop('checked', value);
break;
case 'file':
@ -611,6 +636,9 @@ class InputForm extends EventSystem {
result[form_id] = Math.round(result[form_id] / input_config.step) * input_config.step;
}
break;
case 'num_slider':
result[form_id] = data.slider.get();
break;
case 'vector':
result[form_id] = [];
for (let i = 0; i < (input_config.dimensions || 3); i++) {
@ -645,7 +673,7 @@ class InputForm extends EventSystem {
switch (input_config.type) {
case 'checkbox': return false;
case 'text': case 'textarea': return '';
case 'number': case 'range': return Math.clamp(0, input_config.min, input_config.max);
case 'number': case 'range': case 'num_slider': return Math.clamp(0, input_config.min, input_config.max);
case 'select': case 'inline_select': case 'radio': return Object.keys(input_config.options)[0] ?? '';
case 'inline_multi_select': return {};
case 'file': case 'folder': return '';

View File

@ -233,7 +233,7 @@ class Keybind {
let modifiers_used = new Set();
if (this.variations) {
for (let option in this.variations) {
modifiers_used.add(this.variations[option]);
modifiers_used.add(this.variations[option].replace('unless_', ''));
}
}
return (
@ -250,10 +250,14 @@ class Keybind {
if (variation && option != variation) continue;
let key = this.variations[option];
if (
(key == 'always') ||
(key == 'ctrl' && (event.ctrlOrCmd || Pressing.overrides.ctrl)) ||
(key == 'shift' && (event.shiftKey || Pressing.overrides.shift)) ||
(key == 'alt' && (event.altKey || Pressing.overrides.alt)) ||
(key == 'meta' && (event.metaKey || Pressing.overrides.meta))
(key == 'meta' && (event.metaKey || Pressing.overrides.meta)) ||
(key == 'unless_ctrl' && !(event.ctrlOrCmd || Pressing.overrides.ctrl)) ||
(key == 'unless_shift' && !(event.shiftKey || Pressing.overrides.shift)) ||
(key == 'unless_alt' && !(event.altKey || Pressing.overrides.alt))
) {
return variation ? true : option;
}
@ -531,15 +535,20 @@ onVueSetup(function() {
}
},
component: {
data() {return {
data() {
return {
structure: Keybinds.structure,
open_category: 'navigate',
search_term: '',
modifier_options: {
'': '-',
always: tl('modifier_actions.always'),
ctrl: tl(Blockbench.platform == 'darwin' ? 'keys.meta' : 'keys.ctrl'),
shift: tl('keys.shift'),
alt: tl('keys.alt'),
'': '-',
unless_ctrl: tl('modifier_actions.unless', tl(Blockbench.platform == 'darwin' ? 'keys.meta' : 'keys.ctrl')),
unless_shift: tl('modifier_actions.unless', tl('keys.shift')),
unless_alt: tl('modifier_actions.unless', tl('keys.alt')),
}
}},
methods: {
@ -935,6 +944,12 @@ addEventListeners(document, 'keydown mousedown', function(e) {
ReferenceImageMode.deactivate();
used = true;
}
} else if (Project && Undo.amend_edit_menu && (Keybinds.extra.confirm.keybind.isTriggered(e) || Keybinds.extra.cancel.keybind.isTriggered(e))) {
Undo.closeAmendEditMenu();
} else if (UVEditor.vue.texture_selection_polygon.length && Keybinds.extra.cancel.keybind.isTriggered(e)) {
UVEditor.vue.texture_selection_polygon.empty();
} else if (Prop.active_panel == 'uv' && Modes.paint && Texture.selected && Texture.selected.selection.is_custom) {
if (Keybinds.extra.cancel.keybind.isTriggered(e)) {
SharedActions.run('unselect_all', e);

View File

@ -254,20 +254,6 @@ const MenuBar = {
'delete',
'apply_mirror_modeling',
new MenuSeparator('mesh_specific'),
{name: 'data.mesh', id: 'mesh', icon: 'fa-gem', children: [
'extrude_mesh_selection',
'inset_mesh_selection',
'loop_cut',
'create_face',
'invert_face',
'switch_face_crease',
'merge_vertices',
'dissolve_edges',
'solidify_mesh_selection',
'apply_mesh_rotation',
'split_mesh',
'merge_meshes',
]},
new MenuSeparator('editing_mode'),
'proportional_editing',
'mirror_modeling',
@ -311,6 +297,22 @@ const MenuBar = {
icon: 'open_with',
condition: {modes: ['edit']},
})
new BarMenu('mesh', [
new MenuSeparator('geometry'),
'extrude_mesh_selection',
'inset_mesh_selection',
'loop_cut',
'create_face',
'invert_face',
'switch_face_crease',
'merge_vertices',
'dissolve_edges',
'solidify_mesh_selection',
new MenuSeparator('element'),
'apply_mesh_rotation',
'split_mesh',
'merge_meshes',
], {icon: 'fa-gem', condition: {selected: {mesh: true}, modes: ['edit']}})
new BarMenu('uv', UVEditor.menu.structure, {
condition: {modes: ['edit']},
@ -329,6 +331,7 @@ const MenuBar = {
'adjust_curves',
new MenuSeparator('filters'),
'limit_to_palette',
'split_rgb_into_layers',
'clear_unused_texture_space',
new MenuSeparator('transform'),
'flip_texture_x',
@ -447,20 +450,8 @@ const MenuBar = {
MenuBar.menus.filter = MenuBar.menus.tools;
new BarMenu('view', [
new MenuSeparator('viewport'),
new MenuSeparator('window'),
'fullscreen',
new MenuSeparator('viewport'),
'view_mode',
'toggle_shading',
'toggle_all_grids',
'toggle_ground_plane',
'preview_checkerboard',
'pixel_grid',
'painting_grid',
new MenuSeparator('references'),
'bedrock_animation_mode',
'preview_scene',
'edit_reference_images',
new MenuSeparator('interface'),
{
id: 'panels',
@ -501,6 +492,18 @@ const MenuBar = {
},
'toggle_sidebars',
'split_screen',
new MenuSeparator('viewport'),
'view_mode',
'toggle_shading',
'toggle_all_grids',
'toggle_ground_plane',
'preview_checkerboard',
'pixel_grid',
'painting_grid',
new MenuSeparator('references'),
'bedrock_animation_mode',
'preview_scene',
'edit_reference_images',
new MenuSeparator('model'),
'hide_everything_except_selection',
'focus_on_selection',

View File

@ -11,7 +11,7 @@ class Panel extends EventSystem {
this.condition = data.condition;
this.display_condition = data.display_condition;
this.previous_slot = 'left_bar';
this.optional = data.optional ?? false;
this.optional = data.optional ?? true;
this.plugin = data.plugin || (typeof Plugins != 'undefined' ? Plugins.currently_loading : '');
this.growable = data.growable;

View File

@ -412,6 +412,7 @@ const Settings = {
}});
new Setting('seethrough_outline', {category: 'interface', value: false, onChange(value) {
Canvas.outlineMaterial.depthTest = !value;
Canvas.meshOutlineMaterial.depthTest = !value;
}});
new Setting('outliner_colors', {category: 'interface', value: true});
new Setting('preview_checkerboard', {category: 'interface', value: true, onChange() {
@ -435,7 +436,7 @@ const Settings = {
Canvas.updateShading()
}});
new Setting('antialiasing', {category: 'preview', value: true, requires_restart: true});
new Setting('antialiasing_bleed_fix', {category: 'preview', value: true, requires_restart: true});
new Setting('antialiasing_bleed_fix', {category: 'preview', value: false, requires_restart: true});
new Setting('fov', {category: 'preview', value: 45, type: 'number', min: 1, max: 120, onChange(val) {
Preview.all.forEach(preview => preview.setFOV(val));
}});
@ -489,10 +490,13 @@ const Settings = {
Preview.all.forEach(viewport => viewport.controls.zoomSpeed = value / 100 * 1.5)
}});
new Setting('editor_2d_zoom_speed', {category: 'controls', value: 100, min: 10, max: 1000, type: 'number'});
new Setting('gamepad_controls', {category: 'controls', value: false, name: 'Gamepad Controls', description: 'Use a gamepad or 3D mouse to navigate the viewport'});
new Setting('double_click_switch_tools',{category: 'controls', value: true});
new Setting('canvas_unselect', {category: 'controls', value: false});
new Setting('selection_tolerance', {category: 'controls', value: 10, type: 'number', min: 1, max: 50});
//Edit
new Setting('undo_selections', {category: 'edit', value: false});
new Setting('undo_limit', {category: 'edit', value: 256, type: 'number', min: 1});
new Setting('highlight_cubes', {category: 'edit', value: true, onChange() {
updateCubeHighlights();
@ -524,6 +528,7 @@ const Settings = {
new Setting('outlines_in_paint_mode', {category: 'paint', value: true});
new Setting('move_with_selection_tool', {category: 'paint', value: true});
new Setting('pick_color_opacity', {category: 'paint', value: false});
new Setting('pick_combined_color', {category: 'paint', value: false});
new Setting('paint_through_transparency', {category: 'paint', value: true});
new Setting('paint_side_restrict', {category: 'paint', value: true});
new Setting('paint_with_stylus_only', {category: 'paint', value: false});
@ -623,9 +628,8 @@ const Settings = {
new Setting('sketchfab_token', {category: 'export', value: '', type: 'password'});
new Setting('credit', {category: 'export', value: 'Made with Blockbench', type: 'text'});
Blockbench.onUpdateTo('4.7.1', () => {
settings.brush_opacity_modifier.set('none');
settings.brush_size_modifier.set('none');
Blockbench.onUpdateTo('4.12.1', () => {
settings.antialiasing_bleed_fix.set(false);
})
},
setupProfiles() {

View File

@ -83,10 +83,15 @@ BARS.defineActions(() => {
new Action('delete', {
icon: 'delete',
category: 'edit',
keybind: new Keybind({key: 46}),
keybind: new Keybind({key: 46}, {
keep_vertices: 'alt'
}),
variations: {
keep_vertices: {name: 'action.delete.keep_vertices'}
},
condition: () => !Dialog.open,
click() {
SharedActions.run('delete');
click(event) {
SharedActions.run('delete', event);
}
})
new Action('duplicate', {
@ -94,8 +99,8 @@ BARS.defineActions(() => {
category: 'edit',
condition: () => SharedActions.condition('duplicate'),
keybind: new Keybind({key: 'd', ctrl: true}),
click() {
SharedActions.run('duplicate');
click(event) {
SharedActions.run('duplicate', event);
}
})
new Action('select_all', {
@ -103,8 +108,8 @@ BARS.defineActions(() => {
category: 'select',
condition: () => !Modes.display,
keybind: new Keybind({key: 'a', ctrl: true}),
click() {
SharedActions.run('select_all');
click(event) {
SharedActions.run('select_all', event);
Blockbench.dispatchEvent('select_all');
}
})
@ -112,8 +117,8 @@ BARS.defineActions(() => {
icon: 'border_clear',
category: 'select',
condition: () => !Modes.display,
click() {
SharedActions.run('unselect_all');
click(event) {
SharedActions.run('unselect_all', event);
Blockbench.dispatchEvent('unselect_all');
}
})
@ -121,8 +126,8 @@ BARS.defineActions(() => {
icon: 'swap_vert',
category: 'select',
keybind: new Keybind({key: 'i', ctrl: true}),
click() {
SharedActions.run('invert_selection');
click(event) {
SharedActions.run('invert_selection', event);
Blockbench.dispatchEvent('invert_selection');
}
})

View File

@ -182,15 +182,19 @@ onVueSetup(async function() {
slideshow: [
{
source: "./assets/splash_art/1.webp",
description: "Splash Art 1st Place by [BonoGakure](https://twitter.com/bonogakure) & [GlenFebrian](https://twitter.com/glenn_turu)",
description: "Splash Art 1st Place by [Handon_撼动](https://x.com/_2Lein) & [PICASSO](https://twitter.com/Picasso114514)",
},
{
source: "./assets/splash_art/2.webp",
description: "Splash Art 2nd Place by [Wanwin](https://wan-win.com/#3darts) & Artem x",
description: "Splash Art 2nd Place by [guzuper](https://x.com/guzuper200?s=21) & [rainyday](https://x.com/YuTian131)",
},
{
source: "./assets/splash_art/3.webp",
description: "Splash Art 3rd Place by [FairyZelz](https://x.com/FairyZelz) & [AnolXD](https://x.com/_AnolXD_)",
description: "Splash Art 3rd Place by [PeacedoveWum丨無名.](https://twitter.com/PeacedoveWum) & mccaca",
},
{
source: "./assets/splash_art/4.webp",
description: "Splash Art 3rd Place by [Orange](https://twitter.com/OrangewithMC)",
}
],
show_splash_screen: (Blockbench.hasFlag('after_update') || settings.always_show_splash_art.value),
@ -569,23 +573,39 @@ ModelLoader.loaders = {};
});
documentReady.then(() => {
//Twitter
let twitter_ad;
if (!settings.classroom_mode.value && Blockbench.startup_count < 20 && Blockbench.startup_count % 5 === 4) {
twitter_ad = true;
addStartScreenSection('twitter_link', {
color: '#1da1f2',
//Bluesky
let bsky_ad;
Blockbench.onUpdateTo('4.12.2', () => {
//Bluesky
if (!settings.classroom_mode.value) {
bsky_ad = true;
addStartScreenSection('bluesky_link', {
color: 'rgb(32, 139, 254);',
text_color: '#ffffff',
graphic: {type: 'icon', icon: 'fab.fa-bluesky'},
text: [
{type: 'h3', text: 'Blockbench on Bluesky'},
{text: 'Follow Blockbench on Bluesky for the latest news & cool models from the community! [@blockbench.net](https://bsky.app/profile/blockbench.net)'}
],
last: true
})
}
})
if (!settings.classroom_mode.value && !bsky_ad && Blockbench.startup_count < 20 && Blockbench.startup_count % 5 === 4) {
bsky_ad = true;
addStartScreenSection('bluesky_link', {
color: 'rgb(32, 139, 254);',
text_color: '#ffffff',
graphic: {type: 'icon', icon: 'fab.fa-twitter'},
graphic: {type: 'icon', icon: 'fab.fa-bluesky'},
text: [
{type: 'h2', text: 'Blockbench on Twitter'},
{text: 'Follow Blockbench on Twitter for the latest news as well as cool models from the community! [twitter.com/blockbench](https://twitter.com/blockbench/)'}
{type: 'h3', text: 'Blockbench on Bluesky'},
{text: 'Follow Blockbench on Bluesky for the latest news & cool models from the community! [@blockbench.net](https://bsky.app/profile/blockbench.net)'}
],
last: true
})
}
//Discord
if (!settings.classroom_mode.value && Blockbench.startup_count < 6 && !twitter_ad) {
if (!settings.classroom_mode.value && Blockbench.startup_count < 6 && !bsky_ad) {
addStartScreenSection('discord_link', {
color: '#5865F2',
text_color: '#ffffff',

View File

@ -256,6 +256,7 @@ class ModelFormat {
}
}
new Property(ModelFormat, 'string', 'node_name_regex');
new Property(ModelFormat, 'boolean', 'box_uv');
new Property(ModelFormat, 'boolean', 'optional_box_uv');
new Property(ModelFormat, 'boolean', 'box_uv_float_size');

View File

@ -253,10 +253,17 @@ var codec = new Codec('project', {
model.texture_groups.push(copy);
}
let collections = [];
for (let collection of Collection.all) {
let copy = collection.getSaveCopy();
collections.push(copy);
}
if (collections.length) model.collections = collections;
if (Animation.all.length) {
model.animations = [];
Animation.all.forEach(a => {
model.animations.push(a.getUndoCopy({bone_names: true, absolute_paths: options.absolute_paths}, true))
model.animations.push(a.getUndoCopy({absolute_paths: options.absolute_paths}, true))
})
}
if (AnimationController.all.length) {
@ -325,15 +332,11 @@ var codec = new Codec('project', {
if (options.raw) {
return model;
} else if (options.compressed) {
var json_string = JSON.stringify(model);
var json_string = compileJSON(model, {small: true});
var compressed = '<lz>'+LZUTF8.compress(json_string, {outputEncoding: 'StorageBinaryString'});
return compressed;
} else {
if (Settings.get('minify_bbmodel') || options.minify) {
return JSON.stringify(model);
} else {
return compileJSON(model);
}
return compileJSON(model, {small: Settings.get('minify_bbmodel') || options.minify});
}
},
parse(model, path) {
@ -440,6 +443,12 @@ var codec = new Codec('project', {
if (model.outliner) {
parseGroups(model.outliner)
}
if (model.collections instanceof Array) {
for (let collection_data of model.collections) {
let collection = new Collection(collection_data, collection_data.uuid);
collection.add();
}
}
if (model.animations) {
model.animations.forEach(ani => {
var base_ani = new Animation()
@ -703,6 +712,12 @@ var codec = new Codec('project', {
parseGroups(model.outliner, true);
}
if (model.collections instanceof Array) {
for (let collection_data of model.collections) {
let collection = new Collection(collection_data, collection_data.uuid);
collection.add();
}
}
if (model.animations && Format.animation_mode) {
model.animations.forEach(ani => {
var base_ani = new Animation();

View File

@ -96,7 +96,8 @@ window.BedrockEntityManager = class BedrockEntityManager {
}
}
if (valid_textures_list.length == 1) {
new Texture({keep_size: true, render_mode}).fromPath(valid_textures_list[0]).add()
let texture = new Texture({keep_size: true, render_mode}).fromPath(valid_textures_list[0]).add()
if (isApp) loadAdjacentTextureSet(texture);
if (render_mode == 'layered') {
updateLayeredTextures();
}
@ -169,14 +170,15 @@ window.BedrockEntityManager = class BedrockEntityManager {
cancelIndex: 2,
onButton(index) {
dialog.hide();
let textures_to_import = [];
if (index == 1) {
valid_textures_list.forEach(path => {
new Texture({keep_size: true, render_mode}).fromPath(path).add()
})
textures_to_import = valid_textures_list;
} else if (index == 0) {
selected_textures.forEach(path => {
new Texture({keep_size: true, render_mode}).fromPath(path).add()
})
textures_to_import = selected_textures;
}
for (let path of textures_to_import) {
let texture = new Texture({keep_size: true, render_mode}).fromPath(path).add();
if (isApp) loadAdjacentTextureSet(texture);
}
if (render_mode == 'layered') {
updateLayeredTextures();
@ -234,7 +236,9 @@ window.BedrockEntityManager = class BedrockEntityManager {
try {
let content = fs.readFileSync(path, 'utf8');
Animator.loadFile({path, content}, animation_names);
} catch (err) {}
} catch (err) {
console.err(err)
}
})
}
}
@ -320,7 +324,8 @@ window.BedrockEntityManager = class BedrockEntityManager {
} else {
function tryItWith(extension) {
if (fs.existsSync(texture_path+'.'+extension)) {
var texture = new Texture({keep_size: true}).fromPath(texture_path+'.'+extension).add()
var texture = new Texture({keep_size: true}).fromPath(texture_path+'.'+extension).add();
loadAdjacentTextureSet(texture);
return true;
}
}
@ -452,6 +457,7 @@ window.BedrockBlockManager = class BedrockBlockManager {
])
if (full_texture_path) {
let texture = new Texture({keep_size: true}).fromPath(full_texture_path).add();
if (isApp) loadAdjacentTextureSet(texture);
if (target == '*') {
texture.use_as_default = true;
@ -718,6 +724,11 @@ function calculateVisibleBox() {
if (data.object.item_display_transforms !== undefined) {
DisplayMode.loadJSON(data.object.item_display_transforms)
if (data.object.item_display_transforms.gui) {
if (data.object.item_display_transforms.gui.fit_to_frame == undefined) {
Project.display_settings.gui.fit_to_frame = true;
}
}
}
var bones = {}
@ -1033,7 +1044,6 @@ let entity_file_codec = new Codec('bedrock_entity_file', {
function getFormatVersion() {
if (Format.display_mode) {
let has_new_displays = false;
for (let i in DisplayMode.slots) {
let key = DisplayMode.slots[i]
if (Project.display_settings[key] && Project.display_settings[key].export) {
@ -1045,6 +1055,7 @@ function getFormatVersion() {
}
}
for (let cube of Cube.all) {
if (cube.box_uv) continue;
for (let fkey in cube.faces) {
if (cube.faces[fkey].rotation) return '1.21.0';
}
@ -1150,15 +1161,14 @@ var codec = new Codec('bedrock', {
}
let new_display = {};
let has_new_displays = false;
for (let i in DisplayMode.slots) {
let key = DisplayMode.slots[i]
if (Project.display_settings[key] && Project.display_settings[key].export) {
new_display[key] = Project.display_settings[key].export();
if (new_display[key]) has_new_displays = true;
if (Project.display_settings[key] && Project.display_settings[key].exportBedrock) {
let data = Project.display_settings[key].exportBedrock();
if (data) new_display[key] = data;
}
}
if (has_new_displays) {
if (Object.keys(new_display).length) {
entitymodel.item_display_transforms = new_display
}
@ -1342,6 +1352,7 @@ var entity_format = new ModelFormat({
}
]
},
node_name_regex: '\\w.-',
rotate_cubes: true,
box_uv: true,
optional_box_uv: true,
@ -1381,6 +1392,7 @@ var block_format = new ModelFormat({
}
]
},
node_name_regex: '\\w.-',
show_on_start_screen: new Date().dayOfYear() >= 298 || new Date().getYear() > 122,
rotate_cubes: true,
box_uv: false,

View File

@ -24,4 +24,5 @@ new ModelFormat({
animation_mode: true,
animated_textures: true,
locators: true,
pbr: true,
})

View File

@ -1,6 +1,7 @@
(function() {
let codec = new Codec('image', {
name: tl('format.image'),
extension: 'png',
remember: true,
load_filter: {
@ -117,6 +118,9 @@ let codec = new Codec('image', {
savetype: 'image',
content,
}, path => this.afterDownload(path));
},
write(content, path) {
Blockbench.writeFile(path, {content, savetype: 'image'}, path => this.afterSave(path));
}
})
codec.parse = null;

View File

@ -453,7 +453,7 @@ var codec = new Codec('java_block', {
open_with_textures: {text: 'message.child_model_only.open_with_textures', condition: Texture.all.length > 0}
}
}, (result) => {
if (result) {
if (typeof result == 'string') {
let parent = model.parent.replace(/\w+:/, '');
let path_arr = path.split(osfs);
let index = path_arr.length - path_arr.indexOf('models');

View File

@ -1071,6 +1071,7 @@ var format = new ModelFormat({
]
},
codec,
node_name_regex: '\\w',
box_uv: true,
box_uv_float_size: true,
single_texture: true,

View File

@ -29,7 +29,7 @@ var codec = new Codec('optifine_entity', {
}
entitymodel.textureSize = [Project.texture_width, Project.texture_height];
let default_texture = Texture.getDefault();
if (default_texture?.use_as_default || (settings.optifine_save_default_texture.value && !isAppliedInModel(default_texture))) {
if (default_texture && (default_texture.use_as_default || (settings.optifine_save_default_texture.value && !isAppliedInModel(default_texture)))) {
let texture = Texture.getDefault();
entitymodel.texture = getTexturePath(Texture.getDefault());
entitymodel.textureSize = [texture.uv_width, texture.uv_height];
@ -39,8 +39,7 @@ var codec = new Codec('optifine_entity', {
if (Project.shadow_size != 1) entitymodel.shadowSize = Project.shadow_size;
entitymodel.models = []
Outliner.root.forEach(function(g) {
if (g instanceof Group == false) return;
function compilePart(g) {
if (!settings.export_empty_groups.value && !g.children.find(child => child.export)) return;
//Bone
var bone = {
@ -184,7 +183,22 @@ var codec = new Codec('optifine_entity', {
}
entitymodel.models.push(bone)
})
}
if (options.build_part) {
compilePart({
name: Project.name,
origin: [0, 0, 0],
rotation: [0, 0, 0],
children: Outliner.root.filter(g => g.export)
});
} else {
for (let group of Outliner.root) {
if (group instanceof Group && group.export) {
compilePart(group);
}
}
}
this.dispatchEvent('compile', {entitymodel, options});
@ -238,17 +252,21 @@ var codec = new Codec('optifine_entity', {
//Bone
let texture = importTexture(b.texture, b.textureSize);
let group = new Group({
name: b.part,
origin: b.translate,
rotation: b.rotate,
mirror_uv: (b.mirrorTexture && b.mirrorTexture.includes('u')),
cem_animations: b.animations,
cem_attach: b.attach,
cem_scale: b.scale,
texture: texture ? texture.uuid : undefined,
})
group.origin.V3_multiply(-1);
let group = 0;
if (!model._is_jpm) {
group = new Group({
name: b.part,
origin: b.translate,
rotation: b.rotate,
mirror_uv: (b.mirrorTexture && b.mirrorTexture.includes('u')),
cem_animations: b.animations,
cem_attach: b.attach,
cem_scale: b.scale,
texture: texture ? texture.uuid : undefined,
})
group.origin.V3_multiply(-1);
group.init().addTo();
}
function readContent(submodel, p_group, depth, texture) {
@ -302,7 +320,7 @@ var codec = new Codec('optifine_entity', {
}
})
}
if (p_group.parent !== 'root') {
if (p_group && (p_group.parent !== 'root' || model._is_jpm)) {
for (var i = 0; i < 3; i++) {
base_cube.from[i] += p_group.origin[i];
base_cube.to[i] += p_group.origin[i];
@ -320,7 +338,7 @@ var codec = new Codec('optifine_entity', {
}
let sub_texture = importTexture(subsub.texture, subsub.textureSize);
let group = new Group({
name: subsub.id || `${b.part}_sub_${subcount}`,
name: subsub.id || subsub.comment || `${b.part??'part'}_sub_${subcount}`,
origin: subsub.translate || (depth >= 1 ? submodel.translate : undefined),
rotation: subsub.rotate,
mirror_uv: (subsub.mirrorTexture && subsub.mirrorTexture.includes('u')),
@ -333,7 +351,6 @@ var codec = new Codec('optifine_entity', {
}
}
group.init().addTo()
readContent(b, group, 0, texture || main_texture)
})
}

View File

@ -10,330 +10,41 @@ var part_codec = new Codec('optifine_part', {
extensions: ['jpm']
},
compile(options) {
if (options === undefined) options = {}
var entitymodel = {}
if (Project.credit || settings.credit.value) {
entitymodel.credit = Project.credit || settings.credit.value
let original_options = options??0;
options = options ? Object.assign({}, options) : {};
options.raw = true;
options.build_part = true;
let entitymodel = Codecs.optifine_entity.compile(options);
let part_model = entitymodel.models[0];
part_model.credit = entitymodel.credit;
if (!part_model.textureSize) {
part_model.textureSize = entitymodel.textureSize;
}
var geo_code = 'geometry.'+Project.geometry_name
function getTexturePath(tex) {
return tex.folder ? (tex.folder + '/' + tex.name) : tex.name;
}
entitymodel.textureSize = [Project.texture_width, Project.texture_height];
let default_texture = Texture.getDefault();
if (!settings.optifine_save_default_texture.value && !default_texture?.use_as_default) {
default_texture = null;
}
if (default_texture) {
let texture = Texture.getDefault();
entitymodel.texture = getTexturePath(Texture.getDefault());
entitymodel.textureSize = [texture.uv_width, texture.uv_height];
}
if (Project.shadow_size != 1) entitymodel.shadowSize = Project.shadow_size;
entitymodel.submodels = []
if (part_model.id == '') delete part_model.id;
delete part_model.part;
Outliner.root.forEach(function(g) {
if (g instanceof Group == false) return;
if (!settings.export_empty_groups.value && !g.children.find(child => child.export)) return;
//Bone
var bone = {
part: g.name,
id: g.name,
invertAxis: 'xy',
mirrorTexture: undefined,
translate: g.origin.slice()
}
bone.translate.V3_multiply(-1);
this.dispatchEvent('compile', {model: part_model, original_options});
if (!g.rotation.allEqual(0)) {
bone.rotate = g.rotation.slice()
}
if (entityMode.hardcodes[geo_code]) {
var codes = entityMode.hardcodes[geo_code]
var bone_codes = codes[bone.part] || codes[bone.part+'1']
if (bone_codes) {
if (!bone.rotate) bone.rotate = [0, 0, 0];
bone_codes.rotation.forEach((dft, i) => {
bone.rotate[i] += dft;
})
}
}
if (g.mirror_uv) {
bone.mirrorTexture = 'u'
}
if (g.cem_attach) {
bone.attach = true;
}
if (g.cem_scale) {
bone.scale = g.cem_scale;
}
function populate(p_model, group, depth, parent_texture) {
if (group.children.length === 0) return;
let mirror_sub;
let child_cubes = group.children.filter(obj => obj.export && obj.type === 'cube')
let has_different_mirrored_children = !!child_cubes.find(obj => obj.mirror_uv !== child_cubes[0].mirror_uv);
let texture = parent_texture;
if (group.texture) {
let match = Texture.all.find(t => t.uuid == group.texture);
if (match) texture = match;
}
if (texture && texture != parent_texture) {
p_model.texture = getTexturePath(texture);
if (!parent_texture || texture.uv_width != parent_texture.uv_width || texture.uv_height != parent_texture.uv_height) {
p_model.textureSize = [texture.uv_width, texture.uv_height];
}
}
group.children.forEach(obj => {
if (!obj.export) return;
if (obj.type === 'cube') {
if (obj.box_uv) {
var box = new oneLiner()
} else {
var box = {};
}
var c_size = obj.size()
box.coordinates = [
obj.from[0],
obj.from[1],
obj.from[2],
c_size[0],
c_size[1],
c_size[2]
]
if (p_model && p_model.part === undefined) {
box.coordinates[0] -= p_model.translate[0];
box.coordinates[1] -= p_model.translate[1];
box.coordinates[2] -= p_model.translate[2];
}
if (obj.box_uv) {
box.textureOffset = obj.uv_offset
} else {
for (let face in obj.faces) {
if (obj.faces[face].texture !== null) {
let uv = obj.faces[face].uv;
box[`uv${capitalizeFirstLetter(face)}`] = uv;
}
}
}
if (obj.inflate && typeof obj.inflate === 'number') {
box.sizeAdd = obj.inflate
}
if (obj.mirror_uv !== group.mirror_uv && has_different_mirrored_children) {
if (!mirror_sub) {
mirror_sub = {
invertAxis: 'xy',
mirrorTexture: 'u',
boxes: []
}
if (!p_model.submodels) p_model.submodels = [];
p_model.submodels.splice(0, 0, mirror_sub)
}
mirror_sub.boxes.push(box);
} else {
if (!p_model.boxes) p_model.boxes = [];
if (obj.mirror_uv !== group.mirror_uv) {
p_model.mirrorTexture = obj.mirror_uv ? 'u' : undefined;
}
p_model.boxes.push(box)
}
} else if (obj.type === 'group') {
var bone = {
id: obj.name,
invertAxis: 'xy',
mirrorTexture: undefined,
translate: obj.origin.slice()
}
if (obj.mirror_uv) {
bone.mirrorTexture = 'u';
}
if (!obj.rotation.allEqual(0)) {
bone.rotate = obj.rotation.slice()
}
populate(bone, obj, depth+1, texture)
if (depth >= 1) {
bone.translate[0] -= group.origin[0];
bone.translate[1] -= group.origin[1];
bone.translate[2] -= group.origin[2];
}
if (!p_model.submodels) p_model.submodels = [];
p_model.submodels.push(bone)
}
})
}
populate(bone, g, 0, default_texture)
if (g.cem_animations && g.cem_animations.length) {
bone.animations = g.cem_animations;
}
entitymodel.submodels.push(bone)
})
this.dispatchEvent('compile', {entitymodel, options});
if (options.raw) {
return entitymodel
if (original_options.raw) {
return part_model
} else {
return autoStringify(entitymodel)
return autoStringify(part_model)
}
},
parse(model, path, add) {
parse(model, path) {
this.dispatchEvent('parse', {model});
const imported_textures = {};
function importTexture(string, uv) {
if (typeof string !== 'string') return;
if (imported_textures[string]) return imported_textures[string];
let texture_path = string.replace(/[\\/]/g, osfs);
if (texture_path.match(/^textures/) && path.includes('optifine')) {
texture_path = path.replace(/[\\/]optifine[\\/].+$/i, osfs+texture_path);
} else {
texture_path = path.replace(/[\\/][^\\/]+$/, osfs+texture_path);
}
if (!texture_path.match(/\.\w{3,4}$/)) texture_path = texture_path + '.png';
let texture = new Texture().fromPath(texture_path).add(false);
imported_textures[string] = texture;
if (uv instanceof Array) {
texture.extend({
uv_width: uv[0],
uv_height: uv[1]
})
}
return texture;
}
if (typeof model.credit == 'string') Project.credit = model.credit;
if (model.textureSize) {
Project.texture_width = parseInt(model.textureSize[0])||16;
Project.texture_height = parseInt(model.textureSize[1])||16;
}
let main_texture = importTexture(model.texture, model.textureSize);
if (main_texture) {
main_texture.use_as_default = true;
let jem_model = {
_is_jpm: true,
invertAxis: 'xy',
models: [model]
}
if (typeof model.shadowSize == 'number') Project.shadow_size = model.shadowSize;
let empty_face = {uv: [0, 0, 0, 0], texture: null}
if (model.submodels) {
model.submodels.forEach(function(b) {
if (typeof b !== 'object') return;
let subcount = 0;
//Bone
let texture = importTexture(b.texture, b.textureSize);
let group = new Group({
name: b.part,
origin: b.translate,
rotation: b.rotate,
mirror_uv: (b.mirrorTexture && b.mirrorTexture.includes('u')),
cem_animations: b.animations,
cem_attach: b.attach,
cem_scale: b.scale,
texture: texture ? texture.uuid : undefined,
})
group.origin.V3_multiply(-1);
function readContent(submodel, p_group, depth, texture) {
if (submodel.boxes && submodel.boxes.length) {
submodel.boxes.forEach(box => {
var base_cube = new Cube({
name: box.name || p_group.name,
autouv: 0,
uv_offset: box.textureOffset,
box_uv: !!box.textureOffset,
inflate: box.sizeAdd,
mirror_uv: p_group.mirror_uv
})
/*if (texture) {
for (let fkey in base_cube.faces) {
base_cube.faces[fkey].texture = texture.uuid;
}
}*/
if (box.coordinates) {
base_cube.extend({
from: [
box.coordinates[0],
box.coordinates[1],
box.coordinates[2]
],
to: [
box.coordinates[0]+box.coordinates[3],
box.coordinates[1]+box.coordinates[4],
box.coordinates[2]+box.coordinates[5]
]
})
}
if (!box.textureOffset && (
box.uvNorth
|| box.uvEast
|| box.uvSouth
|| box.uvWest
|| box.uvUp
|| box.uvDown
)) {
base_cube.extend({
box_uv: false,
faces: {
north: box.uvNorth ? {uv: box.uvNorth} : empty_face,
east: box.uvEast ? {uv: box.uvEast} : empty_face,
south: box.uvSouth ? {uv: box.uvSouth} : empty_face,
west: box.uvWest ? {uv: box.uvWest} : empty_face,
up: box.uvUp ? {uv: box.uvUp} : empty_face,
down: box.uvDown ? {uv: box.uvDown} : empty_face,
}
})
}
if (p_group.parent !== 'root') {
for (var i = 0; i < 3; i++) {
base_cube.from[i] += p_group.origin[i];
base_cube.to[i] += p_group.origin[i];
}
}
base_cube.addTo(p_group).init()
})
}
if (submodel.submodels && submodel.submodels.length) {
submodel.submodels.forEach(subsub => {
if (depth >= 1 && subsub.translate) {
subsub.translate[0] += p_group.origin[0];
subsub.translate[1] += p_group.origin[1];
subsub.translate[2] += p_group.origin[2];
}
let sub_texture = importTexture(subsub.texture, subsub.textureSize);
let group = new Group({
name: subsub.id || `${b.part}_sub_${subcount}`,
origin: subsub.translate || (depth >= 1 ? submodel.translate : undefined),
rotation: subsub.rotate,
mirror_uv: (subsub.mirrorTexture && subsub.mirrorTexture.includes('u')),
texture: (sub_texture || texture)?.uuid,
})
subcount++;
group.addTo(p_group).init()
readContent(subsub, group, depth+1, sub_texture || texture)
})
}
}
group.init().addTo()
readContent(b, group, 0, texture || main_texture)
})
}
Project.box_uv = Cube.all.filter(cube => cube.box_uv).length > Cube.all.length/2;
Codecs.optifine_entity.parse(jem_model, path);
this.dispatchEvent('parsed', {model});
Canvas.updateAllBones();
Validator.validate()
}
})

File diff suppressed because it is too large Load Diff

View File

@ -487,149 +487,6 @@ const Extruder = {
Undo.finishEdit('Add extruded texture', {elements: selected, outliner: true, textures: [Texture.all[Texture.all.length-1]]})
}
}
//Json
function compileJSON(object, options = {}) {
let indentation = options.indentation;
if (typeof indentation !== 'string') {
switch (settings.json_indentation.value) {
case 'spaces_4': indentation = ' '; break;
case 'spaces_2': indentation = ' '; break;
case 'tabs': default: indentation = '\t'; break;
}
}
function newLine(tabs) {
if (options.small === true) {return '';}
let s = '\n';
for (let i = 0; i < tabs; i++) {
s += indentation;
}
return s;
}
function escape(string) {
return string.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n|\r\n/g, '\\n').replace(/\t/g, '\\t')
}
function handleVar(o, tabs, breaks = true) {
var out = ''
if (typeof o === 'string') {
//String
out += '"' + escape(o) + '"'
} else if (typeof o === 'boolean') {
//Boolean
out += (o ? 'true' : 'false')
} else if (o === null || o === Infinity || o === -Infinity) {
//Null
out += 'null'
} else if (typeof o === 'number') {
//Number
o = (Math.round(o*100000)/100000).toString()
out += o
} else if (o instanceof Array) {
//Array
let has_content = false
let multiline = !!o.find(item => typeof item === 'object');
if (!multiline) {
let length = 0;
o.forEach(item => {
length += typeof item === 'string' ? (item.length+4) : 3;
});
if (length > 140) multiline = true;
}
out += '['
for (var i = 0; i < o.length; i++) {
var compiled = handleVar(o[i], tabs+1)
if (compiled) {
if (has_content) {out += ',' + ((options.small || multiline) ? '' : ' ')}
if (multiline) {out += newLine(tabs)}
out += compiled
has_content = true
}
}
if (multiline) {out += newLine(tabs-1)}
out += ']'
} else if (typeof o === 'object') {
//Object
breaks = breaks && o.constructor.name !== 'oneLiner';
var has_content = false
out += '{'
for (var key in o) {
if (o.hasOwnProperty(key)) {
var compiled = handleVar(o[key], tabs+1, breaks)
if (compiled) {
if (has_content) {out += ',' + (breaks || options.small?'':' ')}
if (breaks) {out += newLine(tabs)}
out += '"' + escape(key) + '":' + (options.small === true ? '' : ' ')
out += compiled
has_content = true
}
}
}
if (breaks && has_content) {out += newLine(tabs-1)}
out += '}'
}
return out;
}
let file = handleVar(object, 1);
if ((settings.final_newline.value && options.final_newline != false) || options.final_newline == true) {
file += '\n';
}
return file;
}
function autoParseJSON(data, feedback) {
if (data.substr(0, 4) === '<lz>') {
data = LZUTF8.decompress(data.substr(4), {inputEncoding: 'StorageBinaryString'})
}
if (data.charCodeAt(0) === 0xFEFF) {
data = data.substr(1)
}
try {
data = JSON.parse(data)
} catch (err1) {
data = data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, '')
try {
data = JSON.parse(data)
} catch (err) {
if (feedback === false) return;
if (data.match(/\n\r?[><]{7}/)) {
Blockbench.showMessageBox({
title: 'message.invalid_file.title',
icon: 'fab.fa-git-alt',
message: 'message.invalid_file.merge_conflict'
})
return;
}
let error_part = '';
function logErrantPart(whole, start, length) {
var line = whole.substr(0, start).match(/\n/gm)
line = line ? line.length+1 : 1
var result = '';
var lines = whole.substr(start, length).split(/\n/gm)
lines.forEach((s, i) => {
result += `#${line+i} ${s}\n`
})
error_part = result.substr(0, result.length-1) + ' <-- HERE';
console.log(error_part);
}
console.error(err)
var length = err.toString().split('at position ')[1]
if (length) {
length = parseInt(length)
var start = limitNumber(length-32, 0, Infinity)
logErrantPart(data, start, 1+length-start)
} else if (err.toString().includes('Unexpected end of JSON input')) {
logErrantPart(data, data.length-16, 10)
}
Blockbench.showMessageBox({
translateKey: 'invalid_file',
icon: 'error',
message: tl('message.invalid_file.message', [err]) + (error_part ? `\n\n\`\`\`\n${error_part}\n\`\`\`` : '')
})
return;
}
}
return data;
}
BARS.defineActions(function() {
@ -719,7 +576,9 @@ BARS.defineActions(function() {
Codecs.project.write(Codecs.project.compile(), Project.save_path);
}
if (Project.export_path && export_codec?.compile) {
export_codec.write(export_codec.compile(), Project.export_path)
if (export_codec.id != 'image') {
export_codec.write(export_codec.compile(), Project.export_path)
}
} else if (export_codec?.export && !Project.save_path) {
if (export_codec.id === 'project' || settings.dialog_save_codec.value == false) {

View File

@ -71,7 +71,6 @@ class ModelProject {
ProjectData[this.uuid] = {
model_3d: new THREE.Object3D(),
materials: {},
nodes_3d: {}
}
}
@ -135,9 +134,6 @@ class ModelProject {
get model_3d() {
return ProjectData[this.uuid].model_3d;
}
get materials() {
return ProjectData[this.uuid].materials;
}
get nodes_3d() {
return ProjectData[this.uuid].nodes_3d;
}

View File

@ -209,11 +209,15 @@ function updateSelection(options = {}) {
if (Condition(BarItems.layer_blend_mode.condition)) BarItems.layer_blend_mode.set(TextureLayer.selected?.blend_mode);
BARS.updateConditions();
MenuBar.update()
delete TickUpdates.selection;
Blockbench.dispatchEvent('update_selection');
}
function unselectAllElements() {
Project.selected_elements.forEachReverse(obj => obj.unselect())
function unselectAllElements(exceptions) {
Project.selected_elements.forEachReverse(obj => {
if (exceptions instanceof Array && exceptions.includes(obj)) return;
obj.unselect()
})
for (let group of Group.multi_selected) {
group.unselect();
}

View File

@ -677,7 +677,7 @@ class KnifeToolCubeContext {
return getAxisLetter(this.axis);
}
hover(data) {
if (!data) {
if (!data || data.element instanceof Cube == false) {
if (this.cross_mesh.parent) {
this.cross_mesh.parent.remove(this.cross_mesh);
}
@ -1067,7 +1067,8 @@ SharedActions.add('delete', {
condition: () => Modes.edit && Prop.active_panel == 'preview' && Mesh.selected[0] && Project.mesh_selection[Mesh.selected[0].uuid],
run() {
let meshes = Mesh.selected.slice();
Undo.initEdit({elements: meshes, outliner: true})
let keep_vertices = BarItems.delete.keybind.additionalModifierTriggered(event, 'keep_vertices');
Undo.initEdit({elements: meshes, outliner: true, selection: true})
Mesh.selected.forEach(mesh => {
let selected_vertices = mesh.getSelectedVertices();
@ -1076,20 +1077,37 @@ SharedActions.add('delete', {
if ((BarItems.selection_mode.value == 'face' || BarItems.selection_mode.value == 'cluster') && selected_faces.length < Object.keys(mesh.faces).length) {
let affected_vertices = [];
let affected_edges = [];
selected_faces.forEach(fkey => {
affected_vertices.safePush(...mesh.faces[fkey].vertices);
let face = mesh.faces[fkey];
affected_vertices.safePush(...face.vertices);
if (keep_vertices) {
affected_edges.push(...face.getEdges());
}
delete mesh.faces[fkey];
})
affected_vertices.forEach(vertex_key => {
let used = false;
for (let key in mesh.faces) {
let face = mesh.faces[key];
if (face.vertices.includes(vertex_key)) used = true;
if (keep_vertices) {
edges: for (let edge of affected_edges) {
for (let fkey in mesh.faces) {
let vertices = mesh.faces[fkey].vertices;
if (vertices.includes(edge[0]) && vertices.includes(edge[1])) {
continue edges;
}
}
mesh.addFaces(new MeshFace(mesh, {vertices: edge}));
}
if (!used) {
delete mesh.vertices[vertex_key];
}
})
} else {
affected_vertices.forEach(vertex_key => {
let used = false;
for (let key in mesh.faces) {
let face = mesh.faces[key];
if (face.vertices.includes(vertex_key)) used = true;
}
if (!used) {
delete mesh.vertices[vertex_key];
}
})
}
} else if (BarItems.selection_mode.value == 'edge') {
for (let key in mesh.faces) {
let face = mesh.faces[key];
@ -1110,7 +1128,7 @@ SharedActions.add('delete', {
let face = mesh.faces[key];
if (face.vertices.includes(vkey)) used = true;
}
if (!used) {
if (!used && !keep_vertices) {
delete mesh.vertices[vkey];
selected_vertices.remove(vkey);
selected_edges.remove(edge);
@ -1620,7 +1638,7 @@ BARS.defineActions(function() {
elements.push(mesh);
mesh.init()
unselectAll()
unselectAllElements()
mesh.select()
UVEditor.setAutoSize(null, true, Object.keys(mesh.faces));
Undo.finishEdit('Add primitive');
@ -1636,12 +1654,12 @@ BARS.defineActions(function() {
runEdit(false, result);
Undo.amendEdit({
diameter: {label: 'dialog.add_primitive.diameter', type: 'number', value: result.diameter, interval_type: 'position'},
height: {label: 'dialog.add_primitive.height', type: 'number', value: result.height, condition: ['cylinder', 'cone', 'cuboid', 'beveled_cuboid', 'pyramid', 'tube'].includes(result.shape), interval_type: 'position'},
sides: {label: 'dialog.add_primitive.sides', type: 'number', value: result.sides, min: 3, max: 48, condition: ['cylinder', 'cone', 'circle', 'torus', 'sphere', 'tube'].includes(result.shape)},
minor_diameter: {label: 'dialog.add_primitive.minor_diameter', type: 'number', value: result.minor_diameter, condition: ['torus', 'tube'].includes(result.shape), interval_type: 'position'},
minor_sides: {label: 'dialog.add_primitive.minor_sides', type: 'number', value: result.minor_sides, min: 2, max: 32, condition: ['torus'].includes(result.shape)},
edge_size: {label: 'dialog.add_primitive.edge_size', type: 'number', value: result.edge_size, condition: ['beveled_cuboid'].includes(result.shape)},
diameter: {label: 'dialog.add_primitive.diameter', type: 'num_slider', value: result.diameter, interval_type: 'position'},
height: {label: 'dialog.add_primitive.height', type: 'num_slider', value: result.height, condition: ['cylinder', 'cone', 'cuboid', 'beveled_cuboid', 'pyramid', 'tube'].includes(result.shape), interval_type: 'position'},
sides: {label: 'dialog.add_primitive.sides', type: 'num_slider', value: result.sides, min: 3, max: 48, condition: ['cylinder', 'cone', 'circle', 'torus', 'sphere', 'tube'].includes(result.shape)},
minor_diameter: {label: 'dialog.add_primitive.minor_diameter', type: 'num_slider', value: result.minor_diameter, condition: ['torus', 'tube'].includes(result.shape), interval_type: 'position'},
minor_sides: {label: 'dialog.add_primitive.minor_sides', type: 'num_slider', value: result.minor_sides, min: 2, max: 32, condition: ['torus'].includes(result.shape)},
edge_size: {label: 'dialog.add_primitive.edge_size', type: 'num_slider', value: result.edge_size, condition: ['beveled_cuboid'].includes(result.shape)},
}, form => {
Object.assign(result, form);
runEdit(true, result);
@ -2190,9 +2208,9 @@ BARS.defineActions(function() {
Mesh.selected.forEach(mesh => {
let original_vertices = mesh.getSelectedVertices().slice();
let selected_edges = mesh.getSelectedEdges(true);
let selected_face_keys = mesh.getSelectedFaces();
let new_vertices;
let new_face_keys = [];
let selected_face_keys = mesh.getSelectedFaces();
if (original_vertices.length && (BarItems.selection_mode.value == 'vertex' || BarItems.selection_mode.value == 'edge')) {
selected_face_keys.empty();
}
@ -2267,7 +2285,6 @@ BARS.defineActions(function() {
}
}
})
console.log(count, direction.slice());
if (count > 1) {
let magnitude = Math.sqrt(direction[0]**2 + direction[1]**2 + direction[2]**2);
direction.V3_divide(magnitude);
@ -2362,13 +2379,13 @@ BARS.defineActions(function() {
if (vertices.length == 2) delete mesh.faces[selected_face_keys[face_index]];
})
// Create Face between extruded edges
// Create Faces for extruded edges
let new_faces = [];
selected_edges.forEach(edge => {
let face, sorted_vertices;
for (let fkey in mesh.faces) {
let face2 = mesh.faces[fkey];
let vertices = face2.getSortedVertices();
let vertices = face2.vertices;
if (vertices.includes(edge[0]) && vertices.includes(edge[1])) {
face = face2;
sorted_vertices = vertices;
@ -2383,6 +2400,9 @@ BARS.defineActions(function() {
let new_face = new MeshFace(mesh, face).extend({
vertices: [a, b, c, d]
});
if (new_face.getAngleTo(face) > 90) {
new_face.invert();
}
let [face_key] = mesh.addFaces(new_face);
new_face_keys.push(face_key);
new_faces.push(new_face);
@ -2423,7 +2443,7 @@ BARS.defineActions(function() {
runEdit();
Undo.amendEdit({
extend: {type: 'number', value: 1, label: 'edit.extrude_mesh_selection.extend', interval_type: 'position'},
extend: {type: 'num_slider', value: 1, label: 'edit.extrude_mesh_selection.extend', interval_type: 'position'},
direction_mode: {type: 'select', label: 'edit.extrude_mesh_selection.direction', options: {
outwards: 'edit.extrude_mesh_selection.direction.outwards',
average: 'edit.extrude_mesh_selection.direction.average',
@ -2603,7 +2623,7 @@ BARS.defineActions(function() {
runEdit();
Undo.amendEdit({
thickness: {type: 'number', value: 1, label: 'edit.solidify_mesh_selection.thickness', interval_type: 'position'},
thickness: {type: 'num_slider', value: 1, label: 'edit.solidify_mesh_selection.thickness', interval_type: 'position'},
}, form => {
runEdit(true, form.thickness);
})
@ -2727,7 +2747,7 @@ BARS.defineActions(function() {
runEdit();
Undo.amendEdit({
offset: {type: 'number', value: 50, label: 'edit.loop_cut.offset', min: 0, max: 100, interval_type: 'position'},
offset: {type: 'num_slider', value: 50, label: 'edit.loop_cut.offset', min: 0, max: 100, interval_type: 'position'},
}, form => {
runEdit(true, form.offset);
})
@ -3060,9 +3080,9 @@ BARS.defineActions(function() {
runEdit();
Undo.amendEdit({
direction: {type: 'number', value: 0, label: 'edit.loop_cut.direction', condition: !!selected_face, min: 0},
cuts: {type: 'number', value: 1, label: 'edit.loop_cut.cuts', min: 0, max: 16},
offset: {type: 'number', value: length/2, label: 'edit.loop_cut.offset', min: 0, /*max: length,*/ interval_type: 'position'},
direction: {type: 'num_slider', value: 0, label: 'edit.loop_cut.direction', condition: !!selected_face, min: 0},
cuts: {type: 'num_slider', value: 1, label: 'edit.loop_cut.cuts', min: 0, max: 16},
offset: {type: 'num_slider', value: length/2, label: 'edit.loop_cut.offset', min: 0, /*max: length,*/ interval_type: 'position'},
unit: {type: 'inline_select', label: 'edit.loop_cut.unit', options: {size: 'edit.loop_cut.unit.size_units', percent: 'edit.loop_cut.unit.percent'}},
}, (form, form_options) => {
let direction = form.direction || 0;
@ -3612,7 +3632,7 @@ BARS.defineActions(function() {
new Toggle('proportional_editing', {
icon: 'wifi_tethering',
category: 'edit',
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 0)},
condition: {modes: ['edit'], features: ['meshes']},
tool_config: new ToolConfig('proportional_editing_options', {
title: 'action.proportional_editing',
width: 400,

View File

@ -18,6 +18,8 @@ const MirrorModeling = {
},
createClone(original, undo_aspects) {
// Create or update clone
let options = BarItems.mirror_modeling.tool_config.options;
let mirror_uv = options.mirror_uv;
let center = Format.centered_grid ? 0 : 8;
let mirror_element = MirrorModeling.cached_elements[original.uuid]?.counterpart;
let element_before_snapshot;
@ -33,6 +35,30 @@ const MirrorModeling = {
mirror_element.extend({
name: element_before_snapshot.name
});
if (!mirror_uv) {
if (original instanceof Mesh) {
for (let fkey in mirror_element.faces) {
let face = mirror_element.faces[fkey];
let face_before = element_before_snapshot.faces[fkey];
if (face_before) {
face.texture = face_before.texture;
for (let vkey of face_before.vertices) {
if (face.vertices.includes(vkey) && face_before.uv[vkey]) {
face.uv[vkey] = face_before.uv[vkey].slice();
}
}
}
}
} else {
mirror_element.extend({
faces: element_before_snapshot.faces,
uv_offset: element_before_snapshot.uv_offset,
mirror_uv: element_before_snapshot.mirror_uv,
box_uv: element_before_snapshot.box_uv,
autouv: element_before_snapshot.autouv
});
}
}
// Update hierarchy up
function updateParent(child, child_b) {
@ -116,9 +142,51 @@ const MirrorModeling = {
return 16 - input;
}
},
createLocalSymmetry(mesh) {
discoverMeshPartConnections(mesh) {
let data = {
faces: {},
vertices: {},
}
// Detect vertex counterparts
for (let vkey in mesh.vertices) {
if (data.vertices[vkey]) continue;
let vector = Reusable.vec1.fromArray(mesh.vertices[vkey]);
vector.x *= -1;
for (let vkey2 in mesh.vertices) {
//if (vkey == vkey2) continue;
let distance = vector.distanceTo(Reusable.vec2.fromArray(mesh.vertices[vkey2]));
if (distance < 0.001) {
data.vertices[vkey] = vkey2;
data.vertices[vkey2] = vkey;
break;
}
}
}
// Detect face counterparts
for (let fkey in mesh.faces) {
if (data.faces[fkey]) continue;
for (let fkey2 in mesh.faces) {
if (fkey == fkey2) continue;
let match = mesh.faces[fkey].vertices.allAre(vkey => {
let other_vkey = data.vertices[vkey];
if (!other_vkey) return false;
return mesh.faces[fkey2].vertices.includes(other_vkey);
})
if (match) {
data.faces[fkey] = fkey2;
data.faces[fkey2] = fkey;
break;
}
}
}
return data;
},
createLocalSymmetry(mesh, cached_data) {
// Create or update clone
let edit_side = MirrorModeling.getEditSide();
let options = BarItems.mirror_modeling.tool_config.options;
let mirror_uv = options.mirror_uv;
let pre_part_connections = cached_data?.pre_part_connections;
// Delete all vertices on the non-edit side
let deleted_vertices = {};
let deleted_vertices_by_position = {};
@ -155,6 +223,7 @@ const MirrorModeling = {
}
}
// Delete faces temporarily if all their vertices have been removed
let deleted_faces = {};
for (let fkey in mesh.faces) {
let face = mesh.faces[fkey];
@ -165,6 +234,7 @@ const MirrorModeling = {
}
}
// Create mirrored faces
let original_fkeys = Object.keys(mesh.faces);
for (let fkey of original_fkeys) {
let face = mesh.faces[fkey];
@ -201,21 +271,23 @@ const MirrorModeling = {
} else if (deleted_face_vertices.length == 0 && face.vertices.find((vkey) => vkey != vertex_counterpart[vkey])) {
// Recreate face as mirrored
let new_face_key;
for (let key in deleted_faces) {
let deleted_face = deleted_faces[key];
if (face.vertices.allAre(vkey => deleted_face.vertices.includes(vertex_counterpart[vkey]))) {
new_face_key = key;
break;
}
}
let new_face_key = pre_part_connections && pre_part_connections.faces[fkey];
let original_face = deleted_faces[new_face_key];
let new_face = new MeshFace(mesh, face);
face.vertices.forEach((vkey, i) => {
let new_vkey = vertex_counterpart[vkey];
new_face.vertices.splice(i, 1, new_vkey);
delete new_face.uv[vkey];
new_face.uv[new_vkey] = face.uv[vkey].slice();
if (mirror_uv || !original_face) {
new_face.uv[new_vkey] = face.uv[vkey].slice();
} else {
// change
let original_vkey = pre_part_connections.vertices[vkey];
if (original_face.uv[original_vkey]) {
new_face.uv[new_vkey] = original_face.uv[original_vkey].slice();
}
}
})
new_face.invert();
if (new_face_key) {
@ -224,8 +296,14 @@ const MirrorModeling = {
[new_face_key] = mesh.addFaces(new_face);
}
}
}
let selected_vertices = mesh.getSelectedVertices(true);
selected_vertices.replace(selected_vertices.filter(vkey => mesh.vertices[vkey]));
let selected_edges = mesh.getSelectedEdges(true);
selected_edges.replace(selected_edges.filter(edge => edge.allAre(vkey => mesh.vertices[vkey])));
let selected_faces = mesh.getSelectedFaces(true);
selected_faces.replace(selected_faces.filter(fkey => mesh.faces[fkey]));
let {preview_controller} = mesh;
preview_controller.updateGeometry(mesh);
preview_controller.updateFaces(mesh);
@ -331,6 +409,9 @@ Blockbench.on('init_edit', ({aspects}) => {
if (!data.counterpart) data.is_copy = false;
} else {
data.is_copy = false;
if (element instanceof Mesh) {
data.pre_part_connections = MirrorModeling.discoverMeshPartConnections(element)
}
}
}
})
@ -372,15 +453,16 @@ Blockbench.on('finish_edit', ({aspects}) => {
aspects.elements = aspects.elements.slice();
let static_elements_copy = aspects.elements.slice();
static_elements_copy.forEach((element) => {
let cached_data = MirrorModeling.cached_elements[element.uuid]
if (element.allow_mirror_modeling && !element.locked) {
let is_centered = MirrorModeling.isCentered(element);
if (is_centered && element instanceof Mesh) {
// Complete other side of mesh
MirrorModeling.createLocalSymmetry(element);
MirrorModeling.createLocalSymmetry(element, cached_data);
}
if (is_centered) {
let mirror_element = MirrorModeling.cached_elements[element.uuid]?.counterpart;
let mirror_element = cached_data?.counterpart;
if (mirror_element && mirror_element.uuid != element.uuid) {
MirrorModeling.insertElementIntoUndo(mirror_element, Undo.current_save.aspects, mirror_element.getUndoCopy());
mirror_element.remove();
@ -424,7 +506,22 @@ BARS.defineActions(() => {
Project.mirror_modeling_enabled = this.value;
MirrorModeling.cached_elements = {};
updateSelection();
}
},
tool_config: new ToolConfig('mirror_modeling_options', {
title: 'action.mirror_modeling',
form: {
enabled: {type: 'checkbox', label: 'menu.mirror_painting.enabled', value: false},
mirror_uv: {type: 'checkbox', label: 'menu.mirror_modeling.mirror_uv', value: true}
},
onOpen() {
this.setFormValues({enabled: BarItems.mirror_modeling.value}, false);
},
onFormChange(formResult) {
if (BarItems.mirror_modeling.value != formResult.enabled) {
BarItems.mirror_modeling.trigger();
}
}
})
})
let allow_toggle = new Toggle('allow_element_mirror_modeling', {
icon: 'align_horizontal_center',

View File

@ -335,9 +335,9 @@ const Vertexsnap = {
let mode = BarItems.vertex_snap_mode.get();
function ignoreVectorAxes(vector) {
if (options.ignore_x) vector.x = 0;
if (options.ignore_y) vector.y = 0;
if (options.ignore_z) vector.z = 0;
if (options.ignore_axis?.x) vector.x = 0;
if (options.ignore_axis?.y) vector.y = 0;
if (options.ignore_axis?.z) vector.z = 0;
}
if (Vertexsnap.move_origin) {
@ -497,9 +497,7 @@ const Vertexsnap = {
y: tl('edit.vertex_snap.align.align_axis', 'Y'),
z: tl('edit.vertex_snap.align.align_axis', 'Z'),
}},
ignore_x: {type: 'checkbox', label: tl('edit.vertex_snap.ignore_axis', 'X'), value: false},
ignore_y: {type: 'checkbox', label: tl('edit.vertex_snap.ignore_axis', 'Y'), value: false},
ignore_z: {type: 'checkbox', label: tl('edit.vertex_snap.ignore_axis', 'Z'), value: false},
ignore_axis: {type: 'inline_multi_select', label: tl('edit.vertex_snap.ignore_axis', ''), options: {x: 'X', y: 'Y', z: 'Z'}, value: {x: false, y: false, z: false}},
}, form => {
Vertexsnap.snap(data, form, true);
})
@ -508,10 +506,6 @@ const Vertexsnap = {
}
//Center
function centerElementsAll(axis) {
centerElements(0, false);
centerElements(2, false);
}
function centerElements(axis, update) {
if (!Outliner.selected.length) return;
let center = getSelectionCenter()[axis];
@ -526,7 +520,7 @@ function centerElements(axis, update) {
}
})
Group.all.forEach(group => {
if (!Group.multi_selected) return;
if (!group.selected) return;
group.origin[axis] += difference;
})
Canvas.updateView({
@ -540,9 +534,9 @@ function centerElements(axis, update) {
//Move
function moveElementsInSpace(difference, axis) {
let space = Transformer.getTransformSpace()
let space = Transformer.getTransformSpace();
let groups;
if (Format.bone_rig && (Group.multi_selected.length > 1 || Group.first_selected.matchesSelection())) {
if (Format.bone_rig && Group.first_selected && (Group.multi_selected.length > 1 || Group.first_selected.matchesSelection())) {
groups = Group.multi_selected;
}
var group_m;
@ -733,7 +727,7 @@ function getRotationInterval(event) {
return 2.5;
}
}
function getRotationObject() {
function getRotationObjects() {
if (Format.bone_rig && Group.first_selected) return Group.multi_selected;
let elements = Outliner.selected.filter(element => {
return element.rotatable && (element instanceof Cube == false || Format.rotate_cubes);
@ -741,7 +735,7 @@ function getRotationObject() {
if (elements.length) return elements;
}
function rotateOnAxis(modify, axis, slider) {
var things = getRotationObject();
var things = getRotationObjects();
if (!things) return;
if (things instanceof Array == false) things = [things];
//Warning
@ -1329,7 +1323,7 @@ BARS.defineActions(function() {
description: tl('action.slider_rotation.desc', ['X']),
color: 'x',
category: 'transform',
condition: () => ((Modes.edit || Modes.pose) && getRotationObject()),
condition: () => ((Modes.edit || Modes.pose) && getRotationObjects()),
get: function() {
if (Format.bone_rig && Group.first_selected) {
return Group.first_selected.rotation[0];
@ -1348,7 +1342,7 @@ BARS.defineActions(function() {
},
onAfter: function() {
afterRotateOnAxis();
Undo.finishEdit(getRotationObject() instanceof Group ? 'Rotate group' : 'Rotate elements');
Undo.finishEdit(getRotationObjects()?.find(el => el instanceof Group) ? 'Rotate group' : 'Rotate elements');
},
getInterval: getRotationInterval
})
@ -1357,7 +1351,7 @@ BARS.defineActions(function() {
description: tl('action.slider_rotation.desc', ['Y']),
color: 'y',
category: 'transform',
condition: () => ((Modes.edit || Modes.pose) && getRotationObject()),
condition: () => ((Modes.edit || Modes.pose) && getRotationObjects()),
get: function() {
if (Format.bone_rig && Group.first_selected) {
return Group.first_selected.rotation[1];
@ -1376,7 +1370,7 @@ BARS.defineActions(function() {
},
onAfter: function() {
afterRotateOnAxis();
Undo.finishEdit(getRotationObject() instanceof Group ? 'Rotate group' : 'Rotate elements');
Undo.finishEdit(getRotationObjects()?.find(el => el instanceof Group) ? 'Rotate group' : 'Rotate elements');
},
getInterval: getRotationInterval
})
@ -1385,7 +1379,7 @@ BARS.defineActions(function() {
description: tl('action.slider_rotation.desc', ['Z']),
color: 'z',
category: 'transform',
condition: () => ((Modes.edit || Modes.pose) && getRotationObject()),
condition: () => ((Modes.edit || Modes.pose) && getRotationObjects()),
get: function() {
if (Format.bone_rig && Group.first_selected) {
return Group.first_selected.rotation[2];
@ -1404,7 +1398,7 @@ BARS.defineActions(function() {
},
onAfter: function() {
afterRotateOnAxis();
Undo.finishEdit(getRotationObject() instanceof Group ? 'Rotate group' : 'Rotate elements');
Undo.finishEdit(getRotationObjects()?.find(el => el instanceof Group) ? 'Rotate group' : 'Rotate elements');
},
getInterval: getRotationInterval
})
@ -1413,15 +1407,17 @@ BARS.defineActions(function() {
//Origin
function moveOriginOnAxis(modify, axis) {
var rotation_object = getRotationObject()
var rotation_objects = getRotationObjects()
if (rotation_object instanceof Group) {
var val = modify(rotation_object.origin[axis]);
rotation_object.origin[axis] = val;
if (rotation_objects && rotation_objects[0] instanceof Group) {
let elements_to_update = [];
rotation_object.forEachChild(element => elements_to_update.push(element), OutlinerElement);
for (let group of rotation_objects) {
let val = modify(group.origin[axis]);
group.origin[axis] = val;
group.forEachChild(element => elements_to_update.safePush(element), OutlinerElement);
}
Canvas.updateView({
groups: [rotation_object],
groups: rotation_objects,
group_aspects: {transform: true},
elements: elements_to_update,
element_aspects: {transform: true},
@ -1431,11 +1427,11 @@ BARS.defineActions(function() {
Canvas.updateAllBones();
}
} else {
rotation_object.forEach(function(obj, i) {
var val = modify(obj.origin[axis]);
rotation_objects.forEach(function(obj, i) {
let val = modify(obj.origin[axis]);
obj.origin[axis] = val;
})
Canvas.updateView({elements: rotation_object, element_aspects: {transform: true, geometry: true}, selection: true})
Canvas.updateView({elements: rotation_objects, element_aspects: {transform: true, geometry: true}, selection: true})
}
if (Modes.animate) {
Animator.preview();
@ -1446,7 +1442,7 @@ BARS.defineActions(function() {
description: tl('action.slider_origin.desc', ['X']),
color: 'x',
category: 'transform',
condition: () => (Modes.edit || Modes.animate || Modes.pose) && getRotationObject() && (Group.first_selected || Outliner.selected.length > Locator.selected.length),
condition: () => (Modes.edit || Modes.animate || Modes.pose) && getRotationObjects() && (Group.first_selected || Outliner.selected.length > Locator.selected.length),
getInterval: getSpatialInterval,
get: function() {
if (Format.bone_rig && Group.first_selected) {
@ -1473,7 +1469,7 @@ BARS.defineActions(function() {
description: tl('action.slider_origin.desc', ['Y']),
color: 'y',
category: 'transform',
condition: () => (Modes.edit || Modes.animate || Modes.pose) && getRotationObject() && (Group.first_selected || Outliner.selected.length > Locator.selected.length),
condition: () => (Modes.edit || Modes.animate || Modes.pose) && getRotationObjects() && (Group.first_selected || Outliner.selected.length > Locator.selected.length),
getInterval: getSpatialInterval,
get: function() {
if (Format.bone_rig && Group.first_selected) {
@ -1500,7 +1496,7 @@ BARS.defineActions(function() {
description: tl('action.slider_origin.desc', ['Z']),
color: 'z',
category: 'transform',
condition: () => (Modes.edit || Modes.animate || Modes.pose) && getRotationObject() && (Group.first_selected || Outliner.selected.length > Locator.selected.length),
condition: () => (Modes.edit || Modes.animate || Modes.pose) && getRotationObjects() && (Group.first_selected || Outliner.selected.length > Locator.selected.length),
getInterval: getSpatialInterval,
get: function() {
if (Format.bone_rig && Group.first_selected) {
@ -1615,7 +1611,7 @@ BARS.defineActions(function() {
category: 'transform',
click() {
Undo.initEdit({elements: Outliner.selected, outliner: true});
centerElements(0);
centerElements(0, true);
Undo.finishEdit('Center selection on X axis')
}
})
@ -1626,7 +1622,7 @@ BARS.defineActions(function() {
category: 'transform',
click() {
Undo.initEdit({elements: Outliner.selected, outliner: true});
centerElements(1);
centerElements(1, true);
Undo.finishEdit('Center selection on Y axis')
}
})
@ -1637,7 +1633,7 @@ BARS.defineActions(function() {
category: 'transform',
click() {
Undo.initEdit({elements: Outliner.selected, outliner: true});
centerElements(2);
centerElements(2, true);
Undo.finishEdit('Center selection on Z axis')
}
})
@ -1646,7 +1642,8 @@ BARS.defineActions(function() {
category: 'transform',
click() {
Undo.initEdit({elements: Outliner.selected, outliner: true});
centerElementsAll();
centerElements(0, false);
centerElements(2, true);
Undo.finishEdit('Center selection')
}
})
@ -1852,7 +1849,7 @@ BARS.defineActions(function() {
click() {
Undo.initEdit({outliner: true, elements: Outliner.selected})
for (let group of Group.all) {
if (!Group.multi_selected) continue;
if (!group.selected) continue;
let position = new THREE.Vector3();
let amount = 0;
group.children.forEach((obj) => {

View File

@ -805,7 +805,7 @@
scope.attach(element);
}
})
} else if (Group.first_selected && getRotationObject() == Group.first_selected) {
} else if (Group.first_selected && getRotationObjects()?.equals(Group.multi_selected)) {
scope.attach(Group.first_selected)
} else {
this.update()
@ -896,12 +896,12 @@
if (!scope.dragging) Transformer.rotation_selection.set(0, 0, 0);
if (Modes.edit || Modes.pose || Toolbox.selected.id == 'pivot_tool') {
if (Transformer.visible) {
var rotation_tool = Toolbox.selected.id === 'rotate_tool' || Toolbox.selected.id === 'pivot_tool'
var rotation_object = getRotationObject()
let rotation_tool = Toolbox.selected.id === 'rotate_tool' || Toolbox.selected.id === 'pivot_tool'
let rotation_object = getRotationObjects()
if (rotation_object instanceof Array || (!rotation_object && !rotation_tool)) {
var arr = rotation_object instanceof Array ? rotation_object : selected;
let arr = rotation_object instanceof Array ? rotation_object : Outliner.selected;
rotation_object = undefined;
for (var obj of arr) {
for (let obj of arr) {
if (obj.visibility !== false) {
rotation_object = obj;
break;
@ -1023,7 +1023,7 @@
}
this.cancelMovement = function(event, keep_changes = false) {
onPointerUp(event, keep_changes);
Undo.cancelEdit();
Undo.cancelEdit(true);
}
function displayDistance(number) {
Blockbench.setCursorTooltip(trimFloatNumber(number));
@ -1152,7 +1152,7 @@
}
})
}
_has_groups = Format.bone_rig && Group.first_selected && Group.first_selected.matchesSelection() && Toolbox.selected.transformerMode == 'translate';
_has_groups = Format.bone_rig && Group.first_selected && Toolbox.selected.transformerMode == 'translate';
var rotate_group = Format.bone_rig && Group.first_selected && (Toolbox.selected.transformerMode == 'rotate');
if (Toolbox.selected.id == 'move_tool') {

View File

@ -16,23 +16,43 @@ class Collection {
}
select(event) {
this.selected = true;
Outliner.selected.empty();
if (!(event?.shiftKey || Pressing.overrides.shift) && !(event?.ctrlOrCmd || Pressing.overrides.ctrl)) {
unselectAll();
if ((!(event?.shiftKey || Pressing.overrides.shift) && !(event?.ctrlOrCmd || Pressing.overrides.ctrl)) || Modes.animate) {
unselectAllElements();
Collection.all.forEach(c => c.selected = false);
}
this.selected = true;
for (let uuid of this.children) {
let node = OutlinerNode.uuids[uuid];
if (node instanceof Group) {
node.multiSelect();
let i = 0;
if (Modes.animate && Animation.selected && !(event?.ctrlOrCmd || Pressing.overrides.ctrl)) {
Timeline.animators.empty();
}
for (let node of this.getChildren()) {
if (Modes.animate && Animation.selected) {
if (node.constructor.animator) {
let animator = Animation.selected.getBoneAnimator(node);
if (animator) {
animator.addToTimeline(true);
}
if (i == 0) {
node.select();
}
}
} else {
Outliner.selected.push(node);
if (node instanceof Group) {
node.multiSelect();
} else {
Outliner.selected.safePush(node);
}
}
i++;
}
updateSelection();
return this;
}
clickSelect(event) {
Undo.initSelection({collections: true, timeline: Modes.animate});
this.select(event);
Undo.finishSelection('Select collection');
}
getChildren() {
return this.children.map(uuid => OutlinerNode.uuids[uuid]).filter(node => node != undefined);
}
@ -104,7 +124,7 @@ class Collection {
Undo.finishEdit('Toggle collection visibility');
}
showContextMenu(event) {
if (!this.selected) this.select();
if (!this.selected) this.clickSelect(event);
this.menu.open(event, this);
return this;
}
@ -119,7 +139,9 @@ class Collection {
return copy;
}
getSaveCopy() {
let copy = {};
let copy = {
uuid: this.uuid
};
for (var key in Collection.properties) {
Collection.properties[key].copy(this, copy);
}
@ -340,7 +362,7 @@ Object.defineProperty(Collection, 'all', {
})
Object.defineProperty(Collection, 'selected', {
get() {
return Project.collections.filter(c => c.selected);
return Project ? Project.collections.filter(c => c.selected) : [];
}
})
@ -400,7 +422,7 @@ BARS.defineActions(() => {
icon: 'inventory_2',
category: 'select',
keybind: new Keybind({key: 'l', ctrl: true}),
condition: {modes: ['edit', 'paint']},
condition: {modes: ['edit', 'paint', 'animate']},
click() {
Undo.initEdit({collections: []});
let collection = new Collection({});
@ -473,7 +495,7 @@ Interface.definePanels(function() {
float_size: [300, 300],
height: 300
},
condition: {modes: ['edit', 'paint']},
condition: {modes: ['edit', 'paint', 'animate'], method: () => (!Format.image_editor)},
toolbars: [
new Toolbar('collections', {
children: [
@ -637,7 +659,7 @@ Interface.definePanels(function() {
:key="collection.uuid"
:uuid="collection.uuid"
class="collection"
@click.stop="collection.select()"
@click.stop="collection.clickSelect($event)"
@dblclick.stop="collection.propertiesDialog()"
@contextmenu.prevent.stop="collection.showContextMenu($event)"
>

View File

@ -69,12 +69,12 @@ class Group extends OutlinerNode {
if (!event) event = true
var allSelected = Group.multi_selected.length == 1 && Group.first_selected === this && selected.length && this.matchesSelection();
let previous_first_selected = Project.selected_elements[0];
let multi_select = event.ctrlOrCmd || Pressing.overrides.ctrl;
let shift_select = event.shiftKey || Pressing.overrides.shift;
let multi_select = (event.ctrlOrCmd || Pressing.overrides.ctrl) && !Modes.animate;
let shift_select = (event.shiftKey || Pressing.overrides.shift) && !Modes.animate;
//Unselect others
if (!multi_select && !shift_select) {
unselectAll();
unselectAllElements();
Project.groups.forEach(function(s) {
s.selected = false;
})
@ -114,7 +114,7 @@ class Group extends OutlinerNode {
} else {
// Fix for #2401
if (previous_first_selected && previous_first_selected.isChildOf(this)) {
selected.push(previous_first_selected);
selected.safePush(previous_first_selected);
}
this.children.forEach(function(s) {
s.selectLow()
@ -126,6 +126,12 @@ class Group extends OutlinerNode {
updateSelection()
return this;
}
clickSelect(event, is_outliner_click) {
if (Blockbench.hasFlag('renaming') || this.locked) return this;
Undo.initSelection();
this.select(event, is_outliner_click);
Undo.finishSelection('Select group');
}
multiSelect() {
if (this.locked) return this;
this.selected = true;
@ -393,6 +399,7 @@ class Group extends OutlinerNode {
obj.locked = this.locked;
obj.visibility = this.visibility;
obj.autouv = this.autouv;
obj.selected = Group.multi_selected.includes(this);
}
if (this.rotation.allEqual(0)) {
@ -433,7 +440,7 @@ class Group extends OutlinerNode {
Group.prototype.icon = 'folder';
Group.prototype.isParent = true;
Group.prototype.rotatable = true;
Group.prototype.name_regex = () => Format.bone_rig ? 'a-zA-Z0-9_' : false;
Group.prototype.name_regex = () => Format.bone_rig ? (Format.node_name_regex ?? 'a-zA-Z0-9_') : false;
Group.prototype.buttons = [
Outliner.buttons.autouv,
Outliner.buttons.mirror_uv,
@ -447,7 +454,7 @@ class Group extends OutlinerNode {
let elements = Outliner.selected.filter(el => el.setColor)
Undo.initEdit({outliner: true, elements: elements, selection: true})
Group.all.forEach(group => {
if (Group.multi_selected) {
if (group.selected) {
group.color = color;
}
})
@ -471,7 +478,7 @@ class Group extends OutlinerNode {
}})
}},
"randomize_marker_colors",
{name: 'menu.cube.texture', icon: 'collections', condition: () => Format.per_group_texture, children(a, b, c) {
{name: 'menu.cube.texture', icon: 'collections', condition: () => Format.per_group_texture, children(context) {
function applyTexture(texture_value, undo_message) {
let affected_groups = Group.all.filter(g => g.selected);
Undo.initEdit({outliner: true});
@ -490,7 +497,7 @@ class Group extends OutlinerNode {
arr.push({
name: t.name,
icon: (t.mode === 'link' ? t.img : t.source),
marked: t.uuid == /*Group.multi_selected*/context.texture,
marked: t.uuid == context.texture,
click(group) {
applyTexture(t.uuid, 'Apply texture to group');
}
@ -516,7 +523,7 @@ class Group extends OutlinerNode {
})
Object.defineProperty(Group, 'multi_selected', {
get() {
return Project.selected_groups
return Project.selected_groups || []
},
set(arr) {
if (arr instanceof Array == false) {
@ -528,16 +535,20 @@ class Group extends OutlinerNode {
Object.defineProperty(Group, 'selected', {
get() {
console.warn('"Group.selected" will be an array in the future!');
return Project.selected_groups[0]
return Project.selected_groups?.[0]
},
set(group) {
console.warn('"Group.selected" will be an array in the future!');
Project.selected_groups.replace([groups]);
if (group instanceof Group) {
Project.selected_groups.replace([group]);
} else {
Project.selected_groups.empty();
}
}
})
Object.defineProperty(Group, 'first_selected', {
get() {
return Project.selected_groups[0]
return Project.selected_groups?.[0]
},
set(group) {
Project.selected_groups.replace([groups]);
@ -552,7 +563,7 @@ new Property(Group, 'string', 'bedrock_binding', {condition: {formats: ['bedrock
new Property(Group, 'array', 'cem_animations', {condition: {formats: ['optifine_entity']}});
new Property(Group, 'boolean', 'cem_attach', {condition: {formats: ['optifine_entity']}});
new Property(Group, 'number', 'cem_scale', {condition: {formats: ['optifine_entity']}});
new Property(Group, 'string', 'texture', {condition: {formats: ['optifine_entity']}});
new Property(Group, 'string', 'texture', {condition: {features: ['per_group_texture']}});
//new Property(Group, 'vector2', 'texture_size', {condition: {formats: ['optifine_entity']}});
new Property(Group, 'vector', 'skin_original_origin', {condition: {formats: ['skin']}});
new Property(Group, 'number', 'color');
@ -669,7 +680,9 @@ BARS.defineActions(function() {
base_group.createUniqueName()
}
if (add_group instanceof Group) {
add_group.addTo(base_group);
for (let group of Group.multi_selected) {
group.addTo(base_group);
}
} else if (add_group instanceof OutlinerElement) {
Outliner.selected.forEach(function(s, i) {
s.addTo(base_group);
@ -726,7 +739,7 @@ BARS.defineActions(function() {
showPresetMenu(event) {
new Menu([
{
name: 'Main Hand',
name: 'Item Slot',
icon: 'build',
click: () => {
this.binding = 'q.item_slot_to_bone_name(c.item_slot)';
@ -796,11 +809,19 @@ BARS.defineActions(function() {
icon: 'fa-leaf',
condition: {modes: ['edit'], method: () => Group.first_selected},
click() {
let all_elements = [];
for (let group of Group.multi_selected) {
group.forEachChild(obj => {
if (obj instanceof Group == false) {
all_elements.safePush(obj);
}
})
}
Undo.initEdit({outliner: true, elements: all_elements})
for (let group of Group.multi_selected) {
group.resolve(false);
}
Undo.finishEdit('Resolve group')
Undo.finishEdit('Resolve group');
}
})
})

View File

@ -78,7 +78,7 @@ class Locator extends OutlinerElement {
Locator.prototype.title = tl('data.locator');
Locator.prototype.type = 'locator';
Locator.prototype.icon = 'fa-anchor';
Locator.prototype.name_regex = 'a-z0-9_'
Locator.prototype.name_regex = () => Format.node_name_regex ?? 'a-zA-Z0-9_',
Locator.prototype.movable = true;
Locator.prototype.rotatable = true;
Locator.prototype.visibility = true;

View File

@ -31,19 +31,16 @@ class MeshFace extends Face {
}
return this;
}
getNormal(normalize) {
getNormal(normalize, alt_tri) {
let vertices = this.getSortedVertices();
if (vertices.length < 3) return [0, 0, 0];
let a = [
this.mesh.vertices[vertices[1]][0] - this.mesh.vertices[vertices[0]][0],
this.mesh.vertices[vertices[1]][1] - this.mesh.vertices[vertices[0]][1],
this.mesh.vertices[vertices[1]][2] - this.mesh.vertices[vertices[0]][2],
]
let b = [
this.mesh.vertices[vertices[2]][0] - this.mesh.vertices[vertices[0]][0],
this.mesh.vertices[vertices[2]][1] - this.mesh.vertices[vertices[0]][1],
this.mesh.vertices[vertices[2]][2] - this.mesh.vertices[vertices[0]][2],
]
let indices = [0, 1, 2];
if (vertices.length == 4 && alt_tri) {
indices = [0, 2, 3];
}
let base = this.mesh.vertices[vertices[indices[0]]];
let a = this.mesh.vertices[vertices[indices[1]]].slice().V3_subtract(base);
let b = this.mesh.vertices[vertices[indices[2]]].slice().V3_subtract(base);
let direction = [
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
@ -1139,6 +1136,10 @@ new NodePreviewController(Mesh, {
Mesh.preview_controller.updatePixelGrid(element);
if (Project.view_mode == 'wireframe' && this.fixWireframe) {
this.fixWireframe(element);
}
this.dispatchEvent('update_geometry', {element});
},
updateFaces(element) {
@ -1450,5 +1451,20 @@ new NodePreviewController(Mesh, {
mesh.add(box);
this.dispatchEvent('update_painting_grid', {element});
},
fixWireframe(element) {
let geometry_orig = element.mesh.geometry;
if (!geometry_orig) return;
let geometry_clone = element.mesh.geometry.clone();
element.mesh.geometry = geometry_clone;
geometry_orig.dispose();
}
})
Blockbench.dispatchEvent('change_view_mode', ({view_mode}) => {
if (view_mode == 'wireframe') {
for (let mesh of Mesh.selected) {
Mesh.preview_controller.fixWireframe(mesh);
}
}
});

View File

@ -16,15 +16,15 @@ const Outliner = {
visibility: {
id: 'visibility',
title: tl('switches.visibility'),
icon: ' fa fa-eye',
icon_off: ' fa fa-eye-slash',
icon: 'visibility',
icon_off: 'visibility_off',
advanced_option: false
},
locked: {
id: 'locked',
title: tl('switches.lock'),
icon: ' fas fa-lock',
icon_off: ' fas fa-lock-open',
icon: 'fa-lock',
icon_off: 'fa-lock-open',
advanced_option: true,
visibilityException(node) {
return node.locked
@ -33,8 +33,8 @@ const Outliner = {
export: {
id: 'export',
title: tl('switches.export'),
icon: ' far fa-square-check',
icon_off: ' far fa-window-close',
icon: 'far.fa-square-check',
icon_off: 'far.fa-window-close',
advanced_option: true,
condition: {modes: ['edit']},
visibilityException(node) {
@ -45,24 +45,24 @@ const Outliner = {
id: 'shade',
condition: {modes: ['edit'], features: ['java_cube_shading_properties']},
title: tl('switches.shade'),
icon: 'fa fa-star',
icon_off: 'far fa-star',
icon: 'fa-star',
icon_off: 'far.fa-star',
advanced_option: true,
},
mirror_uv: {
id: 'mirror_uv',
condition: {modes: ['edit'], method: (element) => (element instanceof Group) ? element.children.find(c => c.box_uv) : element.box_uv},
title: tl('switches.mirror'),
icon: 'icon-mirror_x icon',
icon_off: 'icon-mirror_x icon',
icon: 'icon-mirror_x',
icon_off: 'icon-mirror_x',
advanced_option: true,
},
autouv: {
id: 'autouv',
title: tl('switches.autouv'),
icon: ' fa fa-thumbtack',
icon_off: ' far fa-times-circle',
icon_alt: ' fa fa-magic',
icon: 'fa-thumbtack',
icon_off: 'far.fa-times-circle',
icon_alt: 'fa-magic',
advanced_option: true,
condition: {modes: ['edit']},
getState(element) {
@ -379,7 +379,7 @@ class OutlinerElement extends OutlinerNode {
showContextMenu(event) {
if (this.locked) return this;
if (!this.selected) {
this.select()
this.clickSelect(event)
}
this.menu.open(event, this)
return this;
@ -441,6 +441,7 @@ class OutlinerElement extends OutlinerNode {
Blockbench.showQuickMessage('message.group_required_to_animate');
return false;
}
Undo.initSelection();
//Shift
var just_selected = [];
let allow_multi_select = (!Modes.paint || (Toolbox.selected.id == 'fill_tool' && BarItems.fill_mode.value == 'selected_elements'));
@ -487,23 +488,26 @@ class OutlinerElement extends OutlinerNode {
//Normal
} else {
unselectAll()
unselectAllElements([this]);
this.selectLow()
just_selected.push(this)
if (settings.outliner_reveal_on_select.value) {
this.showInOutliner()
}
}
for (let group of Group.multi_selected) {
group.unselect();
}
Group.all.forEach(function(s) {
s.selected = false;
})
Blockbench.dispatchEvent('added_to_selection', {added: just_selected})
TickUpdates.selection = true;
return this;
}
clickSelect(event, outliner_click) {
Undo.initSelection();
let result = this.select(event, outliner_click);
if (result === false) {
Undo.cancelSelection();
return;
}
Undo.finishSelection('Select element');
}
selectLow() {
Project.selected_elements.safePush(this);
this.selected = true;
@ -796,7 +800,8 @@ function parseGroups(array, import_reference, startIndex) {
OutlinerNode.uuids[array[i].uuid].removeFromParent();
delete OutlinerNode.uuids[array[i].uuid];
}
var obj = new Group(array[i], array[i].uuid)
// todo: Update old groups instead of rebuilding all
let obj = new Group(array[i], array[i].uuid)
obj.parent = addGroup
obj.isOpen = !!array[i].isOpen
if (array[i].uuid) {
@ -810,6 +815,9 @@ function parseGroups(array, import_reference, startIndex) {
if (array[i].content && array[i].content.length > 0) {
iterate(array[i].content, obj.children, obj)
}
if (array[i].selected) {
obj.multiSelect();
}
}
i++;
}
@ -840,20 +848,20 @@ function moveOutlinerSelectionTo(item, target, event, order) {
iterate(target)
if (is_parent) return;
}
if (item instanceof OutlinerElement && Outliner.selected.includes( item )) {
if (item instanceof OutlinerNode && item.selected) {
var items = [];
// ensure elements are in displayed order
Outliner.root.forEach(node => {
if (node instanceof Group) {
node.forEachChild(child => {
if (child.selected && child instanceof Group == false) items.push(child);
})
if (child.selected && !child.parent.selected && (target instanceof OutlinerNode == false || !target.isChildOf?.(child))) {
items.push(child);
}
}, null, true);
} else if (node.selected) {
items.push(node);
}
})
} else if (item instanceof Group) {
var items = Group.multi_selected.filter(g => !g.parent.selected);
} else {
var items = [item];
}
@ -878,6 +886,9 @@ function moveOutlinerSelectionTo(item, target, event, order) {
}
} else {
item.preview_controller.updateTransform(item);
if (Format.per_group_texture && item.preview_controller.updateFaces) {
item.preview_controller.updateFaces(item);
}
}
}
}
@ -1031,7 +1042,7 @@ SharedActions.add('delete', {
priority: -1,
run() {
let array;
Undo.initEdit({elements: selected, outliner: true, selection: true})
Undo.initEdit({elements: Outliner.selected, outliner: true, selection: true})
if (array == undefined) {
array = selected.slice(0);
} else if (array.constructor !== Array) {
@ -1063,12 +1074,16 @@ SharedActions.add('duplicate', {
}
let all_new = [];
for (let group of Group.multi_selected) {
let old_selected_groups = Group.multi_selected.slice();
Group.multi_selected.empty();
for (let group of old_selected_groups) {
group.selected = false;
let new_group = group.duplicate();
new_group.forEachChild(g => all_new.push(g), Group, true);
new_group.multiSelect();
}
new_group.multiSelect();
updateSelection();
Undo.finishEdit('Duplicate group', {outliner: true, elements: elements.slice().slice(cubes_before), selection: true});
if (Animation.all.length) {
@ -1120,18 +1135,22 @@ SharedActions.add('select_all', {
condition: () => Modes.edit || Modes.paint,
priority: -2,
run() {
Undo.initSelection();
let selectable_elements = Outliner.elements.filter(element => !element.locked);
if (Outliner.selected.length < selectable_elements.length) {
if (Outliner.root.length == 1 && !Outliner.root[0].locked) {
Outliner.root[0].select();
} else {
selectable_elements.forEach(obj => {
obj.selectLow()
})
TickUpdates.selection = true;
for (let node of Outliner.root) {
if (node instanceof Group) {
node.multiSelect();
}
}
selectable_elements.forEach(obj => {
obj.selectLow()
})
TickUpdates.selection = true;
Undo.finishSelection('Select all elements');
} else {
unselectAllElements()
Undo.finishSelection('Unselect all elements');
}
}
})
@ -1140,7 +1159,9 @@ SharedActions.add('unselect_all', {
condition: () => Modes.edit || Modes.paint,
priority: -2,
run() {
unselectAllElements()
Undo.initSelection();
unselectAllElements();
Undo.finishSelection('Unselect all elements');
}
})
SharedActions.add('invert_selection', {
@ -1227,7 +1248,7 @@ BARS.defineActions(function() {
if (Animator.open) {
var sel = 0;
for (let group of Group.all) {
if (Group.multi_selected) sel++;
if (group.selected) sel++;
}
this.set(stringifyLargeInt(sel)+' / '+stringifyLargeInt(Group.all.length));
} else {
@ -1436,7 +1457,7 @@ Interface.definePanels(function() {
class="outliner_object"
v-bind:class="{ cube: node.type === 'cube', group: node.type === 'group', selected: node.selected }"
@contextmenu.prevent.stop="node.showContextMenu($event)"
@click="node.select($event, true)"
@click="node.clickSelect($event, true)"
:title="node.title"
@dblclick.stop.self="!node.locked && renameOutliner()"
>` +
@ -1453,14 +1474,15 @@ Interface.definePanels(function() {
<input type="text" class="cube_name tab_target" :class="{locked: node.locked}" v-model="node.name" disabled>` +
`<i v-for="btn in node.buttons"
`<dynamic-icon v-for="btn in node.buttons"
v-if="Condition(btn, node) && (!btn.advanced_option || options.show_advanced_toggles || (btn.visibilityException && btn.visibilityException(node)) )"
class="outliner_toggle"
:class="getBtnClasses(btn, node)"
:icon="getButtonIcon(btn, node)"
:class="getButtonClasses(btn, node)"
:title="getBtnTooltip(btn, node)"
:toggle="btn.id"
@click.stop
></i>` +
/>` +
'</div>' +
//Other Entries
'<ul v-if="node.isOpen">' +
@ -1504,14 +1526,26 @@ Interface.definePanels(function() {
return node.closedIcon || node.icon;
}
},
getBtnClasses: function (btn, node) {
getButtonIcon: function (btn, node) {
let value = node.isIconEnabled(btn);
let icon_string = '';
if (value === true) {
icon_string = typeof btn.icon == 'function' ? btn.icon(node) : btn.icon;
} else if (value === false) {
icon_string = typeof btn.icon_off == 'function' ? btn.icon_off(node) : btn.icon_off
} else {
icon_string = typeof btn.icon_alt == 'function' ? btn.icon_alt(node) : btn.icon_alt
}
return icon_string.trim().replace(/fa[rs]* /, '');
},
getButtonClasses: function (btn, node) {
let value = node.isIconEnabled(btn);
if (value === true) {
return [(typeof btn.icon == 'function' ? btn.icon(node) : btn.icon)];
return ''
} else if (value === false) {
return [(typeof btn.icon_off == 'function' ? btn.icon_off(node) : btn.icon_off), 'icon_off'];
return 'icon_off';
} else {
return [(typeof btn.icon_alt == 'function' ? btn.icon_alt(node) : btn.icon_alt), 'icon_alt'];
return 'icon_alt';
}
},
getBtnTooltip: function (btn, node) {
@ -1709,7 +1743,11 @@ Interface.definePanels(function() {
function off(e2) {
removeEventListeners(document, 'mouseup touchend', off);
if (e1.target && e1.offsetX > e1.target.clientWidth) return;
if (e2.target && e2.target.id == 'cubes_list') unselectAllElements();
if (e2.target && e2.target.id == 'cubes_list') {
Undo.initSelection({});
unselectAllElements();
Undo.finishSelection('Unselect outliner');
}
}
addEventListeners(document, 'mouseup touchend', off);
return;

View File

@ -405,7 +405,7 @@ class Plugin {
Plugins.sort()
// Save
if (isApp) {
await new Promise((resolve) => {
await new Promise((resolve, reject) => {
let file = originalFs.createWriteStream(Plugins.path+this.id+'.js')
https.get(url, (response) => {
response.pipe(file);

View File

@ -1,4 +1,6 @@
/**
* Original source: https://github.com/mrdoob/three.js, MIT
* Modified for Blockbench
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
* @author alteredq / http://alteredqualia.com/
@ -298,6 +300,10 @@ THREE.OrbitControls = function ( object, preview ) {
}();
this.panLeft = panLeft;
this.panUp = panUp;
// deltaX and deltaY are in pixels; right and down are positive
var pan = function () {

View File

@ -118,11 +118,14 @@ const Canvas = {
gizmos: [rot_origin],
outlineMaterial: new THREE.LineBasicMaterial({
linewidth: 2,
depthTest: settings.seethrough_outline.value == false,
transparent: true,
color: gizmo_colors.outline
}),
meshOutlineMaterial: new THREE.LineBasicMaterial({
linewidth: 2,
depthTest: settings.seethrough_outline.value == false,
transparent: true,
//color: gizmo_colors.outline,
vertexColors: true
}),
@ -1391,6 +1394,20 @@ const Canvas = {
if (height === Infinity) height = 0;
return [width, height]
},
getSelectionBounds() {
let pivot_marker_parent = Canvas.pivot_marker.parent;
let visible_box = new THREE.Box3();
if (pivot_marker_parent) pivot_marker_parent.remove(Canvas.pivot_marker);
Canvas.withoutGizmos(() => {
Outliner.selected.forEach(element => {
if (element.visibility && element.mesh && element.mesh.geometry) {
visible_box.expandByObject(element.mesh);
}
})
})
if (pivot_marker_parent) pivot_marker_parent.add(Canvas.pivot_marker);
return visible_box;
}
}
var buildGrid = Canvas.buildGrid;

View File

@ -412,6 +412,11 @@ class Preview {
} else {
intersects.sort((a, b) => a.distance - b.distance);
}
if (settings.seethrough_outline.value && BarItems.selection_mode.value == 'edge') {
let all_intersects = intersects;
intersects = intersects.filter(a => a.object.isLine);
if (intersects.length == 0) intersects = all_intersects;
}
let intersect = intersects[0];
let intersect_object = intersect.object;
@ -800,6 +805,7 @@ class Preview {
}
if (Toolbox.selected.selectElements && Modes.selected.selectElements && (data.type === 'element' || Toolbox.selected.id == 'knife_tool')) {
Undo.initSelection();
if (Toolbox.selected.selectFace && data.face && data.element.type != 'mesh') {
let face_selection = UVEditor.getSelectedFaces(data.element, true);
if (data.element.selected && (multi_select || group_select)) {
@ -952,14 +958,19 @@ class Preview {
} else {
data.element.select(event);
}
Undo.finishSelection('Select from viewport');
} else if (Animator.open && data.type == 'keyframe') {
if (data.keyframe instanceof Keyframe) {
Undo.initSelection({timeline: true});
data.keyframe.select(event).callPlayhead();
updateSelection();
Undo.finishSelection('Select keyframe');
}
} else if (data.type == 'vertex' && Toolbox.selected.id !== 'vertex_snap_tool') {
Undo.initSelection();
let list = data.element.getSelectedVertices(true);
let edges = data.element.getSelectedEdges(true);
let faces = data.element.getSelectedEdges(true);
@ -973,8 +984,11 @@ class Preview {
faces.empty();
}
updateSelection();
Undo.finishSelection('Select vertex');
} else if (data.type == 'line') {
Undo.initSelection();
let vertices = data.element.getSelectedVertices(true);
let edges = data.element.getSelectedEdges(true);
let faces = data.element.getSelectedFaces(true);
@ -1050,6 +1064,7 @@ class Preview {
splitFace(start_face, data.vertices);
}
updateSelection();
Undo.finishSelection('Select edge');
}
if (typeof Toolbox.selected.onCanvasClick === 'function') {
Toolbox.selected.onCanvasClick(data)
@ -1122,7 +1137,12 @@ class Preview {
brush_coord.x += 8;
brush_coord.z += 8;
}
brush_matrix.multiplyMatrices(intersect.object.parent.matrixWorld, brush_matrix);
// Size
let scale = new THREE.Vector3(BarItems.slider_brush_size.get(), BarItems.slider_brush_size.get(), 1);
brush_matrix.scale(scale);
brush_matrix.multiplyMatrices(intersect.object.matrixWorld, brush_matrix);
// Z-fighting
let z_fight_offset = Preview.selected.calculateControlScale(brush_coord) / 8;
@ -1135,11 +1155,9 @@ class Preview {
let matrix_offset = new THREE.Matrix4().makeTranslation(z_offset.x, z_offset.y, z_offset.z);
brush_matrix.multiplyMatrices(matrix_offset, brush_matrix);
// Size
let scale = new THREE.Vector3(BarItems.slider_brush_size.get(), BarItems.slider_brush_size.get(), 1);
brush_matrix.scale(scale);
brush_matrix.multiplyMatrices(intersect.object.matrix, brush_matrix);
// Since we're setting the brush matrix, we need to multiply in its parents matrix as well in case there are any.
if (Canvas.brush_outline.parent)
brush_matrix.multiplyMatrices(Canvas.brush_outline.parent.matrixWorld.clone().invert(), brush_matrix);
Canvas.brush_outline.matrix = brush_matrix;
}
@ -1276,7 +1294,8 @@ class Preview {
this.selection.old_selected = Outliner.selected.slice();
this.selection.old_mesh_selection = JSON.parse(JSON.stringify(Project.mesh_selection));
this.moveSelRect(event)
Undo.initSelection();
this.moveSelRect(event);
}
}
@ -1480,6 +1499,7 @@ class Preview {
delete this.sr_stop_f;
this.selection.box.detach()
this.selection.activated = false;
Undo.finishSelection('Area select');
}
// Background
loadBackground() {
@ -1728,6 +1748,7 @@ Preview.split_screen = {
Blockbench.on('update_camera_position', e => {
let scale = Preview.selected.calculateControlScale(Transformer.position) || 0.8;
if (Blockbench.isTouch) scale *= 1.5;
scale *= (settings.selection_tolerance.value / 10);
Preview.all.forEach(preview => {
if (preview.canvas.isConnected) {
preview.raycaster.params.Points.threshold = scale * 0.8;
@ -1919,13 +1940,19 @@ class OrbitGizmo {
window.addEventListener("gamepadconnected", function(event) {
if (event.gamepad.id.includes('SpaceMouse') || event.gamepad.id.includes('SpaceNavigator') || event.gamepad.id.includes('3Dconnexion')) {
let is_space_mouse = event.gamepad.id.includes('SpaceMouse') || event.gamepad.id.includes('SpaceNavigator') || event.gamepad.id.includes('3Dconnexion');
let interval = setInterval(() => {
let gamepad = navigator.getGamepads()[event.gamepad.index];
let preview = Preview.selected;
if (!document.hasFocus() || !preview || !gamepad || !gamepad.axes || gamepad.axes.allEqual(0) || gamepad.axes.find(v => isNaN(v)) != undefined) return;
console.log('Gamepad Connected', event);
let zoom_timer = 0;
let interval = setInterval(() => {
let gamepad = navigator.getGamepads()[event.gamepad.index];
let preview = Preview.selected;
if (settings.gamepad_controls.value == false) return;
if (!document.hasFocus() || !preview || !gamepad || !gamepad.axes || !gamepad.connected || gamepad.axes.allEqual(0) || gamepad.axes.find(v => isNaN(v)) != undefined) return;
if (is_space_mouse) {
let offset = new THREE.Vector3(
gamepad.axes[0],
-gamepad.axes[2],
@ -1951,15 +1978,37 @@ window.addEventListener("gamepadconnected", function(event) {
preview.controls.target.copy(camera_diff).add(preview.camera.position);
main_preview.controls.updateSceneScale();
} else {
let drift_threshold = 0.2;
let axes = gamepad.axes.map(v => Math.abs(v) > drift_threshold ? v - drift_threshold * Math.sign(v) : 0);
let camera_matrix = preview.camera.matrixWorld;
let rotate_speed = settings.viewport_rotate_speed.value / 100;
let zoom_speed = settings.viewport_zoom_speed.value / 100;
}, 16)
if (axes[0]) preview.controls.rotateLeft(Math.signedPow(axes[0]) / 8 * rotate_speed);
if (axes[1]) preview.controls.rotateUp(Math.signedPow(axes[1]) / 8 * rotate_speed);
if (axes[2]) preview.controls.panLeft(Math.signedPow(axes[2]) * 1.5, camera_matrix);
if (axes[3]) preview.controls.panUp(Math.signedPow(axes[3]) * 1.5, camera_matrix);
window.addEventListener("gamepadconnected", function(event2) {
if (event2.gamepad.id == event.gamepad.id && event2.gamepad.index == event.gamepad.index) {
clearInterval(interval);
let smooth_zoom = 1-Math.exp(-zoom_timer/10)
if (gamepad.buttons[6]?.pressed) {
preview.controls.dollyOut(1 + 0.03 * zoom_speed * smooth_zoom);
zoom_timer++;
} else if (gamepad.buttons[7]?.pressed) {
preview.controls.dollyIn(1 + 0.03 * zoom_speed * smooth_zoom);
zoom_timer++;
} else {
zoom_timer = 0;
}
})
}
}
}, 16)
window.addEventListener("gamepadconnected", function(event2) {
if (event2.gamepad.id == event.gamepad.id && event2.gamepad.index == event.gamepad.index) {
clearInterval(interval);
}
})
});
//Init/Update
@ -2074,6 +2123,7 @@ function updateShading() {
Sun.intensity = settings_brightness;
let view_mode = window.BarItems ? BarItems.view_mode.value : 'textured';
lights.add(Sun);
if (view_mode == 'material') {
let light = Canvas.material_light;
@ -2106,11 +2156,12 @@ function updateShading() {
let parent = scene;
parent.add(lights);
lights.position.copy(parent.position).multiplyScalar(-1);
} else {
Canvas.scene.add(Sun);
}
if (Canvas.material_light) {
Canvas.scene.remove(Canvas.material_light);
}
lights.add(Sun);
Texture.all.forEach(tex => {
let material = tex.getMaterial();
if (!material.uniforms) return;
@ -2158,6 +2209,7 @@ BARS.defineActions(function() {
material: {name: true, icon: 'pages', condition: () => ((!Toolbox.selected.allowed_view_modes || Toolbox.selected.allowed_view_modes.includes('material')) && TextureGroup.all.find(tg => tg.is_material))},
},
onChange() {
let previous_view_mode = Project.view_mode;
Project.view_mode = this.value;
Canvas.updateViewMode();
if (Modes.id === 'animate') {
@ -2170,6 +2222,9 @@ BARS.defineActions(function() {
if (icon_node) icon_node.replaceWith(icon);
}
})
if (Project.view_mode != previous_view_mode) {
Blockbench.dispatchEvent('change_view_mode', {view_mode: Project.view_mode, previous_view_mode});
}
//Blockbench.showQuickMessage(tl('action.view_mode') + ': ' + tl('action.view_mode.' + this.value));
}
})
@ -2257,14 +2312,19 @@ BARS.defineActions(function() {
icon: 'center_focus_weak',
category: 'view',
condition: () => !Format.image_editor,
keybind: new Keybind({}, {rotate_only: 'shift'}),
keybind: new Keybind({}, {
rotate_only: 'shift',
zoom: 'ctrl'
}),
variations: {
rotate_only: {name: 'action.focus_on_selection.rotate_only'}
rotate_only: {name: 'action.focus_on_selection.rotate_only'},
zoom: {name: 'action.focus_on_selection.zoom'}
},
click(event = 0) {
if (!Project) return;
let zoom = this.keybind.additionalModifierTriggered(event, 'zoom');
if (Prop.active_panel == 'uv') {
UVEditor.focusOnSelection()
UVEditor.focusOnSelection(zoom)
} else {
let preview = Preview.selected;
@ -2277,8 +2337,26 @@ BARS.defineActions(function() {
Transformer.getWorldPosition(center)
}
let zoom_offset;
let difference = new THREE.Vector3().copy(preview.controls.target).sub(center);
difference.divideScalar(6)
let cam_boom = center.clone().sub(preview.camera.position).add(difference);
difference.divideScalar(6);
if (zoom) {
let bounds = Canvas.getSelectionBounds();
let radius = Math.max(
Math.abs(bounds.min.x-center.x), Math.abs(bounds.max.x-center.x),
Math.abs(bounds.min.z-center.z), Math.abs(bounds.max.z-center.z),
);
let height = Math.max(Math.abs(bounds.min.y-center.y), Math.abs(bounds.max.y-center.y));
if (Math.abs(height) != Infinity) {
let focal_length = preview.camera.getFocalLength();
let cam_distance = cam_boom.length();
let target_distance = Math.max(radius, height) * (focal_length / 10);
zoom_factor = target_distance / cam_distance;
zoom_offset = cam_boom.multiplyScalar((zoom_factor-1) / 6);
}
}
let i = 0;
let interval = setInterval(() => {
@ -2287,6 +2365,10 @@ BARS.defineActions(function() {
if (this.keybind.additionalModifierTriggered(event) != 'rotate_only' || preview.angle != null) {
preview.camera.position.sub(difference);
}
if (zoom_offset) {
preview.camera.position.sub(zoom_offset);
}
Transformer.update();
i++;
if (i == 6) clearInterval(interval);

View File

@ -39,7 +39,11 @@ class PreviewScene {
this.cubemap = null;
if (data.cubemap) {
let urls = data.cubemap;
let texture_cube = new THREE.CubeTextureLoader().load( urls );
let texture_cube = new THREE.CubeTextureLoader().load(urls, () => {
if (PreviewScene.active == this && Project.view_mode == 'material') {
Canvas.updateShading();
}
});
texture_cube.colorSpace = THREE.SRGBColorSpace;
texture_cube.mapping = THREE.CubeRefractionMapping;
this.cubemap = texture_cube;
@ -106,9 +110,6 @@ class PreviewScene {
Canvas.global_light_side = this.light_side;
Canvas.scene.background = this.cubemap;
Canvas.scene.fog = this.fog;
let pmremGenerator = new THREE.PMREMGenerator( Preview.selected.renderer );
Canvas.scene.environment = pmremGenerator.fromCubemap(this.cubemap).texture;
if (this.fov && !(Modes.display && display_slot.startsWith('firstperson'))) {
Preview.selected.setFOV(this.fov);

View File

@ -349,14 +349,19 @@ class ReferenceImage {
(e2.clientX - e1.clientX) * multiplier,
(e2.clientY - e1.clientY) * multiplier,
];
this.size[0] = Math.max(original_size[0] + offset[0] * sign_x, 48);
let zoom_level = this.getZoomLevel();
let max_size = [
32 / zoom_level,
24 / zoom_level
];
this.size[0] = Math.max(original_size[0] + offset[0] * sign_x, max_size[0]);
this.position[0] = original_position[0] + offset[0] / 2, 0;
if (!e2.ctrlOrCmd && !Pressing.overrides.ctrl) {
offset[1] = sign_y * (this.size[0] / this.aspect_ratio - original_size[1]);
}
this.size[1] = Math.max(original_size[1] + offset[1] * sign_y, 32);
this.size[1] = Math.max(original_size[1] + offset[1] * sign_y, max_size[1]);
this.position[1] = original_position[1] + offset[1] / 2, 0;
if (this.layer !== 'blueprint') {

View File

@ -123,7 +123,7 @@ BARS.defineActions(function() {
Undo.finishEdit('Adjust brightness and contrast');
},
onCancel() {
Undo.cancelEdit();
Undo.cancelEdit(true);
}
}).show();
}
@ -218,7 +218,7 @@ BARS.defineActions(function() {
Undo.finishEdit('Adjust saturation and hue');
},
onCancel() {
Undo.cancelEdit();
Undo.cancelEdit(true);
}
}).show();
}
@ -500,7 +500,7 @@ BARS.defineActions(function() {
Undo.finishEdit('Adjust curves');
},
onCancel() {
Undo.cancelEdit();
Undo.cancelEdit(true);
}
}).show();
}
@ -596,7 +596,7 @@ BARS.defineActions(function() {
Undo.finishEdit('Adjust opacity');
},
onCancel() {
Undo.cancelEdit();
Undo.cancelEdit(true);
}
}).show();
}
@ -643,6 +643,43 @@ BARS.defineActions(function() {
Undo.finishEdit('Limit texture to palette')
}
})
new Action('split_rgb_into_layers', {
icon: 'stacked_bar_chart',
category: 'textures',
condition: {modes: ['paint'], selected: {texture: true}},
click() {
let texture = Texture.getDefault();
let original_data = texture.ctx.getImageData(0, 0, texture.canvas.width, texture.canvas.height);
Undo.initEdit({textures: [texture], bitmap: true});
texture.layers_enabled = true;
let i = 0;
for (let color of ['red', 'green', 'blue']) {
data_copy = new ImageData(original_data.data.slice(), original_data.width, original_data.height);
for (let j = 0; j < data_copy.data.length; j += 4) {
if (i != 0) data_copy.data[j+0] = 0;
if (i != 1) data_copy.data[j+1] = 0;
if (i != 2) data_copy.data[j+2] = 0;
}
let layer = new TextureLayer({
name: color,
blend_mode: 'add'
}, texture);
layer.setSize(original_data.width, original_data.height);
layer.ctx.putImageData(data_copy, 0, 0);
texture.layers.unshift(layer);
if (color == 'red') {
layer.select();
}
i++;
}
texture.updateLayerChanges(true);
Undo.finishEdit('Split texture into RGB layers');
updateInterfacePanels();
BARS.updateConditions();
}
})
new Action('clear_unused_texture_space', {
icon: 'cleaning_services',
category: 'textures',

View File

@ -58,8 +58,13 @@ class TextureLayer {
BarItems.layer_opacity.update();
BarItems.layer_blend_mode.set(this.blend_mode);
}
clickSelect(event) {
Undo.initSelection();
this.select(event);
Undo.finishSelection();
}
showContextMenu(event) {
if (!this.selected) this.select();
if (!this.selected) this.clickSelect(event);
this.menu.open(event, this);
}
remove(undo) {
@ -359,7 +364,7 @@ new Property(TextureLayer, 'vector2', 'offset');
new Property(TextureLayer, 'vector2', 'scale', {default: [1, 1]});
new Property(TextureLayer, 'number', 'opacity', {default: 100});
new Property(TextureLayer, 'boolean', 'visible', {default: true});
new Property(TextureLayer, 'enum', 'blend_mode', {default: 'default', values: ['default', 'set_opacity', 'color', 'multiply', 'add', 'screen', 'difference']});
new Property(TextureLayer, 'enum', 'blend_mode', {default: 'default', values: ['default', 'set_opacity', 'color', 'multiply', 'add', 'screen', 'overlay', 'difference']});
new Property(TextureLayer, 'boolean', 'in_limbo', {default: false});
Object.defineProperty(TextureLayer, 'all', {
@ -750,7 +755,7 @@ Interface.definePanels(function() {
:key="layer.uuid"
:layer_id="layer.uuid"
class="texture_layer"
@click.stop="layer.select()"
@click.stop="layer.clickSelect()"
@dblclick.stop="layer.propertiesDialog()"
@contextmenu.prevent.stop="layer.showContextMenu($event)"
>

View File

@ -509,15 +509,17 @@ const Painter = {
function paintElement(element) {
if (element instanceof Cube) {
texture.selection.maskCanvas(ctx, offset);
ctx.beginPath();
for (var face in element.faces) {
var tag = element.faces[face]
if (Painter.getTextureToEdit(tag.getTexture()) === texture) {
for (var fkey in element.faces) {
var face = element.faces[fkey]
if (fill_mode === 'face' && fkey !== Painter.current.face) continue;
if (Painter.getTextureToEdit(face.getTexture()) === texture) {
var face_rect = getRectangle(
tag.uv[0] * uvFactorX,
tag.uv[1] * uvFactorY,
tag.uv[2] * uvFactorX,
tag.uv[3] * uvFactorY
face.uv[0] * uvFactorX,
face.uv[1] * uvFactorY,
face.uv[2] * uvFactorX,
face.uv[3] * uvFactorY
)
let animation_offset = texture.currentFrame * texture.display_height;
ctx.rect(
@ -529,6 +531,7 @@ const Painter = {
}
}
ctx.fill()
ctx.restore();
} else if (element instanceof Mesh) {
ctx.beginPath();
@ -542,8 +545,8 @@ const Painter = {
for (let x in matrix) {
for (let y in matrix[x]) {
if (!matrix[x][y]) continue;
if (!texture.selection.allow(x, y)) continue;
x = parseInt(x); y = parseInt(y);
if (!texture.selection.allow(x, y)) continue;
ctx.rect(x, y, 1, 1);
}
}
@ -552,15 +555,13 @@ const Painter = {
}
}
if (element instanceof Cube && fill_mode === 'element') {
paintElement(element);
} else if (element instanceof Mesh && (fill_mode === 'element' || fill_mode === 'face')) {
if ((element instanceof Cube || element instanceof Mesh) && (fill_mode === 'element' || fill_mode === 'face')) {
paintElement(element);
} else if (fill_mode === 'face' || fill_mode === 'element' || fill_mode === 'selection') {
texture.selection.maskCanvas(ctx, offset);
ctx.fill();
ctx.restore();
} else if (fill_mode === 'selected_elements') {
for (let element of Outliner.selected) {
@ -1180,7 +1181,7 @@ const Painter = {
}, {no_undo: true, use_cache: true});
},
colorPicker(texture, x, y, event) {
var ctx = Painter.getCanvas(texture).getContext('2d')
let {ctx} = settings.pick_combined_color.value ? texture : texture.getActiveCanvas();
let color = Painter.getPixelColor(ctx, x, y);
if (settings.pick_color_opacity.value) {
let opacity = Math.floor(color.getAlpha()*256);
@ -1262,6 +1263,15 @@ const Painter = {
mix[ch] = ((1 - ((1-normal_base) * (1-normal_added))) * added.a) + (normal_base * (1-added.a));
break;
case 'overlay':
if (base[ch] < 128) {
mix[ch] = (((2*normal_base*normal_added)) * added.a) + (normal_base * (1-added.a));
}
else{
mix[ch] = ((1 - 2*((1-normal_base) * (1-normal_added))) * added.a) + (normal_base * (1-added.a));
}
break;
//case 'hard_light':
//mix[ch] = ((normal_base / normal_added) * added.a) + (normal_base * (1-added.a));
//break;
@ -1345,6 +1355,7 @@ const Painter = {
case 'add': return 'lighter';
//case 'subtract': return 'darken';
case 'screen': return 'screen';
case 'overlay': return 'overlay';
case 'difference': return 'difference';
default: return 'source-over';
}
@ -1683,6 +1694,7 @@ const Painter = {
add: 'action.blend_mode.add',
//subtract: 'action.blend_mode.subtract',
screen: 'action.blend_mode.screen',
overlay: 'action.blend_mode.overlay',
difference: 'action.blend_mode.difference',
}},
size: {
@ -2036,9 +2048,8 @@ class IntMatrix {
return boxes;
}
maskCanvas(ctx, offset = [0, 0]) {
if (!this.is_custom) return;
ctx.save();
if (!this.is_custom) return;
ctx.beginPath();
let boxes = this.toBoxes();
boxes.forEach(box => {
@ -2658,7 +2669,7 @@ BARS.defineActions(function() {
let selection_tools = {
rectangle: {name: 'action.selection_tool.rectangle', icon: 'select'},
ellipse: {name: 'action.selection_tool.ellipse', icon: 'lasso_select'},
//lasso: {name: 'action.selection_tool.lasso', icon: 'fa-draw-polygon'},
lasso: {name: 'action.selection_tool.lasso', icon: 'fa-draw-polygon'},
wand: {name: 'action.selection_tool.wand', icon: 'fa-magic'},
color: {name: 'action.selection_tool.color', icon: 'fa-eye-dropper'},
};
@ -2723,6 +2734,7 @@ BARS.defineActions(function() {
if (TextureLayer.selected?.in_limbo) {
TextureLayer.selected.resolveLimbo();
}
UVEditor.vue.texture_selection_polygon.empty();
Interface.removeSuggestedModifierKey('alt', 'modifier_actions.drag_to_duplicate');
}
})
@ -2812,6 +2824,7 @@ BARS.defineActions(function() {
add: true,
//subtract: true,
screen: true,
overlay: true,
difference: true,
}
})
@ -3055,7 +3068,6 @@ BARS.defineActions(function() {
}
},
onFormChange(result) {
console.log('abaw')
UVEditor.updateOverlayCanvas();
}
})

View File

@ -36,23 +36,24 @@ const TextureGenerator = {
title: tl('action.create_texture'),
width: 610,
form: {
name: {label: 'generic.name', value: 'texture'},
folder: {label: 'dialog.create_texture.folder', condition: {features: ['texture_folder']}},
type: {label: 'dialog.create_texture.type', type: 'inline_select', options: type_options, condition: Object.keys(type_options).length > 1},
section2: "_",
name: {label: 'generic.name', value: 'texture'},
folder: {label: 'dialog.create_texture.folder', condition: {features: ['texture_folder']}},
type: {label: 'dialog.create_texture.type', type: 'inline_select', options: type_options, condition: Object.keys(type_options).length > 1},
section2: "_",
resolution: {label: 'dialog.create_texture.pixel_density', description: 'dialog.create_texture.pixel_density.desc', type: 'select', value: resolution_presets[resolution] ? resolution : undefined, condition: (form) => (form.type == 'template'), options: resolution_presets},
resolution: {label: 'dialog.create_texture.pixel_density', description: 'dialog.create_texture.pixel_density.desc', type: 'select', value: resolution_presets[resolution] ? resolution : undefined, condition: (form) => (form.type == 'template'), options: resolution_presets},
resolution_vec: {label: 'dialog.create_texture.resolution', type: 'vector', condition: (form) => (form.type == 'blank'), dimensions: 2, value: [Project.texture_width, Project.texture_height], min: 16, max: 2048},
color: {label: 'data.color', type: 'color', colorpicker: TextureGenerator.background_color, toggle_enabled: true, toggle_default: false},
color: {label: 'data.color', type: 'color', colorpicker: TextureGenerator.background_color, toggle_enabled: true, toggle_default: false},
rearrange_uv:{label: 'dialog.create_texture.rearrange_uv', description: 'dialog.create_texture.rearrange_uv.desc', type: 'checkbox', value: true, condition: (form) => (form.type == 'template')},
box_uv: {label: 'dialog.project.uv_mode.box_uv', type: 'checkbox', value: false, condition: (form) => (form.type == 'template' && !Project.box_uv && Cube.all.length)},
power: {label: 'dialog.create_texture.power', description: 'dialog.create_texture.power.desc', type: 'checkbox', value: true, condition: (form) => (form.type !== 'blank' && (form.rearrange_uv || form.type == 'color_map'))},
double_use: {label: 'dialog.create_texture.double_use', description: 'dialog.create_texture.double_use.desc', type: 'checkbox', value: true, condition: ((form) => (form.type == 'template' && form.rearrange_uv))},
combine_polys: {label: 'dialog.create_texture.combine_polys', description: 'dialog.create_texture.combine_polys.desc', type: 'checkbox', value: true, condition: (form) => (form.type == 'template' && form.rearrange_uv && Mesh.selected.length)},
max_edge_angle: {label: 'dialog.create_texture.max_edge_angle', description: 'dialog.create_texture.max_edge_angle.desc', type: 'number', value: 36, condition: (form) => (form.type == 'template' && form.rearrange_uv && Mesh.selected.length)},
rearrange_uv: {label: 'dialog.create_texture.rearrange_uv', description: 'dialog.create_texture.rearrange_uv.desc', type: 'checkbox', value: true, condition: (form) => (form.type == 'template')},
box_uv: {label: 'dialog.project.uv_mode.box_uv', type: 'checkbox', value: false, condition: (form) => (form.type == 'template' && !Project.box_uv && Cube.all.length)},
power: {label: 'dialog.create_texture.power', description: 'dialog.create_texture.power.desc', type: 'checkbox', value: true, condition: (form) => (form.type !== 'blank' && (form.rearrange_uv || form.type == 'color_map'))},
double_use: {label: 'dialog.create_texture.double_use', description: 'dialog.create_texture.double_use.desc', type: 'checkbox', value: true, condition: ((form) => (form.type == 'template' && form.rearrange_uv))},
combine_polys: {label: 'dialog.create_texture.combine_polys', description: 'dialog.create_texture.combine_polys.desc', type: 'checkbox', value: true, condition: (form) => (form.type == 'template' && form.rearrange_uv && Mesh.selected.length)},
max_edge_angle: {label: 'dialog.create_texture.max_edge_angle', description: 'dialog.create_texture.max_edge_angle.desc', type: 'number', value: 36, condition: (form) => (form.type == 'template' && form.rearrange_uv && Mesh.selected.length)},
max_island_angle: {label: 'dialog.create_texture.max_island_angle', description: 'dialog.create_texture.max_island_angle.desc', type: 'number', value: 45, condition: (form) => (form.type == 'template' && form.rearrange_uv && Mesh.selected.length)},
padding: {label: 'dialog.create_texture.padding', description: 'dialog.create_texture.padding.desc', type: 'checkbox', value: Mesh.selected.length > 0, condition: (form) => (form.type == 'template' && form.rearrange_uv)},
padding: {label: 'dialog.create_texture.padding', description: 'dialog.create_texture.padding.desc', type: 'checkbox', value: Mesh.selected.length > 0, condition: (form) => (form.type == 'template' && form.rearrange_uv)},
disable_mirror_uv:{label: 'dialog.create_texture.disable_mirror_uv', description: 'dialog.create_texture.disable_mirror_uv.desc', type: 'checkbox', value: true, condition: (form) => BarItems.mirror_modeling.value && BarItems.mirror_modeling.tool_config.options.mirror_uv},
},
onConfirm: function(results) {
@ -60,6 +61,9 @@ const TextureGenerator = {
if (results.type == 'blank') {
results.resolution = results.resolution_vec;
}
if (results.disable_mirror_uv) {
BarItems.mirror_modeling.tool_config.changeOptions({mirror_uv: false});
}
dialog.hide()
if (Format.edit_mode && Outliner.selected.length == 0) {
SharedActions.runSpecific('select_all', 'outliner');
@ -344,21 +348,23 @@ const TextureGenerator = {
});
function faceRect(cube, face_key, tex, x, y, face_old_pos_id) {
this.cube = cube;
this.face = cube.faces[face_key];
if (options.rearrange_uv) {
this.width = Math.abs(x) * res_multiple;
this.height = Math.abs(y) * res_multiple;
this.mirror_x = Math.sign(this.face.uv_size[0]);
this.mirror_y = Math.sign(this.face.uv_size[1]);
this.width = ((this.width >= 0.01 && this.width < 1) ? 1 : Math.round(this.width)) / res_multiple;
this.height = ((this.height >= 0.01 && this.height < 1) ? 1 : Math.round(this.height)) / res_multiple;
} else {
this.posx = cube.faces[face_key].uv[0], cube.faces[face_key].uv[0+2];
this.posy = cube.faces[face_key].uv[1], cube.faces[face_key].uv[1+2];
this.width = cube.faces[face_key].uv[0+2] - cube.faces[face_key].uv[0];
this.height = cube.faces[face_key].uv[1+2] - cube.faces[face_key].uv[1];
this.posx = this.face.uv[0], this.face.uv[0+2];
this.posy = this.face.uv[1], this.face.uv[1+2];
this.width = this.face.uv[0+2] - this.face.uv[0];
this.height = this.face.uv[1+2] - this.face.uv[1];
}
this.size = this.width * this.height;
this.face_key = face_key;
this.texture = tex
this.face = cube.faces[face_key];
this.face_old_pos_id = face_old_pos_id;
}
function faceOldPositionIdentifier(face) {
@ -370,7 +376,14 @@ const TextureGenerator = {
vertex_identifiers.sort(sort_collator.compare);
uv_id = vertex_identifiers.join(',');
} else if (face.uv instanceof Array) {
uv_id = face.uv.map(v => Math.roundTo(v, 4)).join(',');
let absolute_uv = face.uv.slice();
for (let i = 0; i < 2; i++) {
if (absolute_uv[i] > absolute_uv[i+2]) {
absolute_uv[i] = absolute_uv[i+2];
absolute_uv[i+2] = face.uv[i];
}
}
uv_id = absolute_uv.map(v => Math.roundTo(v, 4)).join(',');
}
let texture = face.getTexture();
return uv_id + ':' + (texture ? texture.uuid : 'blank');
@ -412,6 +425,7 @@ const TextureGenerator = {
if (mirror_modeling_duplicate) return;
if (element instanceof Cube) {
if (element.box_uv || options.box_uv) {
element.box_uv = true;
let template = new TextureGenerator.boxUVCubeTemplate(element, element.box_uv ? 0 : 1);
let mirror_modeling_duplicate = BarItems.mirror_modeling.value && MirrorModeling.cached_elements[element.uuid] && MirrorModeling.cached_elements[element.uuid].is_copy;
@ -433,7 +447,6 @@ const TextureGenerator = {
doubles[double_key] = [template]
}
}
element.box_uv = true;
box_uv_templates.push(template)
avg_size += box_uv_templates[box_uv_templates.length-1].template_size
@ -1404,6 +1417,15 @@ const TextureGenerator = {
uv: flip_rotation ? [pos.y, pos.x] : [pos.x, pos.y]
})
target.face.uv_size = flip_rotation ? [pos.h, pos.w] : [pos.w, pos.h];
if (source != target) {
// Double occupancy mirroring
if (target.mirror_x == -1) {
[target.face.uv[2], target.face.uv[0]] = [target.face.uv[0], target.face.uv[2]];
}
if (target.mirror_y == -1) {
[target.face.uv[3], target.face.uv[1]] = [target.face.uv[1], target.face.uv[3]];
}
}
if (target.face_key == 'up') {
[target.face.uv[2], target.face.uv[0]] = [target.face.uv[0], target.face.uv[2]];
[target.face.uv[3], target.face.uv[1]] = [target.face.uv[1], target.face.uv[3]];

View File

@ -87,22 +87,31 @@ class TextureGroup {
}
updateMaterial() {
/**
* @link https://threejs.org/docs/index.html#api/en/materials/MeshStandardMaterial
* @type {THREE.MeshStandardMaterial}
*/
let material = this._static.properties.material;
if (!material) {
//let g = new THREE.PMREMGenerator(Preview.selected.renderer);
//let pmrem_render_target = g.fromScene(Canvas.scene);
// https://threejs.org/docs/index.html#api/en/materials/MeshStandardMaterial
material = this._static.properties.material = new THREE.MeshStandardMaterial({
envMap: PreviewScene.active?.cubemap ?? null,
envMapIntensity: 0.8,
alphaTest: 0.05,
});
}
if (PreviewScene.active) {
const g = new THREE.PMREMGenerator(Preview.selected.renderer);
material.envMap = g.fromScene(Canvas.scene, 0.0, 100, 1024).texture;
}
let textures = this.getTextures();
let color_tex = textures.find(t => t.pbr_channel == 'color');
let normal_tex = textures.find(t => t.pbr_channel == 'normal');
let height_tex = textures.find(t => t.pbr_channel == 'height');
let mer_tex = textures.find(t => t.pbr_channel == 'mer');
// Albedo
if (color_tex) {
material.map = color_tex.getOwnMaterial().map;
material.color.set('#ffffff');
@ -113,12 +122,15 @@ class TextureGroup {
material.color.set({r: c[0] / 255, g: c[1] / 255, b: c[2] / 255});
material.opacity = c[4] / 255;
}
// Height
if (normal_tex) {
material.normalMap = normal_tex.getOwnMaterial().map;
material.bumpMap = null;
// Use DirectX normal maps for RenderDragon. Flips the "handedness" of the normal map.
material.normalScale = Project.format.id.includes('bedrock') ? new THREE.Vector2(1, -1) : new THREE.Vector2(1, 1);
} else if (height_tex) {
material.bumpMap = height_tex.getOwnMaterial().map;
material.bumpMap = height_tex.getOwnMaterial().map.clone();
material.bumpScale = 0.4;
material.normalMap = null;
// Bump map scale
@ -131,47 +143,74 @@ class TextureGroup {
material.bumpMap.image = canvas;
material.bumpMap.magFilter = THREE.LinearFilter;
material.bumpMap.needsUpdate = true;
} else {
material.normalMap = null;
material.bumpMap = null;
}
if (mer_tex && mer_tex.img?.naturalWidth) {
// MER
if (mer_tex && mer_tex.img?.naturalWidth && mer_tex.width) {
let image_data = mer_tex.canvas.getContext('2d').getImageData(0, 0, mer_tex.width, mer_tex.height);
let image_data_albedo = color_tex.canvas.getContext('2d').getImageData(0, 0, color_tex.width, color_tex.height);
function generateMap(source_channel, target_channel, key) {
let canvas = material[key]?.image ?? document.createElement('canvas');
const extractEmissiveChannel = () => {
// The green channel is the emissive level.
// Use it as an mask on the color texture to create the emissive map.
const color_data = color_tex.canvas.getContext('2d').getImageData(0, 0, color_tex.width, color_tex.height);
let emissive_data = new Uint8ClampedArray(color_data.data.length);
for (let i = 0; i < image_data.data.length; i += 4) {
if (image_data.data[i + 1] > 0) {
emissive_data[i] = color_data.data[i];
emissive_data[i + 1] = color_data.data[i + 1];
emissive_data[i + 2] = color_data.data[i + 2];
emissive_data[i + 3] = 255;
continue;
}
emissive_data[i] = 0;
emissive_data[i + 1] = 0;
emissive_data[i + 2] = 0;
emissive_data[i + 3] = 255;
}
return new ImageData(emissive_data, mer_tex.width, mer_tex.height);
}
const extractGrayscaleValue = (channel) => {
let grayscale_data = new Uint8ClampedArray(image_data.data.length);
for (let i = 0; i < image_data.data.length; i += 4) {
grayscale_data[i + 0] = image_data.data[i + channel];
grayscale_data[i + 1] = image_data.data[i + channel];
grayscale_data[i + 2] = image_data.data[i + channel];
grayscale_data[i + 3] = 255;
}
return new ImageData(grayscale_data, mer_tex.width, mer_tex.height);
}
function generateMap(source_channel, key) {
let canvas = material[key]?.image;
if (!canvas || key == 'emissiveMap') {
canvas = document.createElement('canvas');
}
let ctx = canvas.getContext('2d');
canvas.width = mer_tex.width;
canvas.height = mer_tex.height;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, mer_tex.width, mer_tex.height);
document.body.append(canvas)
// document.body.append(canvas);
let image_data_new = ctx.getImageData(0, 0, mer_tex.width, mer_tex.height);
for (let i = 0; i < image_data.data.length; i += 4) {
if (target_channel == 0) {
let value = image_data.data[i + source_channel] / 255;
image_data_new.data[i + 0] = image_data_albedo.data[i + 0] * value;
image_data_new.data[i + 1] = image_data_albedo.data[i + 1] * value;
image_data_new.data[i + 2] = image_data_albedo.data[i + 2] * value;
} else {
image_data_new.data[i + target_channel] = image_data.data[i + source_channel];
if (source_channel == 2 && image_data_new.data[i + target_channel] == 0) {
//image_data_new.data[i + target_channel] = 255;
}
}
}
ctx.putImageData(image_data_new, 0, 0);
ctx.putImageData(source_channel === 1 ? extractEmissiveChannel() : extractGrayscaleValue(source_channel), 0, 0);
if (!material[key] || true) {
material[key] = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
material[key].needsUpdate = true;
}
//material.map = material[key];
material[key] = new THREE.Texture(canvas, THREE.UVMapping, THREE.RepeatWrapping, THREE.RepeatWrapping, THREE.NearestFilter, THREE.NearestFilter);
material[key].needsUpdate = true;
}
generateMap(0, 2, 'metalnessMap');
generateMap(1, 0, 'emissiveMap');
generateMap(2, 1, 'roughnessMap');
generateMap(0, 'metalnessMap');
generateMap(1, 'emissiveMap');
generateMap(2, 'roughnessMap');
material.emissive.set(0xffffff);
material.emissiveIntensity = 5;
material.emissiveIntensity = 1;
material.metalness = 1;
material.roughness = 1;
} else {
material.metalnessMap = null;
material.emissiveMap = material.map;
@ -288,7 +327,14 @@ class TextureGroupMaterialConfig {
texture_set.color = this.color_value.slice();
}
if (mer_tex) {
texture_set.metalness_emissive_roughness = getTextureName(mer_tex);
let texture_name = getTextureName(mer_tex);
if (this.subsurface_value) {
texture_set.metalness_emissive_roughness_subsurface = texture_name;
} else {
texture_set.metalness_emissive_roughness = texture_name;
}
} else if (this.subsurface_value) {
texture_set.metalness_emissive_roughness_subsurface = [...this.mer_value, this.subsurface_value];
} else if (!this.mer_value.allEqual(0)) {
texture_set.metalness_emissive_roughness = this.mer_value.slice();
}
@ -298,8 +344,12 @@ class TextureGroupMaterialConfig {
texture_set.heightmap = getTextureName(height_tex);
}
let format_version = "1.16.100";
if (texture_set.metalness_emissive_roughness_subsurface) {
format_version = "1.21.30";
}
let file = {
format_version: "1.16.100",
format_version,
"minecraft:texture_set": texture_set
}
return file;
@ -368,7 +418,7 @@ class TextureGroupMaterialConfig {
a: this.color_value[3] / 255
}
},
'mer': '_',
'_mers': '_',
mer: {
type: 'select',
label: 'dialog.material_config.mer',
@ -382,7 +432,21 @@ class TextureGroupMaterialConfig {
min: 0, max: 255, step: 1, force_step: true,
value: this.mer_value.map(v => Math.clamp(v, 0, 255)),
},
'depth': '_',
subsurface: {
type: 'checkbox',
label: 'dialog.material_config.subsurface',
description: 'dialog.material_config.subsurface_enabled.desc',
condition: form => isUUID(form.mer),
value: this.subsurface_value > 0,
},
subsurface_value: {
label: 'dialog.material_config.subsurface',
condition: form => form.mer == 'uniform',
type: 'number',
min: 0, max: 255, step: 1, force_step: true,
value: Math.clamp(this.subsurface_value, 0, 255),
},
'_depth': '_',
depth_type: {
type: 'inline_select',
label: 'dialog.material_config.depth_type',
@ -414,6 +478,9 @@ class TextureGroupMaterialConfig {
let color = result.color_value.toRgb();
let color_array = [color.r, color.g, color.b, Math.round(color.a * 255)];
this.color_value.replace(color_array);
for (let texture of textures) {
if (texture.pbr_channel == 'color') texture.group = '';
}
} else {
let target = textures.find(t => t.uuid == result.color);
if (target) target.pbr_channel = 'color';
@ -421,10 +488,15 @@ class TextureGroupMaterialConfig {
if (result.mer == 'uniform') {
this.mer_value.replace(result.mer_value);
for (let texture of textures) {
if (texture.pbr_channel == 'mer') texture.group = '';
}
this.subsurface_value = result.subsurface_value;
} else {
this.mer_value.replace([0, 0, 0]);
let target = textures.find(t => t.uuid == result.mer);
if (target) target.pbr_channel = 'mer';
this.subsurface_value = result.subsurface ? 1 : 0;
}
if (result.depth_type == 'normal') {
@ -449,6 +521,7 @@ class TextureGroupMaterialConfig {
}
new Property(TextureGroupMaterialConfig, 'vector4', 'color_value', {default: [255, 255, 255, 255]});
new Property(TextureGroupMaterialConfig, 'vector', 'mer_value');
new Property(TextureGroupMaterialConfig, 'number', 'subsurface_value');
new Property(TextureGroupMaterialConfig, 'boolean', 'saved', {default: true});
TextureGroupMaterialConfig.prototype.menu = new Menu('texture_group_material_config', [
'generate_pbr_map',
@ -496,7 +569,7 @@ function importTextureSet(file) {
Undo.initEdit({textures: new_textures, texture_groups: new_texture_groups});
if (file.name.endsWith('texture_set.json')) {
let texture_group = new TextureGroup({is_material: true});
texture_group.name = file.name.replace('.texture_set.json', '');
texture_group.name = file.name.replace('.texture_set.json', '.png material');
let content = fs.readFileSync(file.path, {encoding: 'utf-8'});
let content_json = autoParseJSON(content);
@ -507,6 +580,7 @@ function importTextureSet(file) {
normal: 'normal',
heightmap: 'height',
metalness_emissive_roughness: 'mer',
metalness_emissive_roughness_subsurface: 'mer',
};
for (let key in channels) {
let source = content_json['minecraft:texture_set'][key];
@ -522,6 +596,9 @@ function importTextureSet(file) {
new_textures.push(t);
t.group = texture_group.uuid;
})
if (key == 'metalness_emissive_roughness_subsurface') {
texture_group.material_config.subsurface_value = 1;
}
} else {
let color_array = source;
if (typeof source == 'string') {
@ -536,6 +613,9 @@ function importTextureSet(file) {
}
} else if (key == 'metalness_emissive_roughness') {
texture_group.material_config.mer_value.V3_set(color_array);
} else if (key == 'metalness_emissive_roughness_subsurface') {
texture_group.material_config.mer_value.V3_set(color_array);
texture_group.material_config.subsurface_value = Math.clamp(color_array[3] ?? 0, 0, 255);
}
}
}
@ -547,6 +627,14 @@ function importTextureSet(file) {
}
Undo.finishEdit('Import texture set');
}
function loadAdjacentTextureSet(texture) {
let path = texture.path.replace(/\.png$/i, '.texture_set.json');
if (fs.existsSync(path)) {
Blockbench.read([path], {}, (files) => {
importTextureSet(files[0])
})
}
}
SharedActions.add('rename', {
condition: () => Prop.active_panel == 'textures' && TextureGroup.active_menu_group,
@ -579,6 +667,7 @@ BARS.defineActions(function() {
new Action('create_material', {
icon: 'lightbulb_circle',
category: 'textures',
condition: () => (!Texture.selected || !Texture.selected.getGroup()?.is_material) && Format.pbr,
click() {
let texture = Texture.selected;
let texture_group = new TextureGroup({is_material: true});
@ -604,7 +693,7 @@ BARS.defineActions(function() {
new Action('generate_pbr_map', {
icon: 'texture_add',
category: 'textures',
condition: () => Texture.all[0],
condition: () => Texture.all[0] && Format.pbr,
click() {
let texture = Texture.selected ?? Texture.all[0];
let texture_group = texture.getGroup();
@ -617,7 +706,7 @@ BARS.defineActions(function() {
let new_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
canvas.style.width = 256 + 'px';
canvas.style.height = 256 + 'px';
let original_image = new CanvasFrame(texture.canvas);
let original_image = new CanvasFrame(texture.canvas, true);
original_image.canvas.style.width = 256 + 'px';
original_image.canvas.style.height = 256 + 'px';
@ -683,6 +772,9 @@ BARS.defineActions(function() {
let output = Math.clamp(Math.lerp(result.out_range[0], result.out_range[1], input_1), 0, 255);
new_data.data[i+0] = 0;
new_data.data[i+1] = 0;
new_data.data[i+2] = 0;
new_data.data[i+3] = 255;
switch (result.channel) {
@ -715,6 +807,17 @@ BARS.defineActions(function() {
width: 564,
lines: [preview],
form: {
channel: {
type: 'select',
label: 'PBR Channel',
options: {
//normal: 'menu.texture.pbr_channel.normal',
height: 'menu.texture.pbr_channel.height',
metalness: 'Metalness',
emissive: 'Emissive',
roughness: 'Roughness',
}
},
method: {
type: 'select',
label: 'Source',
@ -728,17 +831,6 @@ BARS.defineActions(function() {
blue: 'Blue',
}
},
channel: {
type: 'select',
label: 'PBR Channel',
options: {
//normal: 'menu.texture.pbr_channel.normal',
height: 'menu.texture.pbr_channel.height',
metalness: 'Metalness',
emissive: 'Emissive',
roughness: 'Roughness',
}
},
in_range: {
type: 'vector',
label: 'Input Range',
@ -759,15 +851,53 @@ BARS.defineActions(function() {
onConfirm(result) {
updateCanvas(result);
let textures = [];
Undo.initEdit({texture_groups: [texture_group], textures});
let pbr_channel = result.channel;
let new_texture = new Texture({
name: texture.name,
pbr_channel,
group: texture_group.uuid,
}).fromDataURL(canvas.toDataURL()).add(false);
textures.push(new_texture);
let pbr_channel;
switch (result.channel) {
case 'height': pbr_channel = result.channel; break;
default: pbr_channel = 'mer'; break;
}
let existing_channel_texture = texture_group.getTextures().find(tex => tex.pbr_channel == pbr_channel);
if (existing_channel_texture && pbr_channel == 'mer') {
Undo.initEdit({textures: [existing_channel_texture], bitmap: true});
if (!existing_channel_texture.layers_enabled) {
existing_channel_texture.activateLayers(false);
}
let layer = new TextureLayer({
name: result.channel,
blend_mode: 'add'
}, existing_channel_texture);
let image_data = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
layer.setSize(canvas.width, canvas.height);
layer.ctx.putImageData(image_data, 0, 0);
layer.addForEditing();
existing_channel_texture.updateLayerChanges(true);
} else {
Undo.initEdit({texture_groups: texture_group ? [texture_group] : null, textures});
let main_texture = texture_group?.getTextures().find(t => t.pbr_channel == 'color');
let name = main_texture ? main_texture.name : texture.name;
name = name.replace('.', `_${pbr_channel}.`);
let new_texture = new Texture({
name,
pbr_channel,
group: texture_group?.uuid,
}).fromDataURL(canvas.toDataURL()).add(false);
textures.push(new_texture);
if (texture_group.material_config) {
texture_group.material_config.saved = false;
}
}
setTimeout(() => {
texture_group.updateMaterial();
}, 50);
Undo.finishEdit('Create PBR map');
updateSelection();
},
onOpen() {
updateCanvas(this.getFormResult());

View File

@ -185,7 +185,7 @@ class Texture {
});
mat.map = tex;
mat.name = this.name;
Project.materials[this.uuid] = mat;
this.material = mat;
var size_control = {};
@ -329,6 +329,12 @@ class Texture {
get selection() {
return this._static.properties.selection;
}
get material() {
return this._static.properties.material;
}
set material(material) {
this._static.properties.material = material;
}
getUVWidth() {
return Format.per_texture_uv_size ? this.uv_width : Project.texture_width;
}
@ -891,10 +897,10 @@ class Texture {
if (group?.is_material && BarItems.view_mode.value == 'material') {
return group.getMaterial();
}
return Project.materials[this.uuid];
return this.material;
}
getOwnMaterial() {
return Project.materials[this.uuid];
return this.material;
}
//Management
select(event) {
@ -995,7 +1001,6 @@ class Texture {
Texture.selected = undefined;
}
Project.textures.splice(Texture.all.indexOf(this), 1)
delete Project.materials[this.uuid];
Blockbench.dispatchEvent('update_texture_selection');
if (!no_update) {
Canvas.updateAllFaces()
@ -1783,6 +1788,9 @@ class Texture {
this.source = this.canvas.toDataURL('image/png', 1);
this.updateImageFromCanvas();
}
if ((this.pbr_channel == 'mer' || this.pbr_channel == 'height') && this.getGroup()?.is_material && BarItems.view_mode.value == 'material') {
this.getGroup().updateMaterial();
}
this.saved = false;
this.syncToOtherProject();
}
@ -1991,6 +1999,7 @@ class Texture {
'adjust_curves',
new MenuSeparator('filters'),
'limit_to_palette',
'split_rgb_into_layers',
'clear_unused_texture_space',
new MenuSeparator('transform'),
'flip_texture_x',
@ -2644,6 +2653,9 @@ Interface.definePanels(function() {
addEventListeners(document, 'mousemove touchmove', move, {passive: false});
addEventListeners(document, 'mouseup touchend', off, {passive: false});
},
closeContextMenu() {
if (Menu.open) Menu.open.hide();
}
},
template: `
@ -2651,7 +2663,7 @@ Interface.definePanels(function() {
v-bind:class="{ selected: texture.selected, multi_selected: texture.multi_selected, particle: texture.particle, use_as_default: texture.use_as_default}"
v-bind:texid="texture.uuid"
class="texture"
@click.stop="texture.select($event)"
@click.stop="closeContextMenu();texture.select($event)"
@mousedown="highlightTexture($event)"
@mouseup="unhighlightTexture($event)"
@dblclick="texture.openMenu($event)"

View File

@ -44,7 +44,10 @@ const UVEditor = {
}
if (Toolbox.selected.id === 'selection_tool') {
if (settings.nearest_rectangle_select.value) {
if (BarItems.selection_tool.mode == 'lasso') {
result.x = mouse_coords[0]/pixel_size;
result.y = mouse_coords[1]/pixel_size;
} else if (settings.nearest_rectangle_select.value) {
result.x = Math.round(mouse_coords[0]/pixel_size*1);
result.y = Math.round(mouse_coords[1]/pixel_size*1);
} else {
@ -254,40 +257,20 @@ const UVEditor = {
}
this.vue.selection_outline = outline;
},
focusOnSelection() {
let min_x = UVEditor.getUVWidth();
let min_y = UVEditor.getUVHeight();
let max_x = 0;
let max_y = 0;
let elements = UVEditor.getMappableElements();
elements.forEach(element => {
if (element instanceof Cube && element.box_uv) {
let size = element.size(undefined, Format.box_uv_float_size != true)
min_x = Math.min(min_x, element.uv_offset[0]);
min_y = Math.min(min_y, element.uv_offset[1]);
max_x = Math.max(max_x, element.uv_offset[0] + (size[0] + size[2]) * 2);
max_y = Math.max(max_y, element.uv_offset[1] + size[1] + size[2]);
} else {
for (let fkey in element.faces) {
if (!UVEditor.getSelectedFaces(element, false).includes(fkey)) continue;
let face = element.faces[fkey];
if (element instanceof Cube) {
min_x = Math.min(min_x, face.uv[0], face.uv[2]);
min_y = Math.min(min_y, face.uv[1], face.uv[3]);
max_x = Math.max(max_x, face.uv[0], face.uv[2]);
max_y = Math.max(max_y, face.uv[1], face.uv[3]);
} else if (element instanceof Mesh) {
face.vertices.forEach(vkey => {
if (!face.uv[vkey]) return;
min_x = Math.min(min_x, face.uv[vkey][0]);
min_y = Math.min(min_y, face.uv[vkey][1]);
max_x = Math.max(max_x, face.uv[vkey][0]);
max_y = Math.max(max_y, face.uv[vkey][1]);
})
}
}
}
})
async focusOnSelection(zoom) {
if (zoom instanceof Event) {
zoom = BarItems.focus_on_selection.keybind.additionalModifierTriggered(zoom, 'zoom');
}
let [min_x, min_y, max_x, max_y] = this.vue.getSelectedUVBoundingBox();
if (zoom) {
let width = (max_x-min_x) / UVEditor.getUVWidth();
let height = (max_y-min_y) / UVEditor.getUVHeight();
let target_zoom_factor = 1/Math.max(width, height);
let target_zoom = Math.clamp(UVEditor.zoom, target_zoom_factor * 0.618, Math.max(1, target_zoom_factor * 0.84));
UVEditor.setZoom(target_zoom);
await new Promise(Vue.nextTick);
}
let pixel_size = UVEditor.inner_width / UVEditor.vue.uv_resolution[0];
let focus = [min_x+max_x, min_y+max_y].map(v => v * 0.5 * pixel_size);
let {viewport} = UVEditor.vue.$refs;
@ -296,7 +279,7 @@ const UVEditor = {
scrollLeft: focus[0] + margin[0] - UVEditor.width / 2,
scrollTop: focus[1] + margin[1] - UVEditor.height / 2,
}, {
duration: 100,
duration: zoom ? 0 : 100,
complete: () => {
UVEditor.updateUVNavigator();
}
@ -797,7 +780,7 @@ const UVEditor = {
if (!box) return;
let uv_viewport = vue.$refs.viewport;
if (!uv_viewport || !Project || Blockbench.hasFlag('switching_project') || !uv_viewport.clientWidth || !uv_viewport.scrollLeft) return;
if (!uv_viewport || !Project || Blockbench.hasFlag('switching_project') || !uv_viewport.clientWidth) return;
let offset = [
(uv_viewport.scrollLeft - vue.width/2) / vue.inner_width,
(uv_viewport.scrollTop - vue.height/2) / vue.inner_height
@ -1294,7 +1277,6 @@ const UVEditor = {
Undo.finishEdit('Toggle cullface')
},
switchTint(event) {
var scope = this;
var val = UVEditor.getReferenceFace().tint === -1 ? 0 : -1;
if (event === 0 || event === false) val = event
@ -1690,30 +1672,38 @@ const UVEditor = {
SharedActions.add('select_all', {
condition: () => Prop.active_panel == 'uv' && Modes.edit,
run() {
Undo.initSelection();
UVEditor.selectAll()
Undo.finishSelection('Select all UV');
}
})
SharedActions.add('select_all', {
condition: () => Prop.active_panel == 'uv' && Modes.paint && UVEditor.texture,
run() {
Undo.initSelection({texture_selection: true});
UVEditor.texture.selection.setOverride(UVEditor.texture.selection.override == true ? false : true);
UVEditor.updateSelectionOutline();
Undo.finishSelection('Select all');
Interface.removeSuggestedModifierKey('alt', 'modifier_actions.drag_to_duplicate');
}
})
SharedActions.add('unselect_all', {
condition: () => Prop.active_panel == 'uv' && Modes.edit,
run() {
Undo.initSelection();
UVEditor.getMappableElements().forEach(element => {
UVEditor.getSelectedFaces(element, true).empty();
})
UVEditor.displayTools();
Undo.finishSelection('Unselect all UV');
}
})
SharedActions.add('unselect_all', {
condition: () => Prop.active_panel == 'uv' && Modes.paint && UVEditor.texture,
run() {
Undo.initSelection({texture_selection: true});
UVEditor.texture.selection.setOverride(false);
Undo.finishSelection('Unselect all');
UVEditor.updateSelectionOutline();
Interface.removeSuggestedModifierKey('alt', 'modifier_actions.drag_to_duplicate');
}
@ -1721,6 +1711,7 @@ SharedActions.add('unselect_all', {
SharedActions.add('invert_selection', {
condition: () => Prop.active_panel == 'uv' && Modes.paint && UVEditor.texture,
run() {
Undo.initSelection({texture_selection: true});
let texture = UVEditor.texture;
if (texture.selection.is_custom) {
texture.selection.forEachPixel((x, y, val, index) => {
@ -1730,6 +1721,7 @@ SharedActions.add('invert_selection', {
texture.selection.setOverride(!texture.selection.override);
}
UVEditor.updateSelectionOutline();
Undo.finishSelection('Invert selection');
}
})
@ -2398,6 +2390,7 @@ Interface.definePanels(function() {
active: false,
ellipse: false
},
texture_selection_polygon: [],
uv_resolution: [16, 16],
elements: [],
@ -2997,7 +2990,7 @@ Interface.definePanels(function() {
}
}
},
drag({event, onDrag, onEnd, onAbort, snap, uv_grid}) {
drag({event, onStart, onDrag, onEnd, onAbort, snap, uv_grid}) {
if (event.which == 2 || event.which == 3) return;
convertTouchEvent(event);
let scope = this;
@ -3007,6 +3000,7 @@ Interface.definePanels(function() {
let viewport = this.$refs.viewport;
let initial_scroll_offset = [viewport.scrollLeft, viewport.scrollTop];
let original_snap = snap;
let on_start_ran = false;
function drag(e1) {
convertTouchEvent(e1);
let step_x, step_y;
@ -3030,6 +3024,10 @@ Interface.definePanels(function() {
pos[1] = Math.round((e1.clientY - event.clientY + viewport.scrollTop - initial_scroll_offset[1]) / step_y) / snap;
if (pos[0] != last_pos[0] || pos[1] != last_pos[1]) {
if (onStart && !on_start_ran) {
on_start_ran = true;
onStart();
}
let applied_difference = onDrag(pos[0] - last_pos[0], pos[1] - last_pos[1], e1)
last_pos[0] += applied_difference[0];
last_pos[1] += applied_difference[1];
@ -3078,78 +3076,82 @@ Interface.definePanels(function() {
})
let overlay_canvas;
if (do_move_uv) {
Undo.initEdit({
elements,
uv_only: true,
bitmap: true,
textures: [this.texture]
});
overlay_canvas = Interface.createElement('canvas', {class: 'move_texture_with_uv'});
let ctx = overlay_canvas.getContext('2d');
overlay_canvas.width = this.texture.width;
overlay_canvas.height = this.texture.height;
this.texture.edit(canvas => {
let tex_ctx = canvas.getContext('2d');
ctx.beginPath();
tex_ctx.save();
tex_ctx.beginPath();
UVEditor.getMappableElements().forEach(el => {
if (el instanceof Mesh) {
for (var fkey in el.faces) {
var face = el.faces[fkey];
if (!UVEditor.getSelectedFaces(el).includes(fkey)) continue;
if (face.vertices.length <= 2 || face.getTexture() !== this.texture) continue;
let matrix = face.getOccupationMatrix(true, [0, 0]);
for (let x in matrix) {
for (let y in matrix[x]) {
if (!matrix[x][y]) continue;
x = parseInt(x); y = parseInt(y);
ctx.rect(x, y, 1, 1);
tex_ctx.rect(x, y, 1, 1);
}
}
}
} else {
let factor_x = this.texture.width / UVEditor.getUVWidth();
let factor_y = this.texture.height / UVEditor.getUVHeight();
for (var fkey in el.faces) {
var face = el.faces[fkey];
if (!UVEditor.getSelectedFaces(el).includes(fkey) && !el.box_uv) continue;
if (face.getTexture() !== this.texture) continue;
let rect = face.getBoundingRect();
let canvasRect = [
Math.floor(rect.ax * factor_x),
Math.floor(rect.ay * factor_y),
Math.ceil(rect.bx * factor_x) - Math.floor(rect.ax * factor_x),
Math.ceil(rect.by * factor_y) - Math.floor(rect.ay * factor_y),
]
ctx.rect(...canvasRect);
tex_ctx.rect(...canvasRect);
}
}
})
ctx.clip();
ctx.drawImage(this.texture.img, 0, 0);
tex_ctx.clip();
tex_ctx.clearRect(0, 0, canvas.width, canvas.height);
tex_ctx.restore();
}, {no_undo: true})
UVEditor.vue.$refs.frame.append(overlay_canvas);
} else {
Undo.initEdit({elements, uv_only: true});
}
let started = false;
this.drag({
event,
snap: UVEditor.isBoxUV() ? 1 : undefined,
onDrag: (diff_x, diff_y) => {
if (!started) {
started = true;
if (do_move_uv) {
Undo.initEdit({
elements,
uv_only: true,
bitmap: true,
textures: [this.texture]
});
overlay_canvas = Interface.createElement('canvas', {class: 'move_texture_with_uv'});
let ctx = overlay_canvas.getContext('2d');
overlay_canvas.width = this.texture.width;
overlay_canvas.height = this.texture.height;
this.texture.edit(canvas => {
let tex_ctx = canvas.getContext('2d');
ctx.beginPath();
tex_ctx.save();
tex_ctx.beginPath();
UVEditor.getMappableElements().forEach(el => {
if (el instanceof Mesh) {
for (var fkey in el.faces) {
var face = el.faces[fkey];
if (!UVEditor.getSelectedFaces(el).includes(fkey)) continue;
if (face.vertices.length <= 2 || face.getTexture() !== this.texture) continue;
let matrix = face.getOccupationMatrix(true, [0, 0]);
for (let x in matrix) {
for (let y in matrix[x]) {
if (!matrix[x][y]) continue;
x = parseInt(x); y = parseInt(y);
ctx.rect(x, y, 1, 1);
tex_ctx.rect(x, y, 1, 1);
}
}
}
} else {
let factor_x = this.texture.width / UVEditor.getUVWidth();
let factor_y = this.texture.height / UVEditor.getUVHeight();
for (var fkey in el.faces) {
var face = el.faces[fkey];
if (!UVEditor.getSelectedFaces(el).includes(fkey) && !el.box_uv) continue;
if (face.getTexture() !== this.texture) continue;
let rect = face.getBoundingRect();
let canvasRect = [
Math.floor(rect.ax * factor_x),
Math.floor(rect.ay * factor_y),
Math.ceil(rect.bx * factor_x) - Math.floor(rect.ax * factor_x),
Math.ceil(rect.by * factor_y) - Math.floor(rect.ay * factor_y),
]
ctx.rect(...canvasRect);
tex_ctx.rect(...canvasRect);
}
}
})
ctx.clip();
ctx.drawImage(this.texture.img, 0, 0);
tex_ctx.clip();
tex_ctx.clearRect(0, 0, canvas.width, canvas.height);
tex_ctx.restore();
}, {no_undo: true})
UVEditor.vue.$refs.frame.append(overlay_canvas);
} else {
Undo.initEdit({elements, uv_only: true});
}
}
elements.forEach(element => {
if (element instanceof Mesh) {
UVEditor.getSelectedFaces(element).forEach(key => {
@ -3229,7 +3231,7 @@ Interface.definePanels(function() {
},
onAbort: () => {
if (do_move_uv) {
overlay_canvas.remove();
if (overlay_canvas) overlay_canvas.remove();
}
if (face_key && Mesh.selected[0]) {
let selected_faces = UVEditor.getSelectedFaces(element, true);
@ -3716,6 +3718,22 @@ Interface.definePanels(function() {
];
return style ? `${margin[1]}px ${margin[0]}px` : margin;
},
getTextureSelectionPolygon() {
return this.texture_selection_polygon.map((point, i) => {
let x = point[0] / this.texture.width * this.inner_width;
let y = point[1] / this.texture.width * this.inner_width;
return `${i?'L':'M'}${x+1} ${y+1}`;
}).join(' ');
},
isSelectionPolygonClosed() {
let polygon = this.texture_selection_polygon;
if (polygon.length <= 3) return false;
let first = polygon[0];
let last = polygon.last()
let distance = Math.sqrt(Math.pow(first[0]-last[0], 2) + Math.pow(first[1]-last[1], 2));
let radius = Blockbench.isTouch ? 12 : 7;
return distance < (radius/UVEditor.getPixelSize());
},
startTextureSelection(x, y, event) {
let texture = UVEditor.texture;
@ -3727,6 +3745,8 @@ Interface.definePanels(function() {
let selection_mode = BarItems.selection_tool.mode;
let op_mode = BarItems.selection_tool_operation_mode.value;
let selection_rect = this.texture_selection_rect;
let selection_polygon = this.texture_selection_polygon;
let scope = this;
let start_x, start_y, calcrect;
let layer = texture.selected_layer;
let move_with_selection_tool = Toolbox.selected.id == 'selection_tool' && op_mode == 'create' && settings.move_with_selection_tool.value && (clicked_val || layer?.in_limbo)
@ -3735,11 +3755,16 @@ Interface.definePanels(function() {
&& !event.target.classList.contains('uv_layer_transform_handles');
let initial_offset = layer ? layer.offset.slice() : [0, 0];
if (!create_selection) {
x = Math.round(x);
y = Math.round(y);
}
start_x = x;
start_y = y;
if (create_selection) {
if (op_mode == 'create') {
Undo.initSelection({texture_selection: true});
if (op_mode == 'create' && (selection_mode != 'lasso' || selection_polygon.length == 0)) {
texture.selection.clear();
}
@ -3804,7 +3829,10 @@ Interface.definePanels(function() {
})
}
UVEditor.updateSelectionOutline();
Undo.finishSelection('Select color');
return;
} else if (selection_mode == 'lasso') {
selection_polygon.push([x, y]);
}
}
@ -3812,11 +3840,18 @@ Interface.definePanels(function() {
let started_movement = false;
function drag(e1) {
var {x, y} = UVEditor.getBrushCoordinates(e1, texture);
let {x, y} = UVEditor.getBrushCoordinates(e1, texture);
if (!create_selection) {
x = Math.round(x);
y = Math.round(y);
}
if (last_x == x && last_y == y) return;
last_x = x, last_y = y;
if (create_selection && selection_mode == 'lasso') {
selection_polygon.push([x, y]);
if (create_selection) {
} else if (create_selection) {
let start_x_here = start_x;
let start_y_here = start_y;
if (!settings.nearest_rectangle_select.value) {
@ -3869,6 +3904,7 @@ Interface.definePanels(function() {
} else {
Undo.initEdit({layers: [layer], bitmap: true});
}
selection_polygon.empty();
texture.selection.clear();
UVEditor.updateSelectionOutline();
}
@ -3887,10 +3923,11 @@ Interface.definePanels(function() {
Blockbench.setCursorTooltip();
if (create_selection) {
if (!calcrect || selection_rect.width == 0 || selection_rect.height == 0) {
if ((!calcrect || selection_rect.width == 0 || selection_rect.height == 0) && selection_mode != 'lasso') {
if (!texture.selection.hasSelection()) {
texture.selection.clear();
UVEditor.updateSelectionOutline();
Undo.finishSelection('Unselect texture area');
}
if (TextureLayer.selected?.in_limbo) {
TextureLayer.selected.resolveLimbo();
@ -3898,7 +3935,7 @@ Interface.definePanels(function() {
return;
}
if (op_mode == 'create') {
if (op_mode == 'create' && selection_mode != 'lasso') {
texture.selection.clear();
}
if (selection_mode == 'rectangle') {
@ -3949,6 +3986,43 @@ Interface.definePanels(function() {
}
}
}
if (selection_mode == 'lasso' && scope.isSelectionPolygonClosed()) {
selection_polygon.pop();
let min_x = Infinity, min_y = Infinity, max_x = 0, max_y = 0;
for (let point of selection_polygon) {
min_x = Math.min(point[0], min_x);
min_y = Math.min(point[1], min_y);
max_x = Math.max(point[0], max_x);
max_y = Math.max(point[1], max_y);
}
min_x = Math.clamp(min_x, 0, UVEditor.texture.img.naturalWidth);
min_y = Math.clamp(min_y, 0, UVEditor.texture.img.naturalHeight);
max_x = Math.clamp(max_x, 0, UVEditor.texture.img.naturalWidth);
max_y = Math.clamp(max_y, 0, UVEditor.texture.img.naturalHeight);
for (let x = Math.floor(min_x); x < max_x; x++) {
for (let y = Math.floor(min_y); y < max_y; y++) {
let is_inside = pointInPolygon([x+0.5, y+0.5], selection_polygon);
if (!is_inside) continue;
switch (op_mode) {
case 'create': case 'add': {
texture.selection.set(x, y, 1);
break;
}
case 'subtract': {
texture.selection.set(x, y, 0);
break;
}
case 'intersect': {
if (texture.selection.get(x, y)) {
texture.selection.set(x, y, 2);
}
break;
}
}
}
}
selection_polygon.empty();
}
if (op_mode == 'intersect') {
for (let x = 0; x < texture.width; x++) {
for (let y = 0; y < texture.height; y++) {
@ -3964,8 +4038,10 @@ Interface.definePanels(function() {
if (!texture.selection.hasSelection()) {
texture.selection.clear();
}
Undo.finishSelection('Select texture area');
UVEditor.updateSelectionOutline();
Interface.addSuggestedModifierKey('alt', 'modifier_actions.drag_to_duplicate');
} else if (!started_movement) {
if (TextureLayer.selected?.in_limbo) {
TextureLayer.selected.resolveLimbo();
@ -4046,8 +4122,8 @@ Interface.definePanels(function() {
height: this.toPixels(box[3] - box[1], 0),
};
},
focusOnSelection() {
UVEditor.focusOnSelection();
focusOnSelection(event) {
UVEditor.focusOnSelection(event);
},
showTransparentFaceText() {
return UVEditor.getSelectedFaces(this.mappable_elements[0]).length;
@ -4127,28 +4203,42 @@ Interface.definePanels(function() {
},
toggleFaceTint(key, event) {
Undo.initEdit({elements: Cube.selected, uv_only: true})
UVEditor.switchTint(event)
UVEditor.vue.$forceUpdate();
let value = UVEditor.getFirstMappableElement()?.faces[key]?.tint === -1 ? 0 : -1;
UVEditor.forCubes(cube => {
cube.faces[key].tint = value;
})
this.$forceUpdate();
Undo.finishEdit('Toggle face tint')
},
changeFaceTint(key, event) {
Undo.initEdit({elements: Cube.selected, uv_only: true})
UVEditor.setTint(event, parseInt(event.target.value));
Undo.finishEdit('Toggle face tint');
let value = parseInt(event.target.value);
UVEditor.forCubes(cube => {
cube.faces[key].tint = value;
})
Undo.finishEdit('Set face tint');
},
setCullface(key, value) {
Undo.initEdit({elements: Cube.selected, uv_only: true})
UVEditor.forCubes(obj => {
UVEditor.getSelectedFaces(obj).forEach(face => {
obj.faces[face].cullface = value;
})
if (obj.faces[key]) {
obj.faces[key].cullface = value;
}
})
Undo.finishEdit(value ? `Set cullface to ${value}` : 'Disable cullface');
},
startInputMaterialInstance(event) {
Undo.initEdit({elements: Cube.selected, uv_only: true})
},
endInputMaterialInstance(event) {
endInputMaterialInstance(event, fkey) {
let value = this.mappable_elements[0]?.faces[fkey]?.material_name;
if (typeof value == 'string') {
for (let element of this.mappable_elements) {
if (element.faces[fkey]) {
element.faces[fkey].material_name = value;
}
}
}
Undo.finishEdit('Change material instances');
},
showInfoBox(title, text) {
@ -4252,7 +4342,7 @@ Interface.definePanels(function() {
title="${tl('uv_editor.face_properties.material_instance')}"
v-model="mappable_elements[0].faces[key].material_name"
@focus="startInputMaterialInstance($event)"
@focusout="endInputMaterialInstance($event)"
@focusout="endInputMaterialInstance($event, key)"
>
</template>
</li>
@ -4443,17 +4533,22 @@ Interface.definePanels(function() {
}">
</div>
<svg id="texture_selection_polygon" v-if="texture_selection_polygon.length">
<path :d="getTextureSelectionPolygon()" />
<circle :cx="texture_selection_polygon[0][0] / texture.width * inner_width + 1" :cy="texture_selection_polygon[0][1] / texture.width * inner_width + 1" r="7" :class="{closed: isSelectionPolygonClosed()}" />
</svg>
<svg id="uv_selection_outline" v-if="mode == 'paint'">
<path :d="selection_outline" />
<path :d="selection_outline" class="dash_overlay" />
</svg>
</div>
<div class="uv_navigator" @click="focusOnSelection()" v-show="mode == 'uv'">
<div class="uv_navigator" @click="focusOnSelection($event)" v-show="mode == 'uv'">
<i class="material-icons icon">navigation</i>
</div>
<div class="uv_transparent_face" v-else-if="showTransparentFaceText()">${tl('uv_editor.transparent_face')}</div>
<div class="uv_transparent_face" v-if="showTransparentFaceText()">${tl('uv_editor.transparent_face')}</div>
</div>
<div class="uv_layer_limbo_options" v-if="isTransformingLayer()">

1059
js/undo.js

File diff suppressed because it is too large Load Diff

View File

@ -111,6 +111,7 @@ Object.defineProperty(Array.prototype, "equals", {enumerable: false});
//Array Vector
Array.prototype.V3_set = function(x, y, z) {
if (x instanceof Array) return this.V3_set(...x);
if (x instanceof THREE.Vector3) return this.V3_set(x.x, x.y, x.z);
if (y === undefined && z === undefined) z = y = x;
this[0] = parseFloat(x)||0;
this[1] = parseFloat(y)||0;

156
js/util/json.js Normal file
View File

@ -0,0 +1,156 @@
function compileJSON(object, options = {}) {
let indentation = options.indentation;
if (typeof indentation !== 'string') {
switch (settings.json_indentation.value) {
case 'spaces_4': indentation = ' '; break;
case 'spaces_2': indentation = ' '; break;
case 'tabs': default: indentation = '\t'; break;
}
}
function newLine(tabs) {
if (options.small === true) {return '';}
let s = '\n';
for (let i = 0; i < tabs; i++) {
s += indentation;
}
return s;
}
function escape(string) {
if (string.includes('\\')) {
string = string.replace(/\\/g, '\\\\');
}
if (string.includes('"')) {
string = string.replace(/"/g, '\\"');
}
if (string.includes('\n')) {
string = string.replace(/\n|\r\n/g, '\\n');
}
if (string.includes('\t')) {
string = string.replace(/\t/g, '\\t');
}
return string;
}
function handleVar(o, tabs, breaks = true) {
var out = ''
let type = typeof o;
if (type === 'string') {
//String
out += '"' + escape(o) + '"'
} else if (type === 'boolean') {
//Boolean
out += (o ? 'true' : 'false')
} else if (o === null || o === Infinity || o === -Infinity) {
//Null
out += 'null'
} else if (type === 'number') {
//Number
o = (Math.round(o*100000)/100000).toString()
if (o == 'NaN') o = null
out += o
} else if (o instanceof Array) {
//Array
let has_content = false
let multiline = !!o.find(item => typeof item === 'object');
if (!multiline) {
let length = 0;
o.forEach(item => {
length += typeof item === 'string' ? (item.length+4) : 3;
});
if (length > 140) multiline = true;
}
out += '['
for (var i = 0; i < o.length; i++) {
var compiled = handleVar(o[i], tabs+1)
if (compiled) {
if (has_content) {out += ',' + ((options.small || multiline) ? '' : ' ')}
if (multiline) {out += newLine(tabs)}
out += compiled
has_content = true
}
}
if (multiline) {out += newLine(tabs-1)}
out += ']'
} else if (type === 'object') {
//Object
breaks = breaks && o.constructor.name !== 'oneLiner';
var has_content = false
out += '{'
for (var key in o) {
if (o.hasOwnProperty(key)) {
var compiled = handleVar(o[key], tabs+1, breaks)
if (compiled) {
if (has_content) {out += ',' + (breaks || options.small?'':' ')}
if (breaks) {out += newLine(tabs)}
out += '"' + escape(key) + '":' + (options.small === true ? '' : ' ')
out += compiled
has_content = true
}
}
}
if (breaks && has_content) {out += newLine(tabs-1)}
out += '}'
}
return out;
}
let file = handleVar(object, 1);
if ((settings.final_newline.value && options.final_newline != false) || options.final_newline == true) {
file += '\n';
}
return file;
}
function autoParseJSON(data, feedback) {
if (data.substr(0, 4) === '<lz>') {
data = LZUTF8.decompress(data.substr(4), {inputEncoding: 'StorageBinaryString'})
}
if (data.charCodeAt(0) === 0xFEFF) {
data = data.substr(1)
}
try {
data = JSON.parse(data)
} catch (err1) {
data = data.replace(/\/\*[^(\*\/)]*\*\/|\/\/.*/g, '')
try {
data = JSON.parse(data)
} catch (err) {
if (feedback === false) return;
if (data.match(/\n\r?[><]{7}/)) {
Blockbench.showMessageBox({
title: 'message.invalid_file.title',
icon: 'fab.fa-git-alt',
message: 'message.invalid_file.merge_conflict'
})
return;
}
let error_part = '';
function logErrantPart(whole, start, length) {
var line = whole.substr(0, start).match(/\n/gm)
line = line ? line.length+1 : 1
var result = '';
var lines = whole.substr(start, length).split(/\n/gm)
lines.forEach((s, i) => {
result += `#${line+i} ${s}\n`
})
error_part = result.substr(0, result.length-1) + ' <-- HERE';
console.log(error_part);
}
console.error(err)
var length = err.toString().split('at position ')[1]
if (length) {
length = parseInt(length)
var start = limitNumber(length-32, 0, Infinity)
logErrantPart(data, start, 1+length-start)
} else if (err.toString().includes('Unexpected end of JSON input')) {
logErrantPart(data, data.length-16, 10)
}
Blockbench.showMessageBox({
translateKey: 'invalid_file',
icon: 'error',
message: tl('message.invalid_file.message', [err]) + (error_part ? `\n\n\`\`\`\n${error_part}\n\`\`\`` : '')
})
return;
}
}
return data;
}

View File

@ -81,6 +81,13 @@ Math.getNextPower = function(num, min) {
}
return i;
}
Math.signedPow = function(num, power=2) {
if (power % 2 == 0) {
return Math.pow(num, power) * Math.sign(num);
} else {
return Math.pow(num, power);
}
}
Math.snapToValues = function(val, snap_points, epsilon = 12) {
let snaps = snap_points.slice().sort((a, b) => {
return Math.abs(val-a) - Math.abs(val-b)

View File

@ -409,8 +409,10 @@ var Merge = {
}
},
molang(obj, source, index) {
if (['string', 'number'].includes(typeof source[index])) {
obj[index] = source[index];
if (typeof source[index] == 'string') {
obj[index] = source[index].replace(/-?\d\.\d+e-\d\d/g, '0');
} else if (typeof source[index] == 'number') {
obj[index] = Math.roundTo(source[index], 9).toString();
}
},
boolean(obj, source, index, validate) {
@ -489,6 +491,21 @@ Object.defineProperty(String.prototype, 'hashCode', {
return hash;
}
});
function exportMolang(input) {
if (!input) return 0;
if (typeof input == 'string') {
if (!isNaN(input)) {
let num = parseFloat(input);
return isNaN(num) ? 0 : num;
} else {
return input.replace(/\n/g, '');
}
} else if (typeof input == 'number') {
return input;
} else {
return 0;
}
}
// HTML
function isNodeUnderCursor(node, event) {
@ -656,6 +673,22 @@ function pointInTriangle(pt, v1, v2, v3) {
return !(has_neg && has_pos);
}
function pointInPolygon(point, polygon_points) {
// ray-casting algorithm based on
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
let x = point[0], y = point[1], vs = polygon_points;
let inside = false;
for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) {
let xi = vs[i][0], yi = vs[i][1];
let xj = vs[j][0], yj = vs[j][1];
let intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
function lineIntersectsTriangle(l1, l2, v1, v2, v3) {
return intersectLines(l1, l2, v1, v2) || intersectLines(l1, l2, v2, v3) || intersectLines(l1, l2, v3, v1);
}

View File

@ -242,7 +242,7 @@ new ValidatorCheck('texture_names', {
let characters = used_path.replace(/^#/, '').match(/[^a-z0-9._/\\-]/)
if (characters) {
this.warn({
message: `Texture "${used_path}" contains the following invalid characters: "${characters.join('')}". Valid characters are: a-z0-9._/\\-. Uppercase letters are invalid.`,
message: `Texture "${used_path}" contains the following invalid characters: "${characters.join('')}". Valid characters are: a-z0-9._/\\-. Uppercase letters and spaces are invalid.`,
buttons: [
{
name: 'Select Texture',

View File

@ -20,7 +20,7 @@ function initializeWebApp() {
if (location.host == 'blockbench-dev.netlify.app') {
let button = $(`<a href="https://www.netlify.com/" style="padding: 10px; color: white; cursor: pointer; text-decoration: none; display: block;" target="_blank" rel="noopener">
Hosted by
<img src="https://www.blockbench.net/_nuxt/74d4819838c06fa271394f626e8c4b16.svg" height="20px" style="vertical-align: text-top;">
<img src="./assets/netlify-full-logo-dark.svg" height="20px" style="vertical-align: text-top;">
</div>`);
button.insertBefore('#start_files');
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "Hlavní font",
"layout.font.headline": "Font nadpisu",
"about.version": "Verze:",
"about.creator": "Tvůrce:",
"about.website": "Webová stránka:",
"about.vertex_snap": "Vertexové přichytávání (Vertex Snapping) je založené na a pluginu od SirBeneta",
"about.icons": "Balíčky ikon:",
"about.libraries": "Knihovny:",
"settings.category.general": "Všeobecné",
"settings.category.preview": "Přehled",
"settings.category.grid": "Mřížka",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "True Isometric Right (30°)",
"camera_angle.true_isometric_left": "True Isometric Left (30°)",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "Repository:",
"settings.update_to_prereleases": "Update to Pre-releases",
"settings.update_to_prereleases.desc": "Automatically update to Blockbench beta versions to test new features. Pre-release versions can be unstable, don't enable this option if you rely on Blockbench for work or other important projects.",
"data.separator.spacer": "Spacer",
@ -1607,7 +1601,7 @@
"menu.mirror_painting.global.desc": "Enabled mirror painting on the model in global space",
"menu.mirror_painting.local": "Local Symmetry",
"menu.mirror_painting.local.desc": "Enable mirror painting in local space for each element",
"menu.mirror_painting.texture_frames": "Repeat on Animated Texture Frames",
"menu.mirror_painting.texture_frames": "Repeat on Flipbook Frames",
"menu.mirror_painting.texture_frames.desc": "Mirror paint strokes to every frame of animated textures",
"format.bedrock_block.info.size_limit": "Size total size of a block is limited to 30 pixels in all dimensions. The limit can be off-centered in all directions by 7 pixels from the block center.",
"format.bedrock_block.info.textures": "Multiple textures can be applied to different cubes in Blockbench, but require additional setup in the behavior pack to work correctly in-game.",
@ -1694,7 +1688,7 @@
"settings_profile.confirm_delete": "Are you sure you want to delete this settings profile?",
"settings_profile.condition.type.selectable": "Manually Selectable",
"settings.interface_mode": "UI Mode",
"settings.interface_mode.desc": "Interface mode. Restart Blockbench to apply changes",
"settings.interface_mode.desc": "Interface mode",
"settings.interface_mode.auto": "Automatic",
"settings.interface_mode.desktop": "Desktop",
"settings.interface_mode.mobile": "Mobile",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Mirror X",
"menu.uv.flip_y": "Mirror Y",
"menu.mirror_painting.enabled": "Enabled",
"menu.mirror_painting.configure_texture_center": "Configure Texture Center...",
"reference_image.position": "Position",
"reference_image.size": "Size",
"reference_image.rotation": "Rotation",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -114,7 +114,7 @@
"dialog.select.title": "Auswahl",
"dialog.select.group": "In ausgewählter Gruppe",
"dialog.select.name": "Name enthält",
"dialog.select.random": "Zufall",
"dialog.select.random": "Zufallschance (%)",
"dialog.select.select": "Auswählen",
"dialog.scale.title": "Modell skalieren",
"dialog.scale.axis": "Achse",
@ -164,11 +164,6 @@
"layout.font.main": "Hauptschriftart",
"layout.font.headline": "Überschriftenschriftart",
"about.version": "Version: ",
"about.creator": "Entwickler: ",
"about.website": "Webseite: ",
"about.vertex_snap": "Der Eckpunktmagnet basiert auf einem Plugin von SirBenet",
"about.icons": "Symbolpakete: ",
"about.libraries": "Bibliotheken: ",
"settings.category.general": "Allgemein",
"settings.category.preview": "Vorschau",
"settings.category.grid": "Gitter",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Isometrisch, rechts (30°)",
"camera_angle.true_isometric_left": "Isometrisch, links (30°)",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "Repository:",
"settings.update_to_prereleases": "Auf Vorabversionen aktualisieren",
"settings.update_to_prereleases.desc": "Blockbench automatisch auf die neusten Vorabversionen aktualisieren, um neue Funktionen zu testen. Vorabversionen können Fehler beinhalten, aktiviere diese Funktion nicht, wenn du dich für deine Arbeit auf die einwandfreie Funktion von Blockbench verlassen musst.",
"data.separator.spacer": "Abstandhalter",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "X spiegeln",
"menu.uv.flip_y": "Y spiegeln",
"menu.mirror_painting.enabled": "Aktiviert",
"menu.mirror_painting.configure_texture_center": "Zentrum in Textur einstellen ...",
"reference_image.position": "Position",
"reference_image.size": "Größe",
"reference_image.rotation": "Drehung",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Speichere die ausgewählten Keyframes als Animationsvorlage",
"action.animation_onion_skin": "Animationszwiebelschalen",
"action.animation_onion_skin.desc": "Zeige die Vorschau eines anderen Standbildes der Animation als Gitternetz an",
"action.animation_onion_skin.off": "Aus",
"action.animation_onion_skin.select": "Auswahl",
"action.animation_onion_skin.previous": "Voriges",
"action.animation_onion_skin.next": "Nächstes",
"action.animation_onion_skin.previous_next": "Voriges + Nächstes",
"action.apply_animation_preset": "Animationsvorlage anwenden",
"action.apply_animation_preset.desc": "Wähle aus einer Liste von Animationsvorlagen und wende die Vorlage auf den ausgewählten Knochen an",
"menu.brush_presets.pixel_perfect": "Pixelgenauer Pinsel",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Füge einen Zeilenumbruch am Ende von exportierten Dateien an",
"action.crop_layer_to_selection": "Ebene auf Auswahl zuschneiden",
"action.edit_mode_uv_overlay.desc": "Überlagert die UV-Maps der Elemente im Bearbeitungsmodus",
"action.animation_onion_skin_selective": "Zwiebelschalen nur für Auswahl",
"action.animation_onion_skin_selective.desc": "Zeige die Zwiebelschalenvorschau nur für den ausgewählten Teil des Modells an",
"menu.image": "Bild",
"menu.texture.discard_changes": "Änderungen verwerfen",
"menu.texture.discard_changes.desc": "Verwerfe alle ungespeicherten Änderungen und lade die neuste Version von der Datei",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Erweiterter Graph",
"message.screenshot_too_large.title": "Problem mit der Auflösung",
"message.screenshot_too_large.message": "Das Bildschirmfoto konnte nicht korrekt aufgezeichnet werden. Versuche es mit einer geringeren Auflösung oder ohne Supersampling.",
"message.rename_elements.numbering": "Verwende Sonderzeichen, um eine Zahlenfolge zu generieren: % wird ersetzt durch den Index des Elements in dessen Gruppe, $ wird ersetzt durch den Index des Elements in der Auswahl."
"message.rename_elements.numbering": "Verwende Sonderzeichen, um eine Zahlenfolge zu generieren: % wird ersetzt durch den Index des Elements in dessen Gruppe, $ wird ersetzt durch den Index des Elements in der Auswahl.",
"generic.edit_externally": "Extern bearbeiten",
"message.settings_require_restart.title": "Neustart erforderlich",
"message.settings_require_restart.message": "Einige Einstellungen treten erst nach einem Neustart des Programms in Effekt.",
"message.settings_require_restart.restart_now": "Jetzt neu starten",
"message.settings_require_restart.restart_later": "Später neu starten",
"message.classroom_mode.install_plugin": "Plugins können im Klassenzimmermodus nicht installiert werden",
"dialog.collection.export_path": "Exportpfad",
"dialog.collection.select_all": "Alle auswählen",
"dialog.collection.select_none": "Auswahl aufheben",
"dialog.collection.add_with_filter": "Mit Filter hinzufügen",
"dialog.collection.remove": "Entfernen",
"dialog.material_config.title": "Materialkonfiguration",
"dialog.material_config.color_value": "Farbwert",
"dialog.material_config.mer": "Metallhaftigkeit-Emissivität-Rauheit",
"dialog.material_config.mer_value": "MER Wert",
"dialog.material_config.depth_type": "Art der Tiefe",
"dialog.create_texture.disable_mirror_uv": "UV Spiegelung deaktivieren",
"dialog.create_texture.disable_mirror_uv.desc": "Deaktiviert die UV Spiegelung im Gespiegelten Modellieren, um separate UV Maps auf jeder Seite des Modells zu bewahren",
"dialog.create_gif.turn.sync_to_anim_length": "Mit Länge der Animation abstimmen",
"settings.category.controls": "Steuerung",
"settings.classroom_mode": "Klassenzimmermodus",
"settings.classroom_mode.desc": "Schränkt Funktionen wie das Installieren von Plugins ein und entfernt Links zu Sozialen Medien",
"settings.antialiasing_bleed_fix": "Kantenglättungsartefakte reduzieren",
"settings.antialiasing_bleed_fix.desc": "Vermeidet Artefakte durch das Übertreten von Texturen die durch Kantenglättung entstehen",
"settings.tone_mapping": "Tonemapping",
"settings.tone_mapping.desc": "Annäherungsmethode für die Darstellung von hohem Dynamikumfang auf einem normalen Bildschirm für PBR Effekte.",
"settings.audio_scrubbing": "Audiovorschau bei Timelinenavigation",
"settings.audio_scrubbing.desc": "Spielt während des Bewegens auf der Timeline kurze Audioschnipsel zur Vorschau ab",
"settings.viewport_rotate_speed": "Rotationsgeschwindigkeit bei Navigation",
"settings.viewport_rotate_speed.desc": "Empfindlichkeit der Steuerung zur Drehung bei der Navigation im Vorschaufenster",
"settings.viewport_zoom_speed": "Zoomgeschwindigkeit bei Navigation",
"settings.viewport_zoom_speed.desc": "Empfindlichkeit der Steuerung zum Zoomen bei der Navigation im Vorschaufenster",
"settings.editor_2d_zoom_speed": "2D Editor Zoomgeschwindigkeit",
"settings.editor_2d_zoom_speed.desc": "Empfindlichkeit der Steuerung beim Zoomen im UV bzw. 2D Editor",
"category.select": "Auswahl",
"action.vertex_snap_mode.rotate": "Drehen",
"action.export_image": "Bild exportieren",
"action.export_image.desc": "Exportiere Texturen als Bilddatei",
"action.apply_mirror_modeling": "Gespiegeltes Modellieren anwenden",
"action.apply_mirror_modeling.desc": "Gespiegeltes Modellieren auf die ausgewählten Elemente anwenden. Die Elemente werden kopiert und auf die andere Seite der X-Achse gespiegelt.",
"action.create_collection": "Sammlung erstellen",
"action.create_collection.desc": "Erstelle eine Sammlung aus den ausgewählten Elementen",
"action.set_collection_content_to_selection": "Auswahl als Sammlungsinhalt festlegen",
"action.set_collection_content_to_selection.desc": "Lege die ausgewählten Gruppen und Elemente als Inhalt der Sammlung fest",
"action.add_to_collection": "Auswahl zur Sammlung hinzufügen",
"action.add_to_collection.desc": "Füge die ausgewählten Gruppen und Elemente zur Sammlung hinzu",
"action.view_mode.material": "Materialvorschau",
"action.create_material": "Material erstellen",
"action.create_material.desc": "Erstelle ein neues PBR Material aus der ausgewählten Textur",
"action.generate_pbr_map": "PBR Map generieren...",
"action.generate_pbr_map.desc": "Generiere eine PBR Map (Höhenmap, oder Metallhaftigkeit, Emissivität, Rauheit) aus einer bestehenden Textur",
"menu.tools.main_tools": "Werkzeugkiste",
"menu.view.panels": "Panele",
"menu.texture.pbr_channel": "PBR Kanal",
"menu.texture.pbr_channel.color": "Farbe",
"menu.texture.pbr_channel.normal": "Normale",
"menu.texture.pbr_channel.height": "Höhe",
"menu.texture.pbr_channel.mer": "MER (Metall-Emission-Rauheit)",
"menu.texture.pbr_channel.mer_subsurface": "MER Verdeckte Lichtstreuung",
"menu.collection.export_project": "Projekt exportieren",
"menu.collection.export_as": "Exportieren als \"%0\"",
"menu.panel.enable": "Aktivieren",
"menu.panel.move_to": "Verschieben",
"menu.panel.move_to.left_bar": "Linke Seitenleiste",
"menu.panel.move_to.right_bar": "Rechte Seitenleiste",
"menu.panel.move_to.top": "Oben",
"menu.panel.move_to.bottom": "Unten",
"menu.panel.move_to.float": "Freischwebend",
"menu.panel.move_to.hidden": "Verstecken",
"menu.panel.fold": "Einklappen",
"menu.mirror_painting.texture_center": "Mittelpunkt",
"menu.mirror_modeling.mirror_uv": "UV Spiegeln",
"menu.animation_onion_skin.frames": "Standbilder",
"menu.animation_onion_skin.select": "Auswahl",
"menu.animation_onion_skin.previous": "Voriger Frame",
"menu.animation_onion_skin.next": "Nächster Frame",
"menu.animation_onion_skin.previous_next": "Voriger + Nächster",
"menu.animation_onion_skin.count": "Anzahl",
"menu.animation_onion_skin.interval": "Intervall",
"menu.animation_onion_skin_selective": "Nur Auswahl",
"menu.animation_onion_skin_selective.desc": "Die Zwiebelschalenansicht nur für die ausgewählten Elemente des Modells aktivieren",
"edit.loop_cut.unit": "Einheit",
"edit.loop_cut.unit.size_units": "Größeneinheit",
"edit.loop_cut.unit.percent": "Prozent",
"edit.extrude_mesh_selection.direction": "Richtung",
"edit.extrude_mesh_selection.direction.outwards": "Nach Außen",
"edit.extrude_mesh_selection.direction.average": "Durchschnitt",
"edit.extrude_mesh_selection.even_extend": "Gleichmäßig",
"edit.vertex_snap.align": "Ausrichtung",
"edit.vertex_snap.align.longest": "Längste Achse",
"edit.vertex_snap.align.direction": "Richtung vom Angelpunkt",
"edit.vertex_snap.align.align_axis": "%0-Achse",
"edit.vertex_snap.ignore_axis": "Achse ignorieren",
"codec.common.format": "Format",
"codec.image.quality": "Qualität",
"panel.collections": "Sammlungen",
"modifier_actions.always": "Immer aktiv",
"modifier_actions.unless": "Immer außer %0",
"settings.undo_selections": "Auswahl rückgängig machen",
"settings.undo_selections.desc": "Auswahlveränderungen im Bearbeitungsverlauf speichern und bei Bedarf rückgängig machen",
"action.focus_on_selection.zoom": "Größe einpassen",
"display.reference.tooting": "Bockshorn beim Abspielen",
"settings.selection_tolerance": "Auswahltoleranz",
"settings.selection_tolerance.desc": "Größe des Bereichs der zur Auswahl eines Eckpunktes oder einer Kante angeklickt werden kann",
"action.delete.keep_vertices": "Kanten/Eckpunkte behalten",
"menu.mesh": "Masche",
"dialog.material_config.subsurface": "Volumenstreuung",
"dialog.material_config.subsurface_enabled.desc": "Verwende den Transparenzkanal der MER Map für Volumenstreuung",
"settings.pick_combined_color": "Farbkombination auswählen",
"settings.pick_combined_color.desc": "Mit der Farbpipette die kombinierte Farbe aller Ebenen auswählen, an Stelle von der Farbe der ausgewählten Ebene",
"action.split_rgb_into_layers": "RGB Farbkanäle in Ebenen aufteilen",
"action.split_rgb_into_layers.desc": "Teile die Textur in eine additive Ebene pro RGB Farbkanal auf"
}

View File

@ -221,6 +221,8 @@
"status_bar.selection.edges": "%0 Edges",
"status_bar.selection.vertices": "%0 Vertices",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"modifier_actions.resize_both_sides": "Resize in both directions",
"modifier_actions.resize_one_side": "Resize in one direction",
"modifier_actions.draw_line": "Draw line",
@ -519,6 +521,8 @@
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"dialog.material_config.depth_type": "Depth Type",
"dialog.edit_texture.preview": "Preview",
@ -678,6 +682,8 @@
"dialog.create_texture.resolution.desc": "The height and width of the texture",
"dialog.create_texture.pixel_density": "Pixel Density",
"dialog.create_texture.pixel_density.desc": "The pixel density of the texture, in pixels per meter. The size of the texture map may differ depending on the amount and size of elements.",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.mirror_painting_texture_center.middle": "Middle",
"dialog.mirror_painting_texture_center.custom": "Custom",
@ -945,7 +951,7 @@
"settings.antialiasing": "Anti-aliasing",
"settings.antialiasing.desc": "Toggle anti-aliasing in the preview",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.render_sides": "Render Sides",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
@ -985,6 +991,8 @@
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"settings.stretch_linked": "Link Stretching",
"settings.stretch_linked.desc": "Stretch the cube in all directions with the same value",
"settings.auto_keyframe": "Auto Keyframe",
@ -1015,6 +1023,8 @@
"settings.ground_plane_double_side": "Ground Plane Double-sided",
"settings.ground_plane_double_side.desc": "Make the ground plane visible from below",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"settings.undo_limit": "Undo Limit",
"settings.undo_limit.desc": "Number of steps you can undo",
"settings.local_move": "Move on Relative Axes",
@ -1071,6 +1081,8 @@
"settings.color_wheel.desc": "Use the color wheel as the main color picker",
"settings.pick_color_opacity": "Pick Color Opacity",
"settings.pick_color_opacity.desc": "Pick the color opacity with the Color Picker and set it as brush opacity",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"settings.brush_cursor_2d": "2D Brush Cursor",
"settings.brush_cursor_2d.desc": "Display an outline around the brush in the 2D workspace",
"settings.brush_cursor_3d": "3D Brush Cursor",
@ -1480,6 +1492,7 @@
"action.duplicate.desc": "Duplicates the selected elements or group",
"action.delete": "Delete",
"action.delete.desc": "Deletes the selected elements or group",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"action.move_to_group": "Move to Group",
"action.move_to_group.desc": "Move the selected elements to a different outliner group",
"action.sort_outliner": "Sort Outliner",
@ -1650,6 +1663,8 @@
"action.adjust_curves.desc": "Adjust the brightness curves of the selected texture",
"action.limit_to_palette": "Limit to Palette",
"action.limit_to_palette.desc": "Limits the colors of the texture to those in the currently loaded palette",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel",
"action.clear_unused_texture_space": "Clear Unused Texture Space",
"action.clear_unused_texture_space.desc": "Clear parts of the texture that are not UV-mapped to any elements",
"action.flip_texture_x": "Flip Horizontally",
@ -1752,6 +1767,7 @@
"action.focus_on_selection": "Center View on Selection",
"action.focus_on_selection.desc": "Align the camera to face the center of the current selection",
"action.focus_on_selection.rotate_only": "Rotate only",
"action.focus_on_selection.zoom": "Zoom to fit",
"action.edit_reference_images": "Edit Reference Images",
"action.edit_reference_images.desc": "Turn on reference image mode to add or edit reference images and blueprints",
@ -1769,7 +1785,7 @@
"action.create_texture_group.desc": "Create a group for your textures",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"action.append_to_template": "Append Elements to Template...",
"action.append_to_template.desc": "Add the currently selected elements to the texture template",
@ -2020,6 +2036,7 @@
"menu.file": "File",
"menu.edit": "Edit",
"menu.transform": "Transform",
"menu.mesh": "Mesh",
"menu.uv": "UV",
"menu.texture": "Texture",
"menu.image": "Image",
@ -2118,7 +2135,7 @@
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Sursurface",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.texture.merge_onto_texture": "Merge Onto Texture Above",
"menu.texture.edit": "Edit",
"menu.texture.edit_externally": "Edit Externally",
@ -2189,6 +2206,8 @@
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_painting.texture_frames": "Repeat on Flipbook Frames",
"menu.mirror_painting.texture_frames.desc": "Mirror paint strokes to every frame of animated textures",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.image_tiled_view.mirrored": "Mirrored Edges",
@ -2265,7 +2284,7 @@
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore %0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"web.download_app": "Download App",
@ -2467,6 +2486,7 @@
"display.reference.bow": "Charged Bow",
"display.reference.crossbow": "Charged Crossbow",
"display.reference.eating": "Eating",
"display.reference.tooting": "Horn Tooting",
"display.reference.block": "Block",
"display.reference.frame": "Item Frame",
"display.reference.frame_invisible": "Item Frame (Invisible)",

View File

@ -14,7 +14,7 @@
"data.preview": "Previsualización",
"data.toolbar": "Barra de herramientas",
"data.image": "Imagen",
"keys.ctrl": "Control",
"keys.ctrl": "Ctrl",
"keys.shift": "Shift",
"keys.alt": "Alt",
"keys.meta": "CMD",
@ -62,7 +62,7 @@
"message.unsaved_textures.title": "Texturas sin guardar",
"message.unsaved_textures.message": "Tu modelo tiene texturas sin guardar. Asegúrate de guardarlas en la carpeta correcta del paquete de recursos",
"message.model_clipping.title": "Módelo muy grande",
"message.model_clipping.message": "Tu modelo contiene %0 cubos que son más grandes que el límite de 3x3x3 bloques establecido por Minecraft. Este modelo no funcionará en Minecraft.",
"message.model_clipping.message": "Tu modelo contiene %0 cubos que son más grandes que el límite de bloques establecido por Minecraft. Este modelo no funcionará en Minecraft.",
"message.loose_texture.title": "Importar Textura",
"message.loose_texture.message": "La texture importada no forma parte de un Resource Pack. Minecraft sólo puede cargar texturas dentro de una carpeta de textures en un Resource Pack cargado.",
"message.loose_texture.change": "Cambiar directorio",
@ -81,9 +81,9 @@
"message.image_editor.title": "Selecciona un editor de imágenes",
"message.image_editor.file": "Seleccionar archivo...",
"message.image_editor.exe": "Seleccionar el ejecutable de un editor de imágenes",
"message.display_skin.title": "Mostrar Skin",
"message.display_skin.title": "Skin de Minecraft",
"message.display_skin.message": "Selecciona un archivo de una skin de tu ordenador o escribe el nombre de un jugador",
"message.display_skin.upload": "Subir Skin",
"message.display_skin.upload": "Seleccionar Archivo",
"message.display_skin.reset": "Restablecer",
"message.invalid_plugin": "Archivo de plugin inválido, lee la Consola",
"message.load_plugin_app": "¿Quieres permitir a este plugin que haga cambios a tu PC? Carga sólo plugins de personas en las que confíes.",
@ -94,7 +94,7 @@
"dialog.project.title": "Proyecto",
"dialog.project.name": "Nombre de Archivo",
"dialog.project.parent": "Modelo Padre",
"dialog.project.geoname": "Nombre de la Geometría del Mob",
"dialog.project.geoname": "Identificador del Modelo",
"dialog.project.ao": "Oclusión Ambiental",
"dialog.texture.title": "Textura",
"dialog.texture.variable": "Variable",
@ -114,7 +114,7 @@
"dialog.select.title": "Seleccionar",
"dialog.select.group": "En el Grupo Seleccionado",
"dialog.select.name": "El Nombre Contiene",
"dialog.select.random": "Aleatorio",
"dialog.select.random": "Oportunidad Aleatoria (%)",
"dialog.select.select": "Seleccionar",
"dialog.scale.title": "Reescalar Modelo",
"dialog.scale.axis": "Ejes",
@ -160,15 +160,10 @@
"layout.color.light": "Claro",
"layout.color.light.desc": "Texto destacado",
"layout.color.accent_text": "Acento del texto",
"layout.color.accent_text.desc": "Texto en elementos claros o acentuados",
"layout.color.accent_text.desc": "Texto sobre fondos con acento",
"layout.font.main": "Fuente principal",
"layout.font.headline": "Fuente para títulos",
"about.version": "Versión:",
"about.creator": "Creador:",
"about.website": "Página web:",
"about.vertex_snap": "El Imán para Vértices está basado en un plugin hecho por SirBenet",
"about.icons": "Paquetes de Iconos:",
"about.libraries": "Librerías:",
"settings.category.general": "General",
"settings.category.preview": "Previsualización",
"settings.category.grid": "Cuadrícula",
@ -178,28 +173,28 @@
"settings.category.dialogs": "Diálogos",
"settings.category.export": "Exportar",
"settings.language": "Lenguaje",
"settings.language.desc": "Lenguaje de la interfaz. Reinicia Blockbench para aplicar los cambios.",
"settings.language.desc": "Lenguaje de Interfaz",
"settings.backup_interval": "Intervalo de Respaldos",
"settings.backup_interval.desc": "Intervalo de los respaldos automáticos en minutos",
"settings.origin_size": "Marcador de Pivote",
"settings.origin_size.desc": "Tamaño del marcador del punto de pivote",
"settings.control_size": "Tamaño del control de los ejes",
"settings.control_size.desc": "Tamaño de la herramienta de control de los 3 ejes",
"settings.display_skin": "Mostrar Skin",
"settings.display_skin.desc": "Skin usada para la referencia del modelo de jugador",
"settings.control_size": "Transformar el tamaño del artilugio",
"settings.control_size.desc": "Tamaño del artilugio de transformación",
"settings.display_skin": "Skin de Minecraft",
"settings.display_skin.desc": "Skin usada para la referencia del modelo jugador",
"settings.shading": "Sombreado",
"settings.shading.desc": "Activar sombreado",
"settings.shading.desc": "Habilitar sombreado en vista previa",
"settings.texture_fps": "FPS de las Texturas Animadas",
"settings.texture_fps.desc": "Cuadros por segundo para texturas animadas",
"settings.base_grid": "Cuadrícula Pequeña",
"settings.base_grid.desc": "Mostrar cuadrícula y ejes pequeños",
"settings.large_grid": "Cuadrícula Grande",
"settings.large_grid.desc": "Mostrar cuadrícula de 3x3",
"settings.full_grid": "Cuadrícula Muy Grande",
"settings.full_grid.desc": "Mostar cuadrícula precisa de 3x3",
"settings.large_box": "Caja grande",
"settings.large_box.desc": "Mostrar los límites de 3x3x3",
"settings.display_grid": "Modo de visualización",
"settings.large_grid": "Cuadrícula de bloques",
"settings.large_grid.desc": "Mostrar cuadrícula de 16x16 bloques",
"settings.full_grid": "Cuadrícula de bloques precisa",
"settings.full_grid.desc": "Mostrar cuadrícula de bloques con precisión de píxeles",
"settings.large_box": "Caja con límite de tamaño",
"settings.large_box.desc": "Mostrar límites de tamaño",
"settings.display_grid": "Modo de Visualización Cuadrícula",
"settings.display_grid.desc": "Mostrar cuadrícula en el modo de visualización",
"settings.undo_limit": "Límite de deshacer",
"settings.undo_limit.desc": "Número de acciones que puedes deshacer",
@ -214,7 +209,7 @@
"settings.create_rename": "Renombrar Nuevo Elemento",
"settings.create_rename.desc": "Campo de nombre de enfoque al crear nuevo elemento o grupo",
"settings.edit_size": "Resolución de la Cuadrícula",
"settings.edit_size.desc": "Resolución de la cuadrícula a la que se engancha el cubo",
"settings.edit_size.desc": "Resolución de la cuadrícula a la que se ajustan los elementos",
"settings.shift_size": "Resolución de Shift",
"settings.shift_size.desc": "Resolución de la cuadrícula al mantener Shift",
"settings.ctrl_size": "Resolución de Control",
@ -222,9 +217,9 @@
"settings.negative_size": "Tamaño Negativo",
"settings.negative_size.desc": "Permitir a la herramienta de reescalado usar tamaños negativos",
"settings.minifiedout": "Exportación minimizada",
"settings.minifiedout.desc": "Escribir el archivo JSON en una sola línea",
"settings.minifiedout.desc": "Escribir archivos JSON en una línea",
"settings.export_groups": "Exportar Grupos en modelos item/bloque de Java",
"settings.export_groups.desc": "Guardar grupos en modelos de bloques",
"settings.export_groups.desc": "Guardar grupos en archivos JSON de bloques java o modelos de item",
"settings.credit": "Comentario de Créditos",
"settings.credit.desc": "Añadir un comentario de créditos a archivos exportados",
"settings.default_path": "Directorio por defecto de las texturas de Minecraft",
@ -255,13 +250,13 @@
"action.slider_brush_softness": "Suavidad",
"action.slider_brush_softness.desc": "Suavidad del pincel en porcentaje",
"action.uv_slider_pos_x": "Mover Horizontal",
"action.uv_slider_pos_x.desc": "Mover la selección del UV de todos los cubos seleccionados horizontalmente",
"action.uv_slider_pos_x.desc": "Mover horizontalmente todas las caras UV seleccionadas",
"action.uv_slider_pos_y": "Mover Vertical",
"action.uv_slider_pos_y.desc": "Mover la selección del UV de todos los cubos seleccionados verticalmente",
"action.uv_slider_size_x": "Reescalar Horizontal",
"action.uv_slider_size_x.desc": "Reescalar la selección del UV de todos los cubos seleccionados horizontalmente",
"action.uv_slider_size_y": "Reescalar Vertical",
"action.uv_slider_size_y.desc": "Reescalar la selección del UV de todos los cubos seleccionados verticalmente",
"action.uv_slider_pos_y.desc": "Mover verticalmente todas las caras UV seleccionadas",
"action.uv_slider_size_x": "Tamaño Horizontal",
"action.uv_slider_size_x.desc": "Redimensionar horizontalmente todas las caras UV seleccionadas",
"action.uv_slider_size_y": "Tamaño Vertical",
"action.uv_slider_size_y.desc": "Redimensionar verticalmente todas las caras UV seleccionadas",
"action.vertex_snap_mode": "Modo Imán",
"action.vertex_snap_mode.desc": "Seleccionar si el Imán para Vertices mueve los elementos a la posición seleccionada o si los reescala",
"action.move_tool": "Mover",
@ -269,7 +264,7 @@
"action.resize_tool": "Reescalar",
"action.resize_tool.desc": "Herramienta para seleccionar y reescalar elementos",
"action.brush_tool": "Pincel de pintura",
"action.brush_tool.desc": "Herramienta para pintar en texturas bitmap en superficies o en el editor de UV",
"action.brush_tool.desc": "Pincel de color para dibujar sobre texturas",
"action.vertex_snap_tool": "Imán para Vértices",
"action.vertex_snap_tool.desc": "Mover un cubo a otro cubo al conectar 2 vértices",
"action.swap_tools": "Cambiar Herramientas",
@ -280,14 +275,14 @@
"action.open_model.desc": "Abre un archivo de modelo de tu ordenador",
"action.extrude_texture": "Textura Extruida",
"action.extrude_texture.desc": "General un modelo al extender una textura",
"action.export_blockmodel": "Exportar Modelo de Bloque",
"action.export_blockmodel.desc": "Exporta un modelo de bloque o de ítem",
"action.export_blockmodel": "Exportar modelo de bloque/item",
"action.export_blockmodel.desc": "Exportar un modelo de bloque o de item de Minecraft Java Edition",
"action.export_optifine_part": "Exportar Parte de Optifine",
"action.export_optifine_part.desc": "Exportar una sola parte para un modelo de entidad de OptiFine",
"action.export_optifine_full": "Exportar a OptiFine JEM",
"action.export_optifine_full.desc": "Exportar un modelo completo de entidad de OptiFine",
"action.export_obj": "Exportar Modelo OBJ",
"action.export_obj.desc": "Exportar a un modelo Wavefront OBJ para renderizar o motores de juego",
"action.export_obj.desc": "Exportar un modelo Wavefront OBJ para su renderización",
"action.settings_window": "Ajustes...",
"action.settings_window.desc": "Abre la ventana de ajustes de Blockbench",
"action.plugins_window": "Plugins...",
@ -315,33 +310,33 @@
"action.outliner_toggle": "Activar Más Opciones",
"action.outliner_toggle.desc": "Cambia los botones para más opciones en el Esquema",
"action.duplicate": "Duplicar",
"action.duplicate.desc": "Duplica los grupos o cubos seleccionados",
"action.duplicate.desc": "Duplica los elementos o el grupo seleccionados",
"action.delete": "Borrar",
"action.delete.desc": "Borra los grupos o cubos seleccionados",
"action.delete.desc": "Elimina los elementos o el grupo seleccionados",
"action.sort_outliner": "Ordenar Esquema",
"action.sort_outliner.desc": "Ordena el esquema alfabéticamente",
"action.select_window": "Seleccionar...",
"action.select_window.desc": "Busca y selecciona cubos basados en sus propiedades",
"action.select_window.desc": "Busca y seleccionar elementos basados en sus propiedades",
"action.invert_selection": "Invertir Selección",
"action.invert_selection.desc": "Invierte la selección actual de los cubos",
"action.invert_selection.desc": "Invertir la selección actual de elementos",
"action.select_all": "Seleccionar Todo",
"action.select_all.desc": "Selecciona todos los elementos, caras, vértices, o fotogramas",
"action.collapse_groups": "Colapsar Grupos",
"action.collapse_groups.desc": "Colapsa todos los grupos",
"action.collapse_groups.desc": "Contraer todos los grupos del esquema",
"action.scale": "Reescalar...",
"action.scale.desc": "Reescala los cubos seleccionados",
"action.scale.desc": "Escalar los elementos seleccionados",
"action.toggle_visibility": "Cambiar Visibilidad",
"action.toggle_visibility.desc": "Cambia el ajuste de visibilidad de los cubos seleccionados.",
"action.toggle_visibility.desc": "Cambiar la visibilidad de los elementos seleccionados",
"action.toggle_export": "Cambiar Exportación",
"action.toggle_export.desc": "Cambia el ajuste de exportación de los cubos seleccionados",
"action.toggle_export.desc": "Cambia el ajuste de exportación de los elementos seleccionados",
"action.toggle_autouv": "Cambiar Auto UV",
"action.toggle_autouv.desc": "Cambia el ajuste de Auto UV de los cubos seleccionados",
"action.toggle_autouv.desc": "Cambia el ajuste de Auto UV de los elementos seleccionados",
"action.toggle_shade": "Cambiar Sombreado",
"action.toggle_shade.desc": "Cambia el ajuste de sombreado de los cubos seleccionados",
"action.toggle_shade.desc": "Cambia el ajuste de sombreado de los elementos seleccionados",
"action.rename": "Renombrar",
"action.rename.desc": "Cambia el nombre de los cubos seleccionados",
"action.rename.desc": "Cambia el nombre de los elementos seleccionados",
"action.add_display_preset": "Nueva Plantilla",
"action.add_display_preset.desc": "Añade una nueva plantilla de ajustes de visualización",
"action.add_display_preset.desc": "Añadir un nuevo pre-ajuste de visualización",
"action.fullscreen": "Pantalla Completa",
"action.fullscreen.desc": "Cambia el modo de pantalla completa",
"action.zoom_in": "Hacer zoom",
@ -400,8 +395,8 @@
"menu.texture.file": "Archivo",
"menu.texture.refresh": "Refrescar",
"menu.texture.change": "Cambiar Archivo",
"menu.texture.folder": "Abrir en Carpeta",
"menu.texture.edit": "Editar Externamente",
"menu.texture.folder": "Mostrar en el Explorador de archivos",
"menu.texture.edit": "Editar",
"menu.texture.export": "Guardar Como",
"menu.texture.save": "Guardar",
"menu.texture.properties": "Propiedades",
@ -465,7 +460,7 @@
"display.reference.baby_zombie": "Zombie bebé",
"display.reference.armor_stand_small": "Armor Stand Pequeño",
"display.reference.monitor": "Normal",
"display.reference.bow": "Arco",
"display.reference.bow": "Arco Cargado",
"display.reference.block": "Bloque",
"display.reference.frame": "Marco de Ítems",
"display.reference.inventory_nine": "3x3",
@ -488,7 +483,7 @@
"action.change_textures_folder.desc": "Cambia la carpeta que en la que se guardan todas las texturas",
"menu.texture.particle": "Usar para Partículas",
"message.update_notification.title": "No fue posible Instalar la Actualización",
"message.update_notification.message": "Una nueva versión está disponible. ¡Active Actualizaciones Automáticas para actualizar!",
"message.update_notification.message": "Una nueva versión de Blockbench está disponible. ¡Active Actualizaciones Automáticas para actualizar!",
"message.untextured": "La superficie no tiene una textura",
"dialog.toolbar_edit.title": "Personalizar Barra de Herramientas",
"keybindings.reset": "Resetear",
@ -509,7 +504,7 @@
"action.uv_mirror_x.desc": "Invierte el UV de esta cara en el eje X",
"action.uv_mirror_y": "Invertir UV en Y",
"action.uv_mirror_y.desc": "Invierte el UV de esta cara en el eje Y",
"action.uv_transparent": "Cara Transparente",
"action.uv_transparent": "Eliminar cara",
"action.uv_transparent.desc": "Convierte la cara actual en transparente",
"action.uv_reset": "Resetear Cara",
"action.uv_reset.desc": "Resetea la cara actual",
@ -555,7 +550,7 @@
"action.move_right": "Mover Hacia Derecha",
"action.move_right.desc": "Mueve los cubos seleccionados hacia la derecha relativo al ángulo actual de la cámara",
"action.move_forth": "Mover Hacia Delante",
"action.move_forth.desc": "Mueve los cubos seleccionados hacia delante relativo al ángulo actual de la cámara",
"action.move_forth.desc": "Mueva los elementos seleccionados hacia adelante en relación con el ángulo actual de la cámara",
"action.move_back": "Mover Hacia Atrás",
"action.move_back.desc": "Mueve los cubos seleccionados hacia atrás relativo al ángulo actual de la cámara",
"layout.color.wireframe": "Estructura",
@ -584,7 +579,7 @@
"action.delete_keyframes": "Eliminar Fotogramas Clave",
"action.delete_keyframes.desc": "Elimina todos los fotogramas clave seleccionados",
"menu.animation": "Animación",
"menu.animation.loop": "Repetición",
"menu.animation.loop": "Modo de bucle",
"menu.animation.override": "Sobreescribir",
"menu.animation.anim_time_update": "Actualizar Variable",
"message.display_skin_model.title": "Modelo de Skin",
@ -600,9 +595,9 @@
"dialog.create_gif.title": "Grabar GIF",
"dialog.create_gif.length": "Duración",
"dialog.create_gif.fps": "FPS",
"dialog.create_gif.play": "Empezar Animación",
"dialog.create_gif.play": "Reproducir Animación",
"category.animation": "Animación",
"action.record_model_gif": "Grabar GIF",
"action.record_model_gif": "Grabar GIF...",
"action.record_model_gif.desc": "Graba un GIF animado de este modelo desde este ángulo",
"display.mirror": "Invertir",
"data.separator": "Separador",
@ -616,8 +611,8 @@
"mode.paint": "Pintar",
"mode.display": "Mostrar",
"mode.animate": "Animar",
"status_bar.recording_gif": "Grabando GIF",
"status_bar.processing_gif": "Procesando GIF",
"status_bar.recording_gif": "Grabando",
"status_bar.processing_gif": "Procesando",
"settings.backup_retain": "Mantenimiento de Respaldos",
"settings.backup_retain.desc": "Ajustar cuanto tiempo Blockbench mantiene respaldos viejos en días",
"action.rotate_tool": "Rotar",
@ -636,7 +631,7 @@
"menu.preview.perspective.reset": "Resetear Cámara",
"action.fill_mode": "Modo de Llenado",
"action.fill_mode.face": "Cara",
"action.fill_mode.color": "Color",
"action.fill_mode.color": "Colores",
"action.toggle_mirror_uv": "Invertir UV",
"action.toggle_mirror_uv.desc": "Activa el invertido de UV en el eje X de los cubos seleccionados",
"menu.texture.blank": "Aplicar a Caras sin Textura",
@ -678,7 +673,7 @@
"action.element_colors.desc": "Muestra los colores de cubo en el borde",
"texture.error.file": "Archivo no encontrado",
"texture.error.parent": "Archivo de textura proveído por el modelo padre",
"message.recover_backup.title": "Recuperar Modelo",
"message.recover_backup.title": "Recuperar Modelos",
"message.recover_backup.message": "Blockbench fue cerrado sin guardar. ¿Quieres recuperar el modelo?",
"message.invalid_session.title": "Token de Sesión Inválido",
"message.invalid_session.message": "La sesión a la que estas intentando entrar ha expirado o el token proveído es inválido.",
@ -723,7 +718,7 @@
"format.java_block": "Item/Bloque de Java",
"format.java_block.desc": "Modelo de bloque o item para la edición Java.",
"format.bedrock": "Entidad de Bedrock",
"format.bedrock.desc": "Modelo para la edición Bedrock.",
"format.bedrock.desc": "Modelo de Minecraft Bedrock Edition para entidades y objetos acoplables",
"format.bedrock_old": "Modelo Antiguo de Bedrock",
"format.bedrock_old.desc": "Modelo de entidad de las ediciones de Bedrock anteriores a 1.12",
"format.modded_entity": "Entidad de Mod",
@ -767,7 +762,7 @@
"action.remove_blank_faces.desc": "Elimina todas las caras sin textura de la selección",
"web.download_app": "Descargar Aplicación",
"uv_editor.turned": "Mapeado Girado",
"display.reference.crossbow": "Ballesta",
"display.reference.crossbow": "Ballesta Cargada",
"dialog.settings.search_results": "Resultados de Búsqueda",
"settings.animation_snap": "Imán de Animación",
"settings.animation_snap.desc": "Intervalo del imán para fotogramas clave en la línea de tiempo de la animación en pasos por segundo. Esto puede ser modificado para cada animación. El valor por defecto es 24.",
@ -806,9 +801,9 @@
"message.removed_faces": "Eliminadas %0 caras",
"dialog.sketchfab_uploader.draft": "Borrador",
"action.slider_pos": "Mover %0",
"action.slider_pos.desc": "Mover cubos en el eje %0",
"action.slider_pos.desc": "Mover elementos en el eje %0",
"action.slider_size": "Tamaño %0",
"action.slider_size.desc": "Redimensionar cubos en el eje %0",
"action.slider_size.desc": "Redimensionar elementos en el eje %0",
"action.slider_rotation": "Rotar %0",
"action.slider_rotation.desc": "Rotar cubos en el eje %0",
"action.slider_origin": "Pivote %0",
@ -890,7 +885,7 @@
"format.skin.desc": "Editar las skins de entidades y jugadores",
"message.sketchfab.setup_guide": "¿Quieres aprender a preparar modelos en Sketchfab? Lee %0",
"dialog.skin.title": "Crear Skin",
"dialog.skin.model": "Skin",
"dialog.skin.model": "Modelo",
"dialog.skin.texture": "Textura (Opcional)",
"action.toggle_skin_layer": "Cambiar Capa de Skin",
"action.toggle_skin_layer.desc": "Cambia la capa del gorro y de la ropa en el modelo de skin",
@ -1075,7 +1070,7 @@
"settings.motion_trails": "Senderos de movimiento",
"settings.motion_trails.desc": "Mostrar senderos de movimiento en el editor de animación",
"settings.antialiasing": "Anti-aliasing",
"settings.antialiasing.desc": "Modificar el anti-aliassing en la vista previa. Debes reiniciar Blockbench para aplicar los cambios",
"settings.antialiasing.desc": "Alternar el anti-aliasing en la vista previa",
"action.timeline_frame_back": "Avanza un fotograma atras",
"action.timeline_frame_forth": "Avanza un fotograma adelante",
"panel.bone.ik": "Cinemáticas inversas (Experimental)",
@ -1083,7 +1078,7 @@
"settings.particle_tick_rate.desc": "Efectos de partículas en la tasa de tic por segundo. El defecto es 30",
"action.lock_motion_trail": "Bloquear el rastro de movimiento",
"action.lock_motion_trail.desc": "Bloquear el rastro de movimiento en el grupo seleccionado",
"menu.animation_file.unload": "Descargar archivo de animación",
"menu.animation_file.unload": "Descargar archivo",
"data.null_object": "Objeto Nulo",
"status_bar.toggle_sidebar": "Mostrarbarralateral",
"message.load_plugin_failed.title": "Falló al cargar el plugin",
@ -1103,7 +1098,7 @@
"settings.ctrl_shift_size": "Resolución de Control + Shift",
"settings.ctrl_shift_size.desc": "Resolución del mapa mientras mantienes presionado control y shift",
"settings.hardware_acceleration": "Aceleración de Hardware",
"settings.hardware_acceleration.desc": "Subcontrato en tareas de renderizado a la tarjeta gráfica. Reinicia Blockbench para aplicar los cambios",
"settings.hardware_acceleration.desc": "Subcontratar tareas de renderizado a la tarjeta gráfica",
"action.explode_skin_model": "Expandir Modelo de Skin",
"action.explode_skin_model.desc": "Alternar a una vista de explosión que le permite editar caras cubiertas",
"action.export_minecraft_skin": "Exportar Skin de Minecraft",
@ -1180,7 +1175,7 @@
"action.load_keymap.cinema4d.desc": "Mapa de Teclas para usuarios que están familiarizados con los controles de Cinema 4D",
"action.load_keymap.maya.desc": "Mapa de Teclas para usuarios que estan familiarizados con los controles de Autodek Maya",
"action.import_keymap": "Importar Mapa de Teclas",
"action.import_keymap.desc": "Importar atajos de teclado como un archivo .bbkeymap",
"action.import_keymap.desc": "Importar atajos de teclado a un archivo .bbkeymap",
"action.export_keymap": "Exportar Mapa de Teclas",
"action.export_keymap.desc": "Exportar los actuales atajos de teclado como un archivo .bbkeymap",
"action.edit_history": "Editar Historial...",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Isométrico correcto derecho (30 grados)",
"camera_angle.true_isometric_left": "Isométrico correcto izquierdo (30 grados)",
"menu.help.wiki": "Wiki de BlockBench",
"about.repository": "Repositorio:",
"settings.update_to_prereleases": "Actualizar a una versión Preliminar",
"settings.update_to_prereleases.desc": "Actualiza automáticamente a una versión beta de Blockbench para probar nuevas características. Las versiones Preliminares pueden ser inestables, no actives esta opción si confía en Blockbench para el trabajo u otros proyectos importantes.",
"data.separator.spacer": "Espaciador",
@ -1235,7 +1229,7 @@
"message.invalid_link": "Link del Modelo Inválido o Expirado",
"message.default_textures.current": "Ruta actual",
"message.update_after_restart": "La actualización será instalada después del próximo reinicio",
"message.copy_paste_tool_viewport": "Este objeto solo puede usarse en el panel UV",
"message.copy_paste_tool_viewport": "Esta herramienta sólo puede utilizarse en el editor 2D",
"dialog.project.shadow_size": "Tamaño de la Sombra",
"dialog.find_replace.target": "Objetivo",
"dialog.find_replace.target.element_names": "Nombres de los Elementos",
@ -1252,22 +1246,22 @@
"dialog.add_primitive.shape.cylinder": "Cilindro",
"dialog.add_primitive.shape.sphere": "Esfera",
"dialog.add_primitive.shape.torus": "Toro",
"dialog.add_primitive.shape.cube": "Cubo",
"dialog.add_primitive.shape.cube": "Cuboide",
"dialog.add_primitive.shape.pyramid": "Pirámide",
"dialog.add_primitive.diameter": "Diámetro",
"dialog.add_primitive.height": "Peso",
"dialog.add_primitive.sides": "Lados",
"dialog.add_primitive.minor_diameter": "Espesor",
"dialog.add_primitive.minor_sides": "Lador Menores",
"dialog.create_texture.combine_polys": "Combinar Caras",
"dialog.create_texture.combine_polys.desc": "Combinar las caras conectadas en una en la sección UV",
"dialog.create_texture.combine_polys": "Combinar islas",
"dialog.create_texture.combine_polys.desc": "Combinar caras en islas UV conectadas",
"dialog.model_stats.meshes": "Mallas",
"dialog.export_private_settings.omit": "Salir",
"layout.select": "Seleccionar",
"layout.options": "Opciones",
"layout.color": "Escama de color",
"layout.documentation": "Documentación",
"layout.color.bright_ui_text": "Interfaz clara",
"layout.color.bright_ui_text": "Texto de interfaz brillante",
"layout.color.bright_ui_text.desc": "Texto en fondos claros",
"layout.name": "Nombre",
"layout.author": "Autor",
@ -1339,8 +1333,8 @@
"action.split_mesh": "Separar mallas",
"action.split_mesh.desc": "Separar las mallas seleccionadas en una nueva malla",
"action.merge_vertices": "Combinar vértices",
"action.merge_vertices.desc": "Combinar los vértices seleccionados en la posición del primer verted seleccionado",
"action.view_mode.normal": "Cara normal",
"action.merge_vertices.desc": "Fusionar los vértices seleccionados en la posición del primer vértice seleccionado",
"action.view_mode.normal": "Orientación de la cara",
"action.snap_uv_to_pixels": "Cambiar UV a píxeles",
"action.snap_uv_to_pixels.desc": "Ajusta los vértices UV seleccionados a la cuadrícula de píxeles",
"menu.file.import.import_open_project": "Importar proyecto abierto",
@ -1436,27 +1430,27 @@
"panel.skin_pose.jumping": "Saltando",
"panel.skin_pose.aiming": "Apuntando",
"edit.loop_cut.direction": "Dirección",
"data.texture_mesh": "Texture Mesh",
"generic.left": "Left",
"generic.right": "Right",
"mode.start.quick_setup": "Quick Setup",
"data.texture_mesh": "Malla de textura",
"generic.left": "Izquierda",
"generic.right": "Derecha",
"mode.start.quick_setup": "Armado rápido",
"mode.start.keymap": "Keymap",
"mode.start.quick_setup.more_themes": "More...",
"dialog.resize_texture.animation_frames": "Animation Frames",
"dialog.export_emission_map.title": "Export Emission Map",
"dialog.export_emission_map.format": "Format",
"dialog.export_emission_map.format.luminance": "Luminance",
"dialog.export_emission_map.format.luminance_inverted": "Luminance Inverted",
"dialog.export_emission_map.format.colors": "Colors",
"mode.start.quick_setup.more_themes": "Más...",
"dialog.resize_texture.animation_frames": "Fotograma de animación",
"dialog.export_emission_map.title": "Exportar Emission Map",
"dialog.export_emission_map.format": "Formato",
"dialog.export_emission_map.format.luminance": "Luminiscencia",
"dialog.export_emission_map.format.luminance_inverted": "Luminiscencia invertida",
"dialog.export_emission_map.format.colors": "Colores",
"dialog.export_emission_map.threshold": "Transparency Threshold",
"dialog.export_emission_map.round_up": "Round Up to %0 x %1",
"dialog.export_emission_map.flip_y": "Invertir Eje Y",
"dialog.select.type": "Element Type",
"dialog.select.type": "Tipo de elemento",
"dialog.create_texture.max_edge_angle": "Edge Angle Threshold",
"dialog.create_texture.max_edge_angle.desc": "The maximum angle between two faces at which they will still be combined",
"dialog.create_texture.max_island_angle": "Island Angle Threshold",
"dialog.create_texture.max_island_angle.desc": "The maximum angle that can be combined into the same UV island",
"settings.mobile_panel_side": "Mobile Panel Side",
"settings.mobile_panel_side": "Panel lateral móvil",
"settings.mobile_panel_side.desc": "Select which side of the screen panels are displayed on when using Blockbench on in landscape orientation",
"settings.obj_face_export_mode": "OBJ Face Export Mode",
"settings.obj_face_export_mode.desc": "Choose to let the OBJ exporter convert all faces into tris or quads",
@ -1472,22 +1466,22 @@
"action.select_seam": "Select UV Seam",
"action.select_seam.desc": "Select the UV seam mode for the selected edges",
"action.select_seam.auto": "Auto",
"action.select_seam.join": "Join",
"action.select_seam.divide": "Divide",
"action.select_seam.join": "Unir",
"action.select_seam.divide": "Dividir",
"action.adjust_brightness_contrast": "Ajustar Brillo y Contraste",
"action.adjust_brightness_contrast.desc": "Ajusta el brillo y contraste de la textura seleccionada",
"action.adjust_saturation_hue": "Adjust Saturation & Hue...",
"action.adjust_saturation_hue.desc": "Adjust the saturation and hue of the selected texture",
"action.adjust_saturation_hue": "Ajustar saturación y hue...",
"action.adjust_saturation_hue.desc": "Ajustar la saturación y el hue de la textura seleccionada",
"action.invert_colors": "Invertir Colores",
"action.invert_colors.desc": "Invert all colors of the selected texture",
"action.adjust_curves": "Adjust Curves...",
"action.adjust_curves.desc": "Adjust the brightness curves of the selected texture",
"action.invert_colors.desc": "Invertir todos los colores de la textura seleccionada",
"action.adjust_curves": "Ajustar curvas...",
"action.adjust_curves.desc": "Ajustar las curvas de brillo de la textura seleccionada",
"action.flip_texture_x": "Invertir Textura Horizontalmente",
"action.flip_texture_y": "Invertir Textura Verticalmente",
"action.resize_texture": "Reescalar Textura...",
"action.view_mode.uv": "UV Preview",
"action.append_to_template": "Append Elements to Template...",
"action.append_to_template.desc": "Add the currently selected elements to the texture template",
"action.append_to_template": "Añadir elementos a la plantilla...",
"action.append_to_template.desc": "Añadir los elementos actualmente seleccionados a la plantilla de textura",
"action.move_texture_with_uv": "Mover textura con UV",
"action.move_texture_with_uv.desc": "Mueve la textura de la cara al arrastrar las caras UV",
"action.timeline_setups": "Configuraciones de Líneas de Tiempo",
@ -1496,18 +1490,18 @@
"menu.texture": "Textura",
"menu.texture.render_mode.default": "Por Defecto",
"menu.texture.merge_onto_texture": "Combinar con la Textura Encima",
"menu.animation.unload": "Unload",
"menu.animation.unload": "Descargar",
"panel.timeline": "Línea de Tiempo",
"action.pan_tool": "Pan Tool",
"action.pan_tool.desc": "Tool to navigate in the viewport and the texture editor",
"mode.start.recent.favorite": "Señalar como Favorito",
"mode.start.info": "Info",
"mode.start.info": "Información",
"mode.start.target": "Objetivo",
"mode.start.start": "Start",
"mode.start.start": "Iniciar",
"mode.start.create_new": "Crear Nuevo Modelo",
"mode.start.format.informations": "Importante:",
"mode.start.format.resources": "Recursos:",
"format.free.info.meshes": "In this format, you can create low poly models using cubes and custom shaped meshes.",
"format.free.info.meshes": "En este formato, puedes crear modelos low poly usando cubos y mallas con formas personalizadas.",
"format.free.info.limitation": "Estos modelos no pueden ser usados en juegos que requieran formatos especializados, como Minecraft.",
"format.skin.info.skin": "Este formato está diseñado para crear skins de Minecraft y texturas para entidades.",
"format.skin.info.model": "Estos modelos no pueden ser modificados. Para realizar cambios, primero convierta a un formato diferente con **Archivo** > **Convertir Projecto**.",
@ -1518,23 +1512,23 @@
"format.bedrock_block": "Bloque de Bedrock",
"format.bedrock_block.desc": "Modelo de Bloque para Minecraft Bedrock",
"format.modded_entity.info.integer_size": "El tamaño de cubos esta limitado a integrales.",
"format.modded_entity.info.format": "Models are written in Java code instead of dedicated data structures like all other Blockbench export formats.",
"format.modded_entity.info.format": "Los modelos son escritos en código java en vez de estructuras de datos como el resto de formatos de exportación de Blockbench.",
"format.optifine_entity.info.optifine_required": "Usuarios sin OptiFine instalado no podrán ver el modelo.",
"format.optifine_entity.info.pivots": "Los pivotes de los huesos están bloqueados, es buena idea dejarlos sin modificar.",
"format_category.low_poly": "Low-Poly",
"format_category.minecraft": "Minecraft",
"format_category.other": "Other",
"format_category.loaders": "Loaders",
"format_category.other": "Otros",
"format_category.loaders": "Cargadores",
"message.recover_backup.recover": "Recuperar",
"message.invalid_characters.title": "Invalid Path",
"message.invalid_characters.title": "Trayectoria invalida",
"message.invalid_characters.message": "La ruta del archivo importado contiene caracteres inválidos, letras mayúsculas, o espacios. Los caracteres permitidos son: %0",
"dialog.share_model.thumbnail": "Miniatura",
"dialog.skin.high_res_texture": "Please note that skins with the selected resolution will not work as regular Minecraft skins. Select a lower resolution.",
"settings.allow_display_slot_mirror": "Allow Display Slot Mirroring",
"settings.allow_display_slot_mirror.desc": "Allow Display slots for Java item models to be mirrored. WARNING: This only works in Minecraft 1.14 or earlier or in special cases.",
"action.switch_tabs": "Switch Tabs",
"action.switch_tabs": "Intercambiar pestañas",
"action.switch_tabs.desc": "Cycle between opened tabs. Hold shift to cycle in the opposite direction.",
"action.unselect_all": "Unselect All",
"action.unselect_all": "Deseleccionar todo",
"action.unselect_all.desc": "Unselect all elements, faces, vertices, or keyframes",
"action.save_palette": "Guardar Paleta...",
"action.save_palette.desc": "Guarda la paleta de colores actual dentro de Blockbench para uso posterior",
@ -1565,7 +1559,7 @@
"settings.default_cube_size.desc": "Cambia el tamaño predeterminado del cubo al crear un nuevo cubo",
"settings.uniform_keyframe": "Reescalar Fotogramas Uniformemente",
"settings.uniform_keyframe.desc": "Establece los fotogramas clave a reescalado uniforme por defecto",
"settings.nearest_rectangle_select": "Rectangle Selection: Nearest Edge",
"settings.nearest_rectangle_select": "Selección de rectángulo: Borde mas cercano",
"settings.nearest_rectangle_select.desc": "Snap rectangle selections to the nearest pixel edge, like in GIMP, instead of entire pixels.",
"settings.pick_color_opacity": "Seleccionar Opacidad del Color",
"settings.pick_color_opacity.desc": "Selecciona la Opacidad del color con el Seleccionador de Color y la establece como la opacidad del pincel",
@ -1584,13 +1578,13 @@
"action.blend_mode.color": "Color",
"action.blend_mode.behind": "Por Detrás",
"action.blend_mode.multiply": "Multiplicar",
"action.blend_mode.divide": "Divide",
"action.blend_mode.add": "Add",
"action.blend_mode.subtract": "Subtract",
"action.blend_mode.divide": "Dividir",
"action.blend_mode.add": "Añadir",
"action.blend_mode.subtract": "Restar",
"action.blend_mode.screen": "Pantalla",
"action.blend_mode.overlay": "Cubierta",
"action.blend_mode.hard_light": "Hard Light",
"action.blend_mode.difference": "Difference",
"action.blend_mode.difference": "Diferencia",
"action.copy_brush": "Pincel de Copia",
"action.copy_brush.desc": "Pincel para clonar partes de tu textura o dibujar patrones",
"action.validator_window": "Ver Problemas del Modelo...",
@ -1612,14 +1606,14 @@
"format.bedrock_block.info.size_limit": "Size total size of a block is limited to 30 pixels in all dimensions. The limit can be off-centered in all directions by 7 pixels from the block center.",
"format.bedrock_block.info.textures": "Multiple textures can be applied to different cubes in Blockbench, but require additional setup in the behavior pack to work correctly in-game.",
"format.image.desc": "Edit images in the 2D image editor",
"generic.delete_all": "Delete All",
"generic.delete_all": "Eliminar todo",
"message.child_model_only.open": "Open Parent",
"message.child_model_only.open_with_textures": "Open Parent & Adopt Textures",
"dialog.project.credit": "Credit",
"dialog.convert_project.create_copy": "Create Copy",
"dialog.project.credit": "Credito",
"dialog.convert_project.create_copy": "Crear copia",
"dialog.texture.frame_time": "Frame Time",
"dialog.texture.frame_time.desc": "Set for how long each frame will be visible, in ticks. Each tick is 1/20th of a second.",
"dialog.texture.frame_interpolate": "Interpolate",
"dialog.texture.frame_interpolate": "Interpolar",
"dialog.texture.frame_interpolate.desc": "Interpolate between animation frames by cross-fading to the next frame",
"dialog.texture.frame_order_type": "Loop Mode",
"dialog.texture.frame_order_type.loop": "Loop",
@ -1633,25 +1627,25 @@
"dialog.select.mode.add": "Add to Selected",
"dialog.select.mode.remove": "Remove from Selected",
"dialog.select.mode.in_selection": "Select only from Selected",
"dialog.predicate_overrides.model": "Model",
"dialog.predicate_overrides.model": "Modelo",
"dialog.predicate_overrides.predicates": "Predicates",
"dialog.predicate_overrides.variants": "Variants",
"dialog.predicate_overrides.start_value": "Start",
"dialog.predicate_overrides.variants": "Variantes",
"dialog.predicate_overrides.start_value": "Inicio",
"dialog.predicate_overrides.add_override": "Add Override",
"dialog.predicate_overrides.add_predicate": "Add Predicate",
"dialog.predicate_overrides.generate_overrides": "Generate Overrides",
"dialog.predicate_overrides.confirm_delete": "Are you sure you want to delete all overrides?",
"dialog.predicate_overrides.predicate.angle": "Compass Angle",
"dialog.predicate_overrides.predicate.blocking": "Is Blocking",
"dialog.predicate_overrides.predicate.broken": "Is Broken",
"dialog.predicate_overrides.predicate.angle": "Angulo de la brújula",
"dialog.predicate_overrides.predicate.blocking": "Esta bloqueando",
"dialog.predicate_overrides.predicate.broken": "Esta roto",
"dialog.predicate_overrides.predicate.cast": "Is Cast",
"dialog.predicate_overrides.predicate.cooldown": "Cooldown",
"dialog.predicate_overrides.predicate.damage": "Damage",
"dialog.predicate_overrides.predicate.damaged": "Is Damaged",
"dialog.predicate_overrides.predicate.lefthanded": "Is Left-Handed",
"dialog.predicate_overrides.predicate.cooldown": "Enfriamiento",
"dialog.predicate_overrides.predicate.damage": "Daño",
"dialog.predicate_overrides.predicate.damaged": "Esta dañado",
"dialog.predicate_overrides.predicate.lefthanded": "Es zurdo",
"dialog.predicate_overrides.predicate.pull": "Pull Amount",
"dialog.predicate_overrides.predicate.pulling": "Is Pulling",
"dialog.predicate_overrides.predicate.charged": "Is Charged",
"dialog.predicate_overrides.predicate.charged": "Esta cargado",
"dialog.predicate_overrides.predicate.firework": "Has Firework",
"dialog.predicate_overrides.predicate.throwing": "Ready to Throw",
"dialog.predicate_overrides.predicate.time": "Time of Day",
@ -1663,22 +1657,22 @@
"settings.model_export_scale.desc": "Factor by which the scale of exported glTF, DAE, and FBX models gets reduced. The default is 16, which converts 16 Blockbench units into 1 meter in the export.",
"action.export_fbx": "Export FBX Model",
"action.export_fbx.desc": "Export model and animations as fbx file to use it in other 3D applications and game engines",
"action.center_lateral": "Center Lateral",
"action.center_lateral": "Centro lateral",
"action.center_lateral.desc": "Center the selected elements on the X and Z axis",
"action.adjust_opacity": "Adjust Opacity...",
"action.adjust_opacity.desc": "Adjust the opacity of the selected texture",
"action.rotate_texture_cw": "Rotate Clockwise",
"action.rotate_texture_ccw": "Rotate Counter-clockwise",
"action.adjust_opacity": "Ajustar opacidad",
"action.adjust_opacity.desc": "Ajustar la opacidad de la textura seleccionada",
"action.rotate_texture_cw": "Rotar en sentido del reloj",
"action.rotate_texture_ccw": "Rotar en sentido contra reloj",
"action.predicate_overrides": "Edit Predicate Overrides...",
"action.predicate_overrides.desc": "Select models to override this model based on selected conditions",
"action.auto_set_cullfaces": "Set Cullfaces Automatically",
"action.auto_set_cullfaces.desc": "Automatically generate cullfaces to hide faces when they are covered by the neighboring block.",
"menu.texture.edit_externally": "Edit Externally",
"menu.mirror_painting.texture": "2D Editor Symmetry",
"menu.mirror_painting.texture.desc": "Enable mirror painting in 2D space on the image or texture",
"menu.texture.edit_externally": "Editar externamente",
"menu.mirror_painting.texture": "Simetría del editor 2D",
"menu.mirror_painting.texture.desc": "Activar el pintado reflejado en el espacio 2D en la imagen o textura",
"menu.animator.rotation_global": "Rotate in Global Space",
"uv_editor.face_properties": "Face Properties",
"uv_editor.face_properties.material_instance": "Material Instance",
"uv_editor.face_properties": "Propiedades de la cara",
"uv_editor.face_properties.material_instance": "Instancia material",
"uv_editor.tint.info": "Tint can be enabled on a face to tell Minecraft to tint it. In vanilla, tint can only be used by specific blocks such as leaves and redstone dust, and can only have a value of 0.",
"uv_editor.cullface.info": "Enabling cullface tells a face on a block to unrender if another full block is placed next to it in the specified direction in your Minecraft world. This can be used to optimize performance.",
"uv_editor.material_instance.info": "Material instances can be set to a user-defined name. That name can be used in the block JSON file in the behavior pack to assign a particular texture and material that the face.",
@ -1694,7 +1688,7 @@
"settings_profile.confirm_delete": "Are you sure you want to delete this settings profile?",
"settings_profile.condition.type.selectable": "Manually Selectable",
"settings.interface_mode": "UI Mode",
"settings.interface_mode.desc": "Interface mode. Restart Blockbench to apply changes",
"settings.interface_mode.desc": "Interface mode",
"settings.interface_mode.auto": "Automatic",
"settings.interface_mode.desktop": "Desktop",
"settings.interface_mode.mobile": "Mobile",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Mirror X",
"menu.uv.flip_y": "Mirror Y",
"menu.mirror_painting.enabled": "Enabled",
"menu.mirror_painting.configure_texture_center": "Configure Texture Center...",
"reference_image.position": "Position",
"reference_image.size": "Size",
"reference_image.rotation": "Rotation",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2173,18 +2159,18 @@
"action.copy.multiple.desc": "Copy all available data individually",
"action.paste.multiple": "Paste All",
"action.randomize_marker_colors": "Randomize Marker Colors",
"action.cube_light_emission": "Light Emission",
"action.cube_light_emission.desc": "Change the emissiveness of the selected cubes, as a value between 0 and 15",
"action.cube_light_emission": "Emisión de luz",
"action.cube_light_emission.desc": "Cambiar la emisividad de los cubos seleccionados, como un valor entre 0 y 15",
"action.view_mode.colored_solid": "Solid with Marker Colors",
"action.focus_on_selection.rotate_only": "Rotate only",
"action.create_texture_group": "Create Texture Group",
"action.create_texture_group.desc": "Create a group for your textures",
"action.uv_maximize.all_faces": "Affect all faces",
"action.retarget_animators": "Retarget Animations",
"action.focus_on_selection.rotate_only": "Solo rotación",
"action.create_texture_group": "Crear grupo de texturas",
"action.create_texture_group.desc": "Crear un grupo para tus texturas",
"action.uv_maximize.all_faces": "Afecta todas las caras",
"action.retarget_animators": "Reorientar animaciones",
"action.retarget_animators.desc": "Select which animator targets which bone or element",
"action.merge_animation": "Merge Animation",
"action.merge_animation.desc": "Merge the animation into another animation",
"action.add_keyframe.reset_values": "With default values",
"action.merge_animation": "Mezclar animación",
"action.merge_animation.desc": "Mezclar la animación en otra animación",
"action.add_keyframe.reset_values": "Con los valores por defecto",
"action.set_timeline_range_start": "Set Timeline Range Start",
"action.set_timeline_range_start.desc": "Set the start point for a custom playback range in the animation timeline",
"action.set_timeline_range_end": "Set Timeline Range End",
@ -2192,41 +2178,153 @@
"action.disable_timeline_range": "Disable Timeline Range",
"action.disable_timeline_range.desc": "Disable the custom playback range in the animation timeline",
"menu.texture_group.resolve": "Resolve",
"menu.image_tiled_view.mirrored": "Mirrored Edges",
"menu.image_onion_skin_view.frame": "Frames",
"menu.image_onion_skin_view.frame.last_viewed": "Last Viewed Frame",
"menu.image_onion_skin_view.frame.previous": "Previous Frame",
"menu.image_onion_skin_view.frame.next": "Next Frame",
"menu.image_onion_skin_view.frame.both": "Previous + Next",
"menu.image_onion_skin_view.display": "Display",
"menu.image_onion_skin_view.display.pixels": "Smaller Pixels",
"menu.image_onion_skin_view.display.transparent": "Transparent",
"menu.image_onion_skin_view.above": "Display Above",
"menu.animation.reload": "Reload",
"switches.autouv.alt": "Relative",
"display.rotation_pivot": "Rotation Pivot",
"display.scale_pivot": "Scale Pivot",
"display.reference.fox": "Fox",
"display.reference.eating": "Eating",
"preview_scene.sky": "Sky",
"preview_scene.space": "Space",
"preview_scene.minecraft_ocean": "Ocean",
"message.import_palette.selection_only": "Selection only",
"menu.image_tiled_view.mirrored": "Bordes reflejados",
"menu.image_onion_skin_view.frame": "Fotogramas",
"menu.image_onion_skin_view.frame.last_viewed": "Fotograma anteriormente visto",
"menu.image_onion_skin_view.frame.previous": "Fotograma previo",
"menu.image_onion_skin_view.frame.next": "Siguiente fotograma",
"menu.image_onion_skin_view.frame.both": "Previo + anterior",
"menu.image_onion_skin_view.display": "Mostrar",
"menu.image_onion_skin_view.display.pixels": "Pixeles mas pequeños",
"menu.image_onion_skin_view.display.transparent": "Transparente",
"menu.image_onion_skin_view.above": "Mostrar abajo",
"menu.animation.reload": "Recargar",
"switches.autouv.alt": "Relativo",
"display.rotation_pivot": "Eje de rotación",
"display.scale_pivot": "Eje de escala",
"display.reference.fox": "Zorro",
"display.reference.eating": "Comer",
"preview_scene.sky": "Cielo",
"preview_scene.space": "Espacio",
"preview_scene.minecraft_ocean": "Oceano",
"message.import_palette.selection_only": "Solo selección",
"dialog.blend_transition_edit.ease_in_out": "Ease-in-out (%0)",
"dialog.blend_transition_edit.generate": "Generate...",
"dialog.blend_transition_edit.generate.learn_more": "More info and preview",
"dialog.blend_transition_edit.generate": "Generar...",
"dialog.blend_transition_edit.generate.learn_more": "Mas info y vista previa",
"dialog.blend_transition_edit.generate.curve": "Easing Type",
"dialog.blend_transition_edit.generate.steps": "Keyframes",
"settings.fps_limit": "FPS Limit",
"settings.fps_limit": "Limite de FPS",
"settings.fps_limit.desc": "Limit how many frames per second Blockbench renders. The actual frame rate is limited to what your device can display.",
"settings.outliner_reveal_on_select": "Reveal Elements on Select",
"settings.outliner_reveal_on_select.desc": "Reveal elements in the ouliner when selected",
"settings.java_export_pivots": "Export Pivots in Java block/item models",
"settings.java_export_pivots.desc": "Save pivot points in Java block/item models on cubes without rotation",
"animation_controllers.state.blend_transition_curve": "Blend Transition Curve",
"menu.slider.reset_vector": "Reset Vector",
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"menu.slider.reset_vector": "Reajustar vector",
"dialog.blend_transition_edit.extended": "Grafico extendido",
"message.screenshot_too_large.title": "Problema en la resolución de la captura",
"message.screenshot_too_large.message": "La captura de pantalla no podrá renderizarse exitosamente. por favor inténtelo otra vez con una resolución mas baja o sin supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "Police principale",
"layout.font.headline": "Police de titre",
"about.version": "Version :",
"about.creator": "Créateur :",
"about.website": "Site Internet :",
"about.vertex_snap": "L'Alignement Vertex est basé sur un plugin de SirBenet",
"about.icons": "Packs d'icônes :",
"about.libraries": "Bibliothèques :",
"settings.category.general": "Général",
"settings.category.preview": "Aperçu",
"settings.category.grid": "Grille",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Vraie droite isométrique (30°)",
"camera_angle.true_isometric_left": "Vraie gauche isométrique (30°)",
"menu.help.wiki": "Wiki Blockbench",
"about.repository": "Dépôt :",
"settings.update_to_prereleases": "Mettre à jour vers les versions expérimentales",
"settings.update_to_prereleases.desc": "Met à jour Blockbench automatiquement vers des versions bêta pour tester les nouvelles fonctionnalités. Les versions expérimentales peuvent être instables, n'activez pas cette option si vous vous servez de Blockbench pour le travail ou d'autres projets importants.",
"data.separator.spacer": "Séparateur",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Miroir X",
"menu.uv.flip_y": "Miroir Y",
"menu.mirror_painting.enabled": "Activer",
"menu.mirror_painting.configure_texture_center": "Configurer le centre de texture...",
"reference_image.position": "Position",
"reference_image.size": "Taille",
"reference_image.rotation": "Rotation",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Sélectionner",
"action.animation_onion_skin.previous": "Précédente",
"action.animation_onion_skin.next": "Suivante",
"action.animation_onion_skin.previous_next": "Précédente + Suivante",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

File diff suppressed because it is too large Load Diff

View File

@ -164,11 +164,6 @@
"layout.font.main": "メインフォント",
"layout.font.headline": "見出しフォント",
"about.version": "バージョン:",
"about.creator": "クリエイター:",
"about.website": "ウェブサイト:",
"about.vertex_snap": "Vertex Snapping は SirBenet によって提供されました",
"about.icons": "アイコンパック:",
"about.libraries": "ライブラリ:",
"settings.category.general": "一般",
"settings.category.preview": "プレビュー",
"settings.category.grid": "グリッド",
@ -178,7 +173,7 @@
"settings.category.dialogs": "ダイアログ",
"settings.category.export": "書き出し",
"settings.language": "言語を変更",
"settings.language.desc": "変更を適用するには Blockbench を再起動してください。",
"settings.language.desc": "インターフェース言語",
"settings.backup_interval": "バックアップ",
"settings.backup_interval.desc": "バックアップの頻度を変更します",
"settings.origin_size": "ピボットマーカー",
@ -258,10 +253,10 @@
"action.uv_slider_pos_x.desc": "選択したキューブの UV を水平方向に移動します",
"action.uv_slider_pos_y": "垂直移動",
"action.uv_slider_pos_y.desc": "選択したキューブの UV を垂直方向に移動します",
"action.uv_slider_size_x": "水平スケール",
"action.uv_slider_size_x.desc": "選択したキューブの UV を水平方向に広げます",
"action.uv_slider_size_y": "垂直スケール",
"action.uv_slider_size_y.desc": "選択したキューブの UV を垂直方向に広げます",
"action.uv_slider_size_x": "水平サイズ",
"action.uv_slider_size_x.desc": "選択した UV を水平方向にリサイズします",
"action.uv_slider_size_y": "垂直サイズ",
"action.uv_slider_size_y.desc": "選択した UV を垂直方向にリサイズします",
"action.vertex_snap_mode": "スナップ",
"action.vertex_snap_mode.desc": "頂点スナップが選択された位置に移動するか、サイズを変更するかを選択します",
"action.move_tool": "移動",
@ -324,7 +319,7 @@
"action.select_window.desc": "プロパティからエレメントを検索します",
"action.invert_selection": "インバート",
"action.invert_selection.desc": "選択中のエレメントを反転します",
"action.select_all": "全てを選択",
"action.select_all": "すべて選択",
"action.select_all.desc": "すべてのエレメントを選択します",
"action.collapse_groups": "折りたたむ",
"action.collapse_groups.desc": "すべてのグループを折りたたみます",
@ -616,8 +611,8 @@
"mode.paint": "Paint",
"mode.display": "Display",
"mode.animate": "Animate",
"status_bar.recording_gif": "レコーディング GIF",
"status_bar.processing_gif": "GIF の加工処理",
"status_bar.recording_gif": "レコーディング",
"status_bar.processing_gif": "加工処理",
"settings.backup_retain": "バックアップ保持期間",
"settings.backup_retain.desc": "バックアップを保持する日数を設定します",
"action.rotate_tool": "回転",
@ -871,7 +866,7 @@
"action.timelapse": "タイムラプス...",
"action.timelapse.desc": "モデリングプロセスのタイムラプスを記録します",
"action.add_keyframe": "キーフレームを追加",
"action.add_keyframe.desc": "キーフレームを自動的に追加します。 Shift キーを押すとデフォルト値が表示されます",
"action.add_keyframe.desc": "アニメーターにキーフレームを追加します",
"action.bring_up_all_animations.desc": "変更されたすべてのアニメーターをタイムラインに組み込みます",
"timeline.timeline": "インストラ",
"menu.palette.load.default": "デフォルト",
@ -989,7 +984,7 @@
"action.load_plugin_from_url.desc": "サーバーからプラグインをロードします",
"action.cube_counter.desc": "現在のキューブ数とその他の統計を表示します",
"action.unlock_everything": "アンロック",
"action.unlock_everything.desc": "アウトラインのてのロックを解除します。",
"action.unlock_everything.desc": "アウトラインのすべてのロックを解除します。",
"action.load_palette": "パレットをロード",
"action.load_palette.desc": "パレットプリセットをロードします",
"action.toggle_locked": "トグルロック",
@ -997,7 +992,7 @@
"action.apply_display_preset": "プリセットを適用",
"action.apply_display_preset.desc": "カスタム表示設定のプリセットを適用します",
"action.apply_display_preset.here": "スロットに適用",
"action.apply_display_preset.everywhere": "てのスロットに適用",
"action.apply_display_preset.everywhere": "すべてのスロットに適用",
"action.resolve_keyframe_expressions": "キーフレームを解除",
"action.resolve_keyframe_expressions.desc": "選択したキーフレームを解除します",
"action.fold_all_animations": "すべてのアニメーターを折りたたむ",
@ -1069,13 +1064,13 @@
"generic.all": "All",
"message.small_face_dimensions.title": "互換性のないフェイス",
"message.small_face_dimensions.message": "選択範囲に 1 より小さいフェイスが含まれています。マッピングシステムは、そのしきい値を下回るフェイスを 0 ピクセルと見なします。これらのフェイスのテクスチャは正しく機能しない可能性があります。",
"message.small_face_dimensions.face_uv": "このフォーマットでは、各フェイスごとの UV マップをサポートしています。\"ファイル\" > \"プロジェクト...\" に移動し、\"UV モード\" を \"Per-face UV\" に変更してください。",
"message.small_face_dimensions.face_uv": "現在のフォーマットは、Per-face UV マップをサポートしています。影響を受けるキューブを右クリックし、「UV Mode 」を 「Per-face UV 」に変更してください。",
"dialog.plugins.outdated_client": "新しいバージョンの Blockbench が必要です",
"dialog.plugins.outdated_plugin": "このバージョンの Blockbench では動作しません",
"settings.motion_trails": "モーショントレイル",
"settings.motion_trails.desc": "アニメーションエディタでモーショントレイルを表示します",
"settings.antialiasing": "アンチエイリアシング",
"settings.antialiasing.desc": "プレビューでアンチエイリアスを切り替えます。 Blockbench を再起動して変更を適用します",
"settings.antialiasing.desc": "プレビューでアンチエイリアスを切り替えます",
"action.timeline_frame_back": "1フレーム戻る",
"action.timeline_frame_forth": "1フレーム進む",
"panel.bone.ik": "逆運動学 (IK)",
@ -1103,7 +1098,7 @@
"settings.ctrl_shift_size": "ダブルステップ",
"settings.ctrl_shift_size.desc": "Control + Shift のグリッド間隔を変更します",
"settings.hardware_acceleration": "アプリを最適化",
"settings.hardware_acceleration.desc": "グラフィックカードを使用し、レンダリングを高速化します。この機能を利用するのには再起動が必要です",
"settings.hardware_acceleration.desc": "グラフィックカードを使用し、レンダリングを高速化します",
"action.explode_skin_model": "モデルを分離",
"action.explode_skin_model.desc": "スキンをバーツごとに分解します",
"action.export_minecraft_skin": "Minecraft Skin",
@ -1147,7 +1142,7 @@
"message.load_keymap": "キーマップをロードしますか? 現在のキーバインドが置き換えられます。",
"message.keymap_loaded": "キーマップのロード",
"dialog.convert_project.current_format": "現在のフォーマット",
"dialog.create_texture.rearrange_uv.desc": "新しい UV アレンジメントを作成して、てのフェイスに独自のテクスチャを与えます",
"dialog.create_texture.rearrange_uv.desc": "新しい UV アレンジメントを作成して、すべてのフェイスに独自のテクスチャを与えます",
"dialog.create_texture.power.desc": "オートテクスチャサイズを正方形に固定します。",
"dialog.create_texture.double_use.desc": "2つの要素に同じ UV スペースが割り当てられている場合、新しいマップでも維持します",
"dialog.create_texture.padding.desc": "テンプレートの間にパディングを追加します",
@ -1220,13 +1215,12 @@
"camera_angle.true_isometric_right": "等角投影 右( 30°",
"camera_angle.true_isometric_left": "等角投影 左( 30°",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "リポジトリ:",
"settings.update_to_prereleases": "プレリリース",
"settings.update_to_prereleases.desc": "新機能をいち早く体験するために、Blockbench のプレリリースバージョンに自動的に更新されます。ただし、プレリリースバージョンは不安定な場合があるため、実行中のプロジェクトがある場合はこのオプションを有効にしないでください。",
"data.separator.spacer": "スペーサー",
"data.separator.linebreak": "改行",
"data.setting": "Setting",
"generic.select_all": "全てを選択",
"generic.select_all": "すべて選択",
"generic.select_none": "クリア",
"projects.new_tab": "New Tab",
"projects.close_tab": "Close Tab",
@ -1352,8 +1346,8 @@
"settings.vertex_merge_distance.desc": "頂点がマージされる距離を変更します",
"settings.show_only_selected_uv": "セレクト UV",
"settings.show_only_selected_uv.desc": "選択した UV フェイスのみを UV エディタに表示します",
"action.merge_vertices.merge_all": "てマージ",
"action.merge_vertices.merge_all_in_center": "中央にてマージ",
"action.merge_vertices.merge_all": "すべてマージ",
"action.merge_vertices.merge_all_in_center": "中央にすべてマージ",
"action.merge_vertices.merge_by_distance": "距離マージ",
"action.merge_vertices.merge_by_distance_in_center": "中央に距離マージ",
"action.uv_rotate_left": "UV を左回転",
@ -1362,12 +1356,12 @@
"action.uv_rotate_right.desc": "選択した UV フェイスを時計回りに回転します",
"menu.uv.display_uv": "UV を表示",
"menu.uv.display_uv.selected_faces": "選択したフェイス",
"menu.uv.display_uv.selected_elements": "てのフェイス",
"menu.uv.display_uv.selected_elements": "すべてのフェイス",
"menu.uv.display_uv.all_elements": "All Faces on All Elements",
"menu.paste.face": "UV フェイス",
"menu.paste.mesh_selection": "メッシュの選択",
"menu.paste.outliner": "エレメント",
"uv_editor.show_all_faces": "てのフェイスを表示",
"uv_editor.show_all_faces": "すべてのフェイスを表示",
"uv_editor.show_selected_faces": "選択したフェイスを表示",
"status_bar.selection.edges": "%0 個のエッジ",
"action.selection_mode.edge": "エッジ",
@ -1398,8 +1392,8 @@
"settings.status_bar_modifier_keys.desc": "状況に応じた修飾キーをステータスバーに表示します",
"settings.ground_plane": "グランド",
"settings.ground_plane.desc": "モデルの下にグランドを表示します",
"settings.preview_paste_behavior": "デフォルトプレビュー",
"settings.preview_paste_behavior.desc": "プレビューに貼り付けるときのオプションを変更します",
"settings.preview_paste_behavior": "デフォルトビューポート",
"settings.preview_paste_behavior.desc": "編集モードでビューポートにペーストする際の動作を選択し、複数のオプションを利用できるようにします",
"settings.preview_paste_behavior.always_ask": "常に尋ねる",
"action.new_window": "新規ウィンドウ",
"action.new_window.desc": "新しい Blockbench ウィンドウを開きます",
@ -1607,12 +1601,12 @@
"menu.mirror_painting.global.desc": "グローバル空間でミラーペインティングを有効にします",
"menu.mirror_painting.local": "ローカル対称性",
"menu.mirror_painting.local.desc": "ローカル空間でミラーペインティングを有効にします",
"menu.mirror_painting.texture_frames": "アニメーションフレームをリピート",
"menu.mirror_painting.texture_frames": "フリップフレームをリピート",
"menu.mirror_painting.texture_frames.desc": "すべてのフレームにペイントストロークをミラーリングします",
"format.bedrock_block.info.size_limit": "ブロックの合計サイズは 30 ピクセル以内に制限されています。",
"format.bedrock_block.info.textures": "Blockbench では、複数のテクスチャをさまざまなキューブに適用できますが、ゲーム内で正しく機能させるには、リソースパックに追加の設定が必要です。",
"format.image.desc": "2D 画像エディタ",
"generic.delete_all": "全てを削除",
"generic.delete_all": "すべて削除",
"message.child_model_only.open": "親モデルを開く",
"message.child_model_only.open_with_textures": "親モデルからテクスチャを適用します",
"dialog.project.credit": "クレジット",
@ -1679,7 +1673,7 @@
"menu.animator.rotation_global": "グローバルスペースで回転",
"uv_editor.face_properties": "プロパティ",
"uv_editor.face_properties.material_instance": "マテリアルインスタンス",
"uv_editor.tint.info": "チルトを有効にして、Minecraft に色合いを付けます。 ただし、葉やレッドストーンダストなどの特定のブロックでのみ使用でき、値は 0 のみです。",
"uv_editor.tint.info": "Tint を有効にすると、Minecraft に色合いを指定できます。バニラでは、色合いは葉っぱやレッドストーンダストなどの特定のブロックにのみ使用できます。",
"uv_editor.cullface.info": "カリングを有効にすると、Minecraft ワールド内で別のブロックが隣接した場合、ブロックのレンダリングが解除されます。これにより、ゲーム内のパフォーマンスが最適化されます。",
"uv_editor.material_instance.info": "マテリアルインスタンスはリソースパックの block.json ファイルにて、フェイスに特定のテクスチャとマテリアルを割り当てることができます。",
"display.reference.frame_invisible": "額縁(透明)",
@ -1694,7 +1688,7 @@
"settings_profile.confirm_delete": "プロファイルの設定を削除してもよろしいですか?",
"settings_profile.condition.type.selectable": "手動で選択",
"settings.interface_mode": "UI モード",
"settings.interface_mode.desc": "お使いの端末に最適なインターフェースを選択します",
"settings.interface_mode.desc": "インターフェースモード",
"settings.interface_mode.auto": "オート",
"settings.interface_mode.desktop": "デスクトップ",
"settings.interface_mode.mobile": "モバイル",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Mirror X",
"menu.uv.flip_y": "Mirror Y",
"menu.mirror_painting.enabled": "有効",
"menu.mirror_painting.configure_texture_center": "テクスチャセンターを設定...",
"reference_image.position": "Position",
"reference_image.size": "Size",
"reference_image.rotation": "Rotation",
@ -1832,7 +1825,7 @@
"reference_image.layer.blueprint": "設計図をロック",
"reference_image.scope": "スコープ",
"reference_image.scope.project": "このプロジェクトのみ",
"reference_image.scope.global": "てのプロジェクト",
"reference_image.scope.global": "すべてのプロジェクト",
"reference_image.enabled_modes": "モードで有効",
"codec.common.encoding": "エンコード",
"codec.common.armature": "グループをアマチュアとしてエクスポート",
@ -1868,7 +1861,7 @@
"dialog.unsaved_work.title": "Unsaved Work",
"dialog.unsaved_work.text": "次のプロジェクトには、保存されていない変更が含まれています。 変更を保存しますか?",
"dialog.unsaved_work.discard_all": "破棄",
"dialog.unsaved_work.save_all": "て保存",
"dialog.unsaved_work.save_all": "すべて保存",
"dialog.resize_texture.mode": "モード",
"dialog.resize_texture.mode.crop": "トリミング/拡大",
"dialog.resize_texture.mode.scale": "スケール",
@ -1919,7 +1912,7 @@
"action.split_screen.triple_top": "トリプルトップ",
"action.split_screen.triple_bottom": "トリプルボトム",
"action.uv_project_from_view": "UV プロジェクト",
"action.uv_project_from_view.desc": "3D ビューの視点から選択した UV を自動的に生成します",
"action.uv_project_from_view.desc": "3D ビューから選択した UV を自動的に生成します",
"action.graph_editor_other_graphs": "他のグラフを表示",
"action.graph_editor_other_graphs.desc": "選択されていない軸のグラフを表示します",
"action.graph_editor_include_other_graphs": "他のグラフを含める",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "選択したキーフレームをアニメーションプリセットとして保存します",
"action.animation_onion_skin": "アニメートレイヤースキン",
"action.animation_onion_skin.desc": "アニメーション中ののワイヤーフレームビューを参照用に表示します",
"action.animation_onion_skin.off": "オフ",
"action.animation_onion_skin.select": "選択",
"action.animation_onion_skin.previous": "戻す",
"action.animation_onion_skin.next": "進む",
"action.animation_onion_skin.previous_next": "戻す 進む",
"action.apply_animation_preset": "アニメーションプリセットを適用",
"action.apply_animation_preset.desc": "アニメーションのプリセットリストから選択して、ボーンに適用します",
"menu.brush_presets.pixel_perfect": "パーフェクトピクセルブラシ",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "ファイルの末尾に改行を挿入します",
"action.crop_layer_to_selection": "レイヤーを選択範囲にトリミング",
"action.edit_mode_uv_overlay.desc": "編集モードで UV マップをオーバーレイとして表示します",
"action.animation_onion_skin_selective": "トグルレイヤースキン",
"action.animation_onion_skin_selective.desc": "選択したレイヤースキンのみを表示します",
"menu.image": "Image",
"menu.texture.discard_changes": "元に戻す",
"menu.texture.discard_changes.desc": "ファイルから最新バージョンをダウンロードします",
@ -2059,65 +2045,65 @@
"message.optimize_animation.keyframes_removed": "%0 個の余分なキーフレームを削除しました",
"message.optimize_animation.nothing_to_optimize": "すでに最適化されています",
"message.duplicate_bone_copy_animation.title": "アニメーションをコピー",
"message.duplicate_bone_copy_animation.message": "The duplicated bone is animated in %0 animations. Do you want to copy the keyframes over to the new bone?",
"message.auto_fix_mesh_edit.title": "Auto Fix",
"message.auto_fix_mesh_edit.revert": "Revert Edit",
"message.auto_fix_mesh_edit.overlapping_vertices": "Certain vertices have been moved into the same spot. How would you like to proceed?",
"message.auto_fix_mesh_edit.concave_quads": "One or more quad faces are now concave, which can cause issues in UV-mapping and rendering. Blockbench can automatically fix it for you:",
"message.auto_fix_mesh_edit.merge_vertices": "Merge Vertices",
"message.auto_fix_mesh_edit.split_quads": "Split Quads",
"message.duplicate_bone_copy_animation.message": "複製したボーンは %0 でアニメーション化されています。キーフレームを新しいボーンにコピーしますか?",
"message.auto_fix_mesh_edit.title": "オートフィックス",
"message.auto_fix_mesh_edit.revert": "編集を取り消す",
"message.auto_fix_mesh_edit.overlapping_vertices": "いくつかの頂点が同じ場所に移動されました。",
"message.auto_fix_mesh_edit.concave_quads": "フェイスが凹状になり、UV マッピングとレンダリングで問題が発生する可能性があります。Blockbench はこれを自動的に修正します:",
"message.auto_fix_mesh_edit.merge_vertices": "頂点をマージ",
"message.auto_fix_mesh_edit.split_quads": "スプリットクワッド",
"message.load_images.add_image": "画像を追加",
"dialog.project.modded_entity_entity_class": "Entity Class",
"dialog.resize_texture.offset": "Offset",
"dialog.animated_texture_editor.code_reference": "Code Reference",
"dialog.project.modded_entity_entity_class": "エンティティクラス",
"dialog.resize_texture.offset": "オフセット",
"dialog.animated_texture_editor.code_reference": "コードリファレンス",
"dialog.animated_texture_editor.code_reference.about": "このコードはテクスチャアニメーションを実装するための参考用に作成されたものであり、そのままでは動作しない場合があります。詳細については、ドキュメントを参照してください。",
"dialog.animated_texture_editor.code_reference.docs": "Documentation",
"dialog.animated_texture_editor.code_reference.docs": "ドキュメント",
"dialog.animated_texture_editor.reframe": "リフレーム",
"dialog.animated_texture_editor.stride": "フレームサイズ",
"dialog.animated_texture_editor.frames": "フレーム数",
"dialog.animated_texture_editor.add_frame": "フレームを追加",
"dialog.animated_texture_editor.resize_frames": "フレームをリサイズ...",
"dialog.animated_texture_editor.apply": "適応",
"dialog.add_primitive.edge_size": "Edge Size",
"dialog.add_primitive.edge_size": "エッジサイズ",
"dialog.change_animation_speed.speed": "スピード",
"dialog.change_animation_speed.adjust_snapping": "Adjust Snapping",
"dialog.optimize_animation.selection": "Selection",
"dialog.change_animation_speed.adjust_snapping": "スナップを調整",
"dialog.optimize_animation.selection": "選択",
"dialog.optimize_animation.selection.selected_keyframes": "キーフレーム",
"dialog.optimize_animation.selection.selected_animation": "アニメーション",
"dialog.optimize_animation.selection.all_animations": "てのアニメーション",
"dialog.optimize_animation.thresholds": "Threshold values",
"dialog.optimize_animation.selection.all_animations": "すべてのアニメーション",
"dialog.optimize_animation.thresholds": "",
"dialog.import_obj.obj": "OBJ ファイル",
"dialog.import_obj.mtl": "MTL ファイル",
"dialog.import_obj.scale": "スケール",
"layout.thumbnail": "Custom Thumbnail CSS",
"layout.thumbnail": "カスタムサムネイル CSS",
"settings.pixel_grid": "ピクセルグリット",
"settings.pixel_grid.desc": "エディットモードで、テクスチャにピクセルグリッドを表示します",
"settings.image_editor_grid_size": "画像エディタのグリットサイズ",
"settings.image_editor_grid_size.desc": "画像エディタの最大グリットサイズを変更します",
"settings.ground_plane_double_side": "Ground Plane Double-sided",
"settings.ground_plane_double_side.desc": "Make the ground plane visible from below",
"settings.optifine_save_default_texture": "OptiFine JEM: Export selected texture",
"settings.optifine_save_default_texture": "OptiFine JEM : テクスチャをエクスポート",
"settings.optifine_save_default_texture.desc": "選択したテクスチャをモデルのデフォルトテクスチャとしてエクスポートします",
"action.slider_color_select_threshold": "Color Select Threshold",
"action.slider_color_select_threshold": "カラー選択しきい値",
"action.slider_color_select_threshold.desc": "How close the color of a neighboring pixel has to be to get selected by color or wand select",
"action.stretch_tool": "ストレッチ",
"action.stretch_tool.desc": "Tool to select and stretch elements",
"action.stretch_tool.desc": "要素を引き伸ばします",
"action.knife_tool": "ナイフ",
"action.knife_tool.desc": "Tool to cut mesh faces into smaller pieces",
"action.knife_tool.desc": "メッシュを小さくカットします",
"action.duplicate_project": "プロジェクトを複製",
"action.duplicate_project.desc": "Creates a copy of the open project",
"action.duplicate_project.desc": "進行中のプロジェクトのコピーを作成します",
"action.transform_space.parent": "Parent",
"action.transform_pivot_space": "Pivot Transform Space",
"action.solidify_mesh_selection": "Solidify Faces",
"action.solidify_mesh_selection.desc": "Solidify the selected faces of the mesh",
"action.solidify_mesh_selection": "ソリット化",
"action.solidify_mesh_selection.desc": "選択したフェイスをソリッド化します",
"action.animated_texture_editor": "フリップブックアニメーション...",
"action.animated_texture_editor.desc": "テクスチャのフリップブックアニメーションを設定、または編集します",
"action.center_individual_pivots": "Center Individual Pivots",
"action.center_individual_pivots.desc": "Set the pivot point of each selected element to its center",
"action.uv_cycle": "Cycle UV",
"action.uv_cycle.desc": "Cycle through the order of UV vertices without changing the UV positions",
"action.uv_cycle_invert": "Cycle Invert UV",
"action.uv_cycle_invert.desc": "Reverse the order of UV vertices without changing the UV positions",
"action.center_individual_pivots": "センターピボット",
"action.center_individual_pivots.desc": "選択したピボットポイントを中心に設定します",
"action.uv_cycle": "サイクル UV",
"action.uv_cycle.desc": "UV 頂点の順序を循環します",
"action.uv_cycle_invert": "逆サイクル UV",
"action.uv_cycle_invert.desc": "UV 頂点の順序を逆にします",
"action.slider_animation_controller_speed": "Controller Playback Speed",
"action.slider_animation_controller_speed.desc": "アニメーションコントローラの再生速度",
"action.optimize_animation": "アニメーションを最適化",
@ -2130,103 +2116,215 @@
"menu.texture.particle.clear": "パーティクルを使用しない",
"menu.texture.use_as_default": "デフォルトに設定",
"menu.texture.use_as_default.clear": "デフォルトを解除",
"menu.toolbar.overflow": "Toolbar Overflow",
"menu.toolbar.overflow": "ツールバーフロー",
"edit.solidify_mesh_selection.thickness": "ティックネス",
"reference_image.sync_to_timeline": "タイムラインに同期",
"reference_image.toggle_playback": "プレイ/ポーズ",
"dialog.add_primitive.shape.beveled_cuboid": "Beveled Cuboid",
"dialog.ignore_all": "Ignore All",
"data.texture_group": "Texture Group",
"data.animation": "Animation",
"dialog.ignore_all": "すべて無視",
"data.texture_group": "テクスチャグループ",
"data.animation": "アニメーション",
"generic.on": "On",
"generic.off": "Off",
"format.free.info.3d_printing": "3D Printing",
"format.free.info.3d_printing": "3D プリント",
"message.invalid_file.merge_conflict": "The file contains unresolved Git merge conflicts.",
"dialog.expand_texture_selection.radius": "Amount",
"dialog.expand_texture_selection.corner": "Corner Shape",
"dialog.expand_texture_selection.corner.round": "Round",
"dialog.expand_texture_selection.corner.square": "Square",
"dialog.expand_texture_selection.corner.manhattan": "Manhattan",
"dialog.merge_animation.merge_target": "Merge into",
"dialog.expand_texture_selection.radius": "大きさ",
"dialog.expand_texture_selection.corner": "コーナーシェイプ",
"dialog.expand_texture_selection.corner.round": "角度",
"dialog.expand_texture_selection.corner.square": "四角形",
"dialog.expand_texture_selection.corner.manhattan": "マンハッタン",
"dialog.merge_animation.merge_target": "マージ",
"keybindings.variation_conflict": "Variation conflicts with the main keybinding",
"settings.recovery_save_interval": "Recovery Point Save Interval",
"settings.recovery_save_interval": "リカバリーポイント間隔",
"settings.recovery_save_interval.desc": "Blockbench regularly saves the open project in the background to recover in case of a computer crash. Set the interval in seconds. Set to 0 to disable saving.",
"settings.save_view_per_tab": "Save View per Tab",
"settings.save_view_per_tab": "タブごとにビューを保存",
"settings.save_view_per_tab.desc": "Save the current view angle for each tab separately",
"settings.inherit_parent_color": "Inherit Parent Color",
"settings.inherit_parent_color.desc": "Set the marker color of a newly created element to the color of the parent instead of a random color",
"keybind.preview_select.multi_select": "Multi-select",
"keybind.preview_select.group_select": "Group-select",
"keybind.preview_select.loop_select": "Loop-select",
"action.fill_mode.selection": "Selection",
"keybind.preview_select.multi_select": "選択-複数",
"keybind.preview_select.group_select": "選択-グループ",
"keybind.preview_select.loop_select": "選択-ループ",
"action.fill_mode.selection": "選択",
"action.fill_mode.selected_elements": "Selected Elements",
"action.image_tiled_view": "Tiled View",
"action.image_tiled_view.description": "Enable the tiled view in the 2D editor",
"action.image_tiled_view": "タイル表示",
"action.image_tiled_view.description": "2D エディタでタイル表示を有効にします",
"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.expand_texture_selection": "Expand Texture Selection",
"action.expand_texture_selection.desc": "Expand or shrink the texture selection",
"action.switch_tabs.reverse_order": "Reverse order",
"action.save_project_incremental": "Save Project With Increment",
"action.save_project_incremental.desc": "Saves the current model as a project file with an increment (ex: project_2.bbmodel)",
"action.copy.multiple": "Copy All",
"action.copy.multiple.desc": "Copy all available data individually",
"action.paste.multiple": "Paste All",
"action.randomize_marker_colors": "Randomize Marker Colors",
"action.cube_light_emission": "Light Emission",
"action.cube_light_emission.desc": "Change the emissiveness of the selected cubes, as a value between 0 and 15",
"action.image_onion_skin_view.description": "2D エディタでオニオンスキン表示を有効にします",
"action.expand_texture_selection": "テクスチャ選択範囲の拡張",
"action.expand_texture_selection.desc": "テクスチャの選択範囲を拡大または縮小します",
"action.switch_tabs.reverse_order": "逆順",
"action.save_project_incremental": "Increment プロジェクトを保存",
"action.save_project_incremental.desc": "現在のモデルをプロジェクトファイルとしてインクリメント付きで保存します (ex: project_2.bbmodel)",
"action.copy.multiple": "すべてコピー",
"action.copy.multiple.desc": "利用可能なすべてのデータを個別にコピーします",
"action.paste.multiple": "すべて貼り付け",
"action.randomize_marker_colors": "ランダムなマーカーカラー",
"action.cube_light_emission": "光源レベル",
"action.cube_light_emission.desc": "選択したキューブの発光レベルを 0 ~ 15 の値で変更します,",
"action.view_mode.colored_solid": "Solid with Marker Colors",
"action.focus_on_selection.rotate_only": "Rotate only",
"action.create_texture_group": "Create Texture Group",
"action.create_texture_group.desc": "Create a group for your textures",
"action.uv_maximize.all_faces": "Affect all faces",
"action.retarget_animators": "Retarget Animations",
"action.retarget_animators.desc": "Select which animator targets which bone or element",
"action.merge_animation": "Merge Animation",
"action.merge_animation.desc": "Merge the animation into another animation",
"action.add_keyframe.reset_values": "With default values",
"action.set_timeline_range_start": "Set Timeline Range Start",
"action.set_timeline_range_start.desc": "Set the start point for a custom playback range in the animation timeline",
"action.set_timeline_range_end": "Set Timeline Range End",
"action.set_timeline_range_end.desc": "Set the end point for a custom playback range in the animation timeline",
"action.disable_timeline_range": "Disable Timeline Range",
"action.disable_timeline_range.desc": "Disable the custom playback range in the animation timeline",
"menu.texture_group.resolve": "Resolve",
"action.focus_on_selection.rotate_only": "ローテートのみ",
"action.create_texture_group": "テクスチャグループを作成",
"action.create_texture_group.desc": "テクスチャごとにグループを作成します",
"action.uv_maximize.all_faces": "すべてのフェイスに適用",
"action.retarget_animators": "アニメーションをリターゲット",
"action.retarget_animators.desc": "アニメーターが新たにターゲットを再選択します",
"action.merge_animation": "アニメーションをマージ",
"action.merge_animation.desc": "アニメーションを別のアニメーションに結合します",
"action.add_keyframe.reset_values": "デフォルト値",
"action.set_timeline_range_start": "タイムラインの開始点を設定します",
"action.set_timeline_range_start.desc": "アニメーションタイムラインで再生範囲の開始点を設定します",
"action.set_timeline_range_end": "タイムラインの終点を設定します",
"action.set_timeline_range_end.desc": "アニメーションタイムラインで再生範囲の終点を設定します",
"action.disable_timeline_range": "タイムライン範囲を無効",
"action.disable_timeline_range.desc": "アニメーションタイムラインのカスタム再生範囲を無効にします",
"menu.texture_group.resolve": "確定",
"menu.image_tiled_view.mirrored": "Mirrored Edges",
"menu.image_onion_skin_view.frame": "Frames",
"menu.image_onion_skin_view.frame.last_viewed": "Last Viewed Frame",
"menu.image_onion_skin_view.frame.previous": "Previous Frame",
"menu.image_onion_skin_view.frame.next": "Next Frame",
"menu.image_onion_skin_view.frame.both": "Previous + Next",
"menu.image_onion_skin_view.display": "Display",
"menu.image_onion_skin_view.frame": "フレーム",
"menu.image_onion_skin_view.frame.last_viewed": "前回のフレーム",
"menu.image_onion_skin_view.frame.previous": "前のフレーム",
"menu.image_onion_skin_view.frame.next": "次のフレーム",
"menu.image_onion_skin_view.frame.both": "比較",
"menu.image_onion_skin_view.display": "表示",
"menu.image_onion_skin_view.display.pixels": "Smaller Pixels",
"menu.image_onion_skin_view.display.transparent": "Transparent",
"menu.image_onion_skin_view.above": "Display Above",
"menu.animation.reload": "Reload",
"switches.autouv.alt": "Relative",
"display.rotation_pivot": "Rotation Pivot",
"display.scale_pivot": "Scale Pivot",
"display.reference.fox": "Fox",
"display.reference.eating": "Eating",
"preview_scene.sky": "Sky",
"preview_scene.space": "Space",
"preview_scene.minecraft_ocean": "Ocean",
"message.import_palette.selection_only": "Selection only",
"dialog.blend_transition_edit.ease_in_out": "Ease-in-out (%0)",
"dialog.blend_transition_edit.generate": "Generate...",
"dialog.blend_transition_edit.generate.learn_more": "More info and preview",
"dialog.blend_transition_edit.generate.curve": "Easing Type",
"dialog.blend_transition_edit.generate.steps": "Keyframes",
"settings.fps_limit": "FPS Limit",
"settings.fps_limit.desc": "Limit how many frames per second Blockbench renders. The actual frame rate is limited to what your device can display.",
"settings.outliner_reveal_on_select": "Reveal Elements on Select",
"settings.outliner_reveal_on_select.desc": "Reveal elements in the ouliner when selected",
"settings.java_export_pivots": "Export Pivots in Java block/item models",
"settings.java_export_pivots.desc": "Save pivot points in Java block/item models on cubes without rotation",
"animation_controllers.state.blend_transition_curve": "Blend Transition Curve",
"menu.slider.reset_vector": "Reset Vector",
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"menu.image_onion_skin_view.display.transparent": "透明",
"menu.image_onion_skin_view.above": "上部に表示",
"menu.animation.reload": "リロード",
"switches.autouv.alt": "相対",
"display.rotation_pivot": "ピボットローテーション",
"display.scale_pivot": "ピボットスケール",
"display.reference.fox": "キツネ",
"display.reference.eating": "食べる",
"preview_scene.sky": "空",
"preview_scene.space": "スペース",
"preview_scene.minecraft_ocean": "海",
"message.import_palette.selection_only": "選択のみ",
"dialog.blend_transition_edit.ease_in_out": "イーズインアウト (%0)",
"dialog.blend_transition_edit.generate": "生成する...",
"dialog.blend_transition_edit.generate.learn_more": "詳細情報とプレビュー",
"dialog.blend_transition_edit.generate.curve": "イージングタイプ",
"dialog.blend_transition_edit.generate.steps": "キーフレーム",
"settings.fps_limit": "フレームレート",
"settings.fps_limit.desc": "Blockbench が 1 秒あたりにレンダリングするフレーム数を制限します。実際のフレームレートは、お使いのデバイスによって変動します。",
"settings.outliner_reveal_on_select": "エレメントをハイライト",
"settings.outliner_reveal_on_select.desc": "選択されたエレメントをハイライト表示します",
"settings.java_export_pivots": "java block/item をピボットでエクスポート",
"settings.java_export_pivots.desc": "キューブ上の Java ブロック/アイテムモデルのピボットポイントを保存します",
"animation_controllers.state.blend_transition_curve": "ブレンド遷移曲線",
"menu.slider.reset_vector": "ベクトルをリセット",
"dialog.blend_transition_edit.extended": "拡張グラフ",
"message.screenshot_too_large.title": "スクリーンショット解像度エラー",
"message.screenshot_too_large.message": "スクリーンショットがうまく表示されませんでした。解像度を下げるか、スーパーサンプリングをオフにして再度お試しください。",
"message.rename_elements.numbering": "連番を生成する際に、特殊文字を活用することができます: % を使うと、グループのインデックスを取得でき、 $ を使うと、選択範囲のインデックスを取得することが出来ます。",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "再起動が必要です",
"message.settings_require_restart.message": "一部の設定は、アプリを再起動したあとに適用されます。",
"message.settings_require_restart.restart_now": "今すぐ再起動",
"message.settings_require_restart.restart_later": "あとで再起動",
"message.classroom_mode.install_plugin": "クラスルームモードではプラグインをインストールできません",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "すべて選択",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "削除",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "UV ミラーリングを無効",
"dialog.create_texture.disable_mirror_uv.desc": "ミラーモデリングの UV ミラーオプションを無効にし、フェイスごとに個別の UV を保存します",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "コントロール",
"settings.classroom_mode": "クラスルームモード",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "トーンマッピング",
"settings.tone_mapping.desc": "PBR レンダリングにハイダイナミックレンジを表示します。",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "ビューポート回転速度",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "ビューポートズーム速度",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D エディタのズーム速度",
"settings.editor_2d_zoom_speed.desc": "UV および 2D ペイントエディタでズームするときの速度を変更します",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "回転",
"action.export_image": "画像をエクスポート",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "マテリアルをプレビュー",
"action.create_material": "マテリアルを作成",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "ノーマル",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "プロジェクトをエクスポート",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move to",
"menu.panel.move_to.left_bar": "Left Side",
"menu.panel.move_to.right_bar": "Right Side",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "フレーム",
"menu.animation_onion_skin.select": "選択",
"menu.animation_onion_skin.previous": "前",
"menu.animation_onion_skin.next": "次",
"menu.animation_onion_skin.previous_next": "前 + 次",
"menu.animation_onion_skin.count": "カウント",
"menu.animation_onion_skin.interval": "インターバル",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "ユニット",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "方向",
"edit.extrude_mesh_selection.direction.outwards": "外側",
"edit.extrude_mesh_selection.direction.average": "平均",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "整列",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 軸",
"edit.vertex_snap.ignore_axis": "%0 軸を無視",
"codec.common.format": "Format",
"codec.image.quality": "クオリティ",
"panel.collections": "Collections",
"modifier_actions.always": "常に有効",
"modifier_actions.unless": "%0 を除く",
"settings.undo_selections": "巻き戻し選択",
"settings.undo_selections.desc": "巻き戻した変更を、ステップごとに追跡します",
"action.focus_on_selection.zoom": "ウィンドウにフィット",
"display.reference.tooting": "角笛を吹く",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "メッシュ",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "주 폰트",
"layout.font.headline": "헤드라인 폰트",
"about.version": "버전:",
"about.creator": "제작자:",
"about.website": "웹사이트:",
"about.vertex_snap": "꼭짓점 맞춤 기능 제작 : SirBenet",
"about.icons": "아이콘 팩:",
"about.libraries": "라이브러리",
"settings.category.general": "일반",
"settings.category.preview": "미리보기",
"settings.category.grid": "격자",
@ -517,7 +512,7 @@
"action.cullface.desc": "선택한 모델의 측면이 덮인 경우 이 면에 대한 렌더링 비활성화",
"action.auto_cullface": "후면 제거 키기",
"action.auto_cullface.desc": "이 표면의 후면 제거를 자체로 설정",
"action.face_tint": "옅은 색",
"action.face_tint": "",
"action.face_tint.desc": "현재 표면에 대한 색조 옵션을 사용 가능으로 설정",
"menu.toolbar.edit": "사용자 정의",
"menu.toolbar.reset": "초기화",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "트루 아이소메트릭 오른쪽 (30°)",
"camera_angle.true_isometric_left": "트루 아이소메트릭 왼쪽 (30°)",
"menu.help.wiki": "Blockbench 위키",
"about.repository": "레포지토리:",
"settings.update_to_prereleases": "사전 릴리즈로 업데이트",
"settings.update_to_prereleases.desc": "새로운 기능을 테스트하기 위해 블록벤치 베타 버전을 자동으로 업데이트합니다. 사전 릴리스 버전은 불안정할 수 있으며, 작업 또는 기타 중요한 프로젝트에 대해 Blockbench에 의존할 경우 이 옵션을 사용하지 마십시오.",
"data.separator.spacer": "스페이서",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "X 반전",
"menu.uv.flip_y": "Y 반전",
"menu.mirror_painting.enabled": "켜짐",
"menu.mirror_painting.configure_texture_center": "텍스쳐 센터 구성...",
"reference_image.position": "위치",
"reference_image.size": "크기",
"reference_image.rotation": "회전",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2102,7 +2088,7 @@
"action.slider_color_select_threshold.desc": "How close the color of a neighboring pixel has to be to get selected by color or wand select",
"action.stretch_tool": "Stretch",
"action.stretch_tool.desc": "Tool to select and stretch elements",
"action.knife_tool": "Knife Tool",
"action.knife_tool": "나이프 도구",
"action.knife_tool.desc": "Tool to cut mesh faces into smaller pieces",
"action.duplicate_project": "Duplicate Project",
"action.duplicate_project.desc": "Creates a copy of the open project",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "Hoofd lettertype",
"layout.font.headline": "Opschriftlettertype",
"about.version": "Versie:",
"about.creator": "Maker:",
"about.website": "Website:",
"about.vertex_snap": "Vertex Snapping is gebaseerd op een plug-in door SirBenet",
"about.icons": "Icon Pakketten:",
"about.libraries": "Bibliotheken:",
"settings.category.general": "Algemeen:",
"settings.category.preview": "Voorvertooning",
"settings.category.grid": "Rooster",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Rechts Isometrisch (30°)",
"camera_angle.true_isometric_left": "Links Isometrisch (30°)",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "Repository:",
"settings.update_to_prereleases": "Update naar Pre-releases",
"settings.update_to_prereleases.desc": "Automatisch updaten naar Blockbench beta versies om nieuwe functies te testen. Pre-release versies kunnen onstabiel zijn, schakel deze optie niet in als u vertrouwt op Blockbench voor werk of andere belangrijke projecten.",
"data.separator.spacer": "Afstandhouder",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Spiegel X",
"menu.uv.flip_y": "Spiegel Y",
"menu.mirror_painting.enabled": "Ingeschakeld",
"menu.mirror_painting.configure_texture_center": "Configureer Textuur Centrum...",
"reference_image.position": "Positie",
"reference_image.size": "Grootte",
"reference_image.rotation": "Rotatie",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "Główna czcionka",
"layout.font.headline": "Czcionka nagłówkowa",
"about.version": "Wersja:",
"about.creator": "Twórca:",
"about.website": "Strona:",
"about.vertex_snap": "Przyciąganie wierzchołków jest bazowane na pluginie autorstwa SirBenet",
"about.icons": "Paczki ikon:",
"about.libraries": "Biblioteki:",
"settings.category.general": "Ogólne",
"settings.category.preview": "Podgląd",
"settings.category.grid": "Siatka",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Prawdziwy izometryczny prawy (30°)",
"camera_angle.true_isometric_left": "Prawdziwy izometryczny lewy (30°)",
"menu.help.wiki": "Wiki Blockbencha",
"about.repository": "Repozytorium:",
"settings.update_to_prereleases": "Aktualizacja do wersji przedpremierowej",
"settings.update_to_prereleases.desc": "Automatycznie aktualizuj Blockbench do wersji beta, aby testować nowe funkcje. Wersje przedpremierowe mogą być niestabilne, nie włączaj tej opcji jeśli polegasz na Blockbench w pracy lub innych ważnych projektach.",
"data.separator.spacer": "Spacer",
@ -1607,7 +1601,7 @@
"menu.mirror_painting.global.desc": "Enabled mirror painting on the model in global space",
"menu.mirror_painting.local": "Local Symmetry",
"menu.mirror_painting.local.desc": "Enable mirror painting in local space for each element",
"menu.mirror_painting.texture_frames": "Repeat on Animated Texture Frames",
"menu.mirror_painting.texture_frames": "Repeat on Flipbook Frames",
"menu.mirror_painting.texture_frames.desc": "Mirror paint strokes to every frame of animated textures",
"format.bedrock_block.info.size_limit": "Size total size of a block is limited to 30 pixels in all dimensions. The limit can be off-centered in all directions by 7 pixels from the block center.",
"format.bedrock_block.info.textures": "Multiple textures can be applied to different cubes in Blockbench, but require additional setup in the behavior pack to work correctly in-game.",
@ -1694,7 +1688,7 @@
"settings_profile.confirm_delete": "Are you sure you want to delete this settings profile?",
"settings_profile.condition.type.selectable": "Manually Selectable",
"settings.interface_mode": "UI Mode",
"settings.interface_mode.desc": "Interface mode. Restart Blockbench to apply changes",
"settings.interface_mode.desc": "Interface mode",
"settings.interface_mode.auto": "Automatic",
"settings.interface_mode.desktop": "Desktop",
"settings.interface_mode.mobile": "Mobile",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Mirror X",
"menu.uv.flip_y": "Mirror Y",
"menu.mirror_painting.enabled": "Enabled",
"menu.mirror_painting.configure_texture_center": "Configure Texture Center...",
"reference_image.position": "Position",
"reference_image.size": "Size",
"reference_image.rotation": "Rotation",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "Fonte principal",
"layout.font.headline": "Fonte de títulos",
"about.version": "Versão:",
"about.creator": "Criado por:",
"about.website": "Página web:",
"about.vertex_snap": "O encaixe de vértices é baseado em uma extensão criada por SirBenet",
"about.icons": "Pacotes de ícones:",
"about.libraries": "Bibliotecas:",
"settings.category.general": "Principal",
"settings.category.preview": "Pré-visualização",
"settings.category.grid": "Grade",
@ -227,7 +222,7 @@
"settings.export_groups.desc": "Salvar grupos em modelos de bloco ou item",
"settings.credit": "Comentário de crédito",
"settings.credit.desc": "Adicionar um comentário de crédito aos arquivos exportados",
"settings.default_path": "Default Minecraft Textures Path",
"settings.default_path": "Caminho Padrão de Texturas do Minecraft",
"settings.default_path.desc": "Pasta da qual o Blockbench carrega texturas padrão",
"settings.image_editor": "Editor de imagem",
"settings.image_editor.desc": "Editor de imagens padrão para editar texturas",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Habilitar direita isométrica (30°)",
"camera_angle.true_isometric_left": "Habilitar esquerda isométrica (30°)",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "Repositório:",
"settings.update_to_prereleases": "Atualizar para Pré-lançamentos",
"settings.update_to_prereleases.desc": "Automatically update to Blockbench beta versions to test new features. Pre-release versions can be unstable, don't enable this option if you rely on Blockbench for work or other important projects.",
"data.separator.spacer": "Espaçador",
@ -1607,7 +1601,7 @@
"menu.mirror_painting.global.desc": "Enabled mirror painting on the model in global space",
"menu.mirror_painting.local": "Local Symmetry",
"menu.mirror_painting.local.desc": "Enable mirror painting in local space for each element",
"menu.mirror_painting.texture_frames": "Repeat on Animated Texture Frames",
"menu.mirror_painting.texture_frames": "Repeat on Flipbook Frames",
"menu.mirror_painting.texture_frames.desc": "Mirror paint strokes to every frame of animated textures",
"format.bedrock_block.info.size_limit": "Size total size of a block is limited to 30 pixels in all dimensions. The limit can be off-centered in all directions by 7 pixels from the block center.",
"format.bedrock_block.info.textures": "Multiple textures can be applied to different cubes in Blockbench, but require additional setup in the behavior pack to work correctly in-game.",
@ -1694,7 +1688,7 @@
"settings_profile.confirm_delete": "Are you sure you want to delete this settings profile?",
"settings_profile.condition.type.selectable": "Manually Selectable",
"settings.interface_mode": "UI Mode",
"settings.interface_mode.desc": "Interface mode. Restart Blockbench to apply changes",
"settings.interface_mode.desc": "Interface mode",
"settings.interface_mode.auto": "Automatic",
"settings.interface_mode.desktop": "Desktop",
"settings.interface_mode.mobile": "Mobile",
@ -1705,7 +1699,7 @@
"action.slider_color_red": "Color Red",
"action.slider_color_green": "Color Green",
"action.slider_color_blue": "Color Blue",
"action.add_animation_controller": "Add Animation Controller",
"action.add_animation_controller": "Adicionar Controlador de Animação",
"action.add_animation_controller.desc": "Create a blank animation controller",
"action.animation_controller_preview_mode": "Controller Preview",
"action.animation_controller_preview_mode.paused": "Paused",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Mirror X",
"menu.uv.flip_y": "Mirror Y",
"menu.mirror_painting.enabled": "Enabled",
"menu.mirror_painting.configure_texture_center": "Configure Texture Center...",
"reference_image.position": "Position",
"reference_image.size": "Size",
"reference_image.rotation": "Rotation",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

File diff suppressed because it is too large Load Diff

View File

@ -164,11 +164,6 @@
"layout.font.main": "Huvudtypsnitt",
"layout.font.headline": "Rubrikstypsnitt",
"about.version": "Version:",
"about.creator": "Skapare:",
"about.website": "Hemsida:",
"about.vertex_snap": "Vortex Snapping är baserat på ett plugin av SirBenet",
"about.icons": "Ikonpaket:",
"about.libraries": "Bibliotek:",
"settings.category.general": "Allmän",
"settings.category.preview": "Förhansvisning",
"settings.category.grid": "Rutnät",
@ -488,7 +483,7 @@
"action.change_textures_folder.desc": "Ändra mapp som alla texturer sparas i",
"menu.texture.particle": "Använd för partiklar",
"message.update_notification.title": "En uppdatering är tillgänglig ",
"message.update_notification.message": "Den nya Blockbench versionen \"%0\" är tillgänglig. Vill du installera den nu?",
"message.update_notification.message": "En ny Blockbench uppdatering är tillgänglig. Sätt på \"Uppdatera automatiskt\" i inställningar för att uppdatera!",
"message.untextured": "Denna ytan har ingen textur",
"dialog.toolbar_edit.title": "Anpassa verktygsfältet",
"keybindings.reset": "Återställ",
@ -963,7 +958,7 @@
"menu.help.developer": "Utvecklare",
"menu.help.developer.dev_tools": "Open Dev Tools",
"menu.help.developer.reset_storage": "Factory Reset",
"menu.help.developer.reset_storage.confirm": "Are you sure you want to reset Blockbench to factory settings? This will delete all custom settings, keybindings and installed plugins.",
"menu.help.developer.reset_storage.confirm": "Är du säker på att du vill fabriksåterställa Blockbenchs inställningar? Om du gör detta kommer alla valda inställningar, kortkommandon och plugins att återställas.",
"menu.help.developer.cache_reload": "Cache Reload",
"menu.preview.orthographic": "Orthographic",
"menu.preview.save_angle": "Spara Vinkel...",
@ -1018,8 +1013,8 @@
"settings.category.application": "Application",
"settings.streamer_mode": "Streamerläge",
"settings.streamer_mode.desc": "Hides sensitive information like recent models",
"settings.automatic_updates": "Automatic Updates",
"settings.automatic_updates.desc": "Automatically download new versions and keep Blockbench up-to-date",
"settings.automatic_updates": "Uppdatera automatiskt",
"settings.automatic_updates.desc": "Laddar automatiskt ned nya uppdateringar",
"action.rotation_space": "Rotation Space",
"action.focus_on_selection": "Center View on Selection",
"action.focus_on_selection.desc": "Align the camera to face the center of the current selection",
@ -1070,12 +1065,12 @@
"message.small_face_dimensions.title": "Incompatible Face Dimensions",
"message.small_face_dimensions.message": "The selection contains faces that are smaller than 1 unit in one direction. The Box UV mapping system considers any faces below that threshold as 0 pixels wide. The texture on those faces therefore may not work correctly.",
"message.small_face_dimensions.face_uv": "The current format supports per-face UV maps which can handle small face dimensions. Right click the affected cubes and change \"UV Mode\" to \"Per-face UV\".",
"dialog.plugins.outdated_client": "Requires a newer version of Blockbench",
"dialog.plugins.outdated_plugin": "Plugin is outdated and does not work with this version of Blockbench",
"dialog.plugins.outdated_client": "Pluginet behöver en nyare version av Blockbench",
"dialog.plugins.outdated_plugin": "Pluginet är utdaterat och kommer inte att fungera med den här versionen av Blockbench",
"settings.motion_trails": "Motion Trails",
"settings.motion_trails.desc": "Show motion trails in the animation editor",
"settings.antialiasing": "Anti-aliasing",
"settings.antialiasing.desc": "Toggle anti-aliasing in the preview. Restart Blockbench to apply changes",
"settings.antialiasing.desc": "Toggle anti-aliasing in the preview",
"action.timeline_frame_back": "Jump 1 Frame Back",
"action.timeline_frame_forth": "Jump 1 Frame Forth",
"panel.bone.ik": "Inverse Kinematics (Experimental)",
@ -1097,13 +1092,13 @@
"layout.color.subtle_text": "Subtle Text",
"layout.color.subtle_text.desc": "Secondary text color with less contrast",
"settings.interface_scale": "Interface Scale",
"settings.interface_scale.desc": "Scale of the entire Blockbench interface",
"settings.interface_scale.desc": "Hela Blockbenchs gränssnittsskala",
"settings.background_rendering": "Background Rendering",
"settings.background_rendering.desc": "Update the preview while the window is not focused",
"settings.ctrl_shift_size": "Control + Shift Resolution",
"settings.ctrl_shift_size.desc": "Resolution of the grid while holding control and shift",
"settings.hardware_acceleration": "Hardware Acceleration",
"settings.hardware_acceleration.desc": "Outsource rendering tasks to the graphics card. Restart Blockbench to apply changes",
"settings.hardware_acceleration.desc": "Låter blockbench utnytja grafikkortet för rendering. Kräver omstart av Blockbench",
"action.explode_skin_model": "Explode Skin Model",
"action.explode_skin_model.desc": "Toggles an explosion view that allows you to edit covered faces",
"action.export_minecraft_skin": "Exportera Minecraft Skin",
@ -1143,7 +1138,7 @@
"dialog.toolbar_edit.hidden_tools": "Some tools might be hidden because they are not available in the current mode, format, or situation.",
"settings.camera_near_plane": "Camera Near Plane",
"settings.camera_near_plane.desc": "The minimum distance from the camera where objects render. Higher values decrease Z-fighting. Default is 1.",
"mode.start.keymap_preference.desc": "If you are new to Blockbench and you are coming from another 3D program, you can select a keymap to make your transition easier. You can change the keymap or individual keybindings later in the settings.",
"mode.start.keymap_preference.desc": "Om du har använt ett annat 3D program innan Blockbench och har svårt att vänja dig kan du använda en \"keymap\" för att göra övergången lättare. I inställningar så kan du ändra varje kortkommando för sig.",
"message.load_keymap": "Are you sure you want to load this keymap? This will overwrite your current keybindings.",
"message.keymap_loaded": "Keymap loaded",
"dialog.convert_project.current_format": "Current Format",
@ -1170,7 +1165,7 @@
"action.import_settings": "Import Settings",
"action.import_settings.desc": "Import a .bbsettings file",
"action.export_settings": "Export Settings",
"action.export_settings.desc": "Export the Blockbench settings as a .bbsettings file",
"action.export_settings.desc": "Exportera dina Blockbench inställningar som en \".bbsettings\" fil",
"action.load_keymap": "Load Keymap",
"action.load_keymap.default": "Default (Trackpad/Mouse)",
"action.load_keymap.mouse": "Default (Mouse)",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "True Isometric Right (30°)",
"camera_angle.true_isometric_left": "True Isometric Left (30°)",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "Repository:",
"settings.update_to_prereleases": "Update to Pre-releases",
"settings.update_to_prereleases.desc": "Automatically update to Blockbench beta versions to test new features. Pre-release versions can be unstable, don't enable this option if you rely on Blockbench for work or other important projects.",
"data.separator.spacer": "Spacer",
@ -1402,7 +1396,7 @@
"settings.preview_paste_behavior.desc": "Select the behavior when pasting something into the viewport in Edit mode and multiple options are available",
"settings.preview_paste_behavior.always_ask": "Always Ask",
"action.new_window": "New Window",
"action.new_window.desc": "Opens a new Blockbench window",
"action.new_window.desc": "Öppnar ett till Blockbench fönster",
"action.export_collada": "Export Collada Model (dae)",
"action.export_collada.desc": "Export model and animations as dae file to use it in other 3D applications",
"action.paint_mode_uv_overlay": "UV Overlay",
@ -1607,7 +1601,7 @@
"menu.mirror_painting.global.desc": "Enabled mirror painting on the model in global space",
"menu.mirror_painting.local": "Local Symmetry",
"menu.mirror_painting.local.desc": "Enable mirror painting in local space for each element",
"menu.mirror_painting.texture_frames": "Repeat on Animated Texture Frames",
"menu.mirror_painting.texture_frames": "Repeat on Flipbook Frames",
"menu.mirror_painting.texture_frames.desc": "Mirror paint strokes to every frame of animated textures",
"format.bedrock_block.info.size_limit": "Size total size of a block is limited to 30 pixels in all dimensions. The limit can be off-centered in all directions by 7 pixels from the block center.",
"format.bedrock_block.info.textures": "Multiple textures can be applied to different cubes in Blockbench, but require additional setup in the behavior pack to work correctly in-game.",
@ -1694,7 +1688,7 @@
"settings_profile.confirm_delete": "Are you sure you want to delete this settings profile?",
"settings_profile.condition.type.selectable": "Manually Selectable",
"settings.interface_mode": "UI Mode",
"settings.interface_mode.desc": "Interface mode. Restart Blockbench to apply changes",
"settings.interface_mode.desc": "Interface mode",
"settings.interface_mode.auto": "Automatic",
"settings.interface_mode.desktop": "Desktop",
"settings.interface_mode.mobile": "Mobile",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Mirror X",
"menu.uv.flip_y": "Mirror Y",
"menu.mirror_painting.enabled": "Enabled",
"menu.mirror_painting.configure_texture_center": "Configure Texture Center...",
"reference_image.position": "Position",
"reference_image.size": "Size",
"reference_image.rotation": "Rotation",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Save the selected keyframes as an animation preset",
"action.animation_onion_skin": "Animation Onion Skin",
"action.animation_onion_skin.desc": "Display an wireframe view of a different frame in the animation for reference",
"action.animation_onion_skin.off": "Off",
"action.animation_onion_skin.select": "Select",
"action.animation_onion_skin.previous": "Previous",
"action.animation_onion_skin.next": "Next",
"action.animation_onion_skin.previous_next": "Previous + Next",
"action.apply_animation_preset": "Apply Animation Preset",
"action.apply_animation_preset.desc": "Select from a list of animation presets and apply it to the selected bone",
"menu.brush_presets.pixel_perfect": "Pixel-perfect Brush",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Insert a newline character at the end of exported files",
"action.crop_layer_to_selection": "Crop Layer to Selection",
"action.edit_mode_uv_overlay.desc": "Display the UV map as an overlay in edit mode",
"action.animation_onion_skin_selective": "Selective Onion Skin",
"action.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"menu.image": "Image",
"menu.texture.discard_changes": "Discard Changes",
"menu.texture.discard_changes.desc": "Discard all unsaved changes and load the latest version from the file",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Extended Graph",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

File diff suppressed because it is too large Load Diff

View File

@ -164,11 +164,6 @@
"layout.font.main": "Phông chữ chính",
"layout.font.headline": "Phông chữ tiêu đề",
"about.version": "Phiên bản:",
"about.creator": "Nhà sáng lập:",
"about.website": "Website:",
"about.vertex_snap": "Tính năng Nối Đỉnh được dựa trên một plugin của SirBenet",
"about.icons": "Các gói Icon",
"about.libraries": "Thư viện:",
"settings.category.general": "Cài đặt chung",
"settings.category.preview": "Xem trước",
"settings.category.grid": "Lưới đồ thị",
@ -298,9 +293,9 @@
"action.load_plugin.desc": "Tải một plugin bằng cách nhập tệp nguồn",
"action.reload_plugins": "Reload các plugin",
"action.reload_plugins.desc": "Tải lại toàn bộ Plugin cho Nhà Phát Triển",
"action.undo": "Quay lại",
"action.undo": "Hoàn tác",
"action.undo.desc": "Quay lại thay đổi trước",
"action.redo": "Tiến",
"action.redo": "Làm lại",
"action.redo.desc": "Quay lại thay đổi cuối",
"action.copy": "Sao chép",
"action.copy.desc": "Sao chép những đồ vật, mặt hay những điều chỉnh hiển thị đã được chọn",
@ -838,7 +833,7 @@
"dialog.timelapse.source.interface": "Giao diện",
"dialog.timelapse.source.locked": "Góc khóa",
"dialog.timelapse.destination": "Thư mục đích",
"layout.color.checkerboard": "Bàn cờ",
"layout.color.checkerboard": "Nền caro",
"layout.color.checkerboard.desc": "Nền của canvas và trình chỉnh sửa UV",
"layout.font.code": "Mã phông chữ",
"layout.css": "CSS tùy chỉnh",
@ -929,10 +924,10 @@
"dialog.sketchfab_uploader.animations": "Hoạt ảnh",
"dialog.settings.theme": "Chủ đề",
"settings.category.interface": "Giao diện",
"settings.preview_checkerboard": "Xem trước bàn cờ",
"settings.preview_checkerboard.desc": "Chuyển đổi nền bàn cờ đằng sau bản xem trước",
"settings.uv_checkerboard": "Chỉnh UV bàn cờ",
"settings.uv_checkerboard.desc": "Chuyển đổi nền bàn cờ phía sau trình chỉnh sửa UV",
"settings.preview_checkerboard": "Xem trước nền caro",
"settings.preview_checkerboard.desc": "Chuyển đổi nền caro đằng sau bản xem trước",
"settings.uv_checkerboard": "Chỉnh UV nền caro",
"settings.uv_checkerboard.desc": "Chuyển đổi nền caro phía sau trình chỉnh sửa UV",
"category.paint": "Vẽ",
"action.fill_mode.color_connected": "Kết nối màu sắc",
"action.draw_shape_type": "Loại hình dạng",
@ -1220,7 +1215,6 @@
"camera_angle.true_isometric_right": "Hình chiếu trục đo phải đúng(30°)",
"camera_angle.true_isometric_left": "Hình chiếu trục đo trái đúng(30°)",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "Kho lưu trữ:",
"settings.update_to_prereleases": "Cập nhật lên bản phát hành trước",
"settings.update_to_prereleases.desc": "Tự động cập nhật lên các phiên bản beta của Blockbench để kiểm tra các tính năng mới. Các phiên bản trước khi phát hành có thể không ổn định, không bật tùy chọn này nếu bạn dùng Blockbench cho công việc hoặc các dự án quan trọng khác.",
"data.separator.spacer": "Đệm",
@ -1253,10 +1247,10 @@
"dialog.add_primitive.shape.sphere": "Hình cầu",
"dialog.add_primitive.shape.torus": "Hình xuyến",
"dialog.add_primitive.shape.cube": "Hình khối",
"dialog.add_primitive.shape.pyramid": "Hình kim tự tháp",
"dialog.add_primitive.shape.pyramid": "Hình chóp",
"dialog.add_primitive.diameter": "Đường kính",
"dialog.add_primitive.height": "Chiều cao",
"dialog.add_primitive.sides": "Bên",
"dialog.add_primitive.sides": "Số mặt bên",
"dialog.add_primitive.minor_diameter": "Độ dày",
"dialog.add_primitive.minor_sides": "Bên nhỏ",
"dialog.create_texture.combine_polys": "liên kết bề mặt",
@ -1288,13 +1282,13 @@
"action.add_plugin.desc": "Cài đặt plugin từ kiểm soát hành động",
"action.remove_plugin": "Xóa plugin khỏi kiểm soát hành động",
"action.remove_plugin.desc": "Gỡ cài đặt plugin thông qua Kiểm soát hành động",
"action.add_mesh": "Thêm khung lưới",
"action.add_mesh": "Thêm lưới",
"action.add_mesh.desc": "Thêm một khung lưới mới",
"action.add_texture_mesh": "Thêm khung lưới kết cấu",
"action.add_texture_mesh": "Thêm lưới kết cấu",
"action.add_texture_mesh.desc": "Thêm một khung lưới kết cấu mới",
"action.find_replace": "Tìm/Thay thế...",
"action.find_replace.desc": "Tìm và thay thế các phần của tên",
"action.hide_everything_except_selection": "Ẩn mọi thứ trừ lựa chọn",
"action.hide_everything_except_selection": "Ẩn mọi thứ (trừ phần lựa chọn)",
"action.hide_everything_except_selection.desc": "Chuyển đổi chế độ hiển thị cho tất cả các phần tử ngoại trừ phần tử đã chọn",
"action.transform_space.normal": "Bình thường",
"action.selection_mode": "Chế độ lựa chọn",
@ -1342,7 +1336,7 @@
"action.merge_vertices.desc": "Hợp nhất các đỉnh đã chọn vào vị trí của đỉnh được chọn đầu tiên",
"action.view_mode.normal": "Mặt thường",
"action.snap_uv_to_pixels": "Khớp UV với điểm ảnh",
"action.snap_uv_to_pixels.desc": "Gắn các đỉnh UV đã chọn vào lưới đồ thị điểm ảnh",
"action.snap_uv_to_pixels.desc": "Gắn các đỉnh UV đã chọn vào lưới điểm ảnh",
"menu.file.import.import_open_project": "Nhập dự án mở",
"menu.help.unlock_projects": "Mở khóa tất cả các dự án",
"status_bar.selection.faces": "%0 mặt",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "Gương X",
"menu.uv.flip_y": "Gương Y",
"menu.mirror_painting.enabled": "Đã bật",
"menu.mirror_painting.configure_texture_center": "Định cấu hình Trung tâm Kết cấu...",
"reference_image.position": "Vị trí",
"reference_image.size": "Kích thước",
"reference_image.rotation": "Xoay",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "Lưu các khung hình chính đã chọn làm giá trị cài sẵn hoạt ảnh",
"action.animation_onion_skin": "Hoạt hoạ da Onion",
"action.animation_onion_skin.desc": "Hiển thị chế độ xem khung dây của một khung khác trong hoạt ảnh để tham khảo",
"action.animation_onion_skin.off": "Tắt",
"action.animation_onion_skin.select": "Lựa chọn",
"action.animation_onion_skin.previous": "Trước",
"action.animation_onion_skin.next": "Tiếp",
"action.animation_onion_skin.previous_next": "Trước + Tiếp",
"action.apply_animation_preset": "Áp dụng giá trị cài sẵn hoạt ảnh",
"action.apply_animation_preset.desc": "Chọn từ danh sách các giá trị cài sẵn hoạt ảnh và áp dụng nó cho xương đã chọn",
"menu.brush_presets.pixel_perfect": "Cọ vẽ Pixel hoàn hảo",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "Chèn ký tự dòng mới vào cuối tệp đã xuất",
"action.crop_layer_to_selection": "Cắt lớp để chọn",
"action.edit_mode_uv_overlay.desc": "Hiển thị bản đồ UV dưới dạng lớp phủ trong chế độ chỉnh sửa",
"action.animation_onion_skin_selective": "Chọn lọc da Onion",
"action.animation_onion_skin_selective.desc": "Chỉ hiển thị da onion cho phần đã chọn của mô hình",
"menu.image": "Hình ảnh",
"menu.texture.discard_changes": "Loại bỏ những thay đổi",
"menu.texture.discard_changes.desc": "Hủy bỏ tất cả các thay đổi chưa được lưu và tải phiên bản mới nhất từ tệp",
@ -2090,7 +2076,7 @@
"dialog.import_obj.mtl": "Tệp MTL",
"dialog.import_obj.scale": "Tỉ lệ",
"layout.thumbnail": "Tùy chỉnh hình thu nhỏ CSS",
"settings.pixel_grid": "Lưới đồ thị điểm ảnh",
"settings.pixel_grid": "Lưới điểm ảnh",
"settings.pixel_grid.desc": "Hiển thị lưới đồ thị kết cấu điểm ảnh trên các phần tử trong chế độ chỉnh sửa",
"settings.image_editor_grid_size": "Kích thước lưới đồ thị của công cụ chỉnh sửa ảnh",
"settings.image_editor_grid_size.desc": "Kích thước lưới đồ thị lớn trong công cụ chỉnh sửa ảnh 2D",
@ -2106,7 +2092,7 @@
"action.knife_tool.desc": "Công cụ để cắt các mặt khung lưới thành các miếng nhỏ hơn",
"action.duplicate_project": "Nhân bản dự án",
"action.duplicate_project.desc": "Tạo một bản sao của dự án",
"action.transform_space.parent": "Phụ huynh",
"action.transform_space.parent": "Gốc",
"action.transform_pivot_space": "Tâm quay thay đổi không gian",
"action.solidify_mesh_selection": "Làm đông đặc các mặt",
"action.solidify_mesh_selection.desc": "Làm đông đặc các mặt được chọn của khung lưới",
@ -2228,5 +2214,117 @@
"dialog.blend_transition_edit.extended": "Đồ thị được mở rộng",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection.",
"generic.edit_externally": "Edit Externally",
"message.settings_require_restart.title": "Restart Required",
"message.settings_require_restart.message": "Some settings will only apply after restarting the program.",
"message.settings_require_restart.restart_now": "Restart Now",
"message.settings_require_restart.restart_later": "Restart Later",
"message.classroom_mode.install_plugin": "Cannot install plugins in Classroom Mode",
"dialog.collection.export_path": "Export Path",
"dialog.collection.select_all": "Select All",
"dialog.collection.select_none": "Select None",
"dialog.collection.add_with_filter": "Add with Filter",
"dialog.collection.remove": "Remove",
"dialog.material_config.title": "Material Config",
"dialog.material_config.color_value": "Color Value",
"dialog.material_config.mer": "Metal-Emissive-Roughness",
"dialog.material_config.mer_value": "MER Value",
"dialog.material_config.depth_type": "Depth Type",
"dialog.create_texture.disable_mirror_uv": "Disable UV Mirroring",
"dialog.create_texture.disable_mirror_uv.desc": "Disable the UV Mirror option in Mirror Modeling to preserve separate UVs for each side of the model",
"dialog.create_gif.turn.sync_to_anim_length": "Sync to animation length",
"settings.category.controls": "Controls",
"settings.classroom_mode": "Classroom Mode",
"settings.classroom_mode.desc": "Restricts functionality such as installing plugins and removes links to social media",
"settings.antialiasing_bleed_fix": "Fix anti-aliasing bleeding",
"settings.antialiasing_bleed_fix.desc": "Fixes texture bleeding when using anti-aliasing. Potentially unsupported on older hardware.",
"settings.tone_mapping": "Tone Mapping",
"settings.tone_mapping.desc": "Approximation method for displaying high dynamic range on a standard screen for PBR rendering.",
"settings.audio_scrubbing": "Timline Scrubbing Audio",
"settings.audio_scrubbing.desc": "Play short previews of the audio while scrubbing through time timeline",
"settings.viewport_rotate_speed": "Viewport Rotate Speed",
"settings.viewport_rotate_speed.desc": "Input sensitivity when rotating in the viewport",
"settings.viewport_zoom_speed": "Viewport Zoom Speed",
"settings.viewport_zoom_speed.desc": "Input sensitivity when zooming in the viewport",
"settings.editor_2d_zoom_speed": "2D Editor Zoom Speed",
"settings.editor_2d_zoom_speed.desc": "Input sensitivity when zooming in the UV and 2D paint editor",
"category.select": "Select",
"action.vertex_snap_mode.rotate": "Rotate",
"action.export_image": "Export Image",
"action.export_image.desc": "Export your texture as an image file",
"action.apply_mirror_modeling": "Apply Mirror Modeling",
"action.apply_mirror_modeling.desc": "Apply Mirror Modeling to the selection. All selected elements will be copied and flipped across the X axis.",
"action.create_collection": "Create Collection",
"action.create_collection.desc": "Create a collection out of the outliner selection",
"action.set_collection_content_to_selection": "Set Collection Content to Selected",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "Add Selected to Collection",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "Material Preview",
"action.create_material": "Create Material",
"action.create_material.desc": "Create a new PBR material out of the selected texture",
"action.generate_pbr_map": "Generate PBR Map...",
"action.generate_pbr_map.desc": "Generate a PBR map (height map or metalness, emissiveness, roughness) from an existing texture",
"menu.tools.main_tools": "Toolbox",
"menu.view.panels": "Panels",
"menu.texture.pbr_channel": "PBR Channel",
"menu.texture.pbr_channel.color": "Color",
"menu.texture.pbr_channel.normal": "Normal",
"menu.texture.pbr_channel.height": "Height",
"menu.texture.pbr_channel.mer": "MER (Metalness-Emissive-Roughness)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "Export Project",
"menu.collection.export_as": "Export as \"%0\"",
"menu.panel.enable": "Enable",
"menu.panel.move_to": "Move To",
"menu.panel.move_to.left_bar": "Left Sidebar",
"menu.panel.move_to.right_bar": "Right Sidebar",
"menu.panel.move_to.top": "Top",
"menu.panel.move_to.bottom": "Bottom",
"menu.panel.move_to.float": "Float",
"menu.panel.move_to.hidden": "Hide",
"menu.panel.fold": "Collapse",
"menu.mirror_painting.texture_center": "Origin",
"menu.mirror_modeling.mirror_uv": "Mirror UV",
"menu.animation_onion_skin.frames": "Frames",
"menu.animation_onion_skin.select": "Select",
"menu.animation_onion_skin.previous": "Previous",
"menu.animation_onion_skin.next": "Next",
"menu.animation_onion_skin.previous_next": "Previous + Next",
"menu.animation_onion_skin.count": "Count",
"menu.animation_onion_skin.interval": "Interval",
"menu.animation_onion_skin_selective": "Selective Onion Skin",
"menu.animation_onion_skin_selective.desc": "Only display onion skin for the selected part of the model",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "Percent",
"edit.extrude_mesh_selection.direction": "Direction",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "Average",
"edit.extrude_mesh_selection.even_extend": "Even Extend",
"edit.vertex_snap.align": "Align",
"edit.vertex_snap.align.longest": "Longest Axis",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "%0 Axis",
"edit.vertex_snap.ignore_axis": "Ignore Axis",
"codec.common.format": "Format",
"codec.image.quality": "Quality",
"panel.collections": "Collections",
"modifier_actions.always": "Always Enabled",
"modifier_actions.unless": "Unless %0",
"settings.undo_selections": "Undo Selection",
"settings.undo_selections.desc": "Track selection changes as a step in the undo history",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "Mesh",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

View File

@ -164,11 +164,6 @@
"layout.font.main": "字体",
"layout.font.headline": "标题字体",
"about.version": "版本:",
"about.creator": "作者:",
"about.website": "网址:",
"about.vertex_snap": "基于 SirBenet 顶点捕捉的插件功能",
"about.icons": "图标包:",
"about.libraries": "库:",
"settings.category.general": "常规",
"settings.category.preview": "预览",
"settings.category.grid": "网格",
@ -324,7 +319,7 @@
"action.select_window.desc": "根据属性搜索并选择块",
"action.invert_selection": "反选",
"action.invert_selection.desc": "反向选择所选块",
"action.select_all": "选",
"action.select_all": "择全部",
"action.select_all.desc": "选择所有元素、面、顶点或关键帧",
"action.collapse_groups": "折叠分组",
"action.collapse_groups.desc": "折叠大纲视图中所有分组",
@ -1219,8 +1214,7 @@
"camera_angle.common_isometric_left": "等距左2:1",
"camera_angle.true_isometric_right": "真等距右30°",
"camera_angle.true_isometric_left": "真等距左30°",
"menu.help.wiki": "Blockbench Wiki",
"about.repository": "储存库:",
"menu.help.wiki": "Blockbench 维基",
"settings.update_to_prereleases": "更新至预发布版",
"settings.update_to_prereleases.desc": "自动更新至 beta 版本的 Blockbench 以测试新功能。预发布版本可能不稳定,如果您依赖 Blockbench 工作或其他重要项目,请不要启用此选项。",
"data.separator.spacer": "间隔",
@ -1521,7 +1515,7 @@
"format.modded_entity.info.format": "模型是用 Java 代码编写的,而不是像所有其他 Blockbench 导出格式那样的专用数据结构。",
"format.optifine_entity.info.optifine_required": "未安装 OptiFine 的用户将看不到该模型。",
"format.optifine_entity.info.pivots": "骨骼枢轴被锁定,因此最好不要触碰它们。",
"format_category.low_poly": "Low-Poly",
"format_category.low_poly": "低多边形",
"format_category.minecraft": "Minecraft",
"format_category.other": "其他",
"format_category.loaders": "加载程序",
@ -1818,7 +1812,6 @@
"menu.uv.flip_x": "反转 X 轴",
"menu.uv.flip_y": "反转 Y 轴",
"menu.mirror_painting.enabled": "启用",
"menu.mirror_painting.configure_texture_center": "配置纹理中心...",
"reference_image.position": "位置",
"reference_image.size": "尺寸",
"reference_image.rotation": "旋转",
@ -2022,11 +2015,6 @@
"action.save_animation_preset.desc": "将所选的关键帧保存为动画预设",
"action.animation_onion_skin": "动画洋葱皮",
"action.animation_onion_skin.desc": "展示动画其他帧的线框作为参考",
"action.animation_onion_skin.off": "关闭",
"action.animation_onion_skin.select": "选取",
"action.animation_onion_skin.previous": "上一个",
"action.animation_onion_skin.next": "下一个",
"action.animation_onion_skin.previous_next": "上一个 + 下一个",
"action.apply_animation_preset": "应用动画映射",
"action.apply_animation_preset.desc": "选择动画映射并应用于所选骨骼",
"menu.brush_presets.pixel_perfect": "完美像素笔刷",
@ -2040,8 +2028,6 @@
"settings.final_newline.desc": "在导出文件的末尾增加一个换行符",
"action.crop_layer_to_selection": "将图层裁切至选区内",
"action.edit_mode_uv_overlay.desc": "在编辑模式中将 UV 映射覆盖进行展示",
"action.animation_onion_skin_selective": "选择性洋葱皮",
"action.animation_onion_skin_selective.desc": "只为模型已选中的区域展示洋葱皮",
"menu.image": "图像",
"menu.texture.discard_changes": "撤销更改",
"menu.texture.discard_changes.desc": "撤销全部未保存更改并从文件中加载最新版本",
@ -2134,7 +2120,7 @@
"edit.solidify_mesh_selection.thickness": "粗细度",
"reference_image.sync_to_timeline": "对齐于时间轴",
"reference_image.toggle_playback": "播放/停止",
"dialog.add_primitive.shape.beveled_cuboid": "使立方体改为斜面",
"dialog.add_primitive.shape.beveled_cuboid": "斜角方形",
"dialog.ignore_all": "忽略所有",
"data.texture_group": "纹理组",
"data.animation": "动画",
@ -2226,7 +2212,119 @@
"animation_controllers.state.blend_transition_curve": "混合过渡曲线",
"menu.slider.reset_vector": "重置向量",
"dialog.blend_transition_edit.extended": "扩展图表",
"message.screenshot_too_large.title": "Screenshot Resolution Issue",
"message.screenshot_too_large.message": "The screenshot could not be rendered successfully. Please try again with a lower resolution or without supersampling.",
"message.rename_elements.numbering": "You can use special characters to generate sequential numbers: % to get the index of the element within its group, $ to get the index within the selection."
"message.screenshot_too_large.title": "截屏分辨率问题",
"message.screenshot_too_large.message": "屏幕截图无法成功渲染。请使用较低的分辨率或不进行超采样重试。",
"message.rename_elements.numbering": "你可以使用特殊字符生成序列号:% 获取元素组内的索引,$ 获取所选内容中的索引。",
"generic.edit_externally": "外部编辑",
"message.settings_require_restart.title": "需要重启",
"message.settings_require_restart.message": "一些设置需要重新启动程序以生效。",
"message.settings_require_restart.restart_now": "立即重启",
"message.settings_require_restart.restart_later": "以后重启",
"message.classroom_mode.install_plugin": "不会教室模式在安装插件",
"dialog.collection.export_path": "导出路径",
"dialog.collection.select_all": "选择全部",
"dialog.collection.select_none": "无选择",
"dialog.collection.add_with_filter": "使用过滤添加",
"dialog.collection.remove": "移除",
"dialog.material_config.title": "材质设置",
"dialog.material_config.color_value": "颜色值",
"dialog.material_config.mer": "金属、自发光、粗糙度",
"dialog.material_config.mer_value": "MER 值",
"dialog.material_config.depth_type": "深度类型",
"dialog.create_texture.disable_mirror_uv": "禁用 UV 镜像",
"dialog.create_texture.disable_mirror_uv.desc": "禁用镜像建模中的 UV 镜像选项,为模型的每一侧保留单独的 UV",
"dialog.create_gif.turn.sync_to_anim_length": "同步到动画长度",
"settings.category.controls": "控制",
"settings.classroom_mode": "教室模式",
"settings.classroom_mode.desc": "限制安装插件等功能并删除指向社交媒体的链接",
"settings.antialiasing_bleed_fix": "修复抗锯齿渗出",
"settings.antialiasing_bleed_fix.desc": "修复使用抗锯齿时的纹理渗出问题",
"settings.tone_mapping": "色调映射",
"settings.tone_mapping.desc": "用于在标准屏幕上显示 HDR 以进行 PBR 渲染的近似方法。",
"settings.audio_scrubbing": "在时间轴上试听音频",
"settings.audio_scrubbing.desc": "播放音频的简短预览,同时拖动时间轴",
"settings.viewport_rotate_speed": "视口旋转速度",
"settings.viewport_rotate_speed.desc": "在视口中旋转时的灵敏度",
"settings.viewport_zoom_speed": "视口缩放速度",
"settings.viewport_zoom_speed.desc": "在视口中缩放时的输入灵敏度",
"settings.editor_2d_zoom_speed": "2D 编辑器缩放速度",
"settings.editor_2d_zoom_speed.desc": "在 UV 和 2D 绘制编辑器中放大时的灵敏度",
"category.select": "选择",
"action.vertex_snap_mode.rotate": "旋转",
"action.export_image": "导出图像",
"action.export_image.desc": "将纹理导出为图像文件",
"action.apply_mirror_modeling": "应用镜像建模",
"action.apply_mirror_modeling.desc": "将镜像建模应用于所选内容。所有选定的元素都将被复制并沿 X 轴翻转。",
"action.create_collection": "创建集合",
"action.create_collection.desc": "从大纲视图选择中创建集合",
"action.set_collection_content_to_selection": "将集合内容设置为选定对象",
"action.set_collection_content_to_selection.desc": "Set the selected groups and elements as the content of the collection",
"action.add_to_collection": "添加选东西择到的集合",
"action.add_to_collection.desc": "Add the selected groups and elements to the collection",
"action.view_mode.material": "材质预览",
"action.create_material": "创建材质",
"action.create_material.desc": "从选定纹理中创建新的 PBR 材质",
"action.generate_pbr_map": "生成 PBR 贴图",
"action.generate_pbr_map.desc": "从现有纹理生成 PBR 贴图(高度贴图或金属度、发光度、粗糙度)",
"menu.tools.main_tools": "工具箱",
"menu.view.panels": "面板",
"menu.texture.pbr_channel": "PBR 通道",
"menu.texture.pbr_channel.color": "颜色",
"menu.texture.pbr_channel.normal": "法线贴图",
"menu.texture.pbr_channel.height": "凹凸贴图",
"menu.texture.pbr_channel.mer": "MER (金属度-自发光-粗糙度)",
"menu.texture.pbr_channel.mer_subsurface": "MER Subsurface",
"menu.collection.export_project": "导出项目",
"menu.collection.export_as": "导出为 “%0\"",
"menu.panel.enable": "启用",
"menu.panel.move_to": "移到",
"menu.panel.move_to.left_bar": "左屏侧边栏",
"menu.panel.move_to.right_bar": "右屏侧边栏",
"menu.panel.move_to.top": "上屏",
"menu.panel.move_to.bottom": "下屏",
"menu.panel.move_to.float": "窗口",
"menu.panel.move_to.hidden": "隐藏",
"menu.panel.fold": "折叠",
"menu.mirror_painting.texture_center": "原点",
"menu.mirror_modeling.mirror_uv": "镜像 UV",
"menu.animation_onion_skin.frames": "帧",
"menu.animation_onion_skin.select": "选择",
"menu.animation_onion_skin.previous": "上一个",
"menu.animation_onion_skin.next": "下一个",
"menu.animation_onion_skin.previous_next": "上一个 + 下一个",
"menu.animation_onion_skin.count": "数量",
"menu.animation_onion_skin.interval": "间隔",
"menu.animation_onion_skin_selective": "选择性洋葱皮",
"menu.animation_onion_skin_selective.desc": "仅显示模型选定部分的洋葱皮",
"edit.loop_cut.unit": "Unit",
"edit.loop_cut.unit.size_units": "Size Units",
"edit.loop_cut.unit.percent": "百分之",
"edit.extrude_mesh_selection.direction": "方向",
"edit.extrude_mesh_selection.direction.outwards": "Outwards",
"edit.extrude_mesh_selection.direction.average": "平均",
"edit.extrude_mesh_selection.even_extend": "均匀拓展",
"edit.vertex_snap.align": "对齐",
"edit.vertex_snap.align.longest": "最长轴",
"edit.vertex_snap.align.direction": "Direction from Pivot",
"edit.vertex_snap.align.align_axis": "轴 %0",
"edit.vertex_snap.ignore_axis": "忽略 轴",
"codec.common.format": "格式",
"codec.image.quality": "品质",
"panel.collections": "集合",
"modifier_actions.always": "始终启用",
"modifier_actions.unless": "除非 %0",
"settings.undo_selections": "撤消选择",
"settings.undo_selections.desc": "将所选内容更改作为撤消历史记录中的一个步骤进行跟踪",
"action.focus_on_selection.zoom": "Zoom to fit",
"display.reference.tooting": "Horn Tooting",
"settings.selection_tolerance": "Selection Tolerance",
"settings.selection_tolerance.desc": "Size of the area that can be clicked to select an edge or vertex",
"action.delete.keep_vertices": "Keep Edges/Vertices",
"menu.mesh": "网格",
"dialog.material_config.subsurface": "Subsurface Scattering",
"dialog.material_config.subsurface_enabled.desc": "Use the MER map alpha channel for subsurface scattering",
"settings.pick_combined_color": "Pick Combined Color",
"settings.pick_combined_color.desc": "Pick the combined color of all layers at the respective pixel, instead of the color on the active layer",
"action.split_rgb_into_layers": "Split RGB Channels into Layers",
"action.split_rgb_into_layers.desc": "Split the texture into additive layers, one for each RGB channel"
}

File diff suppressed because it is too large Load Diff

View File

@ -5,11 +5,11 @@ class CanvasFrame {
/**
*
* @param {Number|HTMLCanvasElement|HTMLImageElement} [a] Image source
* @param {Number} [b]
* @param {Number|Boolean} [b]
*/
constructor(a, b) {
if (a && a.nodeName == 'CANVAS') {
if (a.getContext('2d')) {
if (a.getContext('2d') && b !== true) {
this.canvas = a;
} else {
this.createCanvas(a.width, a.height)

Some files were not shown because too many files have changed in this diff Show More