This repository has been archived by the owner on Jun 19, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
Temp. plant renderer and treegen fixes/improvements #52
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ae0f449
TEMPORARY PLANT RENDERER HAHA
jonas-schievink c21a350
fmt
jonas-schievink 7a334ff
Treegen and treerender fixes
jonas-schievink ad52fed
format moar
jonas-schievink 5e91259
Implement a helper function to create a seeded RNG
jonas-schievink becdf95
Address most comments
jonas-schievink File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ cgmath = "0.10.0" | |
log = "0.3.6" | ||
num-traits = "0.1.33" | ||
rand = "0.3.14" | ||
fnv = "1.0.3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,39 @@ | ||
//! Functionality about procedurally generating content. | ||
//! | ||
|
||
extern crate fnv; | ||
|
||
mod plant; | ||
mod world; | ||
|
||
pub use self::world::WorldGenerator; | ||
pub use self::plant::PlantGenerator; | ||
|
||
use rand::{SeedableRng, XorShiftRng}; | ||
use self::fnv::FnvHasher; | ||
use std::hash::{Hash, Hasher}; | ||
|
||
type Random = XorShiftRng; | ||
|
||
/// Creates a seeded RNG for use in world gen. | ||
/// | ||
/// This function takes 3 seed parameters which are hashed and mixed together. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// * `world_seed`: The constant world seed as set in the config | ||
/// * `feat_seed`: Feature-specific constant seed | ||
/// * `loc_seed`: Location-seed, for example, X/Y coordinates of a feature | ||
fn seeded_rng<T: Hash, U: Hash>(world_seed: u64, feat_seed: T, loc_seed: U) -> Random { | ||
// Hash everything, even `world_seed`, since XorShift really doesn't like seeds | ||
// with many 0s in it | ||
let mut fnv = FnvHasher::default(); | ||
world_seed.hash(&mut fnv); | ||
feat_seed.hash(&mut fnv); | ||
loc_seed.hash(&mut fnv); | ||
let rng_seed = fnv.finish(); | ||
let seed0 = (rng_seed >> 32) as u32; | ||
let seed1 = rng_seed as u32; | ||
|
||
XorShiftRng::from_seed([seed0, seed1, seed0, seed1]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ use std::ops::Range; | |
/// Parameters for the tree generator. | ||
#[derive(Debug)] | ||
struct Preset { | ||
name: &'static str, | ||
/// Diameter of the first branch we create (the trunk). | ||
trunk_diameter: Range<f32>, | ||
/// Trunk height. Note that branches going upward can increase plant height | ||
|
@@ -43,6 +44,7 @@ struct Preset { | |
} | ||
|
||
static PRESETS: &'static [Preset] = &[Preset { | ||
name: "'Regular' Tree", | ||
trunk_diameter: 0.3..0.5, | ||
trunk_height: 3.0..6.0, | ||
trunk_diameter_top: 0.2..0.4, | ||
|
@@ -147,16 +149,22 @@ impl TreeGen { | |
points: points, | ||
// FIXME Fixed color for now, we should use a configurable random color (or at least | ||
// make it brown). | ||
color: Vector3f::new(0.0, 0.0, 1.0), | ||
color: Vector3f::new(0.0, 1.0, 0.0), | ||
}); | ||
} | ||
|
||
/// Given the growing direction of the parent branch, calculates a growing | ||
/// direction to use for a new child branch. | ||
fn gen_branch_direction<R: Rng>(&self, rng: &mut R, parent_dir: Vector3f) -> Vector3f { | ||
let x_angle = range_sample(&self.preset.branch_angle_deg, rng); | ||
let y_angle = range_sample(&self.preset.branch_angle_deg, rng); | ||
// `branch_angle_deg` specifies the angle range in degrees | ||
let mut x_angle = range_sample(&self.preset.branch_angle_deg, rng); | ||
let mut y_angle = range_sample(&self.preset.branch_angle_deg, rng); | ||
|
||
// Invert sign with 50%, to mirror the specified range to the other side | ||
x_angle = if rng.gen() { -x_angle } else { x_angle }; | ||
y_angle = if rng.gen() { -y_angle } else { y_angle }; | ||
|
||
// Rotate the growing direction of the parent branch | ||
let rotation = Basis3::from(Euler { | ||
x: Deg::new(x_angle), | ||
y: Deg::new(y_angle), | ||
|
@@ -169,17 +177,23 @@ impl TreeGen { | |
let trunk_diameter = range_sample(&self.preset.trunk_diameter, rng); | ||
let trunk_height = range_sample(&self.preset.trunk_height, rng); | ||
let trunk_diameter_top = range_sample(&self.preset.trunk_diameter_top, rng); | ||
let min_branch_height = range_sample(&self.preset.min_branch_height, rng); | ||
let min_branch_height = range_sample(&self.preset.min_branch_height, rng) * trunk_height; | ||
|
||
debug!("trunk diam {} to {}, height {}, branch start at {}", | ||
trunk_diameter, | ||
trunk_diameter_top, | ||
trunk_height, | ||
min_branch_height); | ||
|
||
let mut points = Vec::new(); | ||
|
||
{ | ||
let mut add_point = |height, diam| { | ||
let point = Point3f::new(0.0, height, 0.0); | ||
let point = Point3f::new(0.0, 0.0, height); | ||
if height >= min_branch_height { | ||
// FIXME Make branch spawn chance configurable | ||
// 1/5 chance to spawn a branch at any point | ||
if rng.gen_weighted_bool(5) { | ||
// 1/3 chance to spawn a branch at any point | ||
if rng.gen_weighted_bool(3) { | ||
// Build a vector for the branch direction (Z is up) | ||
let dir = self.gen_branch_direction(rng, Vector3f::new(0.0, 0.0, 1.0)); | ||
self.create_branch(rng, point, dir, 1, diam); | ||
|
@@ -194,19 +208,18 @@ impl TreeGen { | |
|
||
let diam_start = Vector1::new(trunk_diameter); | ||
let diam_end = Vector1::new(trunk_diameter_top); | ||
let mut height = 0.0; | ||
while height < trunk_height { | ||
// Current height as a fraction of the total height | ||
let height_frac = if height == 0.0 { 0.0 } else { trunk_height / height }; | ||
|
||
// Split trunk in segments | ||
// FIXME Vary the segment direction like we do for normal branches | ||
// FIXME Make segment count depend on the trunk height | ||
const SEGMENT_COUNT: u32 = 10; | ||
for i in 0..SEGMENT_COUNT + 1 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. C'mon rust-lang/rust#28237 ____ |
||
let height = i as f32 * trunk_height / SEGMENT_COUNT as f32; | ||
let height_frac = height / trunk_height; | ||
let diam = diam_start.lerp(diam_end, height_frac); | ||
|
||
add_point(height, diam.x); | ||
|
||
let segment_len = segment_dist(diam.x); | ||
height += segment_len; | ||
} | ||
|
||
// FIXME Do we need to create another point here? | ||
} | ||
|
||
assert!(points.len() >= 2, | ||
|
@@ -215,7 +228,7 @@ impl TreeGen { | |
points: points, | ||
// FIXME Fixed color for now, we should use a configurable random color (or at least | ||
// make it brown). | ||
color: Vector3f::new(0.0, 0.0, 1.0), | ||
color: Vector3f::new(0.0, 1.0, 0.0), | ||
}); | ||
|
||
debug!("generated tree with {} branches", self.branches.len()); | ||
|
@@ -225,7 +238,6 @@ impl TreeGen { | |
/// | ||
/// The tree is returned as a list of branches for now. | ||
pub fn generate<R: Rng>(mut self, rng: &mut R) -> Vec<Branch> { | ||
info!("treegen activated!"); // deleteme | ||
// Recursively create the tree and put all branches in a buffer. | ||
self.create_trunk(rng); | ||
self.branches | ||
|
@@ -234,8 +246,7 @@ impl TreeGen { | |
|
||
impl Rand for TreeGen { | ||
fn rand<R: Rng>(rng: &mut R) -> Self { | ||
// Create a tree generator with random parameters. | ||
// First, select a random preset: | ||
// Select a random preset that we'll use | ||
let preset = rng.choose(PRESETS).unwrap().clone(); | ||
|
||
TreeGen { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,9 @@ | |
//! | ||
|
||
use world::{CHUNK_SIZE, Chunk, ChunkIndex, ChunkProvider, HeightType, HexPillar}; | ||
use world::{GroundMaterial, PillarSection, Prop, PropType}; | ||
use rand::Rand; | ||
use gen::PlantGenerator; | ||
|
||
/// Main type to generate the game world. Implements the `ChunkProvider` trait | ||
/// (TODO, see #8). | ||
|
@@ -26,12 +29,29 @@ impl ChunkProvider for WorldGenerator { | |
let mut pillars = Vec::new(); | ||
let q = index.0.q * CHUNK_SIZE as i32; | ||
let r = index.0.r * CHUNK_SIZE as i32; | ||
let mut height; | ||
|
||
for i in q..q + CHUNK_SIZE as i32 { | ||
for j in r..r + CHUNK_SIZE as i32 { | ||
height = (((i as f32) * 0.25).sin() * 10.0 + | ||
((j as f32) * 0.25).sin() * 10.0 + 100.0) as u16; | ||
pillars.push(HexPillar::from_height(HeightType(height))); | ||
let height = (((i as f32) * 0.25).sin() * 10.0 + ((j as f32) * 0.25).sin() * 10.0 + | ||
100.0) as u16; | ||
|
||
let ground_section = | ||
PillarSection::new(GroundMaterial::Dirt, HeightType(0), HeightType(height)); | ||
let mut props = Vec::new(); | ||
|
||
// Place a test plant every few blocks | ||
const TREE_SPACING: i32 = 8; | ||
if i % TREE_SPACING == 0 && j % TREE_SPACING == 0 { | ||
let mut rng = super::seeded_rng(self.seed, "TREE", (i, j)); | ||
let gen = PlantGenerator::rand(&mut rng); | ||
|
||
props.push(Prop { | ||
baseline: HeightType(height), | ||
prop: PropType::Plant(gen.generate(&mut rng)), | ||
}); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe if-else to avoid mutable vector? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My intention was that other world features could be added after trees. But we'll probably use a completely different and more flexible system then. |
||
|
||
pillars.push(HexPillar::new(vec![ground_section], props)); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate this
as
cast more every day. It would be way nicer to express your intend clearly in the code, likelet seed1: u32 = rng_seed.truncate();
. Ok but I guess this can't be improved right now 😞