Skip to content

Sir-Irk/si_normalmap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

si_normalmap

A very simple normal map generator written as a single header library.

Features:

  • Convert color buffer to greyscale using either lightness, average or luminance methods
  • Convert greyscale buffer to a normal map with gaussian blur pre-filtering

TODO: add gpu support using Opengl(this is a work in progress).

Interface

typedef enum
{
    sinm_greyscale_none,
    sinm_greyscale_lightness,
    sinm_greyscale_average,
    sinm_greyscale_luminance,
    sinm_greyscale_count, //For iteration only. Not a valid option
} sinm_greyscale_type;

//run greyscale conversion. Can be done in-place if in and out are the same buffer
void sinm_greyscale(const uint32_t *in, uint32_t *out, int32_t w, int32_t h, sinm_greyscale_type type);

//generate normal map. Allocates a new buffer for its output
uint32_t *sinm_normal_map(const uint32_t *in, int32_t w, int32_t h, float scale, float blurRadius, sinm_greyscale_type greyscaleType, int flipY);

//generates normal map. Takes a pre-allocated buffer for its output
int sinm_normal_map_buffer(const uint32_t* in, uint32_t* out, int32_t w, int32_t h, float scale, float blurRadius, sinm_greyscale_type greyscaleType, int flipY)

//normalize the values of "in"
void sinm_normalize(uint32_t* in, int32_t w, int32_t h, float scale, int flipY)

//composite two buffers together. Useful for layering normal maps
void sinm_composite(const uint32_t* in1, const uint32_t* in2, uint32_t* out, int32_t w, int32_t h)

//same as sinm_composite but allocates a new buffer for its output
uint32_t* sinm_composite_alloc(const uint32_t* in1, const uint32_t* in2, int32_t w, int32_t h)

Basic Usage:

#define SI_NORMALMAP_IMPLEMENTATION
#include "si_normalmap.h"

int main()
{
    uint32_t *image = //...load pixels from some image;
    uint32_t *nm = sinm_normal_map(image, imageWidth, imageHeight, 1.0f, 2.0f, sinm_greyscale_average); 

    //... write normalmap to a file
    
    return 0;
}

More specific Example using more features(error checking excluded for brevity. Using stb libraries to load and write https://github.com/nothings/stb)

#define SI_NORMALMAP_IMPLEMENTATION
#define SI_NORMALMAP_STATIC
#include "si_normalmap.h"
#include "inttypes.h"
#include "stdio.h"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

int main(void)
{
    int x, y;
    uint32_t* pixels = (uint32_t*)stbi_load("albedo.png", &x, &y, NULL, 4);

    // Make 2 normal maps at different blur radii and strength and composite them together.
    uint32_t* nm0 = sinm_normal_map(pixels, x, y, 2.0f, 1.0f, sinm_greyscale_luminance, 0);
    uint32_t* nm1 = sinm_normal_map(pixels, x, y, 3.0f, 8.0f, sinm_greyscale_luminance, 0);
    uint32_t* composite = sinm_composite_alloc(nm0, nm1, x, y);

    stbi_write_png("normal.png", x, y, 4, composite, 0);

    free(nm0);
    free(nm1);
    free(composite);
    free(pixels);
}

Compiled on linux with clang -O3 example.c -o example -lm -march=native

Example Output(texture from opengameart.org):

Input:

input

Output:

output

Comparison of lighting without and with normal map(and a second "detail" normal map)

lighting

About

Simple Single Header Normal Map Generator

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages