Package org.terasology.core.world.generator.chunkGenerators

Source Code of org.terasology.core.world.generator.chunkGenerators.TreeGeneratorLSystem

/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.core.world.generator.chunkGenerators;

import org.terasology.math.LSystemRule;
import org.terasology.math.TeraMath;
import org.terasology.utilities.collection.CharSequenceIterator;
import org.terasology.utilities.random.Random;
import org.terasology.world.block.Block;
import org.terasology.world.chunks.CoreChunk;

import javax.vecmath.AxisAngle4f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import java.util.Map;

/**
* Allows the generation of complex trees based on L-Systems.
*
* @author Benjamin Glatzel <benjamin.glatzel@me.com>
*/
public class TreeGeneratorLSystem extends TreeGenerator {

    public static final float MAX_ANGLE_OFFSET = (float) Math.toRadians(5);

    /* SETTINGS */
    private int maxDepth;
    private float angle;
    private Block leafType;
    private Block barkType;

    /* RULES */
    private final String initialAxiom;
    private final Map<Character, LSystemRule> ruleSet;

    /**
     * Init. a new L-System based tree generator.
     *
     * @param initialAxiom The initial axiom to use
     * @param ruleSet      The rule set to use
     * @param maxDepth     The maximum recursion depth
     * @param angle        The angle
     */
    public TreeGeneratorLSystem(String initialAxiom, Map<Character, LSystemRule> ruleSet, int maxDepth, float angle) {
        this.angle = angle;
        this.maxDepth = maxDepth;

        this.initialAxiom = initialAxiom;
        this.ruleSet = ruleSet;
    }

    @Override
    public void generate(CoreChunk view, Random rand, int posX, int posY, int posZ) {
        Vector3f position = new Vector3f(0f, 0f, 0f);

        Matrix4f rotation = new Matrix4f();
        rotation.setIdentity();
        rotation.setRotation(new AxisAngle4f(0f, 0f, 1f, (float) Math.PI / 2f));

        float angleOffset = rand.nextFloat(-MAX_ANGLE_OFFSET, MAX_ANGLE_OFFSET);
        recurse(view, rand, posX, posY, posZ, angleOffset, new CharSequenceIterator(initialAxiom), position, rotation, 0);
    }

    private void recurse(CoreChunk view, Random rand, int posX, int posY, int posZ, float angleOffset,
                         CharSequenceIterator axiomIterator, Vector3f position, Matrix4f rotation, int depth) {
        Matrix4f tempRotation = new Matrix4f();
        while (axiomIterator.hasNext()) {
            char c = axiomIterator.nextChar();
            switch (c) {
                case 'G':
                case 'F':
                    // Tree trunk

                    safelySetBlock(view, posX + (int) position.x + 1, posY + (int) position.y, posZ + (int) position.z, barkType);
                    safelySetBlock(view, posX + (int) position.x - 1, posY + (int) position.y, posZ + (int) position.z, barkType);
                    safelySetBlock(view, posX + (int) position.x, posY + (int) position.y, posZ + (int) position.z + 1, barkType);
                    safelySetBlock(view, posX + (int) position.x, posY + (int) position.y, posZ + (int) position.z - 1, barkType);

                    // Generate leaves
                    if (depth > 1) {
                        int size = 1;

                        for (int x = -size; x <= size; x++) {
                            for (int y = -size; y <= size; y++) {
                                for (int z = -size; z <= size; z++) {
                                    if (Math.abs(x) == size && Math.abs(y) == size && Math.abs(z) == size) {
                                        continue;
                                    }

                                    safelySetBlock(view, posX + (int) position.x + x + 1, posY + (int) position.y + y, posZ + z + (int) position.z, leafType);
                                    safelySetBlock(view, posX + (int) position.x + x - 1, posY + (int) position.y + y, posZ + z + (int) position.z, leafType);
                                    safelySetBlock(view, posX + (int) position.x + x, posY + (int) position.y + y, posZ + z + (int) position.z + 1, leafType);
                                    safelySetBlock(view, posX + (int) position.x + x, posY + (int) position.y + y, posZ + z + (int) position.z - 1, leafType);
                                }
                            }
                        }
                    }

                    Vector3f dir = new Vector3f(1f, 0f, 0f);
                    rotation.transform(dir);

                    position.add(dir);
                    break;
                case '[':
                    recurse(view, rand, posX, posY, posZ, angleOffset, axiomIterator, new Vector3f(position), new Matrix4f(rotation), depth);
                    break;
                case ']':
                    return;
                case '+':
                    tempRotation.setIdentity();
                    tempRotation.setRotation(new AxisAngle4f(0f, 0f, 1f, angle + angleOffset));
                    rotation.mul(tempRotation);
                    break;
                case '-':
                    tempRotation.setIdentity();
                    tempRotation.setRotation(new AxisAngle4f(0f, 0f, -1f, angle + angleOffset));
                    rotation.mul(tempRotation);
                    break;
                case '&':
                    tempRotation.setIdentity();
                    tempRotation.setRotation(new AxisAngle4f(0f, 1f, 0f, angle + angleOffset));
                    rotation.mul(tempRotation);
                    break;
                case '^':
                    tempRotation.setIdentity();
                    tempRotation.setRotation(new AxisAngle4f(0f, -1f, 0f, angle + angleOffset));
                    rotation.mul(tempRotation);
                    break;
                case '*':
                    tempRotation.setIdentity();
                    tempRotation.setRotation(new AxisAngle4f(1f, 0f, 0f, angle));
                    rotation.mul(tempRotation);
                    break;
                case '/':
                    tempRotation.setIdentity();
                    tempRotation.setRotation(new AxisAngle4f(-1f, 0f, 0f, angle));
                    rotation.mul(tempRotation);
                    break;
                default:
                    // If we have already reached the maximum depth, don't ever bother to lookup in the map
                    if (depth == maxDepth - 1) {
                        break;
                    }
                    LSystemRule rule = ruleSet.get(c);
                    if (rule == null) {
                        break;
                    }

                    float weightedFailureProbability = TeraMath.pow(1f - rule.getProbability(), maxDepth - depth);
                    if (rand.nextFloat() < weightedFailureProbability) {
                        break;
                    }

                    recurse(view, rand, posX, posY, posZ, angleOffset, new CharSequenceIterator(rule.getAxiom()), position, rotation, depth + 1);
            }
        }
    }

    public TreeGeneratorLSystem setLeafType(Block b) {
        leafType = b;
        return this;
    }

    public TreeGeneratorLSystem setBarkType(Block b) {
        barkType = b;
        return this;
    }
}
TOP

Related Classes of org.terasology.core.world.generator.chunkGenerators.TreeGeneratorLSystem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.