类net.minecraftforge.common.model.TRSRTransformation源码实例Demo

下面列出了怎么用net.minecraftforge.common.model.TRSRTransformation的API类实例代码及写法,或者点击链接到github查看源代码。

源代码1 项目: Logistics-Pipes-2   文件: BlockGenericPipe.java
@Override
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
      {
          if(part.isPresent())
          {
              // This whole thing is subject to change, but should do for now.
              UnmodifiableIterator<String> parts = Models.getParts(part.get());
              if(parts.hasNext())
              {
                  String name = parts.next();
                  // only interested in the root level
                  if(!parts.hasNext() && hidden.contains(name))
                  {
                      return value;
                  }
              }
          }
          return Optional.absent();
      }
 
源代码2 项目: enderutilities   文件: BakedModelInserter.java
private List<IBakedModel> getSideModels(IBlockState state)
{
    List<IBakedModel> models = new ArrayList<IBakedModel>();

    for (EnumFacing side : EnumFacing.values())
    {
        BlockInserter.Connection conn = state.getValue(BlockInserter.CONNECTIONS.get(side.getIndex()));

        if (conn == BlockInserter.Connection.VALID)
        {
            models.add(this.sideModelValid.bake(TRSRTransformation.from(side), this.format, this.bakedTextureGetter));
        }
        else if (conn == BlockInserter.Connection.INVALID)
        {
            models.add(this.sideModelInvalid.bake(TRSRTransformation.from(side), this.format, this.bakedTextureGetter));
        }
    }

    return models;
}
 
@Nullable
public static IBakedModel getRotatedBakedModel(@Nullable IModel model, @Nullable IBakedModel bakedModelDefault, IBlockState state,
        VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
    if (model != null)
    {
        if (state.getPropertyKeys().contains(BlockEnderUtilities.FACING))
        {
            return model.bake(TRSRTransformation.from(state.getValue(BlockEnderUtilities.FACING)), format, bakedTextureGetter);
        }
        else if (state.getPropertyKeys().contains(BlockEnderUtilities.FACING_H))
        {
            return model.bake(TRSRTransformation.from(state.getValue(BlockEnderUtilities.FACING_H)), format, bakedTextureGetter);
        }
    }

    return bakedModelDefault;
}
 
源代码4 项目: OpenModsLib   文件: TransformProvider.java
public Transformation(Orientation orientation) {
	final javax.vecmath.Matrix4f originalMatrix = new javax.vecmath.Matrix4f();
	originalMatrix.set(orientation.getLocalToWorldMatrix());

	asMatrix = TRSRTransformation.toLwjgl(originalMatrix);

	asBuffer = BufferUtils.createFloatBuffer(16);
	asMatrix.store(asBuffer);
	asBuffer.rewind();

	asInverseMatrix = new Matrix4f();
	Matrix4f.invert(asMatrix, asInverseMatrix);

	asInverseBuffer = BufferUtils.createFloatBuffer(16);
	asInverseMatrix.store(asInverseBuffer);
	asInverseBuffer.rewind();
}
 
源代码5 项目: OpenModsLib   文件: MultiLayerModel.java
public MultiLayerBakedModel(Map<BlockRenderLayer, IBakedModel> models, IBakedModel base, IBakedModel missing, ImmutableMap<TransformType, TRSRTransformation> cameraTransforms) {
	super(base, cameraTransforms);
	this.models = ImmutableMap.copyOf(models);
	this.missing = missing;

	final List<BakedQuad> quads = Lists.newArrayList();

	for (BlockRenderLayer layer : BlockRenderLayer.values()) {
		final IBakedModel model = models.get(layer);
		if (model != null) {
			buildQuadsForLayer(quads, model);
		}
	}

	this.quads = ImmutableList.copyOf(quads);
}
 
