Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Degrotate support for mesh nodes #7840

Merged
merged 5 commits into from
Mar 29, 2021
Merged

Degrotate support for mesh nodes #7840

merged 5 commits into from
Mar 29, 2021

Conversation

numberZero
Copy link
Contributor

@numberZero numberZero commented Nov 5, 2018

For convenience, degrotate range is changed from 180 (2° steps) to 240 (1.5° steps). Most importantly that allows exact diagonals, as requested, while still allowing thirds and fifths (but not ninths).

This also adds a new option, colordegrotate. It has reduced range (24, 15° steps) to support 8 colors but still allows exact diagonals. The range could be 32 (11.25° steps) at most with the same number of colors but I considered thirds more important than additional two-fold.

screenshot_20181111_011427

@numberZero
Copy link
Contributor Author

numberZero commented Nov 5, 2018

@paramat Note that the rotated meshes aren’t cached; that’s too cumbersome and probably pointless. But rotation can be optimized heavily by replacing v3f::rotateXZBy (in `rotateMeshXZby) with (a sort of) matrix multiplication, moving trigonometric functions out of the loop.

@numberZero
Copy link
Contributor Author

For other drawtypes, fine rotation is of little use IMO:

  • normal, liquid, glasslike*, allfaces* are grid-aligned by the very nature,
  • glasslike_framed (again), flowingliquid, fencelike, raillike, firelike, connected nodebox depend on the neighbors so can’t be rotated,
  • torchlike and signlike are wall-mounted and walls are grid-aligned,
  • airlike :D
  • plantlike, plantlike_rooted (probably, only for the plant part) and mesh are supported.

Technically speaking, non-connected nodebox could be rotated. But mesh is far more powerful. The only thing it can’t replace is leveled nodebox, but it will still look ugly if rotated.

@paramat paramat added Feature ✨ PRs that add or enhance a feature @ Script API labels Nov 6, 2018
@paramat
Copy link
Contributor

paramat commented Nov 6, 2018

240 seems optimum to me.
The breakage of the degrotate API seems worth doing, to use this far better approach.

@Wuzzy2
Copy link
Contributor

Wuzzy2 commented Nov 7, 2018

I agree that 240 is the optimum, for the simple reason that 240 is the highest highly-composite number (https://en.wikipedia.org/wiki/Highly_composite_number) in the range from 1 to 255.
240 has 20 divisors, while 180 only has 18.

This means with 240 steps, there will be 20 ways to divide the circle in n equally large parts, not just 18. So yes, this is an improvement. I also like to note that this will unlock two very important angles: 45° (one eighth) and 22.5° (one sixteenth).

Divisors of 180:
1, 2, 3, 4, 5, 6,    9, 10, 12, 15,     18, 20,     30, 36,     45,     60,     90,      180
Divisors of 240:
1, 2, 3, 4, 5, 6, 8,    10, 12, 15, 16,     20, 24, 30,     40,     48, 60, 80,     120,     240

Which means that you can have halves, thirds, fourths, fifts, sixths, eighths, tenths, and many more fractions with 240. Ninths have to go, but this doesn't seem like a big loss to me.

The choice of 24 for colordegrotate is also sound, as it's another highly-composite number with a whopping 8 divisors. Note that 32 is NOT a highly-composite number and only has 6 divisors so you were right for rejecting it.
What is the maximum possible number of steps you could take for colordegrotate?

@paramat
Copy link
Contributor

paramat commented Nov 7, 2018

About caching:

I took another look and it might be more complex. If I understand the code correctly, facedir on meshes currently caches each rotation of the mesh for performance. Degrotate might have performance issues if used on large meshes

Just to check, does this affect in-game performance or is just more processing on client startup?

@numberZero
Copy link
Contributor Author

highly-composite number

Didn’t know that term, thanks) (When choosing the number, I considered mostly prime factors and 8 (for exact diagonals); but for small numbers that’s almost the same).

What is the maximum possible number of steps you could take for colordegrotate?

Depends on your needs. To allow 8 colors, step count must not be larger that 32. Actually, to allow 2^n colors, step count must be at most 2^(8-n), for a natural n. I consider supporting less than 8 colors pointless, so 32 is the top for me, and 24 is the optimum due to better divisibility.

@numberZero
Copy link
Contributor Author

numberZero commented Nov 7, 2018

Just to check, does this affect in-game performance or is just more processing on client startup?

Caching would increase startup time and especially memory usage. And the in-game processing should be fast.

Actually, due to a far from optimal implementation of rotateMesh**by, processing of a large mesh may take some time currently—but caching would only hurt in such case as it would make startup time just insane. And I will make a PR with a faster implementation soon.

@paramat
Copy link
Contributor

paramat commented Nov 7, 2018

I see thanks. So there will be a little in-game performance loss while calculating a specific orientation. Or alternatively, very intensive on startup while caching all orientations although many of those orientations are not used. So i agree that not caching is best.

@paramat
Copy link
Contributor

paramat commented Nov 7, 2018

Nodeboxes are converted to meshnodes, and:

facedir on meshes currently caches each rotation of the mesh for performance.

I assume these 24 facedir rotations continue to be cached as currently?

@numberZero
Copy link
Contributor Author

facedir on meshes currently caches each rotation of the mesh for performance.

I assume these 24 facedir rotations continue to be cached as currently?

I don’t change that in this PR. These are cached if that feature is enabled but smooth lighting is disabled.

@Thomas--S
Copy link
Contributor

Would it be possible to specify the position of the rotation axis in the node definition?

@paramat
Copy link
Contributor

paramat commented Nov 9, 2018

No, that would require so much extra information in param2 you would lose the 240 orientations, making degrotate unusable for what it is applied to. The number of orientations has to be similar or larger than the previous 180.

@numberZero
Copy link
Contributor Author

#7851

@Thomas--S
Copy link
Contributor

@paramat In case your comment is meant as a response to my question (I hope I understood it correctly.), I didn't mean to store the position of the rotation axis param2, but to store the exact position of the rotation axis in nodedef. This way, it would be possible to make off-center rotations. Not all mesh models are neccessarily centered.

@numberZero
Copy link
Contributor Author

@Thomas--S That’s possible ofc, but that would totally break world symmetry, preventing one from rotating constructions as a whole (I mean rebuilding or using WorldEdit). And what could be the use cases?

@numberZero
Copy link
Contributor Author

numberZero commented Nov 10, 2018

Whoops, colors don’t work...

@Thomas--S
Copy link
Contributor

@numberZero I have no special use cases in mind, it was just an idea/suggestion. I don't have a problem when the rotation axis feature is not implemented 🙂

@numberZero
Copy link
Contributor Author

Fixed colors. Now everything seems to work)
Test mod: mese_crystals.zip (these don’t grow but are clickable)

@paramat
Copy link
Contributor

paramat commented Nov 11, 2018

Thomas--S sorry i misunderstood, i was talking about axis orientation instead of position.

@lhofhansl
Copy link
Contributor

What's holding this up?

@paramat
Copy link
Contributor

paramat commented Nov 28, 2018

Nothing apart from tests and reviews.

@rubenwardy rubenwardy added the Rebase needed The PR needs to be rebased by its author label Jun 20, 2019
@rubenwardy rubenwardy force-pushed the master branch 2 times, most recently from 0e3b135 to 39c54e1 Compare June 21, 2019 00:46
@numberZero
Copy link
Contributor Author

Rebased.

What's holding this up?

Nothing apart from tests and reviews.

Assuming that’s still true. @paramat

@SmallJoker SmallJoker removed the Rebase needed The PR needs to be rebased by its author label May 17, 2020
@SmallJoker
Copy link
Member

SmallJoker commented May 17, 2020

Please also add support for the new paramtype2 here:

local color_divisor = nil
if def.paramtype2 == "color" then
color_divisor = 1
elseif def.paramtype2 == "colorwallmounted" then
color_divisor = 8
elseif def.paramtype2 == "colorfacedir" then
color_divisor = 32
end

function core.is_colored_paramtype(ptype)
return (ptype == "color") or (ptype == "colorfacedir") or
(ptype == "colorwallmounted")
end
function core.strip_param2_color(param2, paramtype2)
if not core.is_colored_paramtype(paramtype2) then
return nil
end
if paramtype2 == "colorfacedir" then
param2 = math.floor(param2 / 32) * 32
elseif paramtype2 == "colorwallmounted" then
param2 = math.floor(param2 / 8) * 8
end
-- paramtype2 == "color" requires no modification.
return param2
end

Other than that, the code looks good.

@sfan5
Copy link
Member

sfan5 commented May 17, 2020

For convenience, degrotate range is changed from 180 (2° steps) to 240 (1.5° steps)

^ This is sort of an issue since it breaks backwards compatibility.
An additional parameter could be added to the nodedef to switch between 2° steps and 1.5° steps.

@numberZero
Copy link
Contributor Author

it breaks backwards compatibility

I see these words constantly here. At the time the PR was proposed, that was okay:

The breakage of the degrotate API seems worth doing, to use this far better approach.

A long time passed since then, but: degrotate could only be used for plantlike. Will such change in plant orientation be even noticed?

@numberZero
Copy link
Contributor Author

@SmallJoker Done.

@sfan5
Copy link
Member

sfan5 commented May 19, 2020

Will such change in plant orientation be even noticed?

That's a good question and the answer is probably not.
Yet, breaking whatever existing usecases games/mods have come up with is not good.

@Wuzzy2
Copy link
Contributor

Wuzzy2 commented May 19, 2020

Will such change in plant orientation be even noticed?

The answer is definitely yes. Take param2=99 for example:

  • 99 * 2.0° = 192°
  • 99 * 1.5° = 148.5°

The game/mod author chooses degrotate precisely for a precise rotation of the plant. So changnig that will break assumptions.

That having said, I still prefer 240 over 180. I wonder how it could be done without breaking things. Maybe paramtype2="degrotate240"?

@paramat
Copy link
Contributor

paramat commented May 19, 2020

I still support breaking this API, 240 steps is far better. Degrotate is probably not heavily used.
MT uses diagonals a lot, not being able to acheive an exact diagonal is really bad. Choosing 180 steps was a big mistake.
I think that occasional small breakages are worth it for improving MT and removing nasty stuff.

@SmallJoker SmallJoker self-requested a review May 19, 2020 19:10
@numberZero
Copy link
Contributor Author

numberZero commented May 19, 2020

@Wuzzy2

  1. 99 × 2 = 198 :p
  2. The numbers don’t matter, appearance does. Plantlike is highly symmetrical. The difference is 49.5°, but for a star-shaped plant that is equivalent to −11.5°, for example.
  3. “precisely for a precise rotation of the plant.”
    More likely for a random rotation, as in plantlike_leaves, snow, fireworks, etc. (what’s about cobweb in MineClone2?) I’ve did some search on github and found only one place where precise rotation is probably important: https://github.com/minetest-mirrors/advtrains/blob/master/advtrains_signals_ks/init_degrotate_nodes.lua. The file is unused, and note that degrotate is used on a mesh node...

@sfan5
Copy link
Member

sfan5 commented May 19, 2020

Degrotate is probably not heavily used.

Do we have numbers on this?

@paramat
Copy link
Contributor

paramat commented May 19, 2020

I wonder how it could be done without breaking things. Maybe paramtype2="degrotate240"?

I certainly disapprove of adding another paramtype2 just to avoid a minor breakage.

How much degrotate is used in mods is just my informed guess.
Searching in GitHub counted 6 mods using degrotate https://github.com/search?l=Lua&p=1&q=minetest+degrotate&type=Code (will be more of course outside GitHub).

@SmallJoker
Copy link
Member

SmallJoker commented Sep 7, 2020

My attempt at testing this feature... somehow it changes the color on rotate. Help needed.

diff for devtest (v2, corrected)
diff --git a/games/devtest/mods/testnodes/drawtypes.lua b/games/devtest/mods/testnodes/drawtypes.lua
index 82d862819..5239717c8 100644
--- a/games/devtest/mods/testnodes/drawtypes.lua
+++ b/games/devtest/mods/testnodes/drawtypes.lua
@@ -204,6 +204,31 @@ minetest.register_node("testnodes:plantlike_waving", {
 
 
 -- param2 will rotate
+local function rotate_on_rightclick(pos, node, clicker)
+	local def = minetest.registered_nodes[node.name]
+	local aux1 = clicker:get_player_control().aux1
+
+	local deg, deg_max
+	local color, color_mult = 0, 0
+	if def.paramtype2 == "degrotate" then
+		-- MSB [3x null, 5x rotation] LSB
+		deg = node.param2
+		deg_max = 240
+	elseif def.paramtype2 == "colordegrotate" then
+		-- MSB [3x color, 5x rotation] LSB
+		deg = node.param2 % 2^5
+		deg_max = 24
+		color_mult = 2^5
+		color = math.floor(node.param2 / color_mult)
+	end
+
+	deg = (deg + (aux1 and 10 or 1)) % deg_max
+	node.param2 = color * color_mult + deg
+	minetest.swap_node(pos, node)
+	minetest.chat_send_player(clicker:get_player_name(),
+		"Rotation is now " .. deg .. " / " .. deg_max)
+end
+
 minetest.register_node("testnodes:plantlike_degrotate", {
 	description = S("Degrotate Plantlike Drawtype Test Node"),
 	drawtype = "plantlike",
@@ -211,12 +236,42 @@ minetest.register_node("testnodes:plantlike_degrotate", {
 	paramtype2 = "degrotate",
 	tiles = { "testnodes_plantlike_degrotate.png" },
 
-
+	on_rightclick = rotate_on_rightclick,
+	place_param2 = 7,
 	walkable = false,
 	sunlight_propagates = true,
 	groups = { dig_immediate = 3 },
 })
 
+minetest.register_node("testnodes:mesh_degrotate", {
+	description = S("Degrotate Mesh Drawtype Test Node"),
+	drawtype = "mesh",
+	paramtype = "light",
+	paramtype2 = "degrotate",
+	mesh = "testnodes_pyramid.obj",
+	tiles = { "testnodes_mesh_stripes2.png" },
+
+	on_rightclick = rotate_on_rightclick,
+	place_param2 = 7,
+	sunlight_propagates = true,
+	groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:mesh_colordegrotate", {
+	description = S("Color Degrotate Mesh Drawtype Test Node"),
+	drawtype = "mesh",
+	paramtype2 = "colordegrotate",
+	palette = "testnodes_palette_facedir.png",
+	mesh = "testnodes_pyramid.obj",
+	tiles = { "testnodes_mesh_stripes2.png" },
+
+	on_rightclick = rotate_on_rightclick,
+	-- color index 1, 7 steps rotated
+	place_param2 = 1 * 2^5 + 7,
+	sunlight_propagates = true,
+	groups = { dig_immediate = 3 },
+})
+
 -- param2 will change height
 minetest.register_node("testnodes:plantlike_leveled", {
 	description = S("Leveled Plantlike Drawtype Test Node"),

@numberZero
Copy link
Contributor Author

@SmallJoker The palette should have 8 entries, not 256 (so color index 15 is out of range btw, fix place_param2). You would see the same effect on colorfacedir.
Also, bit mask for plain degrotate is wrong, all 8 bits are used. But the max is 240, not 250.

@SmallJoker
Copy link
Member

Thank you. I updated the code above accordingly. Would you please be so nice and include it in devtest as well (might require rebase)? It might be helpful for future tests.

@numberZero
Copy link
Contributor Author

rebased, added the test nodes

@numberZero
Copy link
Contributor Author

@SmallJoker ?

Copy link
Member

@SmallJoker SmallJoker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-tested. Works.

@sfan5 sfan5 added the Breaking Change Changes an existing API behavior in an incompatible way label Feb 24, 2021
@sfan5
Copy link
Member

sfan5 commented Feb 24, 2021

I suggest merging this right now so we can see how many people complain during 5.5.0-dev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Changes an existing API behavior in an incompatible way Feature ✨ PRs that add or enhance a feature One approval ✅ ◻️ @ Script API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants