From bb3fed2a3b1fdefdc7cfb989b9519308c1753a84 Mon Sep 17 00:00:00 2001 From: JozsefA Date: Sat, 6 Mar 2021 21:46:17 -0800 Subject: [PATCH] Towards better normals. - Easier SuperByteBuffer transform settings. - Some cleanup here and there. --- .../base/BackHalfShaftInstance.java | 2 +- .../contraptions/base/KineticData.java | 7 + .../base/SingleRotatingInstance.java | 2 +- .../components/actors/DrillInstance.java | 2 +- .../chassis/StickerRenderer.java | 9 +- .../gantry/GantryPinionRenderer.java | 24 ++- .../render/ContraptionRenderer.java | 7 - .../relays/belt/BeltRenderer.java | 9 +- .../relays/encased/ShaftInstance.java | 2 +- .../block/mechanicalArm/ArmRenderer.java | 57 ++++--- .../block/SchematicannonRenderer.java | 149 +++++++++--------- .../simibubi/create/events/ClientEvents.java | 1 - .../foundation/render/SuperByteBuffer.java | 31 +++- .../backend/instancing/InstancedModel.java | 8 + .../foundation/utility/MatrixStacker.java | 13 +- 15 files changed, 182 insertions(+), 141 deletions(-) delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java index 0d566b45f..909b380bc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java @@ -15,7 +15,7 @@ public class BackHalfShaftInstance extends HalfShaftInstance { InstancedTileRenderRegistry.instance.register(type, BackHalfShaftInstance::new)); } - public BackHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public BackHalfShaftInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java index 84d8a878a..36ce074fd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticData.java @@ -58,6 +58,13 @@ public class KineticData> extends InstanceData { return (D) this; } + public D nudge(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + return (D) this; + } + public D setBlockLight(int blockLight) { this.blockLight = (byte) ((blockLight & 0xF) << 4); return (D) this; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java index 9008e2f44..65996958c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java @@ -21,7 +21,7 @@ public class SingleRotatingInstance extends KineticTileInstance rotatingModelKey; - public SingleRotatingInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public SingleRotatingInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java index 6ff6d7832..27d2bcdd6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java @@ -24,7 +24,7 @@ public class DrillInstance extends SingleRotatingInstance { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedTileRenderRegistry.instance.register(type, DrillInstance::new)); } - public DrillInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { + public DrillInstance(InstancedTileRenderer modelManager, KineticTileEntity tile) { super(modelManager, tile); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java index 8e6ef665c..e1b3e2741 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java @@ -32,17 +32,16 @@ public class StickerRenderer extends SafeTileEntityRenderer { offset = state.get(StickerBlock.EXTENDED) ? 1 : 0; Direction facing = state.get(StickerBlock.FACING); - ms.push(); - MatrixStacker.of(ms) + head.matrixStacker() .nudge(te.hashCode()) .centre() .rotateY(AngleHelper.horizontalAngle(facing)) .rotateX(AngleHelper.verticalAngle(facing) + 90) - .unCentre(); - ms.translate(0, (offset * offset) * 4 / 16f, 0); + .unCentre() + .translate(0, (offset * offset) * 4 / 16f, 0); + head.light(light) .renderInto(ms, buffer.getBuffer(RenderType.getSolid())); - ms.pop(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java index df2d3b49b..eb5be4809 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionRenderer.java @@ -4,6 +4,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.Iterate; @@ -50,25 +51,20 @@ public class GantryPinionRenderer extends KineticTileEntityRenderer { if (facing == Direction.NORTH || facing == Direction.EAST) angleForTe *= -1; - ms.push(); - - MatrixStacker msr = MatrixStacker.of(ms); - - msr.centre() + SuperByteBuffer cogs = AllBlockPartials.GANTRY_COGS.renderOn(state); + cogs.matrixStacker() + .centre() .rotateY(AngleHelper.horizontalAngle(facing)) .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) - .rotateY(alongFirst ^ facing.getAxis() == Axis.Z ? 90 : 0); + .rotateY(alongFirst ^ facing.getAxis() == Axis.Z ? 90 : 0) + .translate(0, -9 / 16f, 0) + .multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)) + .translate(0, 9 / 16f, 0) + .unCentre(); - ms.translate(0, -9 / 16f, 0); - ms.multiply(Vector3f.POSITIVE_X.getRadialQuaternion(-angleForTe)); - ms.translate(0, 9 / 16f, 0); - - msr.unCentre(); - AllBlockPartials.GANTRY_COGS.renderOn(state) - .light(light) + cogs.light(light) .renderInto(ms, buffer.getBuffer(RenderType.getSolid())); - ms.pop(); } public static float getAngleForTe(KineticTileEntity te, final BlockPos pos, Axis axis) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java deleted file mode 100644 index cf2bd4059..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderer.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; - -public class ContraptionRenderer { - - - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java index c78922e49..9af581f3f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java @@ -71,11 +71,11 @@ public class BeltRenderer extends SafeTileEntityRenderer { boolean sideways = beltSlope == BeltSlope.SIDEWAYS; boolean alongX = facing.getAxis() == Axis.X; - MatrixStacker msr = MatrixStacker.of(ms); + MatrixStack localTransforms = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(localTransforms); IVertexBuilder vb = buffer.getBuffer(RenderType.getSolid()); float renderTick = AnimationTickHolder.getRenderTime(); - ms.push(); msr.centre(); msr.rotateY(AngleHelper.horizontalAngle(facing) + (upward ? 180 : 0) + (sideways ? 270 : 0)); msr.rotateZ(sideways ? 90 : 0); @@ -117,12 +117,13 @@ public class BeltRenderer extends SafeTileEntityRenderer { beltBuffer.shiftUVScrolling(spriteShift, (float) scroll); } - beltBuffer.renderInto(ms, vb); + beltBuffer + .transform(localTransforms) + .renderInto(ms, vb); // Diagonal belt do not have a separate bottom model if (diagonal) break; } - ms.pop(); if (te.hasPulley()) { // TODO 1.15 find a way to cache this model matrix computation diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java index 3dd04f582..de4093d09 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java @@ -17,7 +17,7 @@ public class ShaftInstance extends SingleRotatingInstance { InstancedTileRenderRegistry.instance.register(type, ShaftInstance::new)); } - public ShaftInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { + public ShaftInstance(InstancedTileRenderer dispatcher, KineticTileEntity tile) { super(dispatcher, tile); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java index 40d8c9ccd..a15fca209 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java @@ -41,7 +41,9 @@ public class ArmRenderer extends KineticTileEntityRenderer { ArmTileEntity arm = (ArmTileEntity) te; IVertexBuilder builder = buffer.getBuffer(RenderType.getSolid()); BlockState blockState = te.getBlockState(); - MatrixStacker msr = MatrixStacker.of(ms); + + MatrixStack msLocal = new MatrixStack(); + MatrixStacker msr = MatrixStacker.of(msLocal); int color = 0xFFFFFF; float baseAngle = arm.baseAngle.get(pt); @@ -58,8 +60,6 @@ public class ArmRenderer extends KineticTileEntityRenderer { headAngle = -lowerArmAngle; color = ColorHelper.rainbowColor(AnimationTickHolder.getTicks() * 100); } - - ms.push(); SuperByteBuffer base = AllBlockPartials.ARM_BASE.renderOn(blockState).light(light); SuperByteBuffer lowerBody = AllBlockPartials.ARM_LOWER_BODY.renderOn(blockState).light(light); @@ -73,27 +73,32 @@ public class ArmRenderer extends KineticTileEntityRenderer { if (blockState.get(ArmBlock.CEILING)) msr.rotateX(180); - ms.translate(0, 4 / 16d, 0); + msLocal.translate(0, 4 / 16d, 0); msr.rotateY(baseAngle); - base.renderInto(ms, builder); - - ms.translate(0, 1 / 16d, -2 / 16d); - msr.rotateX(lowerArmAngle); - ms.translate(0, -1 / 16d, 0); - lowerBody.color(color) + base.transform(msLocal) .renderInto(ms, builder); - ms.translate(0, 12 / 16d, 12 / 16d); + msLocal.translate(0, 1 / 16d, -2 / 16d); + msr.rotateX(lowerArmAngle); + msLocal.translate(0, -1 / 16d, 0); + lowerBody.color(color) + .transform(msLocal) + .renderInto(ms, builder); + + msLocal.translate(0, 12 / 16d, 12 / 16d); msr.rotateX(upperArmAngle); upperBody.color(color) + .transform(msLocal) + .renderInto(ms, builder); + + msLocal.translate(0, 11 / 16d, -11 / 16d); + msr.rotateX(headAngle); + head.transform(msLocal) .renderInto(ms, builder); - ms.translate(0, 11 / 16d, -11 / 16d); - msr.rotateX(headAngle); - head.renderInto(ms, builder); - - ms.translate(0, 0, -4 / 16d); - claw.renderInto(ms, builder); + msLocal.translate(0, 0, -4 / 16d); + claw.transform(msLocal) + .renderInto(ms, builder); ItemStack item = arm.heldItem; ItemRenderer itemRenderer = Minecraft.getInstance() .getItemRenderer(); @@ -103,23 +108,27 @@ public class ArmRenderer extends KineticTileEntityRenderer { .isGui3d(); for (int flip : Iterate.positiveAndNegative) { - ms.push(); - ms.translate(0, flip * 3 / 16d, -1 / 16d); + msLocal.push(); + msLocal.translate(0, flip * 3 / 16d, -1 / 16d); msr.rotateX(flip * (hasItem ? isBlockItem ? 0 : -35 : 0)); - clawGrip.light(light).renderInto(ms, builder); - ms.pop(); + clawGrip.light(light).transform(msLocal).renderInto(ms, builder); + msLocal.pop(); } if (hasItem) { + ms.push(); float itemScale = isBlockItem ? .5f : .625f; msr.rotateX(90); - ms.translate(0, -4 / 16f, 0); - ms.scale(itemScale, itemScale, itemScale); + msLocal.translate(0, -4 / 16f, 0); + msLocal.scale(itemScale, itemScale, itemScale); + + ms.peek().getModel().multiply(msLocal.peek().getModel()); + itemRenderer .renderItem(item, TransformType.FIXED, light, overlay, ms, buffer); + ms.pop(); } - ms.pop(); } @Override diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java index bf90d3f84..6163c07fc 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java @@ -42,7 +42,6 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer launched.totalTicks - 10) - recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); - - // Render particles for launch - if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) { - tileEntityIn.firstRenderTick = false; - for (int i = 0; i < 10; i++) { - Random r = tileEntityIn.getWorld().getRandom(); - double sX = cannonOffset.x * .01f; - double sY = (cannonOffset.y + 1) * .01f; - double sZ = cannonOffset.z * .01f; - double rX = r.nextFloat() - sX * 40; - double rY = r.nextFloat() - sY * 40; - double rZ = r.nextFloat() - sZ * 40; - tileEntityIn.getWorld().addParticle(ParticleTypes.CLOUD, start.x + rX, start.y + rY, - start.z + rZ, sX, sY, sZ); - } - } - - } - } + double recoil = !tileEntityIn.flyingBlocks.isEmpty() ? getRecoil(tileEntityIn, partialTicks, ms, buffer, light, overlay) : 0; ms.push(); BlockState state = tileEntityIn.getBlockState(); @@ -163,4 +91,79 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer launched.totalTicks - 10) + recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); + + // Render particles for launch + if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) { + tileEntityIn.firstRenderTick = false; + for (int i = 0; i < 10; i++) { + Random r = tileEntityIn.getWorld().getRandom(); + double sX = cannonOffset.x * .01f; + double sY = (cannonOffset.y + 1) * .01f; + double sZ = cannonOffset.z * .01f; + double rX = r.nextFloat() - sX * 40; + double rY = r.nextFloat() - sY * 40; + double rZ = r.nextFloat() - sZ * 40; + tileEntityIn.getWorld().addParticle(ParticleTypes.CLOUD, start.x + rX, start.y + rY, + start.z + rZ, sX, sY, sZ); + } + } + + } + + return recoil; + } + } diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 1407b4d1e..7aeca6f3b 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -201,7 +201,6 @@ public class ClientEvents { if (!isGameActive()) return; TurntableHandler.gameRenderTick(); - ContraptionRenderDispatcher.renderTick(); } protected static boolean isGameActive() { diff --git a/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java index 62c3f935f..840f5f0f0 100644 --- a/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/render/SuperByteBuffer.java @@ -8,17 +8,15 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.block.render.SpriteShiftEntry; +import com.simibubi.create.foundation.utility.MatrixStacker; import it.unimi.dsi.fastutil.longs.Long2DoubleMap; import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Matrix3f; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.Vector3f; -import net.minecraft.client.renderer.Vector4f; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.LightType; import net.minecraft.world.World; import net.minecraftforge.client.model.pipeline.LightUtil; @@ -107,13 +105,16 @@ public class SuperByteBuffer extends TemplateBuffer { float staticDiffuse = LightUtil.diffuseLight(normalX, normalY, normalZ); normal.set(normalX, normalY, normalZ); normal.transform(normalMat); - float instanceDiffuse = LightUtil.diffuseLight(normal.getX(), normal.getY(), normal.getZ()); + float nx = normal.getX(); + float ny = normal.getY(); + float nz = normal.getZ(); + float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz); pos.set(x, y, z, 1F); pos.transform(modelMat); builder.vertex(pos.getX(), pos.getY(), pos.getZ()); - //builder.color((byte) Math.max(0, normal.getX() * 255), (byte) Math.max(0, normal.getY() * 255), (byte) Math.max(0, normal.getZ() * 255), a); + //builder.color((byte) Math.max(0, nx * 255), (byte) Math.max(0, ny * 255), (byte) Math.max(0, nz * 255), a); if (shouldColor) { //float lum = (r < 0 ? 255 + r : r) / 256f; int colorR = Math.min(255, (int) (((float) this.r) * instanceDiffuse)); @@ -152,7 +153,7 @@ public class SuperByteBuffer extends TemplateBuffer { } else builder.light(getLight(buffer, i)); - builder.normal(normal.getX(), normal.getY(), normal.getZ()) + builder.normal(nx, ny, nz) .endVertex(); } @@ -164,6 +165,14 @@ public class SuperByteBuffer extends TemplateBuffer { otherBlockLight = -1; } + public MatrixStacker matrixStacker() { + return MatrixStacker.of(transforms); + } + + public SuperByteBuffer translate(Vec3d vec) { + return translate(vec.x, vec.y, vec.z); + } + public SuperByteBuffer translate(double x, double y, double z) { return translate((float) x, (float) y, (float) z); } @@ -173,6 +182,12 @@ public class SuperByteBuffer extends TemplateBuffer { return this; } + public SuperByteBuffer transform(MatrixStack stack) { + transforms.peek().getModel().multiply(stack.peek().getModel()); + transforms.peek().getNormal().multiply(stack.peek().getNormal()); + return this; + } + public SuperByteBuffer rotate(Direction axis, float radians) { if (radians == 0) return this; diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java index c59bd573f..2a0255eab 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/instancing/InstancedModel.java @@ -77,6 +77,14 @@ public abstract class InstancedModel extends BufferedMod key.invalidate(); } + public D getInstance(InstanceKey key) { + verifyKey(key); + + markIndexChanged(key.index); + + return this.data.get(key.index); + } + public synchronized void modifyInstance(InstanceKey key, Consumer edit) { verifyKey(key); diff --git a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java index 46555224c..c56938d49 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java +++ b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java @@ -2,6 +2,7 @@ package com.simibubi.create.foundation.utility; import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.renderer.Quaternion; import net.minecraft.client.renderer.Vector3f; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; @@ -10,7 +11,7 @@ import net.minecraft.util.math.Vec3i; public class MatrixStacker { - static Vec3d center = VecHelper.getCenterOf(BlockPos.ZERO); + public static final Vec3d center = VecHelper.getCenterOf(BlockPos.ZERO); static MatrixStacker instance; MatrixStack ms; @@ -63,6 +64,16 @@ public class MatrixStacker { return this; } + public MatrixStacker translate(double x, double y, double z) { + ms.translate(x, y, z); + return this; + } + + public MatrixStacker multiply(Quaternion quaternion) { + ms.multiply(quaternion); + return this; + } + public MatrixStacker nudge(int id) { long randomBits = (long) id * 493286711L; randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L;