源代码6 项目: OpenModsLib   文件: EvalModelTest.java
@Test
public void testDirectApply() {
	EvaluatorFactory factory = new EvaluatorFactory();
	factory.appendStatement("clip(param)");

	final ClipStub clipStub = new ClipStub();
	final IJointClip jointClipMock = clipStub.jointClipMock;

	final TRSRTransformation transform = TRSRTransformation.from(EnumFacing.NORTH);
	Mockito.when(jointClipMock.apply(Matchers.anyFloat())).thenReturn(transform);

	final float param = 1.3f;
	final TRSRTransformation result = factory.createEvaluator(clips("clip", clipStub)).evaluate(DUMMY_JOINT, ImmutableMap.of("param", param));
	Assert.assertEquals(transform, result);

	Mockito.verify(jointClipMock).apply(param);
	Mockito.verifyNoMoreInteractions(jointClipMock);
}
 
源代码7 项目: OpenModsLib   文件: EvalModelTest.java
@Test
public void testVarApply() {
	EvaluatorFactory factory = new EvaluatorFactory();
	factory.appendStatement("param := 1.4");
	factory.appendStatement("clip(param)");

	final ClipStub clipStub = new ClipStub();
	final IJointClip jointClipMock = clipStub.jointClipMock;

	final TRSRTransformation transform = TRSRTransformation.from(EnumFacing.NORTH);
	Mockito.when(jointClipMock.apply(Matchers.anyFloat())).thenReturn(transform);

	final TRSRTransformation result = factory.createEvaluator(clips("clip", clipStub)).evaluate(DUMMY_JOINT, NO_ARGS);
	Assert.assertEquals(transform, result);

	Mockito.verify(jointClipMock).apply(1.4f);
	Mockito.verifyNoMoreInteractions(jointClipMock);
}
 
源代码8 项目: OpenModsLib   文件: EvalModelTest.java
@Test
public void testConstApply() {
	EvaluatorFactory factory = new EvaluatorFactory();
	factory.appendStatement("clip(2.4 + 1/3)");

	final ClipStub clipStub = new ClipStub();
	final IJointClip jointClipMock = clipStub.jointClipMock;

	final TRSRTransformation transform = TRSRTransformation.from(EnumFacing.NORTH);
	Mockito.when(jointClipMock.apply(Matchers.anyFloat())).thenReturn(transform);

	final TRSRTransformation result = factory.createEvaluator(clips("clip", clipStub)).evaluate(DUMMY_JOINT, NO_ARGS);
	Assert.assertEquals(transform, result);

	Mockito.verify(jointClipMock).apply(2.4f + 1f / 3f);
	Mockito.verifyNoMoreInteractions(jointClipMock);
}
 
源代码9 项目: OpenModsLib   文件: EvalModelTest.java
@Test
public void testArithmeticsVarApply() {
	EvaluatorFactory factory = new EvaluatorFactory();
	factory.appendStatement("clip(2.4 / a + 1/(3 * b))");

	final ClipStub clipStub = new ClipStub();
	final IJointClip jointClipMock = clipStub.jointClipMock;

	final TRSRTransformation transform = TRSRTransformation.from(EnumFacing.NORTH);
	Mockito.when(jointClipMock.apply(Matchers.anyFloat())).thenReturn(transform);

	final TRSRTransformation result = factory.createEvaluator(clips("clip", clipStub))
			.evaluate(DUMMY_JOINT, ImmutableMap.of("a", 5.1f, "b", -0.4f));
	Assert.assertEquals(transform, result);

	Mockito.verify(jointClipMock).apply(2.4f / 5.1f + 1f / (3f * -0.4f));
	Mockito.verifyNoMoreInteractions(jointClipMock);
}
 
源代码10 项目: OpenModsLib   文件: EvalModelTest.java
@Test
public void testDoubleApply() {
	EvaluatorFactory factory = new EvaluatorFactory();
	factory.appendStatement("param1 := 1.4");
	factory.appendStatement("clip(param1)");
	factory.appendStatement("clip(param2)");

	final ClipStub clipStub = new ClipStub();
	final IJointClip jointClipMock = clipStub.jointClipMock;

	final TRSRTransformation transform1 = TRSRTransformation.from(EnumFacing.NORTH);
	final TRSRTransformation transform2 = TRSRTransformation.from(EnumFacing.WEST);
	Mockito.when(jointClipMock.apply(1.4f)).thenReturn(transform1);
	Mockito.when(jointClipMock.apply(2.1f)).thenReturn(transform2);

	final TRSRTransformation result = factory.createEvaluator(clips("clip", clipStub)).evaluate(DUMMY_JOINT, ImmutableMap.of("param2", 2.1f));
	Assert.assertEquals(transform1.compose(transform2), result);

	Mockito.verify(jointClipMock).apply(1.4f);
	Mockito.verify(jointClipMock).apply(2.1f);
	Mockito.verifyNoMoreInteractions(jointClipMock);
}
 
源代码11 项目: GT-Classic   文件: GTItemOverrideTestTube.java
@Override
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world,
		EntityLivingBase entity) {
	FluidStack fluidStack = FluidUtil.getFluidContained(stack);
	if (fluidStack == null)
		return originalModel;
	IBakedModel baked = CACHE.get(fluidStack.getFluid().getName());
	if (baked == null) {
		GTBakedTestTube bakedCell = (GTBakedTestTube) originalModel;
		GTModelTestTube model = new GTModelTestTube(fluidStack.getFluid());
		CACHE.put(fluidStack.getFluid().getName(), (baked = model.bake(TRSRTransformation.identity(), bakedCell.format, GTModelUtils.getTextureGetter())));
	}
	return baked;
}
 
源代码12 项目: VanillaFix   文件: VanillaModelWrapper.java
@Override
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) {
    if (!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT)) {
        throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format);
    }
    ModelBlock model = this.model;

    if (model == null) {
        return BuiltinLoader.WRAPPED_MODEL_MISSING.bake(BuiltinLoader.WRAPPED_MODEL_MISSING.getDefaultState(), format, bakedTextureGetter);
    }

    List<TRSRTransformation> newTransforms = Lists.newArrayList();
    for (int i = 0; i < model.getElements().size(); i++) {
        BlockPart part = model.getElements().get(i);
        newTransforms.add(animation.getPartTransform(state, part, i));
    }

    ItemCameraTransforms transforms = model.getAllTransforms();
    Map<ItemCameraTransforms.TransformType, TRSRTransformation> tMap = Maps.newEnumMap(ItemCameraTransforms.TransformType.class);
    tMap.putAll(PerspectiveMapWrapper.getTransforms(transforms));
    tMap.putAll(PerspectiveMapWrapper.getTransforms(state));
    IModelState perState = new SimpleModelState(ImmutableMap.copyOf(tMap));

    if (hasItemModel(model)) {
        return new ItemLayerModel(model).bake(perState, format, bakedTextureGetter);
    }

    if (isCustomRenderer(model)) {
        return new BuiltInModel(transforms, model.createOverrides());
    }

    return bakeNormal(model, perState, state, newTransforms, format, bakedTextureGetter, uvlock);
}
 
源代码13 项目: VanillaFix   文件: WeightedRandomModel.java
public WeightedRandomModel(VariantList variants) throws Exception {
    this.variants = variants.getVariantList();
    locations = new ArrayList<>();
    textures = Sets.newHashSet();
    models = new ArrayList<>();
    ImmutableList.Builder<Pair<IModel, IModelState>> builder = ImmutableList.builder();
    for (Variant variant : this.variants) {
        ResourceLocation location = variant.getModelLocation();
        locations.add(location);

        IModel model = variant.process(ModelLoaderRegistry.getModel(location));

        textures.addAll(model.getTextures());
        models.add(model);

        IModelState modelDefaultState = model.getDefaultState();
        Preconditions.checkNotNull(modelDefaultState, "Model %s returned null as default state", location);
        builder.add(Pair.of(model, new ModelStateComposition(variant.getState(), modelDefaultState)));
    }

    // If all variants are missing, add one with the missing model and default rotation
    if (models.size() == 0) {
        IModel missing = ModelLoaderRegistry.getMissingModel();
        models.add(missing);
        builder.add(Pair.of(missing, TRSRTransformation.identity()));
    }

    defaultState = new MultiModelState(builder.build());
}
 
