LibGame  v0.4.0
The LG Game Engine - Copyright (C) 2024-2025 ETMSoftware
lg_terrain.c File Reference

Functions

LG_Terrainlg_terrain_new (uint16_t width, uint16_t height, float vert_scaling_k, int noise_type, int seed, float frequency, LG_Texture *tex)
 
LG_Terrainlg_terrain_new_from_heightmap (float *heightmap, uint16_t width, uint16_t height, float vert_scaling_k, LG_Texture *tex)
 
void lg_terrain_free (LG_Terrain *terrain)
 
float * lg_heightmap_generate (uint16_t width, uint16_t height, int noise_type, int seed, float frequency)
 
void lg_heightmaps_add (float *heightmap1, float *heightmap2, uint16_t w, uint16_t h, float k)
 
void lg_heightmap_flatten_border (float *heightmap, uint16_t w, uint16_t h, uint16_t k, int border)
 
LG_Meshlg_terrain_to_mesh (LG_Terrain *terrain)
 
Vertex_rgbalg_horiz_grid (int grid_width, int *n_vertices, float scaling, LG_Color_u c)
 
const Vertexlg_horiz_grid0 ()
 
const unsigned short * lg_horiz_grid0_indices ()
 
size_t lg_sizeof_horiz_grid0 ()
 
size_t lg_sizeof_horiz_grid0_indices ()
 

Detailed Description

=== Procedural terrain generation ===

Create heightmaps and terrains with Perlin noise.

We use these data structs to compute:

  • Heightmaps
    === Grid mesh (w x h) ===
    y ^
    |
    6------7------8
    | | |
    | | |
    3------4------5
    | | |
    | | |
    0------1------2---->
    x
    n_vertices = (w + 1) * (h + 1)
    n_faces = w * h * 2
    n_indices = n_faces * 3
    vertex_xy = x + y * (w + 1)
  • Vertex normals
    === Quad ===
    y ^
    |
    v4-----v3
    | |
    | |
    v1-----v2---->
    x
    1 quad = 2 triangles (v1-v3-v4, v1-v2-v3) = 2 faces = 4 vertices
  • VBOs and IBOs
    === 2D array (w x h) ===
    y ^
    |
    -------------
    | e2 | e3 |
    -------------
    | e0 | e1 |
    ----------------->
    x
    n_elements = w * h
    size = n_elements * sizeof(element)
    element_i = element_at_xy = x + y * w

Function Documentation

◆ lg_terrain_new()

LG_Terrain* lg_terrain_new ( uint16_t  width,
uint16_t  height,
float  vert_scaling_k,
int  noise_type,
int  seed,
float  frequency,
LG_Texture tex 
)

Create a horizontally-centered, normalized LG_Terrain VBO and IBO with noise

If noise_type == PERLIN_NOISE

  • seed is ignored if == 0, and default value 1337 is used instead
  • frequency is ignored if < LG_FLOAT_EPSILON (defined in lg_mesh.h), and default value 0.01 is used instead

If noise_type == RANDOM_NOISE, seed and frequency are irrelevant

Height is ambiguous here. So:

  • WIDTH/HEIGHT = WIDTH/HEIGHT OF THE GRID
    Heightmap grid = 2D float array filled with noise values in range [0.0, 1.0]
    float grid[width * heigh]
  • vert_scaling_k relates to the heightmap height values

Returned LG_Terrain must be freed afterwards

Parameters
widthWidth of the heightmap grid, must be < HEIGHTMAP_MAX_W
heightHeight of the heightmap grid, must be < HEIGHTMAP_MAX_H
vert_scaling_kHeightmap vertical scaling k, should be in range [0.0, 1.0] - actually clamped to 1.0
noise_typeNoise type (lg_noise_type enum)
seedSeed, default (if ignored) = 1337
frequencyFrequency, default (if ignored) = 0.01
texA LG_Texture, may be NULL
Returns
A new LG_Terrain if OK, NULL on error

◆ lg_terrain_new_from_heightmap()

LG_Terrain* lg_terrain_new_from_heightmap ( float *  heightmap,
uint16_t  width,
uint16_t  height,
float  vert_scaling_k,
LG_Texture tex 
)

Create a horizontally-centered, normalized LG_Terrain VBO and IBO from a (Vertex_uv_n *) heightmap

Returned LG_Terrain must be freed afterwards

Parameters
heightmapA (Vertex_uv_n *) heightmap
widthWidth of the heightmap grid, must be < HEIGHTMAP_MAX_W
heightHeight of the heightmap grid, must be < HEIGHTMAP_MAX_H
vert_scaling_kHeightmap vertical scaling k, should be in range [0.0, 1.0] - actually clamped to 1.0
texA LG_Texture, may be NULL
Returns
A new LG_Terrain if OK, NULL on error

◆ lg_terrain_free()

void lg_terrain_free ( LG_Terrain terrain)