源代码14 项目: TFC2   文件: TRSRBakedModel.java
/** Rotates around the Y axis and adjusts culling appropriately. South is default. */
public TRSRBakedModel(IBakedModel original, EnumFacing facing) {
	this.original = original;
	this.override = new TRSROverride(this);

	this.faceOffset = 4 + EnumFacing.NORTH.getHorizontalIndex() - facing.getHorizontalIndex();

	double r = Math.PI * (360 - facing.getOpposite().getHorizontalIndex() * 90)/180d;
	TRSRTransformation t = new TRSRTransformation(null, null, null, TRSRTransformation.quatFromXYZ(0, (float)r, 0));
	this.transformation = TRSRTransformation.blockCenterToCorner(t);
}
 
源代码15 项目: TFC2   文件: TRSRBakedModel.java
public Transformer(TRSRTransformation transformation, VertexFormat format) {
	super(new UnpackedBakedQuad.Builder(format));
	// position transform
	this.transformation = transformation.getMatrix();
	// normal transform
	this.normalTransformation = new Matrix3f();
	this.transformation.getRotationScale(this.normalTransformation);
	this.normalTransformation.invert();
	this.normalTransformation.transpose();
}
 
源代码16 项目: TFC2   文件: BakedSmallVesselModel.java
public static ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> getTransforms(IPerspectiveAwareModel model) {
	ImmutableMap.Builder<ItemCameraTransforms.TransformType, TRSRTransformation> builder = ImmutableMap.builder();
	for(ItemCameraTransforms.TransformType type : ItemCameraTransforms.TransformType.values()) {
		TRSRTransformation transformation = new TRSRTransformation(model.handlePerspective(type).getRight());
		if(!transformation.equals(TRSRTransformation.identity())) {
			builder.put(type, TRSRTransformation.blockCenterToCorner(transformation));
		}
	}
	return builder.build();
}
 
源代码17 项目: TFC2   文件: BakedPitKilnModel.java
public static ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> getTransforms(IPerspectiveAwareModel model) {
	ImmutableMap.Builder<ItemCameraTransforms.TransformType, TRSRTransformation> builder = ImmutableMap.builder();
	for(ItemCameraTransforms.TransformType type : ItemCameraTransforms.TransformType.values()) {
		TRSRTransformation transformation = new TRSRTransformation(model.handlePerspective(type).getRight());
		if(!transformation.equals(TRSRTransformation.identity())) {
			builder.put(type, TRSRTransformation.blockCenterToCorner(transformation));
		}
	}
	return builder.build();
}
 
源代码18 项目: TFC2   文件: BakedAnvilModel.java
public static ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> getTransforms(IPerspectiveAwareModel model) {
	ImmutableMap.Builder<ItemCameraTransforms.TransformType, TRSRTransformation> builder = ImmutableMap.builder();
	for(ItemCameraTransforms.TransformType type : ItemCameraTransforms.TransformType.values()) {
		TRSRTransformation transformation = new TRSRTransformation(model.handlePerspective(type).getRight());
		if(!transformation.equals(TRSRTransformation.identity())) {
			builder.put(type, TRSRTransformation.blockCenterToCorner(transformation));
		}
	}
	return builder.build();
}
 
源代码19 项目: enderutilities   文件: ModelEnderBucket.java
public BakedEnderBucket(ModelEnderBucket parent, ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, VertexFormat format,
        ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms, Map<String, IBakedModel> cache)
{
    this.quads = quads;
    this.particle = particle;
    this.format = format;
    this.parent = parent;
    this.transforms = transforms;
    this.cache = cache;
}
 
源代码20 项目: enderutilities   文件: ModelEnderTools.java
public BakedEnderTool(ModelEnderTools parent, ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, VertexFormat format,
        ImmutableMap<ItemCameraTransforms.TransformType, TRSRTransformation> transforms, Map<String, IBakedModel> cache)
{
    this.quads = quads;
    this.particle = particle;
    this.format = format;
    this.parent = parent;
    this.transforms = transforms;
    this.cache = cache;
}
 
源代码21 项目: OpenModsLib   文件: OrientationInfoGenerator.java
private static Multimap<Orientation, ModelRotation> calculateVanillaRotations(Map<Matrix3f, Orientation> fromMatrix) {
	final Multimap<Orientation, ModelRotation> toVanilla = HashMultimap.create();

	for (ModelRotation rot : ModelRotation.values()) {
		final Matrix4f rotMatrix = TRSRTransformation.toVecmath(rot.getMatrix4d());
		final Matrix3f key = roundAndReduceMatrixElements(rotMatrix);
		final Orientation orientation = fromMatrix.get(key);
		Preconditions.checkNotNull(orientation, rot);
		toVanilla.put(orientation, rot);
	}

	return toVanilla;
}
 
源代码22 项目: OpenModsLib   文件: EvaluatorFactory.java
private static ITransformExecutor composeTransformExecutors(List<ITransformExecutor> contents) {
	if (contents.isEmpty()) return (initial, joint, args) -> initial;
	if (contents.size() == 1)
		return contents.get(0);

	final List<ITransformExecutor> executors = ImmutableList.copyOf(contents);
	return (initial, joint, args) -> {
		TRSRTransformation result = initial;
		for (ITransformExecutor e : executors)
			result = e.apply(result, joint, args);

		return result;
	};
}
 
源代码23 项目: OpenModsLib   文件: EvaluatorFactory.java
private static ITransformExecutor createForClip(final IClip clip, final NumericExpr param) {
	return (initial, joint, args) -> {
		final float paramValue = param.evaluate(args);
		final TRSRTransformation clipTransform = clip.apply(joint).apply(paramValue);
		return initial.compose(clipTransform);
	};
}
 
源代码24 项目: OpenModsLib   文件: EvaluatorFactory.java
public ITransformEvaluator createEvaluator(IClipProvider provider) {
	if (statements.isEmpty())
		return (joint, args) -> TRSRTransformation.identity();

	final List<ITransformExecutor> executors = Lists.newArrayList();

	for (IStatement statement : statements)
		executors.add(statement.bind(provider));

	return new EvaluatorImpl(composeTransformExecutors(executors));
}
 
源代码25 项目: OpenModsLib   文件: EvalModelTest.java
@Test
public void testSeparateClipsApply() {
	EvaluatorFactory factory = new EvaluatorFactory();
	factory.appendStatement("param := 2.5");
	factory.appendStatement("clip1(param)");
	factory.appendStatement("clip2(param)");

	final ClipStub clipStub1 = new ClipStub();
	final IJointClip jointClipMock1 = clipStub1.jointClipMock;

	final ClipStub clipStub2 = new ClipStub();
	final IJointClip jointClipMock2 = clipStub2.jointClipMock;

	final TRSRTransformation transform1 = TRSRTransformation.from(EnumFacing.EAST);
	final TRSRTransformation transform2 = TRSRTransformation.from(EnumFacing.UP);
	Mockito.when(jointClipMock1.apply(Matchers.anyFloat())).thenReturn(transform1);
	Mockito.when(jointClipMock2.apply(Matchers.anyFloat())).thenReturn(transform2);

	final TRSRTransformation result = factory.createEvaluator(clips("clip1", clipStub1).put("clip2", clipStub2)).evaluate(DUMMY_JOINT, NO_ARGS);
	Assert.assertEquals(transform1.compose(transform2), result);

	Mockito.verify(jointClipMock1).apply(2.5f);
	Mockito.verifyNoMoreInteractions(jointClipMock1);

	Mockito.verify(jointClipMock2).apply(2.5f);
	Mockito.verifyNoMoreInteractions(jointClipMock2);
}
 
源代码26 项目: GT-Classic   文件: GTModelUtils.java
public static Matrix4f getItemTransform(ItemCameraTransforms.TransformType type) {
	Matrix4f mat = TRANSFORM_MAP_ITEM.get(type);
	return mat != null ? mat : TRSRTransformation.identity().getMatrix();
}
 