Free LG_Terrain's vbo_data, ibo_data, and instance

Parameters
terrainA LG_Terrain instance

◆ lg_heightmap_generate()

float* lg_heightmap_generate ( uint16_t  width,
uint16_t  height,
int  noise_type,
int  seed,
float  frequency 
)

Generate a (non-centered) width x height heightmap (2D float array) filled with noise values in range [0.0, 1.0]

If noise_type == PERLIN_NOISE

  • seed is ignored if == 0, default value 1337 is used instead
  • frequency is ignored if < LG_FLOAT_EPSILON, default value 0.01 is used instead

If noise_type == RANDOM_NOISE, seed and frequency are irrelevant

TODO: add octave param

Returned array must be freed afterwards

Parameters
widthGrid width, must be < HEIGHTMAP_MAX_W
heightGrid height, must be < HEIGHTMAP_MAX_H
noise_typeNoise type (see lg_noise_type enum in lg_terrain.h)
seedSeed, default = 1337
frequencyFrequency, default = 0.01
Returns
A pointer to the first element of a float array (of size width * height * sizeof(float)) if OK, NULL on error

◆ lg_heightmaps_add()

void lg_heightmaps_add ( float *  heightmap1,
float *  heightmap2,
uint16_t  w,
uint16_t  h,
float  k 
)

Add height values of heightmap2 to height values of heightmpap1, then multiply by k

Heightmaps must have same dimensions

Parameters
heightmap1
heightmap2
wWidth of both heightmaps
hHeight of both heightmaps
k

◆ lg_heightmap_flatten_border()

void lg_heightmap_flatten_border ( float *  heightmap,
uint16_t  w,
uint16_t  h,
uint16_t  k,
int  border 
)

'Flatten' heightmap border(s) - useful to join 2 heighmaps

Linear flattening so far, should be Gaussian

border = NORTH_BORDER | SOUTH_BORDER | WEST_BORDER | EAST_BORDER mask

Parameters
heightmap
wWidth
hHeight
khoriz_margin = w / k, vert_margin = h / k, should be in range [2, 6]
borderMask of which border(s) should be flattened

◆ lg_terrain_to_mesh()

LG_Mesh* lg_terrain_to_mesh ( LG_Terrain terrain)

Create a new LG_Mesh instance from a LG_Terrain instance

lg_terrain_new() creates a horizontally-centered, normalized LG_Terrain VBO and IBO so the mesh will also be horizontally-centered and normalized

You can free the LG_Terrain instance afterwards, as new vbo_data and ibo_data are dynamically generated (with malloc3())

Parameters
terrainPointer to LG_Terrain instance
Returns
New mesh if OK, NULL on error

◆ lg_horiz_grid()

Vertex_rgba* lg_horiz_grid ( int  grid_width,
int *  n_vertices,
float  scaling,
LG_Color_u  c 
)

Horiz centered square grid

 Draw with glDrawArrays(GL_LINES, 0, n_vertices)

Must be freed afterwards

Example use:

// Filling a LG_SceneNode->lines3d_vb to draw a grid
typedef struct {
union {
Vertex_rgba vb_array[LG_LINES_N_VERTICES_MAX];
Vertex_rgba *vb_ptr;
};
uint32_t n_vertices;
zboolean dynamic_b;
int n_vertices;
Vertex_rgba *h_grid = lg_horiz_grid(..., &n_vertices, ...);
...
node->lines3d_vb.vb_ptr = h_grid;
node->lines3d_vb.n_vertices = n_vertices;
node->lines3d_vb.dynamic_b = TRUE;
Parameters
grid_widthIf grid_width is odd, we substract one
n_verticesPointer to int with num of array elements
scalingScaling k
cColor
Returns
An array of Vertex_rgba if OK, NULL on error

◆ lg_horiz_grid0()

const Vertex* lg_horiz_grid0 ( )

DEPRECATED

Horiz centered 8 x 8 grid

Vertices = x, y, z

◆ lg_horiz_grid0_indices()

const unsigned short* lg_horiz_grid0_indices ( )

DEPRECATED

◆ lg_sizeof_horiz_grid0()

size_t lg_sizeof_horiz_grid0 ( )

DEPRECATED

◆ lg_sizeof_horiz_grid0_indices()

size_t lg_sizeof_horiz_grid0_indices ( )

DEPRECATED

lg_scenenode_new
LG_SceneNode * lg_scenenode_new(int id, const char *name, lg_scenenode_type type)
Definition: lg_scene_graph.c:31
LG_SceneNode
Definition: lg_scene_graph.h:29
Lines3D_VB
Definition: lg_3d_primitives.h:53
lg_horiz_grid
Vertex_rgba * lg_horiz_grid(int grid_width, int *n_vertices, float scaling, LG_Color_u c)
Definition: lg_terrain.c:605
Vertex_rgba
Definition: lg_vertex.h:60