源代码27 项目: GT-Classic   文件: GTModelUtils.java
public static TRSRTransformation getTransform(float tx, float ty, float tz, float ax, float ay, float az, float s) {
	return new TRSRTransformation(new Vector3f(tx / 16, ty / 16, tz
			/ 16), TRSRTransformation.quatFromXYZDegrees(new Vector3f(ax, ay, az)), new Vector3f(s, s, s), null);
}
 
源代码28 项目: VanillaFix   文件: VanillaModelWrapper.java
private IBakedModel bakeNormal(ModelBlock model, IModelState perState, final IModelState modelState, List<TRSRTransformation> newTransforms, final VertexFormat format, final Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter, boolean uvLocked) {
    final TRSRTransformation baseState = modelState.apply(Optional.empty()).orElse(TRSRTransformation.identity());
    TextureAtlasSprite particle = bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName("particle")));
    SimpleBakedModel.Builder builder = new SimpleBakedModel.Builder(model, model.createOverrides()).setTexture(particle);
    for (int i = 0; i < model.getElements().size(); i++) {
        if (modelState.apply(Optional.of(Models.getHiddenModelPart(ImmutableList.of(Integer.toString(i))))).isPresent()) {
            continue;
        }
        BlockPart part = model.getElements().get(i);
        TRSRTransformation transformation = baseState;
        if (newTransforms.get(i) != null) {
            transformation = transformation.compose(newTransforms.get(i));
            BlockPartRotation rot = part.partRotation;
            if (rot == null) rot = new BlockPartRotation(new org.lwjgl.util.vector.Vector3f(), EnumFacing.Axis.Y, 0, false);
            part = new BlockPart(part.positionFrom, part.positionTo, part.mapFaces, rot, part.shade);
        }
        for (Map.Entry<EnumFacing, BlockPartFace> e : part.mapFaces.entrySet()) {
            TextureAtlasSprite textureatlassprite1 = bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName(e.getValue().texture)));

            if (e.getValue().cullFace == null || !TRSRTransformation.isInteger(transformation.getMatrix())) {
                builder.addGeneralQuad(makeBakedQuad(part, e.getValue(), textureatlassprite1, e.getKey(), transformation, uvLocked));
            } else {
                builder.addFaceQuad(baseState.rotate(e.getValue().cullFace), makeBakedQuad(part, e.getValue(), textureatlassprite1, e.getKey(), transformation, uvLocked));
            }
        }
    }

    return new PerspectiveMapWrapper(builder.makeBakedModel(), perState) {
        private final ItemOverrideList overrides = new AnimationItemOverrideList(VanillaModelWrapper.this, modelState, format, bakedTextureGetter, super.getOverrides());

        @Override
        public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) {
            List<BakedQuad> quads = null;

            if (state instanceof IExtendedBlockState) {
                IExtendedBlockState exState = (IExtendedBlockState) state;
                if (exState.getUnlistedNames().contains(Properties.AnimationProperty)) {
                    IModelState newState = exState.getValue(Properties.AnimationProperty);
                    IExtendedBlockState newExState = exState.withProperty(Properties.AnimationProperty, null);
                    if (newState != null) {
                        quads = bake(new ModelStateComposition(modelState, newState), format, bakedTextureGetter).getQuads(newExState, side, rand);
                    }
                }
            }

            if (quads == null) {
                quads = super.getQuads(state, side, rand);
            }

            return quads;
        }

        @Override
        public ItemOverrideList getOverrides() {
            return overrides;
        }
    };
}
 
源代码29 项目: AdvancedRocketry   文件: ModelRocket.java
@Override
public Optional<TRSRTransformation> apply(
		Optional<? extends IModelPart> part) {
	return Optional.empty();
}
 
源代码30 项目: TFC2   文件: TRSRBakedModel.java
public TRSRBakedModel(IBakedModel original, float x, float y, float z, float rotX, float rotY, float rotZ, float scaleX, float scaleY, float scaleZ) {
	this(original, new TRSRTransformation(new Vector3f(x, y, z),
			null,
			new Vector3f(scaleX, scaleY, scaleZ),
			TRSRTransformation.quatFromXYZ(rotX, rotY, rotZ)));
}
 
 类方法
 同包方法