├── .gitignore ├── test ├── sdfseed.png ├── earth2048.png ├── earthGradient.png ├── test_sdf.c ├── test_pts.c ├── test_earth.c ├── hut.h └── test_planet.c ├── docs ├── _static │ ├── fbm.png │ ├── correct.png │ ├── island.png │ ├── islands.png │ ├── noise.png │ ├── planet.png │ ├── incorrect.png │ ├── sdfresult.png │ ├── archifinal.png │ ├── archipelago.png │ ├── coordfields.png │ └── overrides.css ├── index.rst ├── overview.rst ├── ops.rst ├── image.rst ├── distance.rst ├── lighting.rst ├── importexport.rst ├── color.rst ├── generate.rst ├── Makefile └── conf.py ├── uncrustify.cfg ├── src ├── import.c ├── image.h ├── noise.h ├── gaussian.c ├── image.c ├── wrapjs.cpp ├── export.c ├── draw.c ├── color.c ├── distance.c ├── lighting.c └── points.c ├── kazmath ├── ray3.h ├── ray3.c ├── LICENSE.md ├── kazmath.h ├── utility.c ├── aabb3.h ├── aabb2.h ├── ray2.h ├── utility.h ├── vec4.h ├── plane.h ├── mat3.h ├── mat4.h ├── vec2.h ├── vec3.h ├── quaternion.h ├── aabb3.c ├── aabb2.c ├── vec4.c ├── vec2.c ├── plane.c ├── ray2.c └── vec3.c ├── LICENSE ├── CMakeLists.txt ├── .clang-format └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | build 3 | *.dblite 4 | .DS_Store 5 | docs/_build 6 | -------------------------------------------------------------------------------- /test/sdfseed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/test/sdfseed.png -------------------------------------------------------------------------------- /test/earth2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/test/earth2048.png -------------------------------------------------------------------------------- /docs/_static/fbm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/fbm.png -------------------------------------------------------------------------------- /docs/_static/correct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/correct.png -------------------------------------------------------------------------------- /docs/_static/island.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/island.png -------------------------------------------------------------------------------- /docs/_static/islands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/islands.png -------------------------------------------------------------------------------- /docs/_static/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/noise.png -------------------------------------------------------------------------------- /docs/_static/planet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/planet.png -------------------------------------------------------------------------------- /test/earthGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/test/earthGradient.png -------------------------------------------------------------------------------- /docs/_static/incorrect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/incorrect.png -------------------------------------------------------------------------------- /docs/_static/sdfresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/sdfresult.png -------------------------------------------------------------------------------- /docs/_static/archifinal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/archifinal.png -------------------------------------------------------------------------------- /docs/_static/archipelago.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/archipelago.png -------------------------------------------------------------------------------- /docs/_static/coordfields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/heman/HEAD/docs/_static/coordfields.png -------------------------------------------------------------------------------- /docs/_static/overrides.css: -------------------------------------------------------------------------------- 1 | .wy-side-nav-search a { display: none } 2 | .wy-side-nav-search .version { display: none } 3 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: overview.rst 2 | 3 | Documentation 4 | ------------- 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | overview 10 | image 11 | lighting 12 | distance 13 | color 14 | generate 15 | ops 16 | importexport 17 | -------------------------------------------------------------------------------- /test/test_sdf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hut.h" 3 | 4 | #define OUTFOLDER "build/" 5 | #define INFOLDER "test/" 6 | 7 | int main(int argc, char** argv) 8 | { 9 | heman_image* seed = hut_read_image(INFOLDER "sdfseed.png", 1); 10 | heman_image* sdf = heman_distance_create_sdf(seed); 11 | heman_image_destroy(seed); 12 | hut_write_image(OUTFOLDER "sdfresult.png", sdf, -0.1, 0.1); 13 | heman_image_destroy(sdf); 14 | } 15 | -------------------------------------------------------------------------------- /uncrustify.cfg: -------------------------------------------------------------------------------- 1 | indent_columns = 4 2 | indent_with_tabs = 0 3 | indent_continue = 4 4 | nl_func_leave_one_liners = true 5 | 6 | nl_collapse_empty_body = true 7 | nl_after_return = False 8 | nl_max = 2 9 | nl_after_func_proto = 0 10 | nl_after_func_proto_group = 1 11 | nl_after_func_body = 2 12 | nl_after_func_body_one_liner = 2 13 | nl_before_block_comment = 1 14 | nl_before_cpp_comment = 1 15 | nl_after_multiline_comment = False 16 | nl_after_struct = 1 17 | nl_end_of_file = add 18 | nl_end_of_file_min = 1 19 | -------------------------------------------------------------------------------- /src/import.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | 3 | heman_image* heman_import_u8(int width, int height, int nbands, 4 | const heman_byte* source, HEMAN_FLOAT minval, HEMAN_FLOAT maxval) 5 | { 6 | heman_image* result = heman_image_create(width, height, nbands); 7 | const heman_byte* inp = source; 8 | HEMAN_FLOAT* outp = result->data; 9 | HEMAN_FLOAT scale = (maxval - minval) / 255.0f; 10 | int size = height * width * nbands; 11 | for (int i = 0; i < size; ++i) { 12 | HEMAN_FLOAT v = (*inp++) * scale + minval; 13 | *outp++ = CLAMP(v, minval, maxval); 14 | } 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /kazmath/ray3.h: -------------------------------------------------------------------------------- 1 | #ifndef RAY3_H 2 | #define RAY3_H 3 | 4 | #include "utility.h" 5 | #include "vec3.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | typedef struct kmRay3 { 12 | kmVec3 start; 13 | kmVec3 dir; 14 | } kmRay3; 15 | 16 | struct kmPlane; 17 | 18 | kmRay3* kmRay3Fill(kmRay3* ray, kmScalar px, kmScalar py, kmScalar pz, kmScalar vx, kmScalar vy, kmScalar vz); 19 | kmRay3* kmRay3FromPointAndDirection(kmRay3* ray, const kmVec3* point, const kmVec3* direction); 20 | kmBool kmRay3IntersectPlane(kmVec3* pOut, const kmRay3* ray, const struct kmPlane* plane); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | 26 | #endif /* RAY3_H */ 27 | -------------------------------------------------------------------------------- /src/image.h: -------------------------------------------------------------------------------- 1 | // This is a private header. Clients should not include it. 2 | 3 | #pragma once 4 | #include 5 | 6 | struct heman_image_s { 7 | int width; 8 | int height; 9 | int nbands; 10 | HEMAN_FLOAT* data; 11 | }; 12 | 13 | extern float _gamma; 14 | 15 | #define MIN(a, b) (a > b ? b : a) 16 | #define MAX(a, b) (a > b ? a : b) 17 | #define CLAMP(v, lo, hi) MAX(lo, MIN(hi, v)) 18 | #define CLAMP01(v) CLAMP(v, 0.0f, 1.0f) 19 | #define SGN(x) ((x > 0) - (x < 0)) 20 | #define EDGE(value, upper) MAX(0, MIN(upper - 1, value)) 21 | #define TWO_OVER_PI (0.63661977236) 22 | #define PI (3.1415926535) 23 | #define SQR(x) ((x) * (x)) 24 | #define SWAP(type,a,b) {type _=a;a=b;b=_;} 25 | 26 | inline HEMAN_FLOAT smoothstep( 27 | HEMAN_FLOAT edge0, HEMAN_FLOAT edge1, HEMAN_FLOAT x) 28 | { 29 | HEMAN_FLOAT t; 30 | t = CLAMP01((x - edge0) / (edge1 - edge0)); 31 | return t * t * (3.0 - 2.0 * t); 32 | } 33 | 34 | void generate_gaussian_row(int* target, int fwidth); 35 | void generate_gaussian_splat(HEMAN_FLOAT* target, int fwidth); 36 | -------------------------------------------------------------------------------- /docs/overview.rst: -------------------------------------------------------------------------------- 1 | Heman Overview 2 | ============== 3 | 4 | Heman is a C library of image utilities for dealing with height maps and other floating-point images. 5 | 6 | .. image:: _static/islands.png 7 | 8 | Heman can be used for: 9 | 10 | * Creating random height fields using simplex noise and FBM. 11 | * Generating a normal map from a height map using forwarding differencing. 12 | * Efficiently computing ambient occlusion from a height map. 13 | * Generating a signed distance field (SDF) using a `fast algorithm`_. 14 | * Exporting a 3D mesh in PLY_ format. 15 | * Applying a color gradient to a heightmap (LUT). 16 | * Generating a color gradient, given a list of control points. 17 | * Computing diffuse lighting with an infinite light source. 18 | 19 | Why the name "heman"? 20 | ----------------------- 21 | 22 | It's a subset of letters taken from *height map* and *normal map*. 23 | 24 | Source code 25 | ----------- 26 | 27 | You can access the source code at: https://github.com/prideout/heman 28 | 29 | .. _`fast algorithm`: http://cs.brown.edu/~pff/dt/index.html 30 | .. _PLY: http://paulbourke.net/dataformats/ply/ 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Philip Rideout 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /docs/ops.rst: -------------------------------------------------------------------------------- 1 | Image Operations 2 | ################ 3 | 4 | All functions with the ``heman_ops_`` prefix are meant for doing very simple image operations that are outside of heman's core functionality. 5 | 6 | .. code-block:: c 7 | 8 | // Given a set of same-sized images, copy them into a horizontal filmstrip. 9 | heman_image* heman_ops_stitch_horizontal(heman_image** images, int count); 10 | 11 | // Given a set of same-sized images, copy them into a vertical filmstrip. 12 | heman_image* heman_ops_stitch_vertical(heman_image** images, int count); 13 | 14 | // Transform texel values so that [minval, maxval] map to [0, 1] and return the 15 | // result. Values outside the range are clamped. The source image is 16 | // untouched. 17 | heman_image* heman_ops_normalize_f32( 18 | heman_image* source, HEMAN_FLOAT minval, HEMAN_FLOAT maxval); 19 | 20 | // Generate a monochrome image by applying a step function. 21 | heman_image* heman_ops_step(heman_image* image, HEMAN_FLOAT threshold); 22 | 23 | // Generate a height x 1 x 1 image by averaging the values across each row. 24 | heman_image* heman_ops_sweep(heman_image* image); 25 | -------------------------------------------------------------------------------- /src/noise.h: -------------------------------------------------------------------------------- 1 | #ifndef OPEN_SIMPLEX_NOISE_H__ 2 | #define OPEN_SIMPLEX_NOISE_H__ 3 | 4 | /* 5 | * OpenSimplex (Simplectic) Noise in C. 6 | * Ported to C from Kurt Spencer's java implementation by Stephen M. Cameron 7 | * 8 | * v1.1 (October 6, 2014) 9 | * - Ported to C 10 | * 11 | * v1.1 (October 5, 2014) 12 | * - Added 2D and 4D implementations. 13 | * - Proper gradient sets for all dimensions, from a 14 | * dimensionally-generalizable scheme with an actual 15 | * rhyme and reason behind it. 16 | * - Removed default permutation array in favor of 17 | * default seed. 18 | * - Changed seed-based constructor to be independent 19 | * of any particular randomization library, so results 20 | * will be the same when ported to other languages. 21 | */ 22 | #include 23 | 24 | struct osn_context; 25 | 26 | int open_simplex_noise(int64_t seed, struct osn_context** ctx); 27 | void open_simplex_noise_free(struct osn_context* ctx); 28 | int open_simplex_noise_init_perm( 29 | struct osn_context* ctx, int16_t p[], int nelements); 30 | double open_simplex_noise2(struct osn_context* ctx, double x, double y); 31 | double open_simplex_noise3( 32 | struct osn_context* ctx, double x, double y, double z); 33 | double open_simplex_noise4( 34 | struct osn_context* ctx, double x, double y, double z, double w); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /kazmath/ray3.c: -------------------------------------------------------------------------------- 1 | #include "plane.h" 2 | #include "ray3.h" 3 | 4 | kmRay3* kmRay3Fill(kmRay3* ray, kmScalar px, kmScalar py, kmScalar pz, kmScalar vx, kmScalar vy, kmScalar vz) { 5 | ray->start.x = px; 6 | ray->start.y = py; 7 | ray->start.z = pz; 8 | 9 | ray->dir.x = vx; 10 | ray->dir.y = vy; 11 | ray->dir.z = vz; 12 | 13 | return ray; 14 | } 15 | 16 | kmRay3* kmRay3FromPointAndDirection(kmRay3* ray, const kmVec3* point, const kmVec3* direction) { 17 | kmVec3Assign(&ray->start, point); 18 | kmVec3Assign(&ray->dir, direction); 19 | return ray; 20 | } 21 | 22 | kmBool kmRay3IntersectPlane(kmVec3* pOut, const kmRay3* ray, const kmPlane* plane) { 23 | /*t = - (A*org.x + B*org.y + C*org.z + D) / (A*dir.x + B*dir.y + C*dir.z )*/ 24 | 25 | kmScalar d = (plane->a * ray->dir.x + 26 | plane->b * ray->dir.y + 27 | plane->c * ray->dir.z); 28 | 29 | if(d == 0) 30 | { 31 | return KM_FALSE; 32 | } 33 | 34 | kmScalar t = -(plane->a * ray->start.x + 35 | plane->b * ray->start.y + 36 | plane->c * ray->start.z + plane->d) / d; 37 | 38 | if(t < 0) 39 | { 40 | return KM_FALSE; 41 | } 42 | 43 | kmVec3 scaled_dir; 44 | kmVec3Scale(&scaled_dir, &ray->dir, t); 45 | kmVec3Add(pOut, &ray->start, &scaled_dir); 46 | return KM_TRUE; 47 | } 48 | -------------------------------------------------------------------------------- /src/gaussian.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | 5 | // Compute a particular row in Pascal's triangle. This can also be used 6 | // to sample the Gaussian function using integers, which is kinda neat! 7 | void generate_gaussian_row(int* target, int fwidth) 8 | { 9 | assert(fwidth > 0); 10 | int nbytes = fwidth * sizeof(int); 11 | int* tmp = malloc(nbytes); 12 | target[0] = tmp[0] = 1; 13 | for (int col = 1; col < fwidth; col++) { 14 | target[col] = 0; 15 | tmp[col] = 0; 16 | } 17 | for (int row = 1; row < fwidth; row++) { 18 | for (int col = 1; col <= row; col++) { 19 | target[col] = tmp[col] + tmp[col - 1]; 20 | } 21 | for (int col = 1; col <= row; col++) { 22 | tmp[col] = target[col]; 23 | } 24 | } 25 | free(tmp); 26 | } 27 | 28 | // Fill fwidth * fwidth entries with Gaussian weights. 29 | // The sum of all weights is 1.0. 30 | void generate_gaussian_splat(HEMAN_FLOAT* target, int fwidth) 31 | { 32 | int* gaussian_row = malloc(fwidth * sizeof(int)); 33 | generate_gaussian_row(gaussian_row, fwidth); 34 | int shift = 1 << (fwidth - 1); 35 | HEMAN_FLOAT scale = 1.0 / (shift * shift); 36 | HEMAN_FLOAT* gptr = target; 37 | for (int j = 0; j < fwidth; j++) { 38 | for (int i = 0; i < fwidth; i++) { 39 | *gptr++ = gaussian_row[i] * gaussian_row[j] * scale; 40 | } 41 | } 42 | free(gaussian_row); 43 | } 44 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project(heman) 4 | 5 | find_package(OpenMP) 6 | 7 | include_directories(include .) 8 | 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") 10 | 11 | set(HEMAN_SOURCE 12 | src/color.c 13 | src/distance.c 14 | src/draw.c 15 | src/export.c 16 | src/gaussian.c 17 | src/generate.c 18 | src/image.c 19 | src/image.h 20 | src/import.c 21 | src/lighting.c 22 | src/noise.c 23 | src/noise.h 24 | src/ops.c 25 | src/points.c) 26 | 27 | set(MATH_SOURCE 28 | kazmath/aabb2.c 29 | kazmath/aabb3.c 30 | kazmath/mat3.c 31 | kazmath/mat4.c 32 | kazmath/plane.c 33 | kazmath/quaternion.c 34 | kazmath/ray2.c 35 | kazmath/ray3.c 36 | kazmath/utility.c 37 | kazmath/vec2.c 38 | kazmath/vec3.c 39 | kazmath/vec4.c) 40 | 41 | add_library(heman STATIC ${HEMAN_SOURCE} ${MATH_SOURCE}) 42 | target_include_directories(heman PUBLIC include) 43 | 44 | if(OpenMP_CXX_FOUND) 45 | target_link_libraries(heman PUBLIC OpenMP::OpenMP_CXX) 46 | target_include_directories(heman PUBLIC OpenMP::OpenMP_CXX) 47 | elseif(APPLE) 48 | target_link_directories(heman PUBLIC /usr/local/lib) 49 | target_link_libraries(heman PUBLIC omp) 50 | target_include_directories(heman PUBLIC /usr/local/include) 51 | endif() 52 | 53 | if (APPLE) 54 | target_compile_options(heman PUBLIC -Xclang -fopenmp) 55 | endif() 56 | 57 | if (WIN32) 58 | target_compile_options(heman PUBLIC /openmp) 59 | endif() 60 | -------------------------------------------------------------------------------- /test/test_pts.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "hut.h" 7 | 8 | static const int SIZE = 512; 9 | 10 | #define COUNT(a) (sizeof(a) / sizeof(a[0])) 11 | #define OUTFOLDER "build/" 12 | 13 | int main(int argc, char** argv) 14 | { 15 | printf("%d threads available.\n", omp_get_max_threads()); 16 | const int seed = 1; 17 | const int npts = 5; 18 | const int res = 4096; 19 | 20 | heman_points* pts = heman_image_create(npts, 1, 3); 21 | kmVec3* coords = (kmVec3*) heman_image_data(pts); 22 | coords[0] = (kmVec3){0.3, 0.4, 0.1}; 23 | coords[1] = (kmVec3){0.2, 0.5, 0.1}; 24 | coords[2] = (kmVec3){0.8, 0.7, 0.1}; 25 | coords[3] = (kmVec3){0.8, 0.5, 0.1}; 26 | coords[4] = (kmVec3){0.5, 0.5, 0.2}; 27 | heman_color colors[5] = {0xC8758A, 0xDE935A, 0xE0BB5E, 0xE0BB5E, 0x8EC85D}; 28 | heman_color ocean = 0x83B2B2; 29 | heman_image* contour = heman_image_create(res, res / 2, 3); 30 | heman_image_clear(contour, 0); 31 | heman_draw_contour_from_points(contour, pts, ocean, 0.3, 0.45, 1); 32 | heman_draw_colored_circles(contour, pts, 20, colors); 33 | 34 | heman_image* cpcf = heman_distance_create_cpcf(contour); 35 | heman_image* warped = heman_ops_warp(cpcf, seed, 10); 36 | heman_image* voronoi = heman_color_from_cpcf(warped, contour); 37 | heman_image* toon = heman_ops_sobel(voronoi, 0x303030); 38 | hut_write_image(OUTFOLDER "terrainpts.png", voronoi, 0, 1); 39 | hut_write_image(OUTFOLDER "terrainpts_toon.png", toon, 0, 1); 40 | } 41 | -------------------------------------------------------------------------------- /kazmath/LICENSE.md: -------------------------------------------------------------------------------- 1 | Kazmath is a 3D math library aimed at game programming. It is released under the modified BSD license. 2 | 3 | Authors 4 | 5 | Luke Benstead 6 | Carsten Haubold 7 | 8 | License 9 | 10 | Copyright (c) 2008, Luke Benstead. 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without modification, 14 | are permitted provided that the following conditions are met: 15 | 16 | * Redistributions of source code must retain the above copyright notice, 17 | this list of conditions and the following disclaimer. 18 | * Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/image.rst: -------------------------------------------------------------------------------- 1 | Heman Images 2 | ############ 3 | 4 | All functions with the ``heman_image_`` prefix are meant for creating empty images, freeing memory, or examining image contents. 5 | 6 | Images are simply arrays of floats. By default, the value type is ``float``, but this can be overriden by setting the ``HEMAN_FLOAT`` macro to ``double``. By design, integer-typed images are not allowed, although heman provides some conversion utilities (see `Import / Export `_). 7 | 8 | Each image has a specified number of `bands`, which is usually 1 (height maps, distance fields) or 3 (colors, normal maps). 9 | 10 | .. c:type:: heman_image 11 | 12 | Encapsulates a flat array of floats and its dimensions. The struct definition is not public, so clients must refer to it using a pointer. 13 | 14 | Creating and Destroying 15 | ======================= 16 | 17 | .. code-block:: c 18 | 19 | // Allocate a floating-point image with dimensions width x height x nbands. 20 | heman_image* heman_image_create(int width, int height, int nbands); 21 | 22 | // Obtain image properties. 23 | void heman_image_info(heman_image*, int* width, int* height, int* nbands); 24 | 25 | // Free memory for a image. 26 | void heman_image_destroy(heman_image*); 27 | 28 | Examining Texels 29 | ================ 30 | 31 | .. code-block:: c 32 | 33 | // Peek at the stored texel values. 34 | float* heman_image_data(heman_image*); 35 | 36 | // Peek at the given texel value. 37 | float* heman_image_texel(heman_image*, int x, int y); 38 | 39 | // Find a reasonable value for the given normalized texture coord. 40 | void heman_image_sample(heman_image*, float u, float v, float* result); 41 | 42 | -------------------------------------------------------------------------------- /docs/distance.rst: -------------------------------------------------------------------------------- 1 | Distance Fields 2 | ############### 3 | 4 | All functions with the ``heman_distance_`` prefix are meant for creating distance fields. This is also known as a Euclidean Distance Transform. 5 | 6 | Heman can also create a `closest point coordinate field`_, which is like a distance field except that it encodes the ST of the nearest seed pixel. This can be used to create Voronoi diagrams or pick sheets. 7 | 8 | API 9 | === 10 | 11 | .. code-block:: c 12 | 13 | // Create a one-band "signed distance field" based on the given input, using 14 | // the fast algorithm described in Felzenszwalb 2012. 15 | heman_image* heman_distance_create_sdf(heman_image* monochrome); 16 | 17 | // Create a two-band "closest point coordinate field" containing the 18 | // non-normalized texture coordinates of the nearest seed. The result is 19 | // related to the distance field but has a greater amount of information. 20 | heman_image* heman_distance_create_cpcf(heman_image* seed); 21 | 22 | SDF Example 23 | =========== 24 | 25 | Here's an example of a starting image (the "seed") and its resulting signed distance field (SDF). 26 | 27 | .. image:: ../test/sdfseed.png 28 | :width: 240px 29 | 30 | .. image:: _static/sdfresult.png 31 | :width: 240px 32 | 33 | The above image was generated with the following program: 34 | 35 | .. literalinclude:: ../test/test_sdf.c 36 | :language: c 37 | :linenos: 38 | 39 | CF Example 40 | =========== 41 | 42 | Here's an example of a starting image (the "seed") and its resulting CPCF. 43 | 44 | .. image:: _static/coordfields.png 45 | :width: 512px 46 | 47 | .. _`closest point coordinate field`: http://http://github.prideout.net/coordinate-fields/ 48 | -------------------------------------------------------------------------------- /kazmath/kazmath.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KAZMATH_H_INCLUDED 27 | #define KAZMATH_H_INCLUDED 28 | 29 | #include "vec2.h" 30 | #include "vec3.h" 31 | #include "mat3.h" 32 | #include "mat4.h" 33 | #include "utility.h" 34 | #include "quaternion.h" 35 | #include "plane.h" 36 | #include "aabb2.h" 37 | #include "aabb3.h" 38 | #include "ray2.h" 39 | #include "ray3.h" 40 | 41 | #endif // KAZMATH_H_INCLUDED 42 | -------------------------------------------------------------------------------- /test/test_earth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hut.h" 5 | 6 | #define COUNT(a) (sizeof(a) / sizeof(a[0])) 7 | #define OUTFOLDER "build/" 8 | #define INFOLDER "test/" 9 | 10 | int main(int argc, char** argv) 11 | { 12 | printf("%d threads available.\n", omp_get_max_threads()); 13 | 14 | #if 0 15 | heman_image* grad = hut_read_image(INFOLDER "earthGradient.png", 3); 16 | #else 17 | int cp_locations[] = { 18 | 000, 155, 156, 200, 255, 19 | }; 20 | heman_color cp_colors[] = { 21 | 0x001070, // Dark Blue 22 | 0x2C5A7C, // Light Blue 23 | 0x5D943C, // Dark Green 24 | 0x606011, // Brown 25 | 0xFFFFFF, // White 26 | }; 27 | assert(COUNT(cp_locations) == COUNT(cp_colors)); 28 | heman_image* grad = heman_color_create_gradient( 29 | 256, COUNT(cp_colors), cp_locations, cp_colors); 30 | #endif 31 | 32 | double begin = omp_get_wtime(); 33 | heman_image* hmap = hut_read_image(INFOLDER "earth2048.png", 1); 34 | heman_image* colorized = heman_color_apply_gradient(hmap, 0, 1, grad); 35 | hut_write_image(OUTFOLDER "colorized.png", colorized, 0, 1); 36 | heman_image_destroy(grad); 37 | 38 | float lightpos[] = {-0.5f, 0.5f, 1.0f}; 39 | heman_image* litearth = 40 | heman_lighting_apply(hmap, colorized, 1, 0.5, 0.5, lightpos); 41 | hut_write_image(OUTFOLDER "litearth.png", litearth, 0, 1); 42 | heman_image_destroy(litearth); 43 | heman_image_destroy(colorized); 44 | 45 | heman_image* masked = heman_ops_step(hmap, 0.61); 46 | hut_write_image(OUTFOLDER "masked.png", masked, 0, 1); 47 | heman_image* sweep = heman_ops_sweep(masked); 48 | hut_write_image(OUTFOLDER "sweep.png", sweep, 0, 1); 49 | heman_image_destroy(sweep); 50 | heman_image_destroy(masked); 51 | 52 | heman_image_destroy(hmap); 53 | double duration = omp_get_wtime() - begin; 54 | printf("Processed in %.3f seconds.\n", duration); 55 | } 56 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: false 6 | AlignEscapedNewlinesLeft: true 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | 10 | AllowAllParametersOfDeclarationOnNextLine: false 11 | BinPackParameters: true 12 | BinPackArguments: true 13 | PenaltyBreakBeforeFirstCallParameter: 1000 14 | 15 | AllowShortBlocksOnASingleLine: true 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortIfStatementsOnASingleLine: false 18 | AllowShortLoopsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: true 20 | AlwaysBreakAfterDefinitionReturnType: false 21 | AlwaysBreakTemplateDeclarations: true 22 | AlwaysBreakBeforeMultilineStrings: true 23 | BreakBeforeBinaryOperators: None 24 | BreakBeforeTernaryOperators: true 25 | BreakConstructorInitializersBeforeComma: false 26 | ColumnLimit: 80 27 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 28 | ConstructorInitializerIndentWidth: 4 29 | DerivePointerAlignment: false 30 | PointerAlignment: Left 31 | ExperimentalAutoDetectBinPacking: false 32 | IndentCaseLabels: true 33 | IndentWrappedFunctionNames: false 34 | IndentFunctionDeclarationAfterType: false 35 | MaxEmptyLinesToKeep: 1 36 | KeepEmptyLinesAtTheStartOfBlocks: false 37 | NamespaceIndentation: None 38 | PenaltyBreakComment: 300 39 | PenaltyBreakString: 1000 40 | PenaltyBreakFirstLessLess: 120 41 | PenaltyExcessCharacter: 1000000 42 | PenaltyReturnTypeOnItsOwnLine: 200 43 | SpacesBeforeTrailingComments: 2 44 | Cpp11BracedListStyle: true 45 | Standard: Cpp11 46 | IndentWidth: 4 47 | TabWidth: 8 48 | UseTab: Never 49 | BreakBeforeBraces: Linux 50 | SpacesInParentheses: false 51 | SpacesInSquareBrackets: false 52 | SpacesInAngles: false 53 | SpaceInEmptyParentheses: false 54 | SpacesInCStyleCastParentheses: false 55 | SpaceAfterCStyleCast: true 56 | SpacesInContainerLiterals: true 57 | SpaceBeforeAssignmentOperators: true 58 | ContinuationIndentWidth: 4 59 | CommentPragmas: '^ IWYU pragma:' 60 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 61 | SpaceBeforeParens: ControlStatements 62 | DisableFormat: false 63 | ... 64 | 65 | -------------------------------------------------------------------------------- /test/hut.h: -------------------------------------------------------------------------------- 1 | // Heman utilities. This is part of the test suite, not the core library. 2 | 3 | #define STB_IMAGE_IMPLEMENTATION 4 | #define STB_IMAGE_WRITE_IMPLEMENTATION 5 | #define STB_IMAGE_RESIZE_IMPLEMENTATION 6 | #pragma GCC diagnostic push 7 | #pragma GCC diagnostic ignored "-Wunused-variable" 8 | #pragma GCC diagnostic ignored "-Wunused-value" 9 | #pragma GCC diagnostic ignored "-Wpointer-sign" 10 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 11 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 12 | #include "stb_image_write.h" 13 | #include "stb_image_resize.h" 14 | #include "stb_image.h" 15 | #pragma GCC diagnostic pop 16 | 17 | heman_image* hut_read_image(const char* filename, int nbands) 18 | { 19 | int width = 0, height = 0; 20 | stbi_uc* bytes; 21 | heman_image* retval; 22 | int bands_in_file; 23 | bytes = stbi_load(filename, &width, &height, &bands_in_file, nbands); 24 | assert(bytes); 25 | printf("%4d x %4d x %d :: %s\n", width, height, nbands, filename); 26 | retval = heman_import_u8(width, height, nbands, bytes, 0, 1); 27 | stbi_image_free(bytes); 28 | return retval; 29 | } 30 | 31 | void hut_write_image(const char* filename, heman_image* img, float minv, float maxv) 32 | { 33 | printf("Writing to \"%s\".\n", filename); 34 | int width, height, ncomp; 35 | heman_image_info(img, &width, &height, &ncomp); 36 | unsigned char* bytes = (unsigned char*) malloc(width * height * ncomp); 37 | heman_export_u8(img, minv, maxv, bytes); 38 | stbi_write_png(filename, width, height, ncomp, bytes, width * ncomp); 39 | free(bytes); 40 | } 41 | 42 | void hut_write_image_scaled(const char* filename, heman_image* img, int dwidth, int dheight) 43 | { 44 | printf("Writing to \"%s\".\n", filename); 45 | int width, height, ncomp; 46 | heman_image_info(img, &width, &height, &ncomp); 47 | unsigned char* bytes = (unsigned char*) malloc(width * height * ncomp); 48 | heman_export_u8(img, 0, 1, bytes); 49 | unsigned char* resized = (unsigned char*) malloc(dwidth * dheight * 3); 50 | stbir_resize_uint8(bytes, width, height, 0, resized, dwidth, dheight, 0, 3); 51 | stbi_write_png(filename, dwidth, dheight, ncomp, resized, dwidth * ncomp); 52 | free(resized); 53 | free(bytes); 54 | } 55 | -------------------------------------------------------------------------------- /docs/lighting.rst: -------------------------------------------------------------------------------- 1 | Lighting and AO 2 | ############### 3 | 4 | All functions with the ``heman_lighting_`` prefix are meant for doing things that are useful for lighting, like generating normals or ambient occlusion. 5 | 6 | Normal Maps 7 | =========== 8 | 9 | Normal maps are generated using a simple forward differencing algorithm. 10 | 11 | .. c:function:: heman_image* heman_lighting_compute_normals(heman_image* heightmap) 12 | 13 | Given a 1-band heightmap image, create a 3-band image with surface normals. The resulting image values are in **[-1, +1]**. 14 | 15 | Ambient Occlusion 16 | ================= 17 | 18 | Ambient occlusion is computed by doing 16 sweeps across the height map to find horizon points, as described by Sean Barrett `here`_. 19 | 20 | .. c:function:: heman_image* heman_lighting_compute_occlusion(heman_image* heightmap) 21 | 22 | Compute occlusion values for the given heightmap, returning a new single-band image with values in **[0, 1]**. 23 | 24 | Complete Lighting 25 | ================= 26 | 27 | .. c:function:: heman_image* heman_lighting_apply(heman_image* heightmap, heman_image* colorbuffer, float occlusion, float diffuse, float diffuse_softening, float* light_position) 28 | 29 | High-level utility that generates normals and occlusion behind the scenes, then applies simple diffuse lighting. 30 | 31 | :param heightmap: The source height map, must have exactly one band. 32 | :type heightmap: heman_image* 33 | :param colorbuffer: RGB values used for albedo; must have 3 bands, and the same dimensions as **heightmap**. 34 | :type colorbuffer: heman_image* 35 | :param occlusion: Desired strength of ambient occlusion in **[0, 1]**. 36 | :type occlusion: float 37 | :param diffuse: Desired strength of diffuse lighting in **[0, 1]**. 38 | :type diffuse: float 39 | :param diffuse_softening: Used to flatten the normals by lerping them with **+Z**. Set to **0** to use unaltered normal vectors. 40 | :type diffuse_softening: float 41 | :param light_position: Pointer to three floats representing the light direction. 42 | :type light_position: float* 43 | 44 | Heman automatically un-applies gamma to the albedo, then re-applies gamma after lighting. This behavior can be configured using :c:data:`heman_color_set_gamma`. 45 | 46 | .. _`here`: http://nothings.org/gamedev/horizon/. 47 | -------------------------------------------------------------------------------- /docs/importexport.rst: -------------------------------------------------------------------------------- 1 | Import / Export 2 | ############### 3 | 4 | Heman only knows how to work with in-memory floating-point images. It doesn't know how to read and write image files, although the test suite uses `stb `_ for handling image files. See the heman utility header (`hut.h `_) for an example of this. 5 | 6 | Heman can, however, convert floating-point to unsigned bytes, or vice versa, using one of the following functions. 7 | 8 | .. c:function:: heman_image* heman_import_u8(int width, int height, int nbands, const heman_byte* source, float minval, float maxval) 9 | 10 | Create a single-channel floating point image from bytes, such that [0, 255] maps to the given [minval, maxval] range. 11 | 12 | .. c:function:: void heman_export_u8(heman_image* source, float minval, float maxval, heman_byte* dest) 13 | 14 | Transform texel values so that [minval, maxval] maps to [0, 255], and write the result to "dest". Values outside the range are clamped. 15 | 16 | 17 | Example with STB 18 | ================ 19 | 20 | This function uses ``stbi_load`` to load the given PNG file and convert it into a floating-point image in the range **[0, 1]**. 21 | 22 | .. code-block:: c 23 | 24 | heman_image* read_image(const char* filename, int nbands) 25 | { 26 | int width = 0, height = 0; 27 | stbi_uc* bytes; 28 | heman_image* retval; 29 | bytes = stbi_load(filename, &width, &height, &nbands, nbands); 30 | assert(bytes); 31 | printf("%4d x %4d x %d :: %s\n", width, height, nbands, filename); 32 | retval = heman_import_u8(width, height, nbands, bytes, 0, 1); 33 | stbi_image_free(bytes); 34 | return retval; 35 | } 36 | 37 | 3D Mesh Data 38 | ============ 39 | 40 | Heman can export a binary mesh file representing height field data, where each grid cell in the mesh corresponds to a single texel in the height field: 41 | 42 | .. code-block:: c 43 | 44 | // Create a mesh with (width - 1) x (height - 1) quads. 45 | void heman_export_ply(heman_image*, const char* filename); 46 | 47 | // Create a mesh with (width - 1) x (height - 1) quads and per-vertex colors. 48 | void heman_export_with_colors_ply( 49 | heman_image* heightmap, heman_image* colors, const char* filename); 50 | -------------------------------------------------------------------------------- /docs/color.rst: -------------------------------------------------------------------------------- 1 | Color Gradients 2 | ############### 3 | 4 | This page covers functions with the ``heman_color_`` prefix. 5 | 6 | One-pixel tall images can be interpreted as `gradients`, also known as `lookup tables`. 7 | 8 | Creating Gradients 9 | ================== 10 | 11 | Clients can import a gradient using :c:data:`heman_import_u8`, or they can create one from scratch: 12 | 13 | .. c:function:: heman_image* heman_color_create_gradient(int width, int num_colors, const int* cp_locations, const heman_color* cp_colors) 14 | 15 | Create a 1-pixel tall, 3-band image representing a color gradient that lerps 16 | the given control points. 17 | 18 | :param width: Desired number of entries in the lookup table. 19 | :type width: int 20 | :param num_colors: Number of control points. Must be at least 2. 21 | :type num_colors: int 22 | :param cp_locations: The X coordinate of each control point. The first value must be **0** and the last value must be **width - 1**. 23 | :type cp_locations: int* 24 | :param cp_colors: The RGB values of each control points. 25 | :type cp_colors: heman_color* 26 | 27 | Gamma Correctness 28 | ================= 29 | 30 | The following two images both depict the interpolation of **(1,0,0)** to **(0,1,0)**. Can you tell which one is more correct? 31 | 32 | .. image:: _static/correct.png 33 | :width: 240px 34 | 35 | .. image:: _static/incorrect.png 36 | :width: 240px 37 | 38 | The image on the left is more correct; it interpolates the colors by first unapplying gamma to the control point colors, then performing linear interpolation, then re-applying gamma. Heman does this automatically when you call :c:data:`heman_color_create_gradient`, but the behavior can be controlled with the following function. 39 | 40 | .. c:function:: void heman_color_set_gamma(float f) 41 | 42 | This sets some global state that affects lighting and color interpolation. 43 | The default value is **2.2**. 44 | 45 | 46 | Applying Gradients 47 | ================== 48 | 49 | .. c:function:: heman_image* heman_color_apply_gradient(heman_image* heightmap, float minheight, float maxheight, heman_image* gradient) 50 | 51 | Create a 3-band image with the same dimensions as the given heightmap by 52 | making lookups from a 1-pixel tall color gradient. The heightmap values 53 | are normalized using the given minheight, maxheight range. 54 | -------------------------------------------------------------------------------- /kazmath/utility.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "utility.h" 27 | 28 | /** 29 | * Returns the square of s (e.g. s*s) 30 | */ 31 | kmScalar kmSQR(kmScalar s) { 32 | return s*s; 33 | } 34 | 35 | /** 36 | * Returns degrees as radians. 37 | */ 38 | kmScalar kmDegreesToRadians(kmScalar degrees) { 39 | return degrees * kmPIOver180; 40 | } 41 | 42 | /** 43 | * Returns radians as degrees 44 | */ 45 | kmScalar kmRadiansToDegrees(kmScalar radians) { 46 | return radians * kmPIUnder180; 47 | } 48 | 49 | kmScalar kmMin(kmScalar lhs, kmScalar rhs) { 50 | return (lhs < rhs)? lhs : rhs; 51 | } 52 | 53 | kmScalar kmMax(kmScalar lhs, kmScalar rhs) { 54 | return (lhs > rhs)? lhs : rhs; 55 | } 56 | 57 | kmBool kmAlmostEqual(kmScalar lhs, kmScalar rhs) { 58 | return (lhs + kmEpsilon > rhs && lhs - kmEpsilon < rhs); 59 | } 60 | 61 | kmScalar kmClamp(kmScalar x, kmScalar min, kmScalar max) 62 | { 63 | return x < min ? min : (x > max ? max : x); 64 | } 65 | 66 | kmScalar kmLerp(kmScalar x, kmScalar y, kmScalar t ) 67 | { 68 | return x + t * ( y - x ); 69 | } 70 | -------------------------------------------------------------------------------- /src/image.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | #include 5 | 6 | HEMAN_FLOAT* heman_image_data(heman_image* img) { return img->data; } 7 | 8 | void heman_image_array(heman_image* img, HEMAN_FLOAT** data, int* nfloats) 9 | { 10 | *data = img->data; 11 | *nfloats = img->width * img->height * img->nbands; 12 | } 13 | 14 | void heman_image_info(heman_image* img, int* width, int* height, int* nbands) 15 | { 16 | *width = img->width; 17 | *height = img->height; 18 | *nbands = img->nbands; 19 | } 20 | 21 | HEMAN_FLOAT* heman_image_texel(heman_image* img, int x, int y) 22 | { 23 | return img->data + y * img->width * img->nbands + x * img->nbands; 24 | } 25 | 26 | heman_image* heman_image_create(int width, int height, int nbands) 27 | { 28 | heman_image* img = malloc(sizeof(heman_image)); 29 | img->width = width; 30 | img->height = height; 31 | img->nbands = nbands; 32 | img->data = malloc(sizeof(HEMAN_FLOAT) * width * height * nbands); 33 | return img; 34 | } 35 | 36 | void heman_image_destroy(heman_image* img) 37 | { 38 | free(img->data); 39 | free(img); 40 | } 41 | 42 | void heman_image_sample(heman_image* img, float u, float v, HEMAN_FLOAT* result) 43 | { 44 | int x = CLAMP(img->width * u, 0, img->width - 1); 45 | int y = CLAMP(img->height * v, 0, img->height - 1); 46 | HEMAN_FLOAT* data = heman_image_texel(img, x, y); 47 | for (int b = 0; b < img->nbands; ++b) { 48 | *result++ = *data++; 49 | } 50 | } 51 | 52 | void heman_image_clear(heman_image* img, HEMAN_FLOAT value) 53 | { 54 | int size = img->width * img->height * img->nbands; 55 | HEMAN_FLOAT* dst = img->data; 56 | while (size--) { 57 | *dst++ = value; 58 | } 59 | } 60 | 61 | heman_image* heman_image_extract_alpha(heman_image* img) 62 | { 63 | assert(img->nbands == 4); 64 | heman_image* retval = heman_image_create(img->width, img->height, 1); 65 | int size = img->width * img->height; 66 | HEMAN_FLOAT* src = img->data; 67 | HEMAN_FLOAT* dst = retval->data; 68 | while (size--) { 69 | src += 3; 70 | *dst++ = *src++; 71 | } 72 | return retval; 73 | } 74 | 75 | heman_image* heman_image_extract_rgb(heman_image* img) 76 | { 77 | assert(img->nbands == 4); 78 | heman_image* retval = heman_image_create(img->width, img->height, 3); 79 | int size = img->width * img->height; 80 | HEMAN_FLOAT* src = img->data; 81 | HEMAN_FLOAT* dst = retval->data; 82 | while (size--) { 83 | *dst++ = *src++; 84 | *dst++ = *src++; 85 | *dst++ = *src++; 86 | ++src; 87 | } 88 | return retval; 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/prideout/heman/blob/master/docs/_static/islands.png) 2 | 3 | This toy project is a tiny MIT-licensed C library of image utilities for dealing with **he**ight 4 | **ma**ps, **n**ormal maps, distance fields, and the like. It has a very low-level API, where an 5 | "image" is simply a flat array of floats. There are no dependencies and [only one header 6 | file](https://github.com/prideout/heman/blob/master/include/heman.h). 7 | 8 | **Heman** can do stuff like this: 9 | - Create a random height field using simplex noise and FBM. 10 | - Generate a normal map from a height map. 11 | - Compute ambient occlusion from a height map. 12 | - Generate a signed distance field (SDF). 13 | - Export a 3D mesh in [PLY](http://paulbourke.net/dataformats/ply/) format. 14 | - Apply a color gradient to a heightmap. 15 | - Generate a color gradient, given a list of control points. 16 | - Compute diffuse lighting with an infinite light source. 17 | - Generate a nicely-distributed list of points according to a density field. 18 | 19 | Heman implements some really nice 21st-century algorithms: 20 | 21 | - Ambient occlusion is generated using Sean Barrett's efficient method that makes 16 sweeps over the 22 | height field. 23 | - Distance field computation uses the beautiful algorithm from _Distance Transforms of Sampled 24 | Functions_ (Felzenszwalb and Huttenlocher). 25 | - Density field samples are generated using Robert Bridson's _Fast Poisson Disk Sampling in 26 | Arbitrary Dimensions_. 27 | 28 | ## Example 29 | 30 | The images at the top were generated from code that looks like this: 31 | 32 | ```c 33 | // Generate an island shape using simplex noise and a distance field. 34 | heman_image* elevation = heman_generate_island_heightmap(1024, 1024, rand()); 35 | 36 | // Compute ambient occlusion from the height map. 37 | heman_image* occ = heman_lighting_compute_occlusion(elevation); 38 | 39 | // Visualize the normal vectors. 40 | heman_image* normals = heman_lighting_compute_normals(elevation); 41 | 42 | // Apply a color gradient. 43 | heman_image* gradient = heman_color_create_gradient(...); 44 | heman_image* albedo = heman_color_apply_gradient(elevation, -0.5, 0.5, grad); 45 | 46 | // Apply diffuse lighting. 47 | heman_image* final = heman_lighting_apply(elevation, albedo, ...); 48 | ``` 49 | 50 | For the unabridged version, see `test_lighting()` in 51 | [test/test_heman.c](https://github.com/prideout/heman/blob/master/test/test_heman.c). 52 | 53 | ## Building OpenMP 54 | 55 | ``` 56 | curl -L -O https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.0/openmp-12.0.0.src.tar.xz 57 | tar -xvf openmp-12.0.0.src.tar.xz ; rm openmp-12.0.0.src.tar.xz 58 | cd openmp-12.0.0.src 59 | cmake . -DLIBOMP_ENABLE_SHARED=OFF -DLIBOMP_INSTALL_ALIASES=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 60 | sudo make install 61 | ``` 62 | -------------------------------------------------------------------------------- /kazmath/aabb3.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KAZMATH_AABB3D_H_INCLUDED 27 | #define KAZMATH_AABB3D_H_INCLUDED 28 | 29 | #include "vec3.h" 30 | #include "utility.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /** 37 | * A struture that represents an axis-aligned 38 | * bounding box. 39 | */ 40 | typedef struct kmAABB3 { 41 | kmVec3 min; /** The max corner of the box */ 42 | kmVec3 max; /** The min corner of the box */ 43 | } kmAABB3; 44 | 45 | 46 | kmAABB3* kmAABB3Initialize(kmAABB3* pBox, const kmVec3* centre, const kmScalar width, const kmScalar height, const kmScalar depth); 47 | int kmAABB3ContainsPoint(const kmAABB3* pBox, const kmVec3* pPoint); 48 | kmAABB3* kmAABB3Assign(kmAABB3* pOut, const kmAABB3* pIn); 49 | kmAABB3* kmAABB3Scale(kmAABB3* pOut, const kmAABB3* pIn, kmScalar s); 50 | kmBool kmAABB3IntersectsTriangle(kmAABB3* box, const kmVec3* p1, const kmVec3* p2, const kmVec3* p3); 51 | kmBool kmAABB3IntersectsAABB(const kmAABB3* box, const kmAABB3* other); 52 | kmEnum kmAABB3ContainsAABB(const kmAABB3* container, const kmAABB3* to_check); 53 | kmScalar kmAABB3DiameterX(const kmAABB3* aabb); 54 | kmScalar kmAABB3DiameterY(const kmAABB3* aabb); 55 | kmScalar kmAABB3DiameterZ(const kmAABB3* aabb); 56 | kmVec3* kmAABB3Centre(const kmAABB3* aabb, kmVec3* pOut); 57 | kmAABB3* kmAABB3ExpandToContain(kmAABB3* pOut, const kmAABB3* pIn, const kmAABB3* other); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /kazmath/aabb2.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KAZMATH_AABB2D_H_INCLUDED 27 | #define KAZMATH_AABB2D_H_INCLUDED 28 | 29 | #include "vec2.h" 30 | #include "utility.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /** 37 | * A struture that represents an axis-aligned 38 | * bounding box. 39 | */ 40 | typedef struct kmAABB2 { 41 | kmVec2 min; /** The max corner of the box */ 42 | kmVec2 max; /** The min corner of the box */ 43 | } kmAABB2; 44 | 45 | 46 | kmAABB2* kmAABB2Initialize(kmAABB2* pBox, const kmVec2* centre, const kmScalar width, const kmScalar height, const kmScalar depth); 47 | kmAABB2* kmAABB2Sanitize(kmAABB2* pOut, const kmAABB2* pIn ); 48 | int kmAABB2ContainsPoint(const kmAABB2* pBox, const kmVec2* pPoint); 49 | kmAABB2* kmAABB2Assign(kmAABB2* pOut, const kmAABB2* pIn); 50 | kmAABB2* kmAABB2Translate(kmAABB2* pOut, const kmAABB2* pIn, const kmVec2 *translation ); 51 | kmAABB2* kmAABB2Scale(kmAABB2* pOut, const kmAABB2* pIn, kmScalar s); 52 | kmAABB2* kmAABB2ScaleWithPivot( kmAABB2* pOut, const kmAABB2* pIn, const kmVec2 *pivot, kmScalar s ); 53 | kmEnum kmAABB2ContainsAABB(const kmAABB2* container, const kmAABB2* to_check); 54 | kmScalar kmAABB2DiameterX(const kmAABB2* aabb); 55 | kmScalar kmAABB2DiameterY(const kmAABB2* aabb); 56 | kmVec2* kmAABB2Centre(const kmAABB2* aabb, kmVec2* pOut); 57 | kmAABB2* kmAABB2ExpandToContain(kmAABB2* pOut, const kmAABB2* pIn, const kmAABB2* other); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /kazmath/ray2.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef RAY_2_H 27 | #define RAY_2_H 28 | 29 | #include "utility.h" 30 | #include "vec2.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | typedef struct kmRay2 { 37 | kmVec2 start; 38 | kmVec2 dir; 39 | } kmRay2; 40 | 41 | void kmRay2Fill(kmRay2* ray, kmScalar px, kmScalar py, kmScalar vx, kmScalar vy); 42 | void kmRay2FillWithEndpoints( kmRay2 *ray, const kmVec2 *start, const kmVec2 *end ); 43 | 44 | kmBool kmLine2WithLineIntersection(const kmVec2 *ptA, const kmVec2 *vecA, 45 | const kmVec2 *ptB, const kmVec2 *vecB, 46 | kmScalar *outTA, kmScalar *outTB, 47 | kmVec2 *outIntersection ); 48 | 49 | kmBool kmSegment2WithSegmentIntersection( const kmRay2 *segmentA, 50 | const kmRay2 *segmentB, 51 | kmVec2 *intersection ); 52 | 53 | kmBool kmRay2IntersectLineSegment(const kmRay2* ray, const kmVec2* p1, const kmVec2* p2, kmVec2* intersection); 54 | kmBool kmRay2IntersectTriangle(const kmRay2* ray, const kmVec2* p1, const kmVec2* p2, const kmVec2* p3, kmVec2* intersection, kmVec2* normal_out, kmScalar* distance); 55 | 56 | kmBool kmRay2IntersectBox(const kmRay2* ray, const kmVec2* p1, const kmVec2* p2, const kmVec2* p3, const kmVec2* p4, 57 | kmVec2* intersection, kmVec2* normal_out); 58 | 59 | kmBool kmRay2IntersectCircle(const kmRay2* ray, const kmVec2 centre, const kmScalar radius, kmVec2* intersection); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /kazmath/utility.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef UTILITY_H_INCLUDED 27 | #define UTILITY_H_INCLUDED 28 | 29 | #include 30 | 31 | #ifndef kmScalar 32 | #ifdef USE_DOUBLE_PRECISION 33 | #define kmScalar double 34 | #else 35 | #define kmScalar float 36 | #endif 37 | 38 | #endif 39 | 40 | #ifndef kmBool 41 | #define kmBool unsigned char 42 | #endif 43 | 44 | #ifndef kmUchar 45 | #define kmUchar unsigned char 46 | #endif 47 | 48 | #ifndef kmEnum 49 | #define kmEnum unsigned int 50 | #endif 51 | 52 | #ifndef kmUint 53 | #define kmUint unsigned int 54 | #endif 55 | 56 | #ifndef kmInt 57 | #define kmInt int 58 | #endif 59 | 60 | #ifndef KM_FALSE 61 | #define KM_FALSE 0 62 | #endif 63 | 64 | #ifndef KM_TRUE 65 | #define KM_TRUE 1 66 | #endif 67 | 68 | #define kmPI 3.14159265358979323846f 69 | #define kmPIOver180 (kmPI / 180.0f) 70 | #define kmPIUnder180 (180.0 / kmPI) 71 | #define kmEpsilon 0.0001 72 | 73 | #define KM_CONTAINS_NONE (kmEnum)0 74 | #define KM_CONTAINS_PARTIAL (kmEnum)1 75 | #define KM_CONTAINS_ALL (kmEnum)2 76 | 77 | #ifdef __cplusplus 78 | extern "C" { 79 | #endif 80 | 81 | extern kmScalar kmSQR(kmScalar s); 82 | extern kmScalar kmDegreesToRadians(kmScalar degrees); 83 | extern kmScalar kmRadiansToDegrees(kmScalar radians); 84 | 85 | extern kmScalar kmMin(kmScalar lhs, kmScalar rhs); 86 | extern kmScalar kmMax(kmScalar lhs, kmScalar rhs); 87 | extern kmBool kmAlmostEqual(kmScalar lhs, kmScalar rhs); 88 | 89 | extern kmScalar kmClamp(kmScalar x, kmScalar min, kmScalar max); 90 | extern kmScalar kmLerp(kmScalar x, kmScalar y, kmScalar factor); 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif /* UTILITY_H_INCLUDED */ 97 | -------------------------------------------------------------------------------- /test/test_planet.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hut.h" 3 | 4 | #define COUNT(a) (sizeof(a) / sizeof(a[0])) 5 | #define OUTFOLDER "build/" 6 | #define HEIGHT 128 7 | 8 | static int CP_LOCATIONS[] = { 9 | 000, // Dark Blue 10 | 126, // Light Blue 11 | 127, // Yellow 12 | 150, // Dark Green 13 | 170, // Brown 14 | 200, // Brown 15 | 240, // White 16 | 255, // White 17 | }; 18 | 19 | static heman_color CP_COLORS[] = { 20 | 0x001070, // Dark Blue 21 | 0x2C5A7C, // Light Blue 22 | 0xE0F0A0, // Yellow 23 | 0x5D943C, // Dark Green 24 | 0x606011, // Brown 25 | 0x606011, // Brown 26 | 0xFFFFFF, // White 27 | 0xFFFFFF, // White 28 | }; 29 | 30 | static float LIGHTPOS[] = {-0.5f, 0.5f, 1.0f}; 31 | 32 | heman_image* make_planet(int seed, heman_image* grad) 33 | { 34 | heman_image* hmap = 35 | heman_generate_planet_heightmap(HEIGHT * 2, HEIGHT, seed); 36 | heman_image* albedo = heman_color_apply_gradient(hmap, -0.5, 0.5, grad); 37 | heman_image* planet = 38 | heman_lighting_apply(hmap, albedo, 1, 1, 0.75, LIGHTPOS); 39 | heman_image_destroy(hmap); 40 | heman_image_destroy(albedo); 41 | return planet; 42 | } 43 | 44 | heman_image* make_island(int seed, heman_image* grad) 45 | { 46 | heman_image* hmap = heman_generate_island_heightmap(HEIGHT, HEIGHT, seed); 47 | heman_image* albedo = heman_color_apply_gradient(hmap, -0.5, 0.5, grad); 48 | heman_image* island = 49 | heman_lighting_apply(hmap, albedo, 1, 1, 0.75, LIGHTPOS); 50 | heman_image_destroy(hmap); 51 | heman_image_destroy(albedo); 52 | return island; 53 | } 54 | 55 | int main(int argc, char** argv) 56 | { 57 | heman_image* grad = heman_color_create_gradient( 58 | 256, COUNT(CP_COLORS), CP_LOCATIONS, CP_COLORS); 59 | 60 | heman_image* tiles[4]; 61 | tiles[0] = make_planet(1000, grad); 62 | tiles[1] = make_planet(1001, grad); 63 | heman_image* planets = heman_ops_stitch_vertical(tiles, 2); 64 | heman_image_destroy(tiles[0]); 65 | heman_image_destroy(tiles[1]); 66 | 67 | tiles[0] = make_island(1000, grad); 68 | tiles[1] = make_island(1001, grad); 69 | tiles[2] = make_island(1002, grad); 70 | tiles[3] = make_island(1003, grad); 71 | heman_image* rows[2]; 72 | rows[0] = heman_ops_stitch_horizontal(tiles, 2); 73 | rows[1] = heman_ops_stitch_horizontal(tiles + 2, 2); 74 | heman_image* islands = heman_ops_stitch_vertical(rows, 2); 75 | heman_image_destroy(tiles[0]); 76 | heman_image_destroy(tiles[1]); 77 | heman_image_destroy(tiles[2]); 78 | heman_image_destroy(tiles[3]); 79 | heman_image_destroy(rows[0]); 80 | heman_image_destroy(rows[1]); 81 | 82 | tiles[0] = planets; 83 | tiles[1] = islands; 84 | heman_image* final = heman_ops_stitch_horizontal(tiles, 2); 85 | heman_image_destroy(planets); 86 | heman_image_destroy(islands); 87 | 88 | hut_write_image(OUTFOLDER "stitched.png", final, 0, 1); 89 | heman_image_destroy(final); 90 | heman_image_destroy(grad); 91 | } 92 | -------------------------------------------------------------------------------- /kazmath/vec4.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef VEC4_H_INCLUDED 27 | #define VEC4_H_INCLUDED 28 | 29 | #include "utility.h" 30 | 31 | struct kmMat4; 32 | 33 | #pragma pack(push) /* push current alignment to stack */ 34 | #pragma pack(1) /* set alignment to 1 byte boundary */ 35 | 36 | typedef struct kmVec4 37 | { 38 | kmScalar x; 39 | kmScalar y; 40 | kmScalar z; 41 | kmScalar w; 42 | } kmVec4; 43 | 44 | #pragma pack(pop) 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | kmVec4* kmVec4Fill(kmVec4* pOut, kmScalar x, kmScalar y, kmScalar z, kmScalar w); 51 | kmVec4* kmVec4Add(kmVec4* pOut, const kmVec4* pV1, const kmVec4* pV2); 52 | kmScalar kmVec4Dot(const kmVec4* pV1, const kmVec4* pV2); 53 | kmScalar kmVec4Length(const kmVec4* pIn); 54 | kmScalar kmVec4LengthSq(const kmVec4* pIn); 55 | kmVec4* kmVec4Lerp(kmVec4* pOut, const kmVec4* pV1, const kmVec4* pV2, kmScalar t); 56 | kmVec4* kmVec4Normalize(kmVec4* pOut, const kmVec4* pIn); 57 | kmVec4* kmVec4Scale(kmVec4* pOut, const kmVec4* pIn, const kmScalar s); /**< Scales a vector to length s*/ 58 | kmVec4* kmVec4Subtract(kmVec4* pOut, const kmVec4* pV1, const kmVec4* pV2); 59 | kmVec4* kmVec4Mul( kmVec4* pOut,const kmVec4* pV1, const kmVec4* pV2 ); 60 | kmVec4* kmVec4Div( kmVec4* pOut,const kmVec4* pV1, const kmVec4* pV2 ); 61 | 62 | kmVec4* kmVec4MultiplyMat4(kmVec4* pOut, const kmVec4* pV, const struct kmMat4* pM); 63 | kmVec4* kmVec4Transform(kmVec4* pOut, const kmVec4* pV, const struct kmMat4* pM); 64 | kmVec4* kmVec4TransformArray(kmVec4* pOut, unsigned int outStride, 65 | const kmVec4* pV, unsigned int vStride, const struct kmMat4* pM, unsigned int count); 66 | int kmVec4AreEqual(const kmVec4* p1, const kmVec4* p2); 67 | kmVec4* kmVec4Assign(kmVec4* pOut, const kmVec4* pIn); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif /* VEC4_H_INCLUDED */ 74 | -------------------------------------------------------------------------------- /docs/generate.rst: -------------------------------------------------------------------------------- 1 | Terrain Generation 2 | ################## 3 | 4 | All functions with the ``heman_generate_`` prefix are meant to help in the creation of interesting procedural imagery. 5 | 6 | Noise and FBM 7 | ============= 8 | 9 | The image on the left is Ken Perlin's simplex noise function, which is nice and continuous, but non-fractal. The image on the right adds up several octaves of that same noise function; this is known as `Fractional Brownian Motion` (FBM). This provides a way of generating fractal-like images that look cool when interpreted as a height map. 10 | 11 | .. image:: _static/noise.png 12 | :width: 240px 13 | 14 | .. image:: _static/fbm.png 15 | :width: 240px 16 | 17 | .. c:function:: heman_image* heman_generate_simplex_fbm(int width, int height, float frequency, float amplitude, int octaves, float lacunarity, float gain, int seed) 18 | 19 | Sums up a number of noise octaves and returns the result. A good starting point is to use `lacunarity` = 2.0, `gain` = 0.5, and `octaves` = 3. 20 | 21 | Islands 22 | ======= 23 | 24 | .. c:function:: heman_image* heman_generate_island_heightmap(int width, int height, int random_seed) 25 | 26 | High-level function that uses several octaves of simplex noise and a signed distance field to generate an interesting height map. 27 | 28 | Note that this function creates a "seed point" at the center of the image. To have control over the seed point, see :c:data:`heman_generate_archipelago_heightmap`. 29 | 30 | .. image:: _static/island.png 31 | :width: 256px 32 | 33 | Planets 34 | ======= 35 | 36 | .. c:function:: heman_image* heman_generate_planet_heightmap(int width, int height, int random_seed) 37 | 38 | High-level function that sums up several octaves of `OpenSimplex `_ noise over a 3D domain to generate an interesting lat-long height map. Clients should specify a `width` that is twice the value of `height`. 39 | 40 | .. image:: _static/planet.png 41 | :width: 512px 42 | 43 | Archipelagos 44 | ============ 45 | 46 | Heman proffers two high-level functions for generating archipelagos. They are similar to :c:data:`heman_generate_island_heightmap` but more flexible, allowing the user to specify custom seed points. The first function below generates only a height map; the latter can also generate "political" colors. 47 | 48 | .. c:function:: heman_image* heman_generate_archipelago_heightmap(int width, int height, heman_points* points, float noiseamt, int random_seed) 49 | 50 | 0.3 is a good choice for `noiseamt`, but 0 is useful for diagnostics, as seen in the leftmost panel below. 51 | 52 | `points` can be a list of two-tuples (X Y) or three-tuples (X Y Strength). 53 | 54 | The image below depicts the same archipelago using three different noise amounts. 55 | 56 | .. image:: _static/archipelago.png 57 | :width: 768px 58 | 59 | .. c:function:: void heman_generate_archipelago_political(int width, int height, heman_points* points, const heman_color* colors, heman_color ocean, float noiseamt, int seed, heman_image** elevation, heman_image** political) 60 | 61 | This is a fancier API that generates political colors as well as elevation data. Behind the scenes, it uses :c:data:`heman_distance_create_cpcf`. 62 | 63 | .. image:: _static/archifinal.png 64 | :width: 240px 65 | -------------------------------------------------------------------------------- /kazmath/plane.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef PLANE_H_INCLUDED 27 | #define PLANE_H_INCLUDED 28 | 29 | #define KM_PLANE_LEFT 0 30 | #define KM_PLANE_RIGHT 1 31 | #define KM_PLANE_BOTTOM 2 32 | #define KM_PLANE_TOP 3 33 | #define KM_PLANE_NEAR 4 34 | #define KM_PLANE_FAR 5 35 | 36 | #include "utility.h" 37 | 38 | struct kmVec3; 39 | struct kmVec4; 40 | struct kmMat4; 41 | 42 | typedef struct kmPlane { 43 | kmScalar a, b, c, d; 44 | } kmPlane; 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | typedef enum KM_POINT_CLASSIFICATION { 51 | POINT_BEHIND_PLANE = -1, 52 | POINT_ON_PLANE = 0, 53 | POINT_INFRONT_OF_PLANE = 1 54 | } KM_POINT_CLASSIFICATION; 55 | 56 | kmPlane* kmPlaneFill(kmPlane* plane, kmScalar a, kmScalar b, kmScalar c, kmScalar d); 57 | kmScalar kmPlaneDot(const kmPlane* pP, const struct kmVec4* pV); 58 | kmScalar kmPlaneDotCoord(const kmPlane* pP, const struct kmVec3* pV); 59 | kmScalar kmPlaneDotNormal(const kmPlane* pP, const struct kmVec3* pV); 60 | kmPlane* kmPlaneFromNormalAndDistance(kmPlane* plane, const struct kmVec3* normal, const kmScalar dist); 61 | kmPlane* kmPlaneFromPointAndNormal(kmPlane* pOut, const struct kmVec3* pPoint, const struct kmVec3* pNormal); 62 | kmPlane* kmPlaneFromPoints(kmPlane* pOut, const struct kmVec3* p1, const struct kmVec3* p2, const struct kmVec3* p3); 63 | struct kmVec3* kmPlaneIntersectLine(struct kmVec3* pOut, const kmPlane* pP, const struct kmVec3* pV1, const struct kmVec3* pV2); 64 | kmPlane* kmPlaneNormalize(kmPlane* pOut, const kmPlane* pP); 65 | kmPlane* kmPlaneScale(kmPlane* pOut, const kmPlane* pP, kmScalar s); 66 | KM_POINT_CLASSIFICATION kmPlaneClassifyPoint(const kmPlane* pIn, const struct kmVec3* pP); /** Classifys a point against a plane */ 67 | 68 | kmPlane* kmPlaneExtractFromMat4(kmPlane* pOut, const struct kmMat4* pIn, kmInt row); 69 | struct kmVec3* kmPlaneGetIntersection(struct kmVec3* pOut, const kmPlane* p1, const kmPlane* p2, const kmPlane* p3); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif /* PLANE_H_INCLUDED */ 76 | -------------------------------------------------------------------------------- /src/wrapjs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | #include 6 | #include "image.h" 7 | } 8 | 9 | using namespace emscripten; 10 | 11 | static int buffer_width(heman_image* img) { 12 | return img->width; 13 | } 14 | 15 | static int buffer_height(heman_image* img) { 16 | return img->height; 17 | } 18 | 19 | static int buffer_nbands(heman_image* img) { 20 | return img->nbands; 21 | } 22 | 23 | static int buffer_begin(heman_image* img) { 24 | return ((int) (img->data)) / sizeof(HEMAN_FLOAT); 25 | } 26 | 27 | static int buffer_end(heman_image* img) { 28 | int sz = img->nbands * img->width * img->height; 29 | return buffer_begin(img) + sz; 30 | } 31 | 32 | static heman_image* lighting_apply(heman_image* hmap, float occlusion, 33 | float diffuse, float softening) 34 | { 35 | return heman_lighting_apply(hmap, nullptr, occlusion, diffuse, softening, 36 | nullptr); 37 | } 38 | 39 | EMSCRIPTEN_BINDINGS(heman) { 40 | 41 | allow_raw_pointers arp; 42 | 43 | class_("Buffer") 44 | .function("width", &buffer_width, arp) 45 | .function("height", &buffer_height, arp) 46 | .function("nbands", &buffer_nbands, arp) 47 | .function("begin", &buffer_begin, arp) 48 | .function("end", &buffer_end, arp); 49 | 50 | struct Image {}; 51 | class_("Image") 52 | .class_function("create", &heman_image_create, arp) 53 | .class_function("destroy", &heman_image_destroy, arp); 54 | 55 | struct Generate {}; 56 | class_("Generate") 57 | .class_function("island_heightmap", &heman_generate_island_heightmap, arp) 58 | .class_function("planet_heightmap", &heman_generate_planet_heightmap, arp) 59 | .class_function("archipelago_heightmap", &heman_generate_archipelago_heightmap, arp) 60 | .class_function("simplex_fbm", &heman_generate_simplex_fbm, arp); 61 | 62 | struct Ops {}; 63 | class_("Ops") 64 | .class_function("stitch_horizontal", &heman_ops_stitch_horizontal, arp) 65 | .class_function("stitch_vertical", &heman_ops_stitch_vertical, arp) 66 | .class_function("normalize_f32", &heman_ops_normalize_f32, arp) 67 | .class_function("step", &heman_ops_step, arp) 68 | .class_function("sweep", &heman_ops_sweep, arp) 69 | .class_function("laplacian", &heman_ops_laplacian, arp) 70 | .class_function("accumulate", &heman_ops_accumulate, arp); 71 | 72 | struct Lighting {}; 73 | class_("Lighting") 74 | .class_function("apply", &lighting_apply, arp) 75 | .class_function("compute_normals", &heman_lighting_compute_normals, arp) 76 | .class_function("compute_occlusion", &heman_lighting_compute_occlusion, arp); 77 | 78 | struct Color {}; 79 | class_("Color") 80 | .class_function("create_gadient", &heman_color_create_gradient, arp) 81 | .class_function("set_gamma", &heman_color_set_gamma) 82 | .class_function("apply_gradient", &heman_color_apply_gradient, arp) 83 | .class_function("from_grayscale", &heman_color_from_grayscale, arp); 84 | 85 | struct Distance {}; 86 | class_("Distance") 87 | .class_function("create_sdf", &heman_distance_create_sdf, arp) 88 | .class_function("create_df", &heman_distance_create_df, arp) 89 | .class_function("create_cpcf", &heman_distance_create_cpcf, arp); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /kazmath/mat3.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_8E9D0ABA3C76B989 2 | #define HEADER_8E9D0ABA3C76B989 3 | 4 | /* 5 | Copyright (c) 2008, Luke Benstead. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, 9 | are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | 30 | #ifndef MAT3_H_INCLUDED 31 | #define MAT3_H_INCLUDED 32 | 33 | #include "utility.h" 34 | 35 | struct kmVec3; 36 | struct kmQuaternion; 37 | struct kmMat4; 38 | 39 | typedef struct kmMat3{ 40 | kmScalar mat[9]; 41 | } kmMat3; 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | kmMat3* kmMat3Fill(kmMat3* pOut, const kmScalar* pMat); 48 | kmMat3* kmMat3Adjugate(kmMat3* pOut, const kmMat3* pIn); 49 | kmMat3* kmMat3Identity(kmMat3* pOut); 50 | kmMat3* kmMat3Inverse(kmMat3* pOut, const kmMat3* pM); 51 | int kmMat3IsIdentity(const kmMat3* pIn); 52 | kmMat3* kmMat3Transpose(kmMat3* pOut, const kmMat3* pIn); 53 | kmScalar kmMat3Determinant(const kmMat3* pIn); 54 | kmMat3* kmMat3Multiply(kmMat3* pOut, const kmMat3* pM1, const kmMat3* pM2); 55 | kmMat3* kmMat3ScalarMultiply(kmMat3* pOut, const kmMat3* pM, const kmScalar pFactor); 56 | 57 | kmMat3* kmMat3Assign(kmMat3* pOut, const kmMat3* pIn); 58 | kmMat3* kmMat3AssignMat4(kmMat3* pOut, const struct kmMat4* pIn); 59 | int kmMat3AreEqual(const kmMat3* pM1, const kmMat3* pM2); 60 | 61 | struct kmVec3* kmMat3GetUpVec3(struct kmVec3* pOut, const kmMat3* pIn); 62 | struct kmVec3* kmMat3GetRightVec3(struct kmVec3* pOut, const kmMat3* pIn); 63 | struct kmVec3* kmMat3GetForwardVec3(struct kmVec3* pOut, const kmMat3* pIn); 64 | 65 | kmMat3* kmMat3RotationX(kmMat3* pOut, const kmScalar radians); 66 | kmMat3* kmMat3RotationY(kmMat3* pOut, const kmScalar radians); 67 | kmMat3* kmMat3RotationZ(kmMat3* pOut, const kmScalar radians); 68 | 69 | kmMat3* kmMat3Rotation(kmMat3* pOut, const kmScalar radians); 70 | kmMat3* kmMat3Scaling(kmMat3* pOut, const kmScalar x, const kmScalar y); 71 | kmMat3* kmMat3Translation(kmMat3* pOut, const kmScalar x, const kmScalar y); 72 | 73 | kmMat3* kmMat3RotationQuaternion(kmMat3* pOut, const struct kmQuaternion* pIn); 74 | 75 | kmMat3* kmMat3RotationAxisAngle(kmMat3* pOut, const struct kmVec3* axis, kmScalar radians); 76 | struct kmVec3* kmMat3RotationToAxisAngle(struct kmVec3* pAxis, kmScalar* radians, const kmMat3* pIn); 77 | kmMat3* kmMat3LookAt(kmMat3* pOut, const struct kmVec3* pEye, const struct kmVec3* pCenter, const struct kmVec3* pUp); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | #endif /* MAT3_H_INCLUDED */ 83 | 84 | 85 | #endif /* header guard */ 86 | -------------------------------------------------------------------------------- /kazmath/mat4.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef MAT4_H_INCLUDED 27 | #define MAT4_H_INCLUDED 28 | 29 | #include "utility.h" 30 | 31 | struct kmVec3; 32 | struct kmMat3; 33 | struct kmQuaternion; 34 | struct kmPlane; 35 | 36 | /* 37 | A 4x4 matrix 38 | 39 | | 0 4 8 12 | 40 | mat = | 1 5 9 13 | 41 | | 2 6 10 14 | 42 | | 3 7 11 15 | 43 | */ 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | typedef struct kmMat4 { 50 | kmScalar mat[16]; 51 | } kmMat4; 52 | 53 | kmMat4* kmMat4Fill(kmMat4* pOut, const kmScalar* pMat); 54 | 55 | 56 | kmMat4* kmMat4Identity(kmMat4* pOut); 57 | 58 | kmMat4* kmMat4Inverse(kmMat4* pOut, const kmMat4* pM); 59 | 60 | 61 | int kmMat4IsIdentity(const kmMat4* pIn); 62 | 63 | kmMat4* kmMat4Transpose(kmMat4* pOut, const kmMat4* pIn); 64 | kmMat4* kmMat4Multiply(kmMat4* pOut, const kmMat4* pM1, const kmMat4* pM2); 65 | 66 | kmMat4* kmMat4Assign(kmMat4* pOut, const kmMat4* pIn); 67 | kmMat4* kmMat4AssignMat3(kmMat4* pOut, const struct kmMat3* pIn); 68 | 69 | int kmMat4AreEqual(const kmMat4* pM1, const kmMat4* pM2); 70 | 71 | kmMat4* kmMat4RotationX(kmMat4* pOut, const kmScalar radians); 72 | kmMat4* kmMat4RotationY(kmMat4* pOut, const kmScalar radians); 73 | kmMat4* kmMat4RotationZ(kmMat4* pOut, const kmScalar radians); 74 | kmMat4* kmMat4RotationYawPitchRoll(kmMat4* pOut, const kmScalar pitch, const kmScalar yaw, const kmScalar roll); 75 | kmMat4* kmMat4RotationQuaternion(kmMat4* pOut, const struct kmQuaternion* pQ); 76 | kmMat4* kmMat4RotationTranslation(kmMat4* pOut, const struct kmMat3* rotation, const struct kmVec3* translation); 77 | kmMat4* kmMat4Scaling(kmMat4* pOut, const kmScalar x, const kmScalar y, const kmScalar z); 78 | kmMat4* kmMat4Translation(kmMat4* pOut, const kmScalar x, const kmScalar y, const kmScalar z); 79 | 80 | struct kmVec3* kmMat4GetUpVec3(struct kmVec3* pOut, const kmMat4* pIn); 81 | struct kmVec3* kmMat4GetRightVec3(struct kmVec3* pOut, const kmMat4* pIn); 82 | struct kmVec3* kmMat4GetForwardVec3RH(struct kmVec3* pOut, const kmMat4* pIn); 83 | struct kmVec3* kmMat4GetForwardVec3LH(struct kmVec3* pOut, const kmMat4* pIn); 84 | 85 | kmMat4* kmMat4PerspectiveProjection(kmMat4* pOut, kmScalar fovY, kmScalar aspect, kmScalar zNear, kmScalar zFar); 86 | kmMat4* kmMat4OrthographicProjection(kmMat4* pOut, kmScalar left, kmScalar right, kmScalar bottom, kmScalar top, kmScalar nearVal, kmScalar farVal); 87 | kmMat4* kmMat4LookAt(kmMat4* pOut, const struct kmVec3* pEye, const struct kmVec3* pCenter, const struct kmVec3* pUp); 88 | 89 | kmMat4* kmMat4RotationAxisAngle(kmMat4* pOut, const struct kmVec3* axis, kmScalar radians); 90 | struct kmMat3* kmMat4ExtractRotation(struct kmMat3* pOut, const kmMat4* pIn); 91 | struct kmPlane* kmMat4ExtractPlane(struct kmPlane* pOut, const kmMat4* pIn, const kmEnum plane); 92 | struct kmVec3* kmMat4RotationToAxisAngle(struct kmVec3* pAxis, kmScalar* radians, const kmMat4* pIn); 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | #endif /* MAT4_H_INCLUDED */ 97 | -------------------------------------------------------------------------------- /kazmath/vec2.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef VEC2_H_INCLUDED 27 | #define VEC2_H_INCLUDED 28 | 29 | #include "utility.h" 30 | 31 | struct kmMat3; 32 | 33 | #pragma pack(push) /* push current alignment to stack */ 34 | #pragma pack(1) /* set alignment to 1 byte boundary */ 35 | typedef struct kmVec2 { 36 | kmScalar x; 37 | kmScalar y; 38 | } kmVec2; 39 | 40 | #pragma pack(pop) 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | kmVec2* kmVec2Fill(kmVec2* pOut, kmScalar x, kmScalar y); 47 | kmScalar kmVec2Length(const kmVec2* pIn); /**< Returns the length of the vector*/ 48 | kmScalar kmVec2LengthSq(const kmVec2* pIn); /**< Returns the square of the length of the vector*/ 49 | kmVec2* kmVec2Normalize(kmVec2* pOut, const kmVec2* pIn); /**< Returns the vector passed in set to unit length*/ 50 | kmVec2* kmVec2Lerp(kmVec2* pOut, const kmVec2* pV1, const kmVec2* pV2, kmScalar t); 51 | kmVec2* kmVec2Add(kmVec2* pOut, const kmVec2* pV1, const kmVec2* pV2); /**< Adds 2 vectors and returns the result*/ 52 | kmScalar kmVec2Dot(const kmVec2* pV1, const kmVec2* pV2); /** Returns the Dot product which is the cosine of the angle between the two vectors multiplied by their lengths */ 53 | kmScalar kmVec2Cross(const kmVec2* pV1, const kmVec2* pV2); 54 | kmVec2* kmVec2Subtract(kmVec2* pOut, const kmVec2* pV1, const kmVec2* pV2); /**< Subtracts 2 vectors and returns the result*/ 55 | kmVec2* kmVec2Mul( kmVec2* pOut,const kmVec2* pV1, const kmVec2* pV2 ); /**< Component-wise multiplication */ 56 | kmVec2* kmVec2Div( kmVec2* pOut,const kmVec2* pV1, const kmVec2* pV2 ); /**< Component-wise division*/ 57 | kmVec2* kmVec2Transform(kmVec2* pOut, const kmVec2* pV1, const struct kmMat3* pM); /** Transform the Vector */ 58 | kmVec2* kmVec2TransformCoord(kmVec2* pOut, const kmVec2* pV, const struct kmMat3* pM); /** 3 | #include 4 | #include 5 | 6 | void heman_export_ply(heman_image* img, const char* filename) 7 | { 8 | assert(img->nbands == 1); 9 | FILE* fout = fopen(filename, "wb"); 10 | int ncols = (img->width - 1); 11 | int nrows = (img->height - 1); 12 | int ncells = ncols * nrows; 13 | int nverts = img->width * img->height; 14 | fprintf(fout, 15 | "ply\n" 16 | "format binary_little_endian 1.0\n" 17 | "comment heman\n" 18 | "element vertex %d\n" 19 | "property float32 x\n" 20 | "property float32 y\n" 21 | "property float32 z\n" 22 | "element face %d\n" 23 | "property list int32 int32 vertex_indices\n" 24 | "end_header\n", 25 | nverts, ncells); 26 | float invw = 2.0f / img->width; 27 | float invh = 2.0f / img->height; 28 | float vert[3]; 29 | for (int j = 0; j < img->height; j++) { 30 | for (int i = 0; i < img->width; i++) { 31 | vert[0] = -1 + i * invw; 32 | vert[1] = -1 + j * invh; 33 | vert[2] = *heman_image_texel(img, i, j); 34 | fwrite(vert, sizeof(vert), 1, fout); 35 | } 36 | } 37 | int face[5]; 38 | face[0] = 4; 39 | for (int j = 0; j < nrows; j++) { 40 | int p = j * img->width; 41 | for (int i = 0; i < ncols; i++, p++) { 42 | face[1] = p; 43 | face[2] = p + 1; 44 | face[3] = p + img->width + 1; 45 | face[4] = p + img->width; 46 | fwrite(face, sizeof(face), 1, fout); 47 | } 48 | } 49 | fclose(fout); 50 | } 51 | 52 | void heman_export_with_colors_ply( 53 | heman_image* hmap, heman_image* colors, const char* filename) 54 | { 55 | int width = hmap->width; 56 | int height = hmap->height; 57 | assert(hmap->nbands == 1); 58 | assert(colors->nbands == 3); 59 | assert(colors->width == width); 60 | assert(colors->height == height); 61 | FILE* fout = fopen(filename, "wb"); 62 | int ncols = (hmap->width - 1); 63 | int nrows = (hmap->height - 1); 64 | int ncells = ncols * nrows; 65 | int nverts = hmap->width * hmap->height; 66 | unsigned char* colordata = malloc(width * height * 3); 67 | heman_export_u8(colors, 0.0, 1.0, colordata); 68 | fprintf(fout, 69 | "ply\n" 70 | "format binary_little_endian 1.0\n" 71 | "comment heman\n" 72 | "element vertex %d\n" 73 | "property float32 x\n" 74 | "property float32 y\n" 75 | "property float32 z\n" 76 | "property uchar red\n" 77 | "property uchar green\n" 78 | "property uchar blue\n" 79 | "property uchar alpha\n" 80 | "element face %d\n" 81 | "property list int32 int32 vertex_indices\n" 82 | "end_header\n", 83 | nverts, ncells); 84 | float invw = 2.0f / width; 85 | float invh = 2.0f / height; 86 | heman_byte* pcolor = colordata; 87 | float vert[3]; 88 | for (int j = 0; j < height; j++) { 89 | for (int i = 0; i < width; i++) { 90 | vert[0] = -1 + i * invw; 91 | vert[1] = -1 + j * invh; 92 | vert[2] = *heman_image_texel(hmap, i, j); 93 | fwrite(vert, sizeof(vert), 1, fout); 94 | fwrite(pcolor, 3, 1, fout); 95 | pcolor += 3; 96 | fputc(255, fout); 97 | } 98 | } 99 | int face[5]; 100 | face[0] = 4; 101 | for (int j = 0; j < nrows; j++) { 102 | int p = j * width; 103 | for (int i = 0; i < ncols; i++, p++) { 104 | face[1] = p; 105 | face[2] = p + 1; 106 | face[3] = p + hmap->width + 1; 107 | face[4] = p + hmap->width; 108 | fwrite(face, sizeof(face), 1, fout); 109 | } 110 | } 111 | fclose(fout); 112 | free(colordata); 113 | } 114 | 115 | void heman_export_u8( 116 | heman_image* source, HEMAN_FLOAT minv, HEMAN_FLOAT maxv, heman_byte* outp) 117 | { 118 | const HEMAN_FLOAT* inp = source->data; 119 | HEMAN_FLOAT scale = 1.0f / (maxv - minv); 120 | int size = source->height * source->width * source->nbands; 121 | for (int i = 0; i < size; ++i) { 122 | HEMAN_FLOAT v = 255 * (*inp++ - minv) * scale; 123 | *outp++ = CLAMP(v, 0, 255); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /kazmath/vec3.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef VEC3_H_INCLUDED 27 | #define VEC3_H_INCLUDED 28 | 29 | #include 30 | #include "utility.h" 31 | 32 | struct kmMat4; 33 | struct kmMat3; 34 | struct kmPlane; 35 | 36 | typedef struct kmVec3 { 37 | kmScalar x; 38 | kmScalar y; 39 | kmScalar z; 40 | } kmVec3; 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | kmVec3* kmVec3Fill(kmVec3* pOut, kmScalar x, kmScalar y, kmScalar z); 47 | kmScalar kmVec3Length(const kmVec3* pIn); /** Returns the length of the vector */ 48 | kmScalar kmVec3LengthSq(const kmVec3* pIn); /** Returns the square of the length of the vector */ 49 | kmVec3* kmVec3Lerp(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2, kmScalar t); 50 | kmVec3* kmVec3Normalize(kmVec3* pOut, const kmVec3* pIn); /** Returns the vector passed in set to unit length */ 51 | kmVec3* kmVec3Cross(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2); /** Returns a vector perpendicular to 2 other vectors */ 52 | kmScalar kmVec3Dot(const kmVec3* pV1, const kmVec3* pV2); /** Returns the cosine of the angle between 2 vectors */ 53 | kmVec3* kmVec3Add(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2); /** Adds 2 vectors and returns the result */ 54 | kmVec3* kmVec3Subtract(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2); /** Subtracts 2 vectors and returns the result */ 55 | kmVec3* kmVec3Mul( kmVec3* pOut,const kmVec3* pV1, const kmVec3* pV2 ); 56 | kmVec3* kmVec3Div( kmVec3* pOut,const kmVec3* pV1, const kmVec3* pV2 ); 57 | 58 | kmVec3* kmVec3MultiplyMat3(kmVec3 *pOut, const kmVec3 *pV, const struct kmMat3* pM); 59 | kmVec3* kmVec3MultiplyMat4(kmVec3* pOut, const kmVec3* pV, const struct kmMat4* pM); 60 | 61 | kmVec3* kmVec3Transform(kmVec3* pOut, const kmVec3* pV1, const struct kmMat4* pM); /** Transforms a vector (assuming w=1) by a given matrix */ 62 | kmVec3* kmVec3TransformNormal(kmVec3* pOut, const kmVec3* pV, const struct kmMat4* pM);/**Transforms a 3D normal by a given matrix */ 63 | kmVec3* kmVec3TransformCoord(kmVec3* pOut, const kmVec3* pV, const struct kmMat4* pM); /**Transforms a 3D vector by a given matrix, projecting the result back into w = 1. */ 64 | 65 | kmVec3* kmVec3Scale(kmVec3* pOut, const kmVec3* pIn, const kmScalar s); /** Scales a vector to length s */ 66 | int kmVec3AreEqual(const kmVec3* p1, const kmVec3* p2); 67 | kmVec3* kmVec3InverseTransform(kmVec3* pOut, const kmVec3* pV, const struct kmMat4* pM); 68 | kmVec3* kmVec3InverseTransformNormal(kmVec3* pOut, const kmVec3* pVect, const struct kmMat4* pM); 69 | kmVec3* kmVec3Assign(kmVec3* pOut, const kmVec3* pIn); 70 | kmVec3* kmVec3Zero(kmVec3* pOut); 71 | kmVec3* kmVec3GetHorizontalAngle(kmVec3* pOut, const kmVec3 *pIn); /** Get the rotations that would make a (0,0,1) direction vector point in the same direction as this direction vector. */ 72 | kmVec3* kmVec3RotationToDirection(kmVec3* pOut, const kmVec3* pIn, const kmVec3* forwards); /** Builds a direction vector from input vector. */ 73 | 74 | kmVec3* kmVec3ProjectOnToPlane(kmVec3* pOut, const kmVec3* point, const struct kmPlane* plane); 75 | 76 | kmVec3* kmVec3Reflect(kmVec3* pOut, const kmVec3* pIn, const kmVec3* normal); /**< Reflects a vector about a given surface normal. The surface normal is assumed to be of unit length. */ 77 | 78 | extern const kmVec3 KM_VEC3_NEG_Z; 79 | extern const kmVec3 KM_VEC3_POS_Z; 80 | extern const kmVec3 KM_VEC3_POS_Y; 81 | extern const kmVec3 KM_VEC3_NEG_Y; 82 | extern const kmVec3 KM_VEC3_NEG_X; 83 | extern const kmVec3 KM_VEC3_POS_X; 84 | extern const kmVec3 KM_VEC3_ZERO; 85 | 86 | #ifdef __cplusplus 87 | } 88 | #endif 89 | #endif /* VEC3_H_INCLUDED */ 90 | -------------------------------------------------------------------------------- /kazmath/quaternion.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef QUATERNION_H_INCLUDED 27 | #define QUATERNION_H_INCLUDED 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #include "utility.h" 34 | 35 | struct kmMat4; 36 | struct kmMat3; 37 | struct kmVec3; 38 | 39 | typedef struct kmQuaternion { 40 | kmScalar x; 41 | kmScalar y; 42 | kmScalar z; 43 | kmScalar w; 44 | } kmQuaternion; 45 | 46 | int kmQuaternionAreEqual(const kmQuaternion* p1, const kmQuaternion* p2); 47 | kmQuaternion* kmQuaternionFill(kmQuaternion* pOut, kmScalar x, kmScalar y, kmScalar z, kmScalar w); 48 | kmScalar kmQuaternionDot(const kmQuaternion* q1, const kmQuaternion* q2); /**< Returns the dot product of the 2 quaternions*/ 49 | 50 | kmQuaternion* kmQuaternionExp(kmQuaternion* pOut, const kmQuaternion* pIn); /**< Returns the exponential of the quaternion*/ 51 | 52 | /**< Makes the passed quaternion an identity quaternion*/ 53 | 54 | kmQuaternion* kmQuaternionIdentity(kmQuaternion* pOut); 55 | 56 | /**< Returns the inverse of the passed Quaternion*/ 57 | 58 | kmQuaternion* kmQuaternionInverse(kmQuaternion* pOut, const kmQuaternion* pIn); 59 | 60 | /**< Returns true if the quaternion is an identity quaternion*/ 61 | 62 | int kmQuaternionIsIdentity(const kmQuaternion* pIn); 63 | 64 | /**< Returns the length of the quaternion*/ 65 | 66 | kmScalar kmQuaternionLength(const kmQuaternion* pIn); 67 | 68 | /**< Returns the length of the quaternion squared (prevents a sqrt)*/ 69 | 70 | kmScalar kmQuaternionLengthSq(const kmQuaternion* pIn); 71 | 72 | /**< Returns the natural logarithm*/ 73 | 74 | kmQuaternion* kmQuaternionLn(kmQuaternion* pOut, const kmQuaternion* pIn); 75 | 76 | /**< Multiplies 2 quaternions together*/ 77 | 78 | kmQuaternion* kmQuaternionMultiply(kmQuaternion* pOut, const kmQuaternion* q1, const kmQuaternion* q2); 79 | 80 | /**< Normalizes a quaternion*/ 81 | 82 | kmQuaternion* kmQuaternionNormalize(kmQuaternion* pOut, const kmQuaternion* pIn); 83 | 84 | /**< Rotates a quaternion around an axis*/ 85 | 86 | kmQuaternion* kmQuaternionRotationAxisAngle(kmQuaternion* pOut, const struct kmVec3* pV, kmScalar angle); 87 | 88 | /**< Creates a quaternion from a rotation matrix*/ 89 | 90 | kmQuaternion* kmQuaternionRotationMatrix(kmQuaternion* pOut, const struct kmMat3* pIn); 91 | 92 | /**< Create a quaternion from yaw, pitch and roll*/ 93 | 94 | kmQuaternion* kmQuaternionRotationPitchYawRoll(kmQuaternion* pOut, kmScalar pitch, kmScalar yaw, kmScalar roll); 95 | /**< Interpolate between 2 quaternions*/ 96 | kmQuaternion* kmQuaternionSlerp(kmQuaternion* pOut, const kmQuaternion* q1, const kmQuaternion* q2, kmScalar t); 97 | 98 | /**< Get the axis and angle of rotation from a quaternion*/ 99 | void kmQuaternionToAxisAngle(const kmQuaternion* pIn, struct kmVec3* pVector, kmScalar* pAngle); 100 | 101 | /**< Scale a quaternion*/ 102 | kmQuaternion* kmQuaternionScale(kmQuaternion* pOut, const kmQuaternion* pIn, kmScalar s); 103 | kmQuaternion* kmQuaternionAssign(kmQuaternion* pOut, const kmQuaternion* pIn); 104 | kmQuaternion* kmQuaternionAdd(kmQuaternion* pOut, const kmQuaternion* pQ1, const kmQuaternion* pQ2); 105 | kmQuaternion* kmQuaternionSubtract(kmQuaternion* pOut, const kmQuaternion* pQ1, const kmQuaternion* pQ2); 106 | 107 | kmQuaternion* kmQuaternionRotationBetweenVec3(kmQuaternion* pOut, const struct kmVec3* vec1, const struct kmVec3* vec2, const struct kmVec3* fallback); 108 | struct kmVec3* kmQuaternionMultiplyVec3(struct kmVec3* pOut, const kmQuaternion* q, const struct kmVec3* v); 109 | 110 | kmVec3* kmQuaternionGetUpVec3(kmVec3* pOut, const kmQuaternion* pIn); 111 | kmVec3* kmQuaternionGetRightVec3(kmVec3* pOut, const kmQuaternion* pIn); 112 | kmVec3* kmQuaternionGetForwardVec3RH(kmVec3* pOut, const kmQuaternion* pIn); 113 | kmVec3* kmQuaternionGetForwardVec3LH(kmVec3* pOut, const kmQuaternion* pIn); 114 | 115 | kmScalar kmQuaternionGetPitch(const kmQuaternion* q); 116 | kmScalar kmQuaternionGetYaw(const kmQuaternion* q); 117 | kmScalar kmQuaternionGetRoll(const kmQuaternion* q); 118 | 119 | kmQuaternion* kmQuaternionLookRotation(kmQuaternion* pOut, const kmVec3* direction, const kmVec3* up); 120 | 121 | #ifdef __cplusplus 122 | } 123 | #endif 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /src/draw.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | 5 | void heman_draw_points(heman_image* target, heman_points* pts, HEMAN_FLOAT val) 6 | { 7 | HEMAN_FLOAT* src = pts->data; 8 | for (int k = 0; k < pts->width; k++) { 9 | HEMAN_FLOAT x = src[0]; 10 | HEMAN_FLOAT y = src[1]; 11 | src += pts->nbands; 12 | int i = x * target->width; 13 | int j = y * target->height; 14 | if (i < 0 || i >= target->width || j < 0 || j >= target->height) { 15 | continue; 16 | } 17 | HEMAN_FLOAT* texel = heman_image_texel(target, i, j); 18 | for (int c = 0; c < target->nbands; c++) { 19 | *texel++ = val; 20 | } 21 | } 22 | } 23 | 24 | void heman_draw_colored_points( 25 | heman_image* target, heman_points* pts, const heman_color* colors) 26 | { 27 | assert(target->nbands == 3 || target->nbands == 4); 28 | HEMAN_FLOAT* src = pts->data; 29 | HEMAN_FLOAT inv = 1.0f / 255.0f; 30 | for (int k = 0; k < pts->width; k++) { 31 | HEMAN_FLOAT x = src[0]; 32 | HEMAN_FLOAT y = src[1]; 33 | src += pts->nbands; 34 | int i = x * target->width; 35 | int j = y * target->height; 36 | if (i < 0 || i >= target->width || j < 0 || j >= target->height) { 37 | continue; 38 | } 39 | HEMAN_FLOAT* texel = heman_image_texel(target, i, j); 40 | heman_color rgb = colors[k]; 41 | *texel++ = (HEMAN_FLOAT)((rgb >> 16) & 0xff) * inv; 42 | *texel++ = (HEMAN_FLOAT)((rgb >> 8) & 0xff) * inv; 43 | *texel++ = (HEMAN_FLOAT)(rgb & 0xff) * inv; 44 | if (target->nbands == 4) { 45 | *texel = (HEMAN_FLOAT)(rgb >> 24) * inv; 46 | } 47 | } 48 | } 49 | 50 | void heman_draw_colored_circles(heman_image* target, heman_points* pts, 51 | int radius, const heman_color* colors) 52 | { 53 | int fwidth = radius * 2 + 1; 54 | int radius2 = radius * radius; 55 | HEMAN_FLOAT* src = pts->data; 56 | HEMAN_FLOAT inv = 1.0f / 255.0f; 57 | int w = target->width; 58 | int h = target->height; 59 | for (int k = 0; k < pts->width; k++) { 60 | HEMAN_FLOAT x = src[0]; 61 | HEMAN_FLOAT y = src[1]; 62 | src += pts->nbands; 63 | int ii = x * w - radius; 64 | int jj = y * h - radius; 65 | for (int kj = 0; kj < fwidth; kj++) { 66 | for (int ki = 0; ki < fwidth; ki++) { 67 | int i = ii + ki; 68 | int j = jj + kj; 69 | int r2 = SQR(i - x * w) + SQR(j - y * h); 70 | if (r2 > radius2) { 71 | continue; 72 | } 73 | HEMAN_FLOAT* texel = heman_image_texel(target, i, j); 74 | heman_color rgb = colors[k]; 75 | *texel++ = (HEMAN_FLOAT)(rgb >> 16) * inv; 76 | *texel++ = (HEMAN_FLOAT)((rgb >> 8) & 0xff) * inv; 77 | *texel = (HEMAN_FLOAT)(rgb & 0xff) * inv; 78 | } 79 | } 80 | } 81 | } 82 | 83 | void heman_draw_splats( 84 | heman_image* target, heman_points* pts, int radius, int blend_mode) 85 | { 86 | int fwidth = radius * 2 + 1; 87 | HEMAN_FLOAT* gaussian_splat = malloc(fwidth * fwidth * sizeof(HEMAN_FLOAT)); 88 | generate_gaussian_splat(gaussian_splat, fwidth); 89 | HEMAN_FLOAT* src = pts->data; 90 | int w = target->width; 91 | int h = target->height; 92 | for (int i = 0; i < pts->width; i++) { 93 | HEMAN_FLOAT x = *src++; 94 | HEMAN_FLOAT y = *src++; 95 | int ii = x * w - radius; 96 | int jj = y * h - radius; 97 | for (int kj = 0; kj < fwidth; kj++) { 98 | for (int ki = 0; ki < fwidth; ki++) { 99 | int i = ii + ki; 100 | int j = jj + kj; 101 | if (i < 0 || i >= w || j < 0 || j >= h) { 102 | continue; 103 | } 104 | HEMAN_FLOAT* texel = heman_image_texel(target, i, j); 105 | for (int c = 0; c < target->nbands; c++) { 106 | *texel++ += gaussian_splat[kj * fwidth + ki]; 107 | } 108 | } 109 | } 110 | } 111 | free(gaussian_splat); 112 | } 113 | 114 | void heman_internal_draw_seeds(heman_image* target, heman_points* pts, int filterd); 115 | 116 | void heman_draw_contour_from_points(heman_image* target, heman_points* coords, 117 | heman_color rgb, float mind, float maxd, int filterd) 118 | { 119 | assert(target->nbands == 3 || target->nbands == 4); 120 | int width = target->width; 121 | int height = target->height; 122 | heman_image* seed = heman_image_create(width, height, 1); 123 | heman_image_clear(seed, 0); 124 | 125 | heman_internal_draw_seeds(seed, coords, filterd); 126 | 127 | HEMAN_FLOAT inv = 1.0f / 255.0f; 128 | HEMAN_FLOAT r = (HEMAN_FLOAT)((rgb >> 16) & 0xff) * inv; 129 | HEMAN_FLOAT g = (HEMAN_FLOAT)((rgb >> 8) & 0xff) * inv; 130 | HEMAN_FLOAT b = (HEMAN_FLOAT)(rgb & 0xff) * inv; 131 | HEMAN_FLOAT a = 1; 132 | if (target->nbands == 4) { 133 | a = (HEMAN_FLOAT)(rgb >> 24) * inv; 134 | } 135 | 136 | int y; 137 | #pragma omp parallel for 138 | for (y = 0; y < height; y++) { 139 | HEMAN_FLOAT* dst = target->data + y * width * target->nbands; 140 | for (int x = 0; x < width; x++) { 141 | HEMAN_FLOAT dist = *heman_image_texel(seed, x, y); 142 | if (dist > mind && dist < maxd) { 143 | dst[0] = r; 144 | dst[1] = g; 145 | dst[2] = b; 146 | if (target->nbands == 4) { 147 | dst[3] = a; 148 | } 149 | } 150 | dst += target->nbands; 151 | } 152 | } 153 | 154 | heman_points_destroy(seed); 155 | } 156 | -------------------------------------------------------------------------------- /src/color.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | #include 5 | 6 | float _gamma = 2.2f; 7 | 8 | void heman_color_set_gamma(float g) { _gamma = g; } 9 | 10 | heman_image* heman_color_create_gradient(int width, int num_colors, 11 | const int* cp_locations, const heman_color* cp_values) 12 | { 13 | assert(width > 0 && num_colors >= 2); 14 | assert(cp_locations[0] == 0); 15 | assert(cp_locations[num_colors - 1] == width - 1); 16 | 17 | // Convert incoming colors to HEMAN_FLOATs and decode gamma. 18 | HEMAN_FLOAT* f32colors = malloc(sizeof(HEMAN_FLOAT) * 3 * num_colors); 19 | HEMAN_FLOAT inv = 1.0f / 255.0f; 20 | HEMAN_FLOAT* f32color = f32colors; 21 | const heman_color* u32color = cp_values; 22 | for (int index = 0; index < num_colors; index++) { 23 | heman_color rgb = *u32color++; 24 | HEMAN_FLOAT r = (HEMAN_FLOAT)(rgb >> 16) * inv; 25 | HEMAN_FLOAT g = (HEMAN_FLOAT)((rgb >> 8) & 0xff) * inv; 26 | HEMAN_FLOAT b = (HEMAN_FLOAT)(rgb & 0xff) * inv; 27 | *f32color++ = pow(r, _gamma); 28 | *f32color++ = pow(g, _gamma); 29 | *f32color++ = pow(b, _gamma); 30 | } 31 | 32 | // Create and populate a width x 1 image. 33 | heman_image* result = heman_image_create(width, 1, 3); 34 | int index0 = 0; 35 | int index1 = 1; 36 | HEMAN_FLOAT* dst = result->data; 37 | HEMAN_FLOAT t, invgamma = 1.0f / _gamma; 38 | for (int x = 0; x < width; x++) { 39 | int loc0 = cp_locations[index0]; 40 | int loc1 = cp_locations[index1]; 41 | if (loc0 == loc1) { 42 | t = 0; 43 | } else { 44 | t = (x - loc0) / (HEMAN_FLOAT)(loc1 - loc0); 45 | if (t >= 1) { 46 | --x; 47 | ++index0; 48 | index1 = MIN(index1 + 1, num_colors - 1); 49 | continue; 50 | } 51 | } 52 | HEMAN_FLOAT r0 = f32colors[index0 * 3]; 53 | HEMAN_FLOAT g0 = f32colors[index0 * 3 + 1]; 54 | HEMAN_FLOAT b0 = f32colors[index0 * 3 + 2]; 55 | HEMAN_FLOAT r1 = f32colors[index1 * 3]; 56 | HEMAN_FLOAT g1 = f32colors[index1 * 3 + 1]; 57 | HEMAN_FLOAT b1 = f32colors[index1 * 3 + 2]; 58 | HEMAN_FLOAT invt = 1.0f - t; 59 | HEMAN_FLOAT r = (r0 * invt) + (r1 * t); 60 | HEMAN_FLOAT g = (g0 * invt) + (g1 * t); 61 | HEMAN_FLOAT b = (b0 * invt) + (b1 * t); 62 | *dst++ = pow(r, invgamma); 63 | *dst++ = pow(g, invgamma); 64 | *dst++ = pow(b, invgamma); 65 | } 66 | 67 | free(f32colors); 68 | return result; 69 | } 70 | 71 | heman_image* heman_color_apply_gradient(heman_image* heightmap, 72 | HEMAN_FLOAT minheight, HEMAN_FLOAT maxheight, heman_image* gradient) 73 | { 74 | assert(heightmap->nbands == 1); 75 | assert(gradient->height == 1); 76 | assert(gradient->nbands == 3); 77 | int w = heightmap->width; 78 | int h = heightmap->height; 79 | heman_image* result = heman_image_create(w, h, 3); 80 | int size = result->height * result->width; 81 | HEMAN_FLOAT* dst = result->data; 82 | const HEMAN_FLOAT* src = heightmap->data; 83 | HEMAN_FLOAT scale = 1.0f / (maxheight - minheight); 84 | for (int i = 0; i < size; i++, dst += 3, src++) { 85 | HEMAN_FLOAT u = CLAMP01((*src - minheight) * scale); 86 | heman_image_sample(gradient, u, 0.5f, dst); 87 | } 88 | return result; 89 | } 90 | 91 | heman_image* heman_color_from_grayscale(heman_image* grayscale) 92 | { 93 | assert(grayscale->nbands == 1); 94 | int w = grayscale->width; 95 | int h = grayscale->height; 96 | heman_image* result = heman_image_create(w, h, 3); 97 | int size = w * h; 98 | HEMAN_FLOAT* dst = result->data; 99 | const HEMAN_FLOAT* src = grayscale->data; 100 | for (int i = 0; i < size; i++) { 101 | HEMAN_FLOAT v = *src++; 102 | *dst++ = v; 103 | *dst++ = v; 104 | *dst++ = v; 105 | } 106 | return result; 107 | } 108 | 109 | heman_image* heman_color_to_grayscale(heman_image* colorimg) 110 | { 111 | assert(colorimg->nbands == 3); 112 | int w = colorimg->width; 113 | int h = colorimg->height; 114 | heman_image* result = heman_image_create(w, h, 1); 115 | int size = w * h; 116 | HEMAN_FLOAT* dst = result->data; 117 | const HEMAN_FLOAT* src = colorimg->data; 118 | for (int i = 0; i < size; i++) { 119 | HEMAN_FLOAT r = *src++; 120 | HEMAN_FLOAT g = *src++; 121 | HEMAN_FLOAT b = *src++; 122 | *dst++ = 0.299 * r + 0.587 * g + 0.114 * b; 123 | } 124 | return result; 125 | } 126 | 127 | heman_image* heman_internal_rg(heman_image* cfield) 128 | { 129 | assert(cfield->nbands == 2); 130 | int w = cfield->width; 131 | int h = cfield->height; 132 | heman_image* target = heman_image_create(w, h, 3); 133 | HEMAN_FLOAT* dst = target->data; 134 | HEMAN_FLOAT* src = cfield->data; 135 | int size = w * h; 136 | for (int i = 0; i < size; i++) { 137 | HEMAN_FLOAT u = *src++ / w; 138 | HEMAN_FLOAT v = *src++ / h; 139 | *dst++ = u; 140 | *dst++ = v; 141 | *dst++ = 0; 142 | } 143 | return target; 144 | } 145 | 146 | heman_image* heman_color_from_cpcf(heman_image* cfield, heman_image* texture) 147 | { 148 | if (!texture) { 149 | return heman_internal_rg(cfield); 150 | } 151 | assert(cfield->nbands == 2); 152 | assert(texture->nbands == 3 || texture->nbands == 4); 153 | assert(cfield->width == texture->width); 154 | assert(cfield->height == texture->height); 155 | int w = cfield->width; 156 | int h = cfield->height; 157 | heman_image* target = heman_image_create(w, h, texture->nbands); 158 | HEMAN_FLOAT* dst = target->data; 159 | HEMAN_FLOAT* src = cfield->data; 160 | int size = w * h; 161 | for (int i = 0; i < size; i++) { 162 | HEMAN_FLOAT u = *src++; 163 | HEMAN_FLOAT v = *src++; 164 | HEMAN_FLOAT* texel = heman_image_texel(texture, u, v); 165 | for (int c = 0; c < texture->nbands; c++) { 166 | *dst++ = *texel++; 167 | } 168 | } 169 | return target; 170 | } 171 | -------------------------------------------------------------------------------- /kazmath/aabb3.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "aabb3.h" 27 | 28 | 29 | /** 30 | Initializes the AABB around a central point. If centre is NULL then the origin 31 | is used. Returns pBox. 32 | */ 33 | kmAABB3* kmAABB3Initialize(kmAABB3* pBox, const kmVec3* centre, const kmScalar width, const kmScalar height, const kmScalar depth) { 34 | if(!pBox) return 0; 35 | 36 | kmVec3 origin; 37 | kmVec3* point = centre ? (kmVec3*) centre : &origin; 38 | kmVec3Zero(&origin); 39 | 40 | pBox->min.x = point->x - (width / 2); 41 | pBox->min.y = point->y - (height / 2); 42 | pBox->min.z = point->z - (depth / 2); 43 | 44 | pBox->max.x = point->x + (width / 2); 45 | pBox->max.y = point->y + (height / 2); 46 | pBox->max.z = point->z + (depth / 2); 47 | 48 | return pBox; 49 | } 50 | 51 | /** 52 | * Returns KM_TRUE if point is in the specified AABB, returns 53 | * KM_FALSE otherwise. 54 | */ 55 | int kmAABB3ContainsPoint(const kmAABB3* pBox, const kmVec3* pPoint) 56 | { 57 | if(pPoint->x >= pBox->min.x && pPoint->x <= pBox->max.x && 58 | pPoint->y >= pBox->min.y && pPoint->y <= pBox->max.y && 59 | pPoint->z >= pBox->min.z && pPoint->z <= pBox->max.z) { 60 | return KM_TRUE; 61 | } 62 | 63 | return KM_FALSE; 64 | } 65 | 66 | /** 67 | * Assigns pIn to pOut, returns pOut. 68 | */ 69 | kmAABB3* kmAABB3Assign(kmAABB3* pOut, const kmAABB3* pIn) 70 | { 71 | kmVec3Assign(&pOut->min, &pIn->min); 72 | kmVec3Assign(&pOut->max, &pIn->max); 73 | return pOut; 74 | } 75 | 76 | /** 77 | * Scales pIn by s, stores the resulting AABB in pOut. Returns pOut 78 | */ 79 | kmAABB3* kmAABB3Scale(kmAABB3* pOut, const kmAABB3* pIn, kmScalar s) 80 | { 81 | assert(0 && "Not implemented"); 82 | return pOut; 83 | } 84 | 85 | kmBool kmAABB3IntersectsTriangle(kmAABB3* box, const kmVec3* p1, const kmVec3* p2, const kmVec3* p3) { 86 | assert(0 && "Not implemented"); 87 | return KM_TRUE; 88 | } 89 | 90 | kmBool kmAABB3IntersectsAABB(const kmAABB3* box, const kmAABB3* other) { 91 | return kmAABB3ContainsAABB(box, other) != KM_CONTAINS_NONE; 92 | } 93 | 94 | kmEnum kmAABB3ContainsAABB(const kmAABB3* container, const kmAABB3* to_check) { 95 | kmVec3 corners[8]; 96 | kmEnum result = KM_CONTAINS_ALL; 97 | kmBool found = KM_FALSE; 98 | 99 | kmVec3Fill(&corners[0], to_check->min.x, to_check->min.y, to_check->min.z); 100 | kmVec3Fill(&corners[1], to_check->max.x, to_check->min.y, to_check->min.z); 101 | kmVec3Fill(&corners[2], to_check->max.x, to_check->max.y, to_check->min.z); 102 | kmVec3Fill(&corners[3], to_check->min.x, to_check->max.y, to_check->min.z); 103 | kmVec3Fill(&corners[4], to_check->min.x, to_check->min.y, to_check->max.z); 104 | kmVec3Fill(&corners[5], to_check->max.x, to_check->min.y, to_check->max.z); 105 | kmVec3Fill(&corners[6], to_check->max.x, to_check->max.y, to_check->max.z); 106 | kmVec3Fill(&corners[7], to_check->min.x, to_check->max.y, to_check->max.z); 107 | 108 | for(kmUchar i = 0; i < 8; ++i) { 109 | if(!kmAABB3ContainsPoint(container, &corners[i])) { 110 | result = KM_CONTAINS_PARTIAL; 111 | if(found) { 112 | /*If we previously found a corner that was within the container*/ 113 | /*We know that partial is the final result*/ 114 | return result; 115 | } 116 | } else { 117 | found = KM_TRUE; 118 | } 119 | } 120 | 121 | if(!found) { 122 | result = KM_CONTAINS_NONE; 123 | } 124 | 125 | return result; 126 | } 127 | 128 | kmScalar kmAABB3DiameterX(const kmAABB3* aabb) { 129 | return fabs(aabb->max.x - aabb->min.x); 130 | } 131 | 132 | kmScalar kmAABB3DiameterY(const kmAABB3* aabb) { 133 | return fabs(aabb->max.y - aabb->min.y); 134 | } 135 | 136 | kmScalar kmAABB3DiameterZ(const kmAABB3* aabb) { 137 | return fabs(aabb->max.z - aabb->min.z); 138 | } 139 | 140 | kmVec3* kmAABB3Centre(const kmAABB3* aabb, kmVec3* pOut) { 141 | kmVec3Add(pOut, &aabb->min, &aabb->max); 142 | kmVec3Scale(pOut, pOut, 0.5); 143 | return pOut; 144 | } 145 | 146 | /** 147 | * @brief kmAABB3ExpandToContain 148 | * @param pOut - The resulting AABB 149 | * @param pIn - The original AABB 150 | * @param other - Another AABB that you want pIn expanded to contain 151 | * @return 152 | */ 153 | kmAABB3* kmAABB3ExpandToContain(kmAABB3* pOut, const kmAABB3* pIn, const kmAABB3* other) { 154 | kmAABB3 result; 155 | 156 | result.min.x = (pIn->min.x < other->min.x)?pIn->min.x:other->min.x; 157 | result.max.x = (pIn->max.x > other->max.x)?pIn->max.x:other->max.x; 158 | result.min.y = (pIn->min.y < other->min.y)?pIn->min.y:other->min.y; 159 | result.max.y = (pIn->max.y > other->max.y)?pIn->max.y:other->max.y; 160 | result.min.z = (pIn->min.z < other->min.z)?pIn->min.z:other->min.z; 161 | result.max.z = (pIn->max.z > other->max.z)?pIn->max.z:other->max.z; 162 | 163 | kmAABB3Assign(pOut, &result); 164 | 165 | return pOut; 166 | } 167 | -------------------------------------------------------------------------------- /kazmath/aabb2.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "aabb2.h" 27 | 28 | 29 | /** 30 | Initializes the AABB around a central point. If centre is NULL then the origin 31 | is used. Returns pBox. 32 | */ 33 | kmAABB2* kmAABB2Initialize( kmAABB2* pBox, const kmVec2* centre, const kmScalar width, const kmScalar height, const kmScalar depth) { 34 | if(!pBox) return 0; 35 | 36 | kmVec2 origin; 37 | kmVec2* point = centre ? (kmVec2*) centre : &origin; 38 | kmVec2Fill(&origin, .0f, .0f); 39 | 40 | pBox->min.x = point->x - (width / 2); 41 | pBox->min.y = point->y - (height / 2); 42 | 43 | pBox->max.x = point->x + (width / 2); 44 | pBox->max.y = point->y + (height / 2); 45 | 46 | return pBox; 47 | } 48 | 49 | /** 50 | * Makes sure that min corresponds to the minimum values and max 51 | * to the maximum 52 | */ 53 | kmAABB2* kmAABB2Sanitize(kmAABB2* pOut, const kmAABB2* pIn) 54 | { 55 | if( pIn->min.x <= pIn->max.x ){ 56 | pOut->min.x = pIn->min.x; 57 | pOut->max.x = pIn->max.x; 58 | }else{ 59 | pOut->min.x = pIn->max.x; 60 | pOut->max.x = pIn->min.x; 61 | } 62 | 63 | if( pIn->min.y <= pIn->max.y ){ 64 | pOut->min.y = pIn->min.y; 65 | pOut->max.y = pIn->max.y; 66 | }else{ 67 | pOut->min.y = pIn->max.y; 68 | pOut->max.y = pIn->min.y; 69 | } 70 | 71 | return pOut; 72 | } 73 | 74 | /** 75 | * Returns KM_TRUE if point is in the specified AABB, returns 76 | * KM_FALSE otherwise. 77 | */ 78 | int kmAABB2ContainsPoint(const kmAABB2* pBox, const kmVec2* pPoint) 79 | { 80 | if(pPoint->x >= pBox->min.x && pPoint->x <= pBox->max.x && 81 | pPoint->y >= pBox->min.y && pPoint->y <= pBox->max.y ) { 82 | return KM_TRUE; 83 | } 84 | 85 | return KM_FALSE; 86 | } 87 | 88 | /** 89 | * Assigns pIn to pOut, returns pOut. 90 | */ 91 | kmAABB2* kmAABB2Assign(kmAABB2* pOut, const kmAABB2* pIn) 92 | { 93 | kmVec2Assign(&pOut->min, &pIn->min); 94 | kmVec2Assign(&pOut->max, &pIn->max); 95 | return pOut; 96 | } 97 | 98 | kmAABB2* kmAABB2Translate( kmAABB2* pOut, const kmAABB2* pIn, const kmVec2 *translation ) 99 | { 100 | kmVec2Add( &(pOut->min), &(pIn->min), translation ); 101 | kmVec2Add( &(pOut->max), &(pIn->max), translation ); 102 | return pOut; 103 | } 104 | 105 | /** 106 | * Scales pIn by s, stores the resulting AABB in pOut. Returns pOut. 107 | * It modifies both points, so position of the box will be changed. Use 108 | * kmAABB2ScaleWithPivot to specify the origin of the scale. 109 | */ 110 | kmAABB2* kmAABB2Scale(kmAABB2* pOut, const kmAABB2* pIn, kmScalar s) 111 | { 112 | kmVec2Scale( &(pOut->max), &(pIn->max), s ); 113 | kmVec2Scale( &(pOut->min), &(pIn->min), s ); 114 | return pOut; 115 | } 116 | 117 | /** 118 | * Scales pIn by s, using pivot as the origin for the scale. 119 | */ 120 | kmAABB2* kmAABB2ScaleWithPivot( kmAABB2* pOut, const kmAABB2* pIn, const kmVec2 *pivot, kmScalar s ) 121 | { 122 | kmVec2 translate; 123 | translate.x = -pivot->x; 124 | translate.y = -pivot->y; 125 | 126 | kmAABB2Translate( pOut, pIn, &translate ); 127 | kmAABB2Scale( pOut, pIn, s ); 128 | kmAABB2Translate( pOut, pIn, pivot ); 129 | 130 | return pOut; 131 | } 132 | 133 | kmEnum kmAABB2ContainsAABB(const kmAABB2* container, const kmAABB2* to_check) { 134 | kmVec2 corners[4]; 135 | kmVec2Fill(&corners[0], to_check->min.x, to_check->min.y); 136 | kmVec2Fill(&corners[1], to_check->max.x, to_check->min.y); 137 | kmVec2Fill(&corners[2], to_check->max.x, to_check->max.y); 138 | kmVec2Fill(&corners[3], to_check->min.x, to_check->max.y); 139 | 140 | // since KM_TRUE equals 1 , we can count the number of contained points 141 | // by actually adding the results: 142 | int nContains = kmAABB2ContainsPoint( container, &corners[0] ) + 143 | kmAABB2ContainsPoint( container, &corners[1] ) + 144 | kmAABB2ContainsPoint( container, &corners[2] ) + 145 | kmAABB2ContainsPoint( container, &corners[3] ); 146 | 147 | if( nContains == 0 ){ 148 | return KM_CONTAINS_NONE; 149 | }else if( nContains < 4 ){ 150 | return KM_CONTAINS_PARTIAL; 151 | }else{ 152 | return KM_CONTAINS_ALL; 153 | } 154 | } 155 | 156 | kmScalar kmAABB2DiameterX(const kmAABB2* aabb) { 157 | return aabb->max.x - aabb->min.x; 158 | } 159 | 160 | kmScalar kmAABB2DiameterY(const kmAABB2* aabb) { 161 | return aabb->max.y - aabb->min.y; 162 | } 163 | 164 | kmVec2* kmAABB2Centre(const kmAABB2* aabb, kmVec2* pOut) { 165 | kmVec2Add(pOut, &aabb->min, &aabb->max); 166 | kmVec2Scale(pOut, pOut, 0.5); 167 | return pOut; 168 | } 169 | 170 | /** 171 | * @brief kmAABB2ExpandToContain 172 | * @param pOut - The resulting AABB 173 | * @param pIn - The original AABB 174 | * @param other - Another AABB that you want pIn expanded to contain 175 | * @return 176 | */ 177 | kmAABB2* kmAABB2ExpandToContain(kmAABB2* pOut, const kmAABB2* pIn, const kmAABB2* other) { 178 | kmAABB2 result; 179 | 180 | result.min.x = (pIn->min.x < other->min.x)?pIn->min.x:other->min.x; 181 | result.max.x = (pIn->max.x > other->max.x)?pIn->max.x:other->max.x; 182 | result.min.y = (pIn->min.y < other->min.y)?pIn->min.y:other->min.y; 183 | result.max.y = (pIn->max.y > other->max.y)?pIn->max.y:other->max.y; 184 | 185 | kmAABB2Assign(pOut, &result); 186 | 187 | return pOut; 188 | } -------------------------------------------------------------------------------- /kazmath/vec4.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | #include 28 | #include 29 | 30 | #include "utility.h" 31 | #include "vec4.h" 32 | #include "mat4.h" 33 | 34 | 35 | kmVec4* kmVec4Fill(kmVec4* pOut, kmScalar x, kmScalar y, kmScalar z, kmScalar w) 36 | { 37 | pOut->x = x; 38 | pOut->y = y; 39 | pOut->z = z; 40 | pOut->w = w; 41 | return pOut; 42 | } 43 | 44 | 45 | /** Adds 2 4D vectors together. The result is store in pOut, the function returns*/ 46 | /** pOut so that it can be nested in another function.*/ 47 | kmVec4* kmVec4Add(kmVec4* pOut, const kmVec4* pV1, const kmVec4* pV2) { 48 | pOut->x = pV1->x + pV2->x; 49 | pOut->y = pV1->y + pV2->y; 50 | pOut->z = pV1->z + pV2->z; 51 | pOut->w = pV1->w + pV2->w; 52 | 53 | return pOut; 54 | } 55 | 56 | /** Returns the dot product of 2 4D vectors*/ 57 | kmScalar kmVec4Dot(const kmVec4* pV1, const kmVec4* pV2) { 58 | return ( pV1->x * pV2->x 59 | + pV1->y * pV2->y 60 | + pV1->z * pV2->z 61 | + pV1->w * pV2->w ); 62 | } 63 | 64 | /** Returns the length of a 4D vector, this uses a sqrt so if the squared length will do use*/ 65 | /** kmVec4LengthSq*/ 66 | kmScalar kmVec4Length(const kmVec4* pIn) { 67 | return sqrtf(kmSQR(pIn->x) + kmSQR(pIn->y) + kmSQR(pIn->z) + kmSQR(pIn->w)); 68 | } 69 | 70 | /** Returns the length of the 4D vector squared.*/ 71 | kmScalar kmVec4LengthSq(const kmVec4* pIn) { 72 | return kmSQR(pIn->x) + kmSQR(pIn->y) + kmSQR(pIn->z) + kmSQR(pIn->w); 73 | } 74 | 75 | /** Returns the interpolation of 2 4D vectors based on t.*/ 76 | kmVec4* kmVec4Lerp(kmVec4* pOut, const kmVec4* pV1, const kmVec4* pV2, kmScalar t) { 77 | pOut->x = pV1->x + t * ( pV2->x - pV1->x ); 78 | pOut->y = pV1->y + t * ( pV2->y - pV1->y ); 79 | pOut->z = pV1->z + t * ( pV2->z - pV1->z ); 80 | pOut->w = pV1->w + t * ( pV2->w - pV1->w ); 81 | return pOut; 82 | } 83 | 84 | /** Normalizes a 4D vector. The result is stored in pOut. pOut is returned*/ 85 | kmVec4* kmVec4Normalize(kmVec4* pOut, const kmVec4* pIn) { 86 | if (!pIn->x && !pIn->y && !pIn->z && !pIn->w){ 87 | return kmVec4Assign(pOut, pIn); 88 | } 89 | 90 | kmScalar l = 1.0f / kmVec4Length(pIn); 91 | pOut->x = pIn->x * l; 92 | pOut->y = pIn->y * l; 93 | pOut->z = pIn->z * l; 94 | pOut->w = pIn->w * l; 95 | 96 | return pOut; 97 | } 98 | 99 | /** Scales a vector to the required length. This performs a Normalize before multiplying by S.*/ 100 | kmVec4* kmVec4Scale(kmVec4* pOut, const kmVec4* pIn, const kmScalar s) { 101 | kmVec4Normalize(pOut, pIn); 102 | 103 | pOut->x *= s; 104 | pOut->y *= s; 105 | pOut->z *= s; 106 | pOut->w *= s; 107 | return pOut; 108 | } 109 | 110 | /** Subtracts one 4D pV2 from pV1. The result is stored in pOut. pOut is returned*/ 111 | kmVec4* kmVec4Subtract(kmVec4* pOut, const kmVec4* pV1, const kmVec4* pV2) { 112 | pOut->x = pV1->x - pV2->x; 113 | pOut->y = pV1->y - pV2->y; 114 | pOut->z = pV1->z - pV2->z; 115 | pOut->w = pV1->w - pV2->w; 116 | 117 | return pOut; 118 | } 119 | 120 | kmVec4* kmVec4Mul( kmVec4* pOut,const kmVec4* pV1, const kmVec4* pV2 ) { 121 | pOut->x = pV1->x * pV2->x; 122 | pOut->y = pV1->y * pV2->y; 123 | pOut->z = pV1->z * pV2->z; 124 | pOut->w = pV1->w * pV2->w; 125 | return pOut; 126 | } 127 | 128 | kmVec4* kmVec4Div( kmVec4* pOut,const kmVec4* pV1, const kmVec4* pV2 ) { 129 | if ( pV2->x && pV2->y && pV2->z && pV2->w){ 130 | pOut->x = pV1->x / pV2->x; 131 | pOut->y = pV1->y / pV2->y; 132 | pOut->z = pV1->z / pV2->z; 133 | pOut->w = pV1->w / pV2->w; 134 | } 135 | return pOut; 136 | } 137 | 138 | /** Multiplies a 4D vector by a matrix, the result is stored in pOut, and pOut is returned.*/ 139 | kmVec4* kmVec4MultiplyMat4(kmVec4* pOut, const kmVec4* pV, const struct kmMat4* pM) { 140 | pOut->x = pV->x * pM->mat[0] + pV->y * pM->mat[4] + pV->z * pM->mat[8] + pV->w * pM->mat[12]; 141 | pOut->y = pV->x * pM->mat[1] + pV->y * pM->mat[5] + pV->z * pM->mat[9] + pV->w * pM->mat[13]; 142 | pOut->z = pV->x * pM->mat[2] + pV->y * pM->mat[6] + pV->z * pM->mat[10] + pV->w * pM->mat[14]; 143 | pOut->w = pV->x * pM->mat[3] + pV->y * pM->mat[7] + pV->z * pM->mat[11] + pV->w * pM->mat[15]; 144 | return pOut; 145 | } 146 | 147 | kmVec4* kmVec4Transform(kmVec4* pOut, const kmVec4* pV, const kmMat4* pM) { 148 | return kmVec4MultiplyMat4(pOut, pV, pM); 149 | } 150 | 151 | /** Loops through an input array transforming each vec4 by the matrix.*/ 152 | kmVec4* kmVec4TransformArray(kmVec4* pOut, unsigned int outStride, 153 | const kmVec4* pV, unsigned int vStride, const kmMat4* pM, unsigned int count) { 154 | unsigned int i = 0; 155 | /*Go through all of the vectors*/ 156 | while (i < count) { 157 | const kmVec4* in = pV + (i * vStride); /*Get a pointer to the current input*/ 158 | kmVec4* out = pOut + (i * outStride); /*and the current output*/ 159 | kmVec4Transform(out, in, pM); /*Perform transform on it*/ 160 | ++i; 161 | } 162 | 163 | return pOut; 164 | } 165 | 166 | int kmVec4AreEqual(const kmVec4* p1, const kmVec4* p2) { 167 | return ( 168 | (p1->x < p2->x + kmEpsilon && p1->x > p2->x - kmEpsilon) && 169 | (p1->y < p2->y + kmEpsilon && p1->y > p2->y - kmEpsilon) && 170 | (p1->z < p2->z + kmEpsilon && p1->z > p2->z - kmEpsilon) && 171 | (p1->w < p2->w + kmEpsilon && p1->w > p2->w - kmEpsilon) 172 | ); 173 | } 174 | 175 | kmVec4* kmVec4Assign(kmVec4* pOut, const kmVec4* pIn) { 176 | assert(pOut != pIn); 177 | 178 | memcpy(pOut, pIn, sizeof(kmScalar) * 4); 179 | 180 | return pOut; 181 | } 182 | 183 | -------------------------------------------------------------------------------- /kazmath/vec2.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include "mat3.h" 30 | #include "vec2.h" 31 | #include "utility.h" 32 | 33 | const kmVec2 KM_VEC2_POS_Y = { 0, 1 }; 34 | const kmVec2 KM_VEC2_NEG_Y = { 0, -1 }; 35 | const kmVec2 KM_VEC2_NEG_X = { -1, 0 }; 36 | const kmVec2 KM_VEC2_POS_X = { 1, 0 }; 37 | const kmVec2 KM_VEC2_ZERO = { 0, 0 }; 38 | 39 | kmVec2* kmVec2Fill(kmVec2* pOut, kmScalar x, kmScalar y) 40 | { 41 | pOut->x = x; 42 | pOut->y = y; 43 | return pOut; 44 | } 45 | 46 | kmScalar kmVec2Length(const kmVec2* pIn) 47 | { 48 | return sqrtf(kmSQR(pIn->x) + kmSQR(pIn->y)); 49 | } 50 | 51 | kmScalar kmVec2LengthSq(const kmVec2* pIn) 52 | { 53 | return kmSQR(pIn->x) + kmSQR(pIn->y); 54 | } 55 | 56 | kmVec2* kmVec2Lerp(kmVec2* pOut, const kmVec2* pV1, const kmVec2* pV2, kmScalar t) { 57 | pOut->x = pV1->x + t * ( pV2->x - pV1->x ); 58 | pOut->y = pV1->y + t * ( pV2->y - pV1->y ); 59 | return pOut; 60 | } 61 | 62 | kmVec2* kmVec2Normalize(kmVec2* pOut, const kmVec2* pIn) 63 | { 64 | if (!pIn->x && !pIn->y) 65 | return kmVec2Assign(pOut, pIn); 66 | 67 | kmScalar l = 1.0f / kmVec2Length(pIn); 68 | 69 | kmVec2 v; 70 | v.x = pIn->x * l; 71 | v.y = pIn->y * l; 72 | 73 | pOut->x = v.x; 74 | pOut->y = v.y; 75 | 76 | return pOut; 77 | } 78 | 79 | kmVec2* kmVec2Add(kmVec2* pOut, const kmVec2* pV1, const kmVec2* pV2) 80 | { 81 | pOut->x = pV1->x + pV2->x; 82 | pOut->y = pV1->y + pV2->y; 83 | 84 | return pOut; 85 | } 86 | 87 | kmScalar kmVec2Dot(const kmVec2* pV1, const kmVec2* pV2) 88 | { 89 | return pV1->x * pV2->x + pV1->y * pV2->y; 90 | } 91 | 92 | kmScalar kmVec2Cross(const kmVec2* pV1, const kmVec2* pV2) 93 | { 94 | return pV1->x * pV2->y - pV1->y * pV2->x; 95 | } 96 | 97 | kmVec2* kmVec2Subtract(kmVec2* pOut, const kmVec2* pV1, const kmVec2* pV2) 98 | { 99 | pOut->x = pV1->x - pV2->x; 100 | pOut->y = pV1->y - pV2->y; 101 | 102 | return pOut; 103 | } 104 | 105 | kmVec2* kmVec2Mul( kmVec2* pOut,const kmVec2* pV1, const kmVec2* pV2 ) { 106 | pOut->x = pV1->x * pV2->x; 107 | pOut->y = pV1->y * pV2->y; 108 | return pOut; 109 | } 110 | 111 | kmVec2* kmVec2Div( kmVec2* pOut,const kmVec2* pV1, const kmVec2* pV2 ) { 112 | if ( pV2->x && pV2->y ){ 113 | pOut->x = pV1->x / pV2->x; 114 | pOut->y = pV1->y / pV2->y; 115 | } 116 | return pOut; 117 | } 118 | 119 | kmVec2* kmVec2Transform(kmVec2* pOut, const kmVec2* pV, const kmMat3* pM) 120 | { 121 | kmVec2 v; 122 | 123 | v.x = pV->x * pM->mat[0] + pV->y * pM->mat[3] + pM->mat[6]; 124 | v.y = pV->x * pM->mat[1] + pV->y * pM->mat[4] + pM->mat[7]; 125 | 126 | pOut->x = v.x; 127 | pOut->y = v.y; 128 | 129 | return pOut; 130 | } 131 | 132 | kmVec2* kmVec2TransformCoord(kmVec2* pOut, const kmVec2* pV, const kmMat3* pM) 133 | { 134 | assert(0); 135 | return NULL; 136 | } 137 | 138 | kmVec2* kmVec2Scale(kmVec2* pOut, const kmVec2* pIn, const kmScalar s) 139 | { 140 | pOut->x = pIn->x * s; 141 | pOut->y = pIn->y * s; 142 | 143 | return pOut; 144 | } 145 | 146 | int kmVec2AreEqual(const kmVec2* p1, const kmVec2* p2) 147 | { 148 | return ( 149 | (p1->x < p2->x + kmEpsilon && p1->x > p2->x - kmEpsilon) && 150 | (p1->y < p2->y + kmEpsilon && p1->y > p2->y - kmEpsilon) 151 | ); 152 | } 153 | 154 | /** 155 | * Assigns pIn to pOut. Returns pOut. If pIn and pOut are the same 156 | * then nothing happens but pOut is still returned 157 | */ 158 | kmVec2* kmVec2Assign(kmVec2* pOut, const kmVec2* pIn) { 159 | if (pOut == pIn) { 160 | return pOut; 161 | } 162 | 163 | pOut->x = pIn->x; 164 | pOut->y = pIn->y; 165 | 166 | return pOut; 167 | } 168 | 169 | /** 170 | * Rotates the point anticlockwise around a center 171 | * by an amount of degrees. 172 | * 173 | * Code ported from Irrlicht: http://irrlicht.sourceforge.net/ 174 | */ 175 | kmVec2* kmVec2RotateBy(kmVec2* pOut, const kmVec2* pIn, 176 | const kmScalar degrees, const kmVec2* center) 177 | { 178 | kmScalar x, y; 179 | const kmScalar radians = kmDegreesToRadians(degrees); 180 | const kmScalar cs = cosf(radians), sn = sinf(radians); 181 | 182 | pOut->x = pIn->x - center->x; 183 | pOut->y = pIn->y - center->y; 184 | 185 | x = pOut->x * cs - pOut->y * sn; 186 | y = pOut->x * sn + pOut->y * cs; 187 | 188 | pOut->x = x + center->x; 189 | pOut->y = y + center->y; 190 | 191 | return pOut; 192 | } 193 | 194 | /** 195 | * Returns the angle in degrees between the two vectors 196 | */ 197 | kmScalar kmVec2DegreesBetween(const kmVec2* v1, const kmVec2* v2) { 198 | if(kmVec2AreEqual(v1, v2)) { 199 | return 0.0; 200 | } 201 | 202 | kmVec2 t1, t2; 203 | kmVec2Normalize(&t1, v1); 204 | kmVec2Normalize(&t2, v2); 205 | 206 | kmScalar cross = kmVec2Cross(&t1, &t2); 207 | kmScalar dot = kmVec2Dot(&t1, &t2); 208 | 209 | /* 210 | * acos is only defined for -1 to 1. Outside the range we 211 | * get NaN even if that's just because of a floating point error 212 | * so we clamp to the -1 - 1 range 213 | */ 214 | 215 | if(dot > 1.0) dot = 1.0; 216 | if(dot < -1.0) dot = -1.0; 217 | 218 | return kmRadiansToDegrees(atan2(cross, dot)); 219 | } 220 | 221 | /** 222 | * Returns the distance between the two points 223 | */ 224 | kmScalar kmVec2DistanceBetween(const kmVec2* v1, const kmVec2* v2) { 225 | kmVec2 diff; 226 | kmVec2Subtract(&diff, v2, v1); 227 | return fabs(kmVec2Length(&diff)); 228 | } 229 | /** 230 | * Returns the point mid-way between two others 231 | */ 232 | kmVec2* kmVec2MidPointBetween(kmVec2* pOut, const kmVec2* v1, const kmVec2* v2) { 233 | kmVec2 sum; 234 | kmVec2Add(&sum, v1, v2); 235 | pOut->x = sum.x / 2.0f; 236 | pOut->y = sum.y / 2.0f; 237 | 238 | return pOut; 239 | } 240 | 241 | /** 242 | * Reflects a vector about a given surface normal. The surface normal is 243 | * assumed to be of unit length. 244 | */ 245 | kmVec2* kmVec2Reflect(kmVec2* pOut, const kmVec2* pIn, const kmVec2* normal) { 246 | kmVec2 tmp; 247 | kmVec2Scale(&tmp, normal, 2.0f * kmVec2Dot(pIn, normal)); 248 | kmVec2Subtract(pOut, pIn, &tmp); 249 | 250 | return pOut; 251 | } 252 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/heman.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/heman.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/heman" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/heman" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /kazmath/plane.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include "vec3.h" 30 | #include "vec4.h" 31 | #include "plane.h" 32 | #include "mat4.h" 33 | 34 | kmScalar kmPlaneDot(const kmPlane* pP, const kmVec4* pV) 35 | { 36 | /*a*x + b*y + c*z + d*w*/ 37 | 38 | return (pP->a * pV->x + 39 | pP->b * pV->y + 40 | pP->c * pV->z + 41 | pP->d * pV->w); 42 | } 43 | 44 | kmScalar kmPlaneDotCoord(const kmPlane* pP, const kmVec3* pV) 45 | { 46 | return (pP->a * pV->x + 47 | pP->b * pV->y + 48 | pP->c * pV->z + pP->d); 49 | } 50 | 51 | kmScalar kmPlaneDotNormal(const kmPlane* pP, const kmVec3* pV) 52 | { 53 | return (pP->a * pV->x + 54 | pP->b * pV->y + 55 | pP->c * pV->z); 56 | } 57 | 58 | kmPlane* kmPlaneFromNormalAndDistance(kmPlane* plane, const struct kmVec3* normal, const kmScalar dist) { 59 | plane->a = normal->x; 60 | plane->b = normal->y; 61 | plane->c = normal->z; 62 | plane->d = dist; 63 | 64 | return plane; 65 | } 66 | 67 | kmPlane* kmPlaneFromPointAndNormal(kmPlane* pOut, const kmVec3* pPoint, const kmVec3* pNormal) 68 | { 69 | /* 70 | Planea = Nx 71 | Planeb = Ny 72 | Planec = Nz 73 | Planed = −N⋅P 74 | */ 75 | 76 | 77 | pOut->a = pNormal->x; 78 | pOut->b = pNormal->y; 79 | pOut->c = pNormal->z; 80 | pOut->d = -kmVec3Dot(pNormal, pPoint); 81 | 82 | return pOut; 83 | } 84 | 85 | /** 86 | * Creates a plane from 3 points. The result is stored in pOut. 87 | * pOut is returned. 88 | */ 89 | kmPlane* kmPlaneFromPoints(kmPlane* pOut, const kmVec3* p1, const kmVec3* p2, const kmVec3* p3) 90 | { 91 | /* 92 | v = (B − A) × (C − A) 93 | n = 1⁄|v| v 94 | Outa = nx 95 | Outb = ny 96 | Outc = nz 97 | Outd = −n⋅A 98 | */ 99 | 100 | kmVec3 n, v1, v2; 101 | kmVec3Subtract(&v1, p2, p1); /*Create the vectors for the 2 sides of the triangle*/ 102 | kmVec3Subtract(&v2, p3, p1); 103 | kmVec3Cross(&n, &v1, &v2); /*Use the cross product to get the normal*/ 104 | 105 | kmVec3Normalize(&n, &n); /*Normalize it and assign to pOut->m_N*/ 106 | 107 | pOut->a = n.x; 108 | pOut->b = n.y; 109 | pOut->c = n.z; 110 | pOut->d = kmVec3Dot(kmVec3Scale(&n, &n, -1.0), p1); 111 | 112 | return pOut; 113 | } 114 | 115 | /* Added by tlensing (http://icedcoffee-framework.org)*/ 116 | kmVec3* kmPlaneIntersectLine(kmVec3* pOut, const kmPlane* pP, const kmVec3* pV1, const kmVec3* pV2) 117 | { 118 | /* 119 | n = (Planea, Planeb, Planec) 120 | d = V − U 121 | Out = U − d⋅(Pd + n⋅U)⁄(d⋅n) [iff d⋅n ≠ 0] 122 | */ 123 | kmVec3 d; /* direction from V1 to V2*/ 124 | kmVec3Subtract(&d, pV2, pV1); /* Get the direction vector*/ 125 | 126 | kmVec3 n; /* plane normal*/ 127 | n.x = pP->a; 128 | n.y = pP->b; 129 | n.z = pP->c; 130 | kmVec3Normalize(&n, &n); 131 | 132 | kmScalar nt = -(n.x * pV1->x + n.y * pV1->y + n.z * pV1->z + pP->d); 133 | kmScalar dt = (n.x * d.x + n.y * d.y + n.z * d.z); 134 | 135 | if (fabs(dt) < kmEpsilon) { 136 | pOut = NULL; 137 | return pOut; /* line parallel or contained*/ 138 | } 139 | 140 | kmScalar t = nt/dt; 141 | pOut->x = pV1->x + d.x * t; 142 | pOut->y = pV1->y + d.y * t; 143 | pOut->z = pV1->z + d.z * t; 144 | 145 | return pOut; 146 | } 147 | 148 | kmPlane* kmPlaneNormalize(kmPlane* pOut, const kmPlane* pP) 149 | { 150 | kmVec3 n; 151 | kmScalar l = 0; 152 | 153 | if (!pP->a && !pP->b && !pP->c) { 154 | pOut->a = pP->a; 155 | pOut->b = pP->b; 156 | pOut->c = pP->c; 157 | pOut->d = pP->d; 158 | return pOut; 159 | } 160 | 161 | n.x = pP->a; 162 | n.y = pP->b; 163 | n.z = pP->c; 164 | 165 | l = 1.0f / kmVec3Length(&n); /*Get 1/length*/ 166 | kmVec3Normalize(&n, &n); /*Normalize the vector and assign to pOut*/ 167 | 168 | pOut->a = n.x; 169 | pOut->b = n.y; 170 | pOut->c = n.z; 171 | 172 | pOut->d = pP->d * l; /*Scale the D value and assign to pOut*/ 173 | 174 | return pOut; 175 | } 176 | 177 | kmPlane* kmPlaneScale(kmPlane* pOut, const kmPlane* pP, kmScalar s) 178 | { 179 | assert(0 && "Not implemented"); 180 | return NULL; 181 | } 182 | 183 | /** 184 | * Returns POINT_INFRONT_OF_PLANE if pP is infront of pIn. Returns 185 | * POINT_BEHIND_PLANE if it is behind. Returns POINT_ON_PLANE otherwise 186 | */ 187 | KM_POINT_CLASSIFICATION kmPlaneClassifyPoint(const kmPlane* pIn, const kmVec3* pP) 188 | { 189 | /* This function will determine if a point is on, in front of, or behind*/ 190 | /* the plane. First we store the dot product of the plane and the point.*/ 191 | kmScalar distance = pIn->a * pP->x + pIn->b * pP->y + pIn->c * pP->z + pIn->d; 192 | 193 | /* Simply put if the dot product is greater than 0 then it is infront of it.*/ 194 | /* If it is less than 0 then it is behind it. And if it is 0 then it is on it.*/ 195 | if(distance > kmEpsilon) return POINT_INFRONT_OF_PLANE; 196 | if(distance < -kmEpsilon) return POINT_BEHIND_PLANE; 197 | 198 | return POINT_ON_PLANE; 199 | } 200 | 201 | kmPlane* kmPlaneExtractFromMat4(kmPlane* pOut, const struct kmMat4* pIn, kmInt row) { 202 | int scale = (row < 0) ? -1 : 1; 203 | row = abs(row) - 1; 204 | 205 | pOut->a = pIn->mat[3] + scale * pIn->mat[row]; 206 | pOut->b = pIn->mat[7] + scale * pIn->mat[row + 4]; 207 | pOut->c = pIn->mat[11] + scale * pIn->mat[row + 8]; 208 | pOut->d = pIn->mat[15] + scale * pIn->mat[row + 12]; 209 | 210 | return kmPlaneNormalize(pOut, pOut); 211 | } 212 | 213 | kmVec3* kmPlaneGetIntersection(kmVec3* pOut, const kmPlane* p1, const kmPlane* p2, const kmPlane* p3) { 214 | kmVec3 n1, n2, n3, cross; 215 | kmVec3 r1, r2, r3; 216 | double denom = 0; 217 | 218 | kmVec3Fill(&n1, p1->a, p1->b, p1->c); 219 | kmVec3Fill(&n2, p2->a, p2->b, p2->c); 220 | kmVec3Fill(&n3, p3->a, p3->b, p3->c); 221 | 222 | kmVec3Cross(&cross, &n2, &n3); 223 | 224 | denom = kmVec3Dot(&n1, &cross); 225 | 226 | if (kmAlmostEqual(denom, 0.0)) { 227 | return NULL; 228 | } 229 | 230 | kmVec3Cross(&r1, &n2, &n3); 231 | kmVec3Cross(&r2, &n3, &n1); 232 | kmVec3Cross(&r3, &n1, &n2); 233 | 234 | kmVec3Scale(&r1, &r1, -p1->d); 235 | kmVec3Scale(&r2, &r2, p2->d); 236 | kmVec3Scale(&r3, &r3, p3->d); 237 | 238 | kmVec3Subtract(pOut, &r1, &r2); 239 | kmVec3Subtract(pOut, pOut, &r3); 240 | kmVec3Scale(pOut, pOut, 1.0 / denom); 241 | 242 | /*p = -d1 * ( n2.Cross ( n3 ) ) – d2 * ( n3.Cross ( n1 ) ) – d3 * ( n1.Cross ( n2 ) ) / denom;*/ 243 | 244 | return pOut; 245 | } 246 | 247 | kmPlane* kmPlaneFill(kmPlane* plane, kmScalar a, kmScalar b, kmScalar c, kmScalar d) { 248 | plane->a = a; 249 | plane->b = b; 250 | plane->c = c; 251 | plane->d = d; 252 | 253 | return plane; 254 | } 255 | -------------------------------------------------------------------------------- /kazmath/ray2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ray2.h" 4 | 5 | void kmRay2Fill(kmRay2* ray, kmScalar px, kmScalar py, kmScalar vx, kmScalar vy) { 6 | ray->start.x = px; 7 | ray->start.y = py; 8 | ray->dir.x = vx; 9 | ray->dir.y = vy; 10 | } 11 | 12 | void kmRay2FillWithEndpoints( kmRay2 *ray, const kmVec2 *start, const kmVec2 *end ) { 13 | ray->start.x = start->x; 14 | ray->start.y = start->y; 15 | ray->dir.x = end->x - start->x; 16 | ray->dir.y = end->y - start->y; 17 | } 18 | 19 | 20 | /* 21 | Lines are defined by a pt and a vector. It outputs the vector multiply factor 22 | that gives the intersection point 23 | */ 24 | kmBool kmLine2WithLineIntersection(const kmVec2 *ptA, const kmVec2 *vecA, // first line 25 | const kmVec2 *ptB, const kmVec2 *vecB, // seconf line 26 | kmScalar *outTA, kmScalar *outTB, 27 | kmVec2 *outIntersection ) 28 | { 29 | kmScalar x1 = ptA->x; 30 | kmScalar y1 = ptA->y; 31 | kmScalar x2 = x1 + vecA->x; 32 | kmScalar y2 = y1 + vecA->y; 33 | kmScalar x3 = ptB->x; 34 | kmScalar y3 = ptB->y; 35 | kmScalar x4 = x3 + vecB->x; 36 | kmScalar y4 = y3 + vecB->y; 37 | 38 | kmScalar denom = (y4 -y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); 39 | 40 | /*If denom is zero, the lines are parallel*/ 41 | if(denom > -kmEpsilon && denom < kmEpsilon) { 42 | return KM_FALSE; 43 | } 44 | 45 | kmScalar ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom; 46 | kmScalar ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom; 47 | 48 | kmScalar x = x1 + ua * (x2 - x1); 49 | kmScalar y = y1 + ua * (y2 - y1); 50 | 51 | if( outTA ){ 52 | *outTA = ua; 53 | } 54 | if( outTB ){ 55 | *outTB = ub; 56 | } 57 | if( outIntersection ){ 58 | outIntersection->x = x; 59 | outIntersection->y = y; 60 | } 61 | return KM_TRUE; 62 | } 63 | 64 | kmBool kmSegment2WithSegmentIntersection( const kmRay2 *segmentA, const kmRay2 *segmentB, kmVec2 *intersection ) 65 | { 66 | kmScalar ua; 67 | kmScalar ub; 68 | kmVec2 pt; 69 | 70 | if( kmLine2WithLineIntersection( &(segmentA->start), &(segmentA->dir), 71 | &(segmentB->start), &(segmentB->start), 72 | &ua, &ub, &pt ) && 73 | (0.0 <= ua) && (ua <= 1.0) && (0.0 <= ub) && (ub <= 1.0)) { 74 | intersection->x = pt.x; 75 | intersection->y = pt.y; 76 | return KM_TRUE; 77 | } 78 | 79 | return KM_FALSE; 80 | } 81 | 82 | kmBool kmRay2IntersectLineSegment(const kmRay2* ray, const kmVec2* p1, const kmVec2* p2, kmVec2* intersection) { 83 | 84 | kmScalar ua; 85 | kmScalar ub; 86 | kmVec2 pt; 87 | 88 | kmRay2 otherSegment; 89 | kmRay2FillWithEndpoints(&otherSegment, p1, p2); 90 | 91 | if( kmLine2WithLineIntersection( &(ray->start), &(ray->dir), 92 | &(otherSegment.start), &(otherSegment.dir), 93 | &ua, &ub, &pt ) && 94 | (0.0 <= ua) && (0.0 <= ub) && (ub <= 1.0)) { 95 | 96 | intersection->x = pt.x; 97 | intersection->y = pt.y; 98 | return KM_TRUE; 99 | } 100 | 101 | return KM_FALSE; 102 | } 103 | 104 | void calculate_line_normal(kmVec2 p1, kmVec2 p2, kmVec2 other_point, kmVec2* normal_out) { 105 | /* 106 | A = (3,4) 107 | B = (2,1) 108 | C = (1,3) 109 | 110 | AB = (2,1) - (3,4) = (-1,-3) 111 | AC = (1,3) - (3,4) = (-2,-1) 112 | N = n(AB) = (-3,1) 113 | D = dot(N,AC) = 6 + -1 = 5 114 | 115 | since D > 0: 116 | N = -N = (3,-1) 117 | */ 118 | 119 | kmVec2 edge, other_edge; 120 | kmVec2Subtract(&edge, &p2, &p1); 121 | kmVec2Subtract(&other_edge, &other_point, &p1); 122 | kmVec2Normalize(&edge, &edge); 123 | kmVec2Normalize(&other_edge, &other_edge); 124 | 125 | kmVec2 n; 126 | n.x = edge.y; 127 | n.y = -edge.x; 128 | 129 | kmScalar d = kmVec2Dot(&n, &other_edge); 130 | if(d > 0.0f) { 131 | n.x = -n.x; 132 | n.y = -n.y; 133 | } 134 | 135 | normal_out->x = n.x; 136 | normal_out->y = n.y; 137 | kmVec2Normalize(normal_out, normal_out); 138 | } 139 | 140 | kmBool kmRay2IntersectTriangle(const kmRay2* ray, const kmVec2* p1, const kmVec2* p2, const kmVec2* p3, kmVec2* intersection, kmVec2* normal_out, kmScalar* distance_out) { 141 | kmVec2 intersect; 142 | kmVec2 final_intersect; 143 | kmVec2 normal; 144 | kmScalar distance = 10000.0f; 145 | kmBool intersected = KM_FALSE; 146 | 147 | if(kmRay2IntersectLineSegment(ray, p1, p2, &intersect)) { 148 | kmVec2 tmp; 149 | kmScalar this_distance = kmVec2Length(kmVec2Subtract(&tmp, &intersect, &ray->start)); 150 | kmVec2 this_normal; 151 | calculate_line_normal(*p1, *p2, *p3, &this_normal); 152 | if(this_distance < distance && kmVec2Dot(&this_normal, &ray->dir) < 0.0f) { 153 | final_intersect.x = intersect.x; 154 | final_intersect.y = intersect.y; 155 | distance = this_distance; 156 | kmVec2Assign(&normal, &this_normal); 157 | intersected = KM_TRUE; 158 | } 159 | } 160 | 161 | if(kmRay2IntersectLineSegment(ray, p2, p3, &intersect)) { 162 | kmVec2 tmp; 163 | kmScalar this_distance = kmVec2Length(kmVec2Subtract(&tmp, &intersect, &ray->start)); 164 | 165 | kmVec2 this_normal; 166 | calculate_line_normal(*p2, *p3, *p1, &this_normal); 167 | 168 | if(this_distance < distance && kmVec2Dot(&this_normal, &ray->dir) < 0.0f) { 169 | final_intersect.x = intersect.x; 170 | final_intersect.y = intersect.y; 171 | distance = this_distance; 172 | kmVec2Assign(&normal, &this_normal); 173 | intersected = KM_TRUE; 174 | } 175 | } 176 | 177 | if(kmRay2IntersectLineSegment(ray, p3, p1, &intersect)) { 178 | 179 | kmVec2 tmp; 180 | kmScalar this_distance = kmVec2Length(kmVec2Subtract(&tmp, &intersect, &ray->start)); 181 | 182 | kmVec2 this_normal; 183 | calculate_line_normal(*p3, *p1, *p2, &this_normal); 184 | if(this_distance < distance && kmVec2Dot(&this_normal, &ray->dir) < 0.0f) { 185 | final_intersect.x = intersect.x; 186 | final_intersect.y = intersect.y; 187 | distance = this_distance; 188 | kmVec2Assign(&normal, &this_normal); 189 | intersected = KM_TRUE; 190 | } 191 | } 192 | 193 | if(intersected) { 194 | intersection->x = final_intersect.x; 195 | intersection->y = final_intersect.y; 196 | if(normal_out) { 197 | normal_out->x = normal.x; 198 | normal_out->y = normal.y; 199 | } 200 | if(distance) { 201 | *distance_out = distance; 202 | } 203 | } 204 | 205 | return intersected; 206 | } 207 | 208 | kmBool kmRay2IntersectBox(const kmRay2* ray, const kmVec2* p1, const kmVec2* p2, const kmVec2* p3, const kmVec2* p4, 209 | kmVec2* intersection, kmVec2* normal_out) { 210 | kmBool intersected = KM_FALSE; 211 | kmVec2 intersect, final_intersect, normal; 212 | kmScalar distance = 10000.0f; 213 | 214 | const kmVec2* points[4]; 215 | points[0] = p1; 216 | points[1] = p2; 217 | points[2] = p3; 218 | points[3] = p4; 219 | 220 | unsigned int i = 0; 221 | for(; i < 4; ++i) { 222 | const kmVec2* this_point = points[i]; 223 | const kmVec2* next_point = (i == 3) ? points[0] : points[i+1]; 224 | const kmVec2* other_point = (i == 3 || i == 0) ? points[1] : points[0]; 225 | 226 | if(kmRay2IntersectLineSegment(ray, this_point, next_point, &intersect)) { 227 | 228 | kmVec2 tmp; 229 | kmScalar this_distance = kmVec2Length(kmVec2Subtract(&tmp, &intersect, &ray->start)); 230 | 231 | kmVec2 this_normal; 232 | 233 | calculate_line_normal(*this_point, *next_point, *other_point, &this_normal); 234 | if(this_distance < distance && kmVec2Dot(&this_normal, &ray->dir) < 0.0f) { 235 | kmVec2Assign(&final_intersect, &intersect); 236 | distance = this_distance; 237 | intersected = KM_TRUE; 238 | kmVec2Assign(&normal, &this_normal); 239 | } 240 | } 241 | } 242 | 243 | if(intersected) { 244 | intersection->x = final_intersect.x; 245 | intersection->y = final_intersect.y; 246 | if(normal_out) { 247 | normal_out->x = normal.x; 248 | normal_out->y = normal.y; 249 | } 250 | } 251 | 252 | return intersected; 253 | } 254 | 255 | kmBool kmRay2IntersectCircle(const kmRay2* ray, const kmVec2 centre, const kmScalar radius, kmVec2* intersection) { 256 | assert(0 && "Not implemented"); 257 | return KM_TRUE; 258 | } 259 | -------------------------------------------------------------------------------- /src/distance.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | const HEMAN_FLOAT INF = 1E20; 8 | 9 | #define NEW(t, n) calloc(n, sizeof(t)) 10 | #define SDISTFIELD_TEXEL(x, y) (*(sdf->data + y * width + x)) 11 | #define COORDFIELD_TEXEL(x, y, c) (*(cf->data + 2 * (y * width + x) + c)) 12 | 13 | static void edt( 14 | HEMAN_FLOAT* f, HEMAN_FLOAT* d, HEMAN_FLOAT* z, uint16_t* w, int n) 15 | { 16 | int k = 0; 17 | HEMAN_FLOAT s; 18 | w[0] = 0; 19 | z[0] = -INF; 20 | z[1] = +INF; 21 | for (int q = 1; q < n; ++q) { 22 | s = ((f[q] + SQR(q)) - (f[w[k]] + SQR(w[k]))) / (2 * q - 2 * w[k]); 23 | while (s <= z[k]) { 24 | --k; 25 | s = ((f[q] + SQR(q)) - (f[w[k]] + SQR(w[k]))) / (2 * q - 2 * w[k]); 26 | } 27 | w[++k] = q; 28 | z[k] = s; 29 | z[k + 1] = +INF; 30 | } 31 | k = 0; 32 | for (int q = 0; q < n; ++q) { 33 | while (z[k + 1] < q) { 34 | ++k; 35 | } 36 | d[q] = SQR(q - w[k]) + f[w[k]]; 37 | } 38 | } 39 | 40 | static void edt_with_payload(HEMAN_FLOAT* f, HEMAN_FLOAT* d, HEMAN_FLOAT* z, 41 | uint16_t* w, int n, HEMAN_FLOAT* payload_in, HEMAN_FLOAT* payload_out) 42 | { 43 | int k = 0; 44 | HEMAN_FLOAT s; 45 | w[0] = 0; 46 | z[0] = -INF; 47 | z[1] = +INF; 48 | for (int q = 1; q < n; ++q) { 49 | s = ((f[q] + SQR(q)) - (f[w[k]] + SQR(w[k]))) / (2 * q - 2 * w[k]); 50 | while (s <= z[k]) { 51 | --k; 52 | s = ((f[q] + SQR(q)) - (f[w[k]] + SQR(w[k]))) / (2 * q - 2 * w[k]); 53 | } 54 | w[++k] = q; 55 | z[k] = s; 56 | z[k + 1] = +INF; 57 | } 58 | k = 0; 59 | for (int q = 0; q < n; ++q) { 60 | while (z[k + 1] < q) { 61 | ++k; 62 | } 63 | d[q] = SQR(q - w[k]) + f[w[k]]; 64 | payload_out[q * 2] = payload_in[w[k] * 2]; 65 | payload_out[q * 2 + 1] = payload_in[w[k] * 2 + 1]; 66 | } 67 | } 68 | 69 | static void transform_to_distance(heman_image* sdf) 70 | { 71 | int width = sdf->width; 72 | int height = sdf->height; 73 | int size = width * height; 74 | HEMAN_FLOAT* ff = NEW(HEMAN_FLOAT, size); 75 | HEMAN_FLOAT* dd = NEW(HEMAN_FLOAT, size); 76 | HEMAN_FLOAT* zz = NEW(HEMAN_FLOAT, (height + 1) * (width + 1)); 77 | uint16_t* ww = NEW(uint16_t, size); 78 | 79 | int x; 80 | #pragma omp parallel for 81 | for (x = 0; x < width; ++x) { 82 | HEMAN_FLOAT* f = ff + height * x; 83 | HEMAN_FLOAT* d = dd + height * x; 84 | HEMAN_FLOAT* z = zz + (height + 1) * x; 85 | uint16_t* w = ww + height * x; 86 | for (int y = 0; y < height; ++y) { 87 | f[y] = SDISTFIELD_TEXEL(x, y); 88 | } 89 | edt(f, d, z, w, height); 90 | for (int y = 0; y < height; ++y) { 91 | SDISTFIELD_TEXEL(x, y) = d[y]; 92 | } 93 | } 94 | 95 | int y; 96 | #pragma omp parallel for 97 | for (y = 0; y < height; ++y) { 98 | HEMAN_FLOAT* f = ff + width * y; 99 | HEMAN_FLOAT* d = dd + width * y; 100 | HEMAN_FLOAT* z = zz + (width + 1) * y; 101 | uint16_t* w = ww + width * y; 102 | for (int x = 0; x < width; ++x) { 103 | f[x] = SDISTFIELD_TEXEL(x, y); 104 | } 105 | edt(f, d, z, w, width); 106 | for (int x = 0; x < width; ++x) { 107 | SDISTFIELD_TEXEL(x, y) = d[x]; 108 | } 109 | } 110 | 111 | free(ff); 112 | free(dd); 113 | free(zz); 114 | free(ww); 115 | } 116 | 117 | static void transform_to_coordfield(heman_image* sdf, heman_image* cf) 118 | { 119 | int width = sdf->width; 120 | int height = sdf->height; 121 | int size = width * height; 122 | HEMAN_FLOAT* ff = NEW(HEMAN_FLOAT, size); 123 | HEMAN_FLOAT* dd = NEW(HEMAN_FLOAT, size); 124 | HEMAN_FLOAT* zz = NEW(HEMAN_FLOAT, (height + 1) * (width + 1)); 125 | uint16_t* ww = NEW(uint16_t, size); 126 | 127 | int x; 128 | #pragma omp parallel for 129 | for (x = 0; x < width; ++x) { 130 | HEMAN_FLOAT* pl1 = NEW(HEMAN_FLOAT, height * 2); 131 | HEMAN_FLOAT* pl2 = NEW(HEMAN_FLOAT, height * 2); 132 | HEMAN_FLOAT* f = ff + height * x; 133 | HEMAN_FLOAT* d = dd + height * x; 134 | HEMAN_FLOAT* z = zz + (height + 1) * x; 135 | uint16_t* w = ww + height * x; 136 | for (int y = 0; y < height; ++y) { 137 | f[y] = SDISTFIELD_TEXEL(x, y); 138 | pl1[y * 2] = COORDFIELD_TEXEL(x, y, 0); 139 | pl1[y * 2 + 1] = COORDFIELD_TEXEL(x, y, 1); 140 | } 141 | edt_with_payload(f, d, z, w, height, pl1, pl2); 142 | for (int y = 0; y < height; ++y) { 143 | SDISTFIELD_TEXEL(x, y) = d[y]; 144 | COORDFIELD_TEXEL(x, y, 0) = pl2[2 * y]; 145 | COORDFIELD_TEXEL(x, y, 1) = pl2[2 * y + 1]; 146 | } 147 | free(pl1); 148 | free(pl2); 149 | } 150 | 151 | int y; 152 | #pragma omp parallel for 153 | for (y = 0; y < height; ++y) { 154 | HEMAN_FLOAT* pl1 = NEW(HEMAN_FLOAT, width * 2); 155 | HEMAN_FLOAT* pl2 = NEW(HEMAN_FLOAT, width * 2); 156 | HEMAN_FLOAT* f = ff + width * y; 157 | HEMAN_FLOAT* d = dd + width * y; 158 | HEMAN_FLOAT* z = zz + (width + 1) * y; 159 | uint16_t* w = ww + width * y; 160 | for (int x = 0; x < width; ++x) { 161 | f[x] = SDISTFIELD_TEXEL(x, y); 162 | pl1[x * 2] = COORDFIELD_TEXEL(x, y, 0); 163 | pl1[x * 2 + 1] = COORDFIELD_TEXEL(x, y, 1); 164 | } 165 | edt_with_payload(f, d, z, w, width, pl1, pl2); 166 | for (int x = 0; x < width; ++x) { 167 | SDISTFIELD_TEXEL(x, y) = d[x]; 168 | COORDFIELD_TEXEL(x, y, 0) = pl2[2 * x]; 169 | COORDFIELD_TEXEL(x, y, 1) = pl2[2 * x + 1]; 170 | } 171 | free(pl1); 172 | free(pl2); 173 | } 174 | 175 | free(ff); 176 | free(dd); 177 | free(zz); 178 | free(ww); 179 | } 180 | 181 | heman_image* heman_distance_create_sdf(heman_image* src) 182 | { 183 | assert(src->nbands == 1 && "Distance field input must have only 1 band."); 184 | heman_image* positive = heman_image_create(src->width, src->height, 1); 185 | heman_image* negative = heman_image_create(src->width, src->height, 1); 186 | int size = src->height * src->width; 187 | HEMAN_FLOAT* pptr = positive->data; 188 | HEMAN_FLOAT* nptr = negative->data; 189 | HEMAN_FLOAT* sptr = src->data; 190 | for (int i = 0; i < size; ++i, ++sptr) { 191 | *pptr++ = *sptr ? INF : 0; 192 | *nptr++ = *sptr ? 0 : INF; 193 | } 194 | transform_to_distance(positive); 195 | transform_to_distance(negative); 196 | HEMAN_FLOAT inv = 1.0f / src->width; 197 | pptr = positive->data; 198 | nptr = negative->data; 199 | for (int i = 0; i < size; ++i, ++pptr, ++nptr) { 200 | *pptr = (sqrt(*pptr) - sqrt(*nptr)) * inv; 201 | } 202 | heman_image_destroy(negative); 203 | return positive; 204 | } 205 | 206 | heman_image* heman_distance_create_df(heman_image* src) 207 | { 208 | assert(src->nbands == 1 && "Distance field input must have only 1 band."); 209 | heman_image* positive = heman_image_create(src->width, src->height, 1); 210 | int size = src->height * src->width; 211 | HEMAN_FLOAT* pptr = positive->data; 212 | HEMAN_FLOAT* sptr = src->data; 213 | for (int i = 0; i < size; ++i, ++sptr) { 214 | *pptr++ = *sptr ? 0 : INF; 215 | } 216 | transform_to_distance(positive); 217 | HEMAN_FLOAT inv = 1.0f / src->width; 218 | pptr = positive->data; 219 | for (int i = 0; i < size; ++i, ++pptr) { 220 | *pptr = sqrt(*pptr) * inv; 221 | } 222 | return positive; 223 | } 224 | 225 | heman_image* heman_distance_identity_cpcf(int width, int height) 226 | { 227 | heman_image* retval = heman_image_create(width, height, 2); 228 | HEMAN_FLOAT* cdata = retval->data; 229 | for (int y = 0; y < height; y++) { 230 | for (int x = 0; x < width; x++) { 231 | *cdata++ = x; 232 | *cdata++ = y; 233 | } 234 | } 235 | return retval; 236 | } 237 | 238 | heman_image* heman_distance_create_cpcf(heman_image* src) 239 | { 240 | heman_image* negative = heman_image_create(src->width, src->height, 1); 241 | int size = src->height * src->width; 242 | HEMAN_FLOAT* nptr = negative->data; 243 | HEMAN_FLOAT* sptr = src->data; 244 | for (int i = 0; i < size; ++i) { 245 | HEMAN_FLOAT val = 0; 246 | for (int b = 0; b < src->nbands; ++b) { 247 | val += *sptr++; 248 | } 249 | *nptr++ = val ? 0 : INF; 250 | } 251 | heman_image* coordfield = heman_distance_identity_cpcf(src->width, src->height); 252 | transform_to_coordfield(negative, coordfield); 253 | heman_image_destroy(negative); 254 | return coordfield; 255 | } 256 | 257 | heman_image* heman_distance_from_cpcf(heman_image* cf) 258 | { 259 | assert(cf->nbands == 2 && "Coordinate field input must have 2 bands."); 260 | heman_image* udf = heman_image_create(cf->width, cf->height, 1); 261 | HEMAN_FLOAT* dptr = udf->data; 262 | HEMAN_FLOAT* sptr = cf->data; 263 | HEMAN_FLOAT scale = 1.0f / sqrt(SQR(cf->width) + SQR(cf->height)); 264 | for (int y = 0; y < cf->height; y++) { 265 | for (int x = 0; x < cf->width; x++) { 266 | HEMAN_FLOAT u = *sptr++; 267 | HEMAN_FLOAT v = *sptr++; 268 | HEMAN_FLOAT dist = sqrt(SQR(u - x) + SQR(v - y)) * scale; 269 | *dptr++ = dist; 270 | } 271 | } 272 | return udf; 273 | } 274 | -------------------------------------------------------------------------------- /src/lighting.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static float _occlusion_scale = 1.0f; 8 | 9 | void heman_lighting_set_occlusion_scale(float s) 10 | { 11 | _occlusion_scale = s; 12 | } 13 | 14 | heman_image* heman_lighting_compute_normals(heman_image* heightmap) 15 | { 16 | assert(heightmap->nbands == 1); 17 | int width = heightmap->width; 18 | int height = heightmap->height; 19 | heman_image* result = heman_image_create(width, height, 3); 20 | HEMAN_FLOAT invh = 1.0f / height; 21 | HEMAN_FLOAT invw = 1.0f / width; 22 | int maxx = width - 1; 23 | int maxy = height - 1; 24 | kmVec3* normals = (kmVec3*) result->data; 25 | int y; 26 | #pragma omp parallel for 27 | for (y = 0; y < height; y++) { 28 | HEMAN_FLOAT v = y * invh; 29 | int y1 = MIN(y + 1, maxy); 30 | kmVec3 p; 31 | kmVec3 px; 32 | kmVec3 py; 33 | kmVec3* n = normals + y * width; 34 | for (int x = 0; x < width; x++, n++) { 35 | HEMAN_FLOAT u = x * invw; 36 | int x1 = MIN(x + 1, maxx); 37 | p.x = u; 38 | p.y = v; 39 | p.z = *heman_image_texel(heightmap, x, y); 40 | px.x = u + invw; 41 | px.y = v; 42 | px.z = *heman_image_texel(heightmap, x1, y); 43 | py.x = u; 44 | py.y = v + invh; 45 | py.z = *heman_image_texel(heightmap, x, y1); 46 | kmVec3Subtract(&px, &px, &p); 47 | kmVec3Subtract(&py, &py, &p); 48 | kmVec3Cross(n, &px, &py); 49 | kmVec3Normalize(n, n); 50 | n->y *= -1; 51 | } 52 | } 53 | 54 | return result; 55 | } 56 | 57 | heman_image* heman_lighting_apply(heman_image* heightmap, heman_image* albedo, 58 | float occlusion, float diffuse, float diffuse_softening, 59 | const float* light_position) 60 | { 61 | assert(heightmap->nbands == 1); 62 | int width = heightmap->width; 63 | int height = heightmap->height; 64 | heman_image* final = heman_image_create(width, height, 3); 65 | heman_image* normals = heman_lighting_compute_normals(heightmap); 66 | heman_image* occ = heman_lighting_compute_occlusion(heightmap); 67 | 68 | if (albedo) { 69 | assert(albedo->nbands == 3); 70 | assert(albedo->width == width); 71 | assert(albedo->height == height); 72 | } 73 | 74 | static float default_pos[] = {-0.5f, 0.5f, 1.0f}; 75 | if (!light_position) { 76 | light_position = default_pos; 77 | } 78 | 79 | kmVec3* colors = (kmVec3*) final->data; 80 | HEMAN_FLOAT invgamma = 1.0f / _gamma; 81 | 82 | kmVec3 L; 83 | L.x = light_position[0]; 84 | L.y = light_position[1]; 85 | L.z = light_position[2]; 86 | kmVec3Normalize(&L, &L); 87 | 88 | int y; 89 | #pragma omp parallel for 90 | for (y = 0; y < height; y++) { 91 | kmVec3* color = colors + y * width; 92 | for (int x = 0; x < width; x++, color++) { 93 | kmVec3* N = (kmVec3*) heman_image_texel(normals, x, y); 94 | kmVec3Lerp(N, N, &KM_VEC3_POS_Z, diffuse_softening); 95 | HEMAN_FLOAT df = 96 | 1 - diffuse * (1 - kmClamp(kmVec3Dot(N, &L), 0, 1)); 97 | HEMAN_FLOAT of = 98 | 1 - occlusion * (1 - *heman_image_texel(occ, x, y)); 99 | if (albedo) { 100 | *color = *((kmVec3*) heman_image_texel(albedo, x, y)); 101 | } else { 102 | color->x = color->y = color->z = 1; 103 | } 104 | color->x = pow(color->x, _gamma); 105 | color->y = pow(color->y, _gamma); 106 | color->z = pow(color->z, _gamma); 107 | kmVec3Scale(color, color, df * of); 108 | color->x = pow(color->x, invgamma); 109 | color->y = pow(color->y, invgamma); 110 | color->z = pow(color->z, invgamma); 111 | } 112 | } 113 | 114 | heman_image_destroy(normals); 115 | heman_image_destroy(occ); 116 | return final; 117 | } 118 | 119 | #define NUM_SCANS (16) 120 | #define INV_SCANS (1.0f / 16.0f) 121 | 122 | static HEMAN_FLOAT azimuth_slope(kmVec3 a, kmVec3 b) 123 | { 124 | kmVec3 d; 125 | kmVec3Subtract(&d, &a, &b); 126 | HEMAN_FLOAT x = kmVec3Length(&d); 127 | HEMAN_FLOAT y = b.z - a.z; 128 | return y / x; 129 | } 130 | 131 | static HEMAN_FLOAT compute_occlusion(kmVec3 thispt, kmVec3 horizonpt) 132 | { 133 | kmVec3 direction; 134 | kmVec3Subtract(&direction, &horizonpt, &thispt); 135 | kmVec3Normalize(&direction, &direction); 136 | HEMAN_FLOAT dot = kmVec3Dot(&direction, &KM_VEC3_POS_Z); 137 | return atan(MAX(dot, 0.0f)) * TWO_OVER_PI; 138 | } 139 | 140 | static void horizon_scan( 141 | heman_image* heightmap, heman_image* result, int* startpts, int dx, int dy) 142 | { 143 | int w = heightmap->width, h = heightmap->height; 144 | int sx = SGN(dx), sy = SGN(dy); 145 | int ax = abs(dx), ay = abs(dy); 146 | 147 | // Generate the start positions for each sweep line. The start positions 148 | // occur just outside the image boundary. 149 | int nsweeps = ay * w + ax * h - (ax + ay - 1); 150 | int* p = startpts; 151 | for (int x = -ax; x < w - ax; x++) { 152 | for (int y = -ay; y < h - ay; y++) { 153 | if (x >= 0 && x < w && y >= 0 && y < h) { 154 | continue; 155 | } 156 | *p++ = (sx < 0) ? (w - x - 1) : x; 157 | *p++ = (sy < 0) ? (h - y - 1) : y; 158 | } 159 | } 160 | assert(nsweeps == (p - startpts) / 2); 161 | 162 | // Compute the number of steps by doing a mock sweep. 163 | int pathlen = 0; 164 | int i = startpts[0], j = startpts[1]; 165 | do { 166 | i += dx; 167 | j += dy; 168 | ++pathlen; 169 | } while (i >= 0 && i < w && j >= 0 && j < h); 170 | 171 | // Each cell in the grid has a certain width and height. These can be 172 | // multiplied by row / column indices to get world-space X / Y values, 173 | // which are in the same coordinate system as the height values. 174 | HEMAN_FLOAT cellw = _occlusion_scale / MAX(w, h); 175 | HEMAN_FLOAT cellh = _occlusion_scale / MAX(w, h); 176 | 177 | // Initialize a stack of candidate horizon points, one for each sweep. In a 178 | // serial implementation we wouldn't need to allocate this much memory, but 179 | // we're trying to make life easy for multithreading. 180 | kmVec3* hull_buffer = malloc(sizeof(kmVec3) * pathlen * nsweeps); 181 | 182 | // Finally, perform the actual sweeps. We're careful to touch each pixel 183 | // exactly once, which makes this embarassingly threadable. 184 | int sweep; 185 | 186 | #pragma omp parallel for 187 | for (sweep = 0; sweep < nsweeps; sweep++) { 188 | kmVec3* convex_hull = hull_buffer + sweep * pathlen; 189 | int* p = startpts + sweep * 2; 190 | int i = p[0]; 191 | int j = p[1]; 192 | kmVec3 thispt, horizonpt; 193 | thispt.x = i * cellw; 194 | thispt.y = j * cellh; 195 | thispt.z = *heman_image_texel(heightmap, EDGE(i, w), EDGE(j, h)); 196 | int stack_top = 0; 197 | convex_hull[0] = thispt; 198 | i += dx, j += dy; 199 | while (i >= 0 && i < w && j >= 0 && j < h) { 200 | thispt.x = i * cellw; 201 | thispt.y = j * cellh; 202 | thispt.z = *heman_image_texel(heightmap, i, j); 203 | while (stack_top > 0) { 204 | HEMAN_FLOAT s1 = azimuth_slope(thispt, convex_hull[stack_top]); 205 | HEMAN_FLOAT s2 = 206 | azimuth_slope(thispt, convex_hull[stack_top - 1]); 207 | if (s1 >= s2) { 208 | break; 209 | } 210 | stack_top--; 211 | } 212 | horizonpt = convex_hull[stack_top++]; 213 | assert(stack_top < pathlen); 214 | convex_hull[stack_top] = thispt; 215 | HEMAN_FLOAT occlusion = compute_occlusion(thispt, horizonpt); 216 | *heman_image_texel(result, i, j) += INV_SCANS * occlusion; 217 | i += dx; 218 | j += dy; 219 | } 220 | } 221 | 222 | free(hull_buffer); 223 | } 224 | 225 | heman_image* heman_lighting_compute_occlusion(heman_image* heightmap) 226 | { 227 | assert(heightmap->nbands == 1); 228 | int width = heightmap->width; 229 | int height = heightmap->height; 230 | heman_image* result = heman_image_create(width, height, 1); 231 | memset(result->data, 0, sizeof(HEMAN_FLOAT) * width * height); 232 | 233 | // Define sixteen 2D vectors, used for the sweep directions. 234 | const int scans[NUM_SCANS * 2] = { 235 | 1, 0, 0, 1, -1, 0, 0, -1, // Rook 236 | 1, 1, -1, -1, 1, -1, -1, 1, // Bishop 237 | 2, 1, 2, -1, -2, 1, -2, -1, 1, 2, 1, -2, -1, 2, -1, -2 // Knight 238 | }; 239 | 240 | // Allocate memory that will store the starting positions of each sweep. 241 | int* startpts = malloc(sizeof(int) * 2 * 3 * kmMax(width, height)); 242 | 243 | // Make each sweep serially, accumulating the result. 244 | for (int i = 0; i < NUM_SCANS; i++) { 245 | int dx = scans[i * 2]; 246 | int dy = scans[i * 2 + 1]; 247 | horizon_scan(heightmap, result, startpts, dx, dy); 248 | } 249 | 250 | // Invert the occlusion values and make sure they are valid. 251 | for (int i = 0; i < width * height; i++) { 252 | result->data[i] = 1.0f - result->data[i]; 253 | assert(result->data[i] >= 0.0 && result->data[i] <= 1.0f); 254 | } 255 | 256 | free(startpts); 257 | return result; 258 | } 259 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # heman documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Aug 15 20:35:58 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | import shlex 18 | 19 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 20 | 21 | # If extensions (or modules to document with autodoc) are in another directory, 22 | # add these directories to sys.path here. If the directory is relative to the 23 | # documentation root, use os.path.abspath to make it absolute, like shown here. 24 | #sys.path.insert(0, os.path.abspath('.')) 25 | 26 | # -- General configuration ------------------------------------------------ 27 | 28 | # If your documentation needs a minimal Sphinx version, state it here. 29 | #needs_sphinx = '1.0' 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = [] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ['_templates'] 38 | 39 | # The suffix(es) of source filenames. 40 | # You can specify multiple suffix as a list of string: 41 | # source_suffix = ['.rst', '.md'] 42 | source_suffix = '.rst' 43 | 44 | # The encoding of source files. 45 | #source_encoding = 'utf-8-sig' 46 | 47 | # The master toctree document. 48 | master_doc = 'index' 49 | 50 | # General information about the project. 51 | project = u'heman' 52 | copyright = u'2015, Philip Rideout' 53 | author = u'Philip Rideout' 54 | 55 | # The version info for the project you're documenting, acts as replacement for 56 | # |version| and |release|, also used in various other places throughout the 57 | # built documents. 58 | # 59 | # The short X.Y version. 60 | version = 'r1' 61 | # The full version, including alpha/beta/rc tags. 62 | release = 'r1' 63 | 64 | # The language for content autogenerated by Sphinx. Refer to documentation 65 | # for a list of supported languages. 66 | # 67 | # This is also used if you do content translation via gettext catalogs. 68 | # Usually you set "language" from the command line for these cases. 69 | language = None 70 | 71 | # There are two options for replacing |today|: either, you set today to some 72 | # non-false value, then it is used: 73 | #today = '' 74 | # Else, today_fmt is used as the format for a strftime call. 75 | #today_fmt = '%B %d, %Y' 76 | 77 | # List of patterns, relative to source directory, that match files and 78 | # directories to ignore when looking for source files. 79 | exclude_patterns = ['_build'] 80 | 81 | # The reST default role (used for this markup: `text`) to use for all 82 | # documents. 83 | #default_role = None 84 | 85 | # If true, '()' will be appended to :func: etc. cross-reference text. 86 | #add_function_parentheses = True 87 | 88 | # If true, the current module name will be prepended to all description 89 | # unit titles (such as .. function::). 90 | #add_module_names = True 91 | 92 | # If true, sectionauthor and moduleauthor directives will be shown in the 93 | # output. They are ignored by default. 94 | #show_authors = False 95 | 96 | # The name of the Pygments (syntax highlighting) style to use. 97 | pygments_style = 'sphinx' 98 | 99 | # A list of ignored prefixes for module index sorting. 100 | #modindex_common_prefix = [] 101 | 102 | # If true, keep warnings as "system message" paragraphs in the built documents. 103 | #keep_warnings = False 104 | 105 | # If true, `todo` and `todoList` produce output, else they produce nothing. 106 | todo_include_todos = False 107 | 108 | 109 | # -- Options for HTML output ---------------------------------------------- 110 | 111 | # The theme to use for HTML and HTML Help pages. See the documentation for 112 | # a list of builtin themes. 113 | html_theme = 'default' 114 | if not on_rtd: 115 | try: 116 | import sphinx_rtd_theme 117 | html_theme = 'sphinx_rtd_theme' 118 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 119 | except ImportError: 120 | pass 121 | 122 | # Theme options are theme-specific and customize the look and feel of a theme 123 | # further. For a list of options available for each theme, see the 124 | # documentation. 125 | #html_theme_options = {} 126 | 127 | # Add any paths that contain custom themes here, relative to this directory. 128 | #html_theme_path = [] 129 | 130 | # The name for this set of Sphinx documents. If None, it defaults to 131 | # " v documentation". 132 | #html_title = None 133 | 134 | # A shorter title for the navigation bar. Default is the same as html_title. 135 | #html_short_title = None 136 | 137 | # The name of an image file (relative to this directory) to place at the top 138 | # of the sidebar. 139 | #html_logo = None 140 | 141 | # The name of an image file (within the static path) to use as favicon of the 142 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 143 | # pixels large. 144 | #html_favicon = None 145 | 146 | # Add any paths that contain custom static files (such as style sheets) here, 147 | # relative to this directory. They are copied after the builtin static files, 148 | # so a file named "default.css" will overwrite the builtin "default.css". 149 | html_static_path = ['_static'] 150 | 151 | # Add any extra paths that contain custom files (such as robots.txt or 152 | # .htaccess) here, relative to this directory. These files are copied 153 | # directly to the root of the documentation. 154 | #html_extra_path = [] 155 | 156 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 157 | # using the given strftime format. 158 | #html_last_updated_fmt = '%b %d, %Y' 159 | 160 | # If true, SmartyPants will be used to convert quotes and dashes to 161 | # typographically correct entities. 162 | #html_use_smartypants = True 163 | 164 | # Custom sidebar templates, maps document names to template names. 165 | #html_sidebars = {} 166 | 167 | # Additional templates that should be rendered to pages, maps page names to 168 | # template names. 169 | #html_additional_pages = {} 170 | 171 | # If false, no module index is generated. 172 | #html_domain_indices = True 173 | 174 | # If false, no index is generated. 175 | #html_use_index = True 176 | 177 | # If true, the index is split into individual pages for each letter. 178 | #html_split_index = False 179 | 180 | # If true, links to the reST sources are added to the pages. 181 | #html_show_sourcelink = True 182 | 183 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 184 | #html_show_sphinx = True 185 | 186 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 187 | html_show_copyright = False 188 | 189 | # If true, an OpenSearch description file will be output, and all pages will 190 | # contain a tag referring to it. The value of this option must be the 191 | # base URL from which the finished HTML is served. 192 | #html_use_opensearch = '' 193 | 194 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 195 | #html_file_suffix = None 196 | 197 | # Language to be used for generating the HTML full-text search index. 198 | # Sphinx supports the following languages: 199 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 200 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 201 | #html_search_language = 'en' 202 | 203 | # A dictionary with options for the search language support, empty by default. 204 | # Now only 'ja' uses this config value 205 | #html_search_options = {'type': 'default'} 206 | 207 | # The name of a javascript file (relative to the configuration directory) that 208 | # implements a search results scorer. If empty, the default will be used. 209 | #html_search_scorer = 'scorer.js' 210 | 211 | # Output file base name for HTML help builder. 212 | htmlhelp_basename = 'hemandoc' 213 | 214 | def setup(app): 215 | # overrides for wide tables in RTD theme 216 | app.add_stylesheet('overrides.css') # path relative to _static 217 | 218 | # -- Options for LaTeX output --------------------------------------------- 219 | 220 | latex_elements = { 221 | # The paper size ('letterpaper' or 'a4paper'). 222 | #'papersize': 'letterpaper', 223 | 224 | # The font size ('10pt', '11pt' or '12pt'). 225 | #'pointsize': '10pt', 226 | 227 | # Additional stuff for the LaTeX preamble. 228 | #'preamble': '', 229 | 230 | # Latex figure (float) alignment 231 | #'figure_align': 'htbp', 232 | } 233 | 234 | # Grouping the document tree into LaTeX files. List of tuples 235 | # (source start file, target name, title, 236 | # author, documentclass [howto, manual, or own class]). 237 | latex_documents = [ 238 | (master_doc, 'heman.tex', u'heman Documentation', 239 | u'Philip Rideout', 'manual'), 240 | ] 241 | 242 | # The name of an image file (relative to this directory) to place at the top of 243 | # the title page. 244 | #latex_logo = None 245 | 246 | # For "manual" documents, if this is true, then toplevel headings are parts, 247 | # not chapters. 248 | #latex_use_parts = False 249 | 250 | # If true, show page references after internal links. 251 | #latex_show_pagerefs = False 252 | 253 | # If true, show URL addresses after external links. 254 | #latex_show_urls = False 255 | 256 | # Documents to append as an appendix to all manuals. 257 | #latex_appendices = [] 258 | 259 | # If false, no module index is generated. 260 | #latex_domain_indices = True 261 | 262 | 263 | # -- Options for manual page output --------------------------------------- 264 | 265 | # One entry per manual page. List of tuples 266 | # (source start file, name, description, authors, manual section). 267 | man_pages = [ 268 | (master_doc, 'heman', u'heman Documentation', 269 | [author], 1) 270 | ] 271 | 272 | # If true, show URL addresses after external links. 273 | #man_show_urls = False 274 | 275 | 276 | # -- Options for Texinfo output ------------------------------------------- 277 | 278 | # Grouping the document tree into Texinfo files. List of tuples 279 | # (source start file, target name, title, author, 280 | # dir menu entry, description, category) 281 | texinfo_documents = [ 282 | (master_doc, 'heman', u'heman Documentation', 283 | author, 'heman', 'One line description of project.', 284 | 'Miscellaneous'), 285 | ] 286 | 287 | # Documents to append as an appendix to all manuals. 288 | #texinfo_appendices = [] 289 | 290 | # If false, no module index is generated. 291 | #texinfo_domain_indices = True 292 | 293 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 294 | #texinfo_show_urls = 'footnote' 295 | 296 | # If true, do not generate a @detailmenu in the "Top" node's menu. 297 | #texinfo_no_detailmenu = False 298 | -------------------------------------------------------------------------------- /src/points.c: -------------------------------------------------------------------------------- 1 | #include "image.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // Transforms even the sequence 0,1,2,3,... into reasonably good random numbers. 9 | unsigned int randhash(unsigned int seed) 10 | { 11 | unsigned int i = (seed ^ 12345391u) * 2654435769u; 12 | i ^= (i << 6) ^ (i >> 26); 13 | i *= 2654435769u; 14 | i += (i << 5) ^ (i >> 12); 15 | return i; 16 | } 17 | 18 | float randhashf(unsigned int seed, float a, float b) 19 | { 20 | return (b - a) * randhash(seed) / (float) UINT_MAX + a; 21 | } 22 | 23 | heman_image* heman_points_create(HEMAN_FLOAT* xy, int npoints, int nbands) 24 | { 25 | heman_points* img = malloc(sizeof(heman_image)); 26 | img->width = npoints; 27 | img->height = 1; 28 | img->nbands = nbands; 29 | int nbytes = sizeof(HEMAN_FLOAT) * npoints * nbands; 30 | img->data = malloc(nbytes); 31 | memcpy(img->data, xy, nbytes); 32 | return img; 33 | } 34 | 35 | void heman_points_destroy(heman_points* img) 36 | { 37 | free(img->data); 38 | free(img); 39 | } 40 | 41 | heman_points* heman_points_from_grid(HEMAN_FLOAT width, HEMAN_FLOAT height, 42 | HEMAN_FLOAT cellsize, HEMAN_FLOAT jitter) 43 | { 44 | int cols = width / cellsize; 45 | int rows = height / cellsize; 46 | int ncells = cols * rows; 47 | heman_points* result = heman_image_create(ncells, 1, 2); 48 | HEMAN_FLOAT rscale = 2.0 * jitter / (HEMAN_FLOAT) RAND_MAX; 49 | 50 | // TODO it would be good to avoid ANSI rand() and add some determinism 51 | // in a thread-safe way. Maybe we should add a seed argument and use 52 | // Bridson's randhash? 53 | 54 | int j; 55 | #pragma omp parallel for 56 | for (j = 0; j < rows; j++) { 57 | HEMAN_FLOAT* dst = result->data + j * cols * 2; 58 | HEMAN_FLOAT y = cellsize * 0.5 + cellsize * j; 59 | HEMAN_FLOAT x = cellsize * 0.5; 60 | for (int i = 0; i < cols; i++) { 61 | HEMAN_FLOAT rx = rand() * rscale - jitter; 62 | HEMAN_FLOAT ry = rand() * rscale - jitter; 63 | *dst++ = x + rx; 64 | *dst++ = y + ry; 65 | x += cellsize; 66 | } 67 | } 68 | 69 | return result; 70 | } 71 | 72 | kmVec2 sample_annulus(float radius, kmVec2 center, unsigned int* seedptr) 73 | { 74 | unsigned int seed = *seedptr; 75 | kmVec2 r; 76 | float rscale = 1.0f / UINT_MAX; 77 | while (1) { 78 | r.x = 4 * rscale * randhash(seed++) - 2; 79 | r.y = 4 * rscale * randhash(seed++) - 2; 80 | float r2 = kmVec2LengthSq(&r); 81 | if (r2 > 1 && r2 <= 4) { 82 | break; 83 | } 84 | } 85 | *seedptr = seed; 86 | kmVec2Scale(&r, &r, radius); 87 | kmVec2Add(&r, &r, ¢er); 88 | return r; 89 | } 90 | 91 | #define GRIDF(vec) \ 92 | grid[(int) (vec.x * invcell) + ncols * (int) (vec.y * invcell)] 93 | 94 | #define GRIDI(vec) grid[(int) vec.y * ncols + (int) vec.x] 95 | 96 | heman_points* heman_points_from_poisson( 97 | HEMAN_FLOAT width, HEMAN_FLOAT height, HEMAN_FLOAT radius) 98 | { 99 | int maxattempts = 30; 100 | float rscale = 1.0f / UINT_MAX; 101 | unsigned int seed = 0; 102 | kmVec2 rvec; 103 | rvec.x = rvec.y = radius; 104 | float r2 = radius * radius; 105 | 106 | // Acceleration grid. 107 | float cellsize = radius / sqrtf(2); 108 | float invcell = 1.0f / cellsize; 109 | int ncols = ceil(width * invcell); 110 | int nrows = ceil(height * invcell); 111 | int maxcol = ncols - 1; 112 | int maxrow = nrows - 1; 113 | int ncells = ncols * nrows; 114 | int* grid = malloc(ncells * sizeof(int)); 115 | for (int i = 0; i < ncells; i++) { 116 | grid[i] = -1; 117 | } 118 | 119 | // Active list and resulting sample list. 120 | int* actives = malloc(ncells * sizeof(int)); 121 | int nactives = 0; 122 | heman_points* result = heman_image_create(ncells, 1, 2); 123 | kmVec2* samples = (kmVec2*) result->data; 124 | int nsamples = 0; 125 | 126 | // First sample. 127 | kmVec2 pt; 128 | pt.x = width * randhash(seed++) * rscale; 129 | pt.y = height * randhash(seed++) * rscale; 130 | GRIDF(pt) = actives[nactives++] = nsamples; 131 | samples[nsamples++] = pt; 132 | 133 | while (nsamples < ncells) { 134 | int aindex = MIN(randhashf(seed++, 0, nactives), nactives - 1); 135 | int sindex = actives[aindex]; 136 | int found = 0; 137 | kmVec2 j, minj, maxj, delta; 138 | int attempt; 139 | for (attempt = 0; attempt < maxattempts && !found; attempt++) { 140 | pt = sample_annulus(radius, samples[sindex], &seed); 141 | 142 | // Check that this sample is within bounds. 143 | if (pt.x < 0 || pt.x >= width || pt.y < 0 || pt.y >= height) { 144 | continue; 145 | } 146 | 147 | // Test proximity to nearby samples. 148 | minj = maxj = pt; 149 | kmVec2Add(&maxj, &maxj, &rvec); 150 | kmVec2Subtract(&minj, &minj, &rvec); 151 | kmVec2Scale(&minj, &minj, invcell); 152 | kmVec2Scale(&maxj, &maxj, invcell); 153 | minj.x = CLAMP((int) minj.x, 0, maxcol); 154 | maxj.x = CLAMP((int) maxj.x, 0, maxcol); 155 | minj.y = CLAMP((int) minj.y, 0, maxrow); 156 | maxj.y = CLAMP((int) maxj.y, 0, maxrow); 157 | int reject = 0; 158 | for (j.y = minj.y; j.y <= maxj.y && !reject; j.y++) { 159 | for (j.x = minj.x; j.x <= maxj.x && !reject; j.x++) { 160 | int entry = GRIDI(j); 161 | if (entry > -1 && entry != sindex) { 162 | kmVec2Subtract(&delta, &samples[entry], &pt); 163 | if (kmVec2LengthSq(&delta) < r2) { 164 | reject = 1; 165 | } 166 | } 167 | } 168 | } 169 | if (reject) { 170 | continue; 171 | } 172 | found = 1; 173 | } 174 | if (found) { 175 | GRIDF(pt) = actives[nactives++] = nsamples; 176 | samples[nsamples++] = pt; 177 | } else { 178 | if (--nactives <= 0) { 179 | break; 180 | } 181 | actives[aindex] = actives[nactives]; 182 | } 183 | } 184 | 185 | // The following line probably isn't necessary. Paranoia. 186 | result->width = nsamples; 187 | 188 | free(grid); 189 | free(actives); 190 | return result; 191 | } 192 | 193 | #undef GRIDF 194 | #undef GRIDI 195 | 196 | #define NGRID_INDEX(fpt) \ 197 | ((int) (fpt.x * invcell) + ncols * (int) (fpt.y * invcell)) 198 | 199 | #define GRID_INDEX(fpt) (gcapacity * NGRID_INDEX(fpt)) 200 | 201 | #define GRID_INSERT(fpt, sindex) \ 202 | gindex = NGRID_INDEX(fpt); \ 203 | grid[gcapacity * gindex + ngrid[gindex]] = sindex; \ 204 | ngrid[gindex]++ 205 | 206 | #define NGRID_BEGIN(ipt) ((int) ipt.y * ncols + (int) ipt.x) 207 | 208 | #define GRID_BEGIN(ipt) (NGRID_BEGIN(ipt) * gcapacity) 209 | 210 | #define GRID_END(ipt) (GRID_BEGIN(ipt) + ngrid[NGRID_BEGIN(ipt)]) 211 | 212 | heman_points* heman_points_from_density( 213 | heman_image* density, HEMAN_FLOAT minradius, HEMAN_FLOAT maxradius) 214 | { 215 | assert(density->nbands == 1); 216 | float width = 1, height = 1; 217 | int maxattempts = 30; 218 | float rscale = 1.0f / UINT_MAX; 219 | unsigned int seed = 0; 220 | kmVec2 rvec; 221 | rvec.x = rvec.y = maxradius; 222 | int gindex; 223 | 224 | // Acceleration grid. 225 | float cellsize = maxradius / sqrtf(2); 226 | float invcell = 1.0f / cellsize; 227 | int ncols = ceil(width * invcell); 228 | int nrows = ceil(height * invcell); 229 | int maxcol = ncols - 1; 230 | int maxrow = nrows - 1; 231 | int ncells = ncols * nrows; 232 | int ntexels = cellsize * density->width; 233 | int gcapacity = ntexels * ntexels; 234 | int* grid = malloc(ncells * sizeof(int) * gcapacity); 235 | int* ngrid = malloc(ncells * sizeof(int)); 236 | for (int i = 0; i < ncells; i++) { 237 | ngrid[i] = 0; 238 | } 239 | 240 | // Active list and resulting sample list. 241 | int* actives = malloc(ncells * sizeof(int)); 242 | int nactives = 0; 243 | int maxsamples = ncells * gcapacity; 244 | heman_points* result = heman_image_create(maxsamples, 1, 2); 245 | kmVec2* samples = (kmVec2*) result->data; 246 | int nsamples = 0; 247 | 248 | // First sample. 249 | kmVec2 pt; 250 | pt.x = width * randhash(seed++) * rscale; 251 | pt.y = height * randhash(seed++) * rscale; 252 | actives[nactives++] = nsamples; 253 | GRID_INSERT(pt, nsamples); 254 | samples[nsamples++] = pt; 255 | 256 | while (nsamples < maxsamples) { 257 | int aindex = MIN(randhashf(seed++, 0, nactives), nactives - 1); 258 | int sindex = actives[aindex]; 259 | int found = 0; 260 | kmVec2 j, minj, maxj, delta; 261 | int attempt; 262 | for (attempt = 0; attempt < maxattempts && !found; attempt++) { 263 | pt = sample_annulus(maxradius, samples[sindex], &seed); 264 | 265 | // Check that this sample is within bounds. 266 | if (pt.x < 0 || pt.x >= width || pt.y < 0 || pt.y >= height) { 267 | continue; 268 | } 269 | 270 | // Test proximity to nearby samples. 271 | minj = maxj = pt; 272 | kmVec2Add(&maxj, &maxj, &rvec); 273 | kmVec2Subtract(&minj, &minj, &rvec); 274 | kmVec2Scale(&minj, &minj, invcell); 275 | kmVec2Scale(&maxj, &maxj, invcell); 276 | minj.x = CLAMP((int) minj.x, 0, maxcol); 277 | maxj.x = CLAMP((int) maxj.x, 0, maxcol); 278 | minj.y = CLAMP((int) minj.y, 0, maxrow); 279 | maxj.y = CLAMP((int) maxj.y, 0, maxrow); 280 | int reject = 0; 281 | 282 | HEMAN_FLOAT densityval; 283 | heman_image_sample(density, pt.x, pt.y, &densityval); 284 | 285 | // The following square root seems to lead to more satisfying 286 | // results, although we should perhaps let the client decide... 287 | densityval = sqrt(densityval); 288 | 289 | float mindist = maxradius - densityval * (maxradius - minradius); 290 | float r2 = mindist * mindist; 291 | 292 | for (j.y = minj.y; j.y <= maxj.y && !reject; j.y++) { 293 | for (j.x = minj.x; j.x <= maxj.x && !reject; j.x++) { 294 | for (int g = GRID_BEGIN(j); g < GRID_END(j); ++g) { 295 | int entry = grid[g]; 296 | if (entry != sindex) { 297 | kmVec2Subtract(&delta, &samples[entry], &pt); 298 | if (kmVec2LengthSq(&delta) < r2) { 299 | reject = 1; 300 | } 301 | } 302 | } 303 | } 304 | } 305 | if (reject) { 306 | continue; 307 | } 308 | found = 1; 309 | } 310 | if (found && ngrid[NGRID_INDEX(pt)] >= gcapacity) { 311 | found = 0; 312 | } 313 | if (found) { 314 | actives[nactives++] = nsamples; 315 | GRID_INSERT(pt, nsamples); 316 | samples[nsamples++] = pt; 317 | } else { 318 | if (--nactives <= 0) { 319 | break; 320 | } 321 | actives[aindex] = actives[nactives]; 322 | } 323 | } 324 | 325 | // We don't usually fill the pre-allocated buffer, since it was 326 | // allocated for the worst case, so adjust the size: 327 | result->width = nsamples; 328 | 329 | free(grid); 330 | free(ngrid); 331 | free(actives); 332 | return result; 333 | } 334 | -------------------------------------------------------------------------------- /kazmath/vec3.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008, Luke Benstead. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | /** 27 | * @file vec3.c 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | #include "utility.h" 34 | #include "vec4.h" 35 | #include "mat4.h" 36 | #include "mat3.h" 37 | #include "vec3.h" 38 | #include "plane.h" 39 | #include "ray3.h" 40 | 41 | const kmVec3 KM_VEC3_POS_Z = { 0, 0, 1 }; 42 | const kmVec3 KM_VEC3_NEG_Z = { 0, 0, -1 }; 43 | const kmVec3 KM_VEC3_POS_Y = { 0, 1, 0 }; 44 | const kmVec3 KM_VEC3_NEG_Y = { 0, -1, 0 }; 45 | const kmVec3 KM_VEC3_NEG_X = { -1, 0, 0 }; 46 | const kmVec3 KM_VEC3_POS_X = { 1, 0, 0 }; 47 | const kmVec3 KM_VEC3_ZERO = { 0, 0, 0 }; 48 | 49 | /** 50 | * Fill a kmVec3 structure using 3 floating point values 51 | * The result is store in pOut, returns pOut 52 | */ 53 | kmVec3* kmVec3Fill(kmVec3* pOut, kmScalar x, kmScalar y, kmScalar z) 54 | { 55 | pOut->x = x; 56 | pOut->y = y; 57 | pOut->z = z; 58 | return pOut; 59 | } 60 | 61 | 62 | /** 63 | * Returns the length of the vector 64 | */ 65 | kmScalar kmVec3Length(const kmVec3* pIn) 66 | { 67 | return sqrtf(kmSQR(pIn->x) + kmSQR(pIn->y) + kmSQR(pIn->z)); 68 | } 69 | 70 | /** 71 | * Returns the square of the length of the vector 72 | */ 73 | kmScalar kmVec3LengthSq(const kmVec3* pIn) 74 | { 75 | return kmSQR(pIn->x) + kmSQR(pIn->y) + kmSQR(pIn->z); 76 | } 77 | 78 | /** Returns the interpolation of 2 4D vectors based on t.*/ 79 | kmVec3* kmVec3Lerp(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2, kmScalar t) { 80 | pOut->x = pV1->x + t * ( pV2->x - pV1->x ); 81 | pOut->y = pV1->y + t * ( pV2->y - pV1->y ); 82 | pOut->z = pV1->z + t * ( pV2->z - pV1->z ); 83 | return pOut; 84 | } 85 | 86 | /** 87 | * Returns the vector passed in set to unit length 88 | * the result is stored in pOut. 89 | */ 90 | kmVec3* kmVec3Normalize(kmVec3* pOut, const kmVec3* pIn) 91 | { 92 | if (!pIn->x && !pIn->y && !pIn->z) 93 | return kmVec3Assign(pOut, pIn); 94 | 95 | kmScalar l = 1.0f / kmVec3Length(pIn); 96 | 97 | kmVec3 v; 98 | v.x = pIn->x * l; 99 | v.y = pIn->y * l; 100 | v.z = pIn->z * l; 101 | 102 | pOut->x = v.x; 103 | pOut->y = v.y; 104 | pOut->z = v.z; 105 | 106 | return pOut; 107 | } 108 | 109 | /** 110 | * Returns a vector perpendicular to 2 other vectors. 111 | * The result is stored in pOut. 112 | */ 113 | kmVec3* kmVec3Cross(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2) 114 | { 115 | 116 | kmVec3 v; 117 | 118 | v.x = (pV1->y * pV2->z) - (pV1->z * pV2->y); 119 | v.y = (pV1->z * pV2->x) - (pV1->x * pV2->z); 120 | v.z = (pV1->x * pV2->y) - (pV1->y * pV2->x); 121 | 122 | pOut->x = v.x; 123 | pOut->y = v.y; 124 | pOut->z = v.z; 125 | 126 | return pOut; 127 | } 128 | 129 | /** 130 | * Returns the cosine of the angle between 2 vectors 131 | */ 132 | kmScalar kmVec3Dot(const kmVec3* pV1, const kmVec3* pV2) 133 | { 134 | return ( pV1->x * pV2->x 135 | + pV1->y * pV2->y 136 | + pV1->z * pV2->z ); 137 | } 138 | 139 | /** 140 | * Adds 2 vectors and returns the result. The resulting 141 | * vector is stored in pOut. 142 | */ 143 | kmVec3* kmVec3Add(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2) 144 | { 145 | kmVec3 v; 146 | 147 | v.x = pV1->x + pV2->x; 148 | v.y = pV1->y + pV2->y; 149 | v.z = pV1->z + pV2->z; 150 | 151 | pOut->x = v.x; 152 | pOut->y = v.y; 153 | pOut->z = v.z; 154 | 155 | return pOut; 156 | } 157 | 158 | /** 159 | * Subtracts 2 vectors and returns the result. The result is stored in 160 | * pOut. 161 | */ 162 | kmVec3* kmVec3Subtract(kmVec3* pOut, const kmVec3* pV1, const kmVec3* pV2) 163 | { 164 | kmVec3 v; 165 | 166 | v.x = pV1->x - pV2->x; 167 | v.y = pV1->y - pV2->y; 168 | v.z = pV1->z - pV2->z; 169 | 170 | pOut->x = v.x; 171 | pOut->y = v.y; 172 | pOut->z = v.z; 173 | 174 | return pOut; 175 | } 176 | 177 | kmVec3* kmVec3Mul( kmVec3* pOut,const kmVec3* pV1, const kmVec3* pV2 ) { 178 | pOut->x = pV1->x * pV2->x; 179 | pOut->y = pV1->y * pV2->y; 180 | pOut->z = pV1->z * pV2->z; 181 | return pOut; 182 | } 183 | 184 | kmVec3* kmVec3Div( kmVec3* pOut,const kmVec3* pV1, const kmVec3* pV2 ) { 185 | if ( pV2->x && pV2->y && pV2->z ){ 186 | pOut->x = pV1->x / pV2->x; 187 | pOut->y = pV1->y / pV2->y; 188 | pOut->z = pV1->z / pV2->z; 189 | } 190 | return pOut; 191 | } 192 | 193 | kmVec3* kmVec3MultiplyMat3(kmVec3* pOut, const kmVec3* pV, const kmMat3* pM) { 194 | kmVec3 v; 195 | 196 | v.x = pV->x * pM->mat[0] + pV->y * pM->mat[3] + pV->z * pM->mat[6]; 197 | v.y = pV->x * pM->mat[1] + pV->y * pM->mat[4] + pV->z * pM->mat[7]; 198 | v.z = pV->x * pM->mat[2] + pV->y * pM->mat[5] + pV->z * pM->mat[8]; 199 | 200 | pOut->x = v.x; 201 | pOut->y = v.y; 202 | pOut->z = v.z; 203 | 204 | return pOut; 205 | } 206 | 207 | /** 208 | * Multiplies vector (x, y, z, 1) by a given matrix. The result 209 | * is stored in pOut. pOut is returned. 210 | */ 211 | 212 | kmVec3* kmVec3MultiplyMat4(kmVec3* pOut, const kmVec3* pV, const kmMat4* pM) { 213 | kmVec3 v; 214 | 215 | v.x = pV->x * pM->mat[0] + pV->y * pM->mat[4] + pV->z * pM->mat[8] + pM->mat[12]; 216 | v.y = pV->x * pM->mat[1] + pV->y * pM->mat[5] + pV->z * pM->mat[9] + pM->mat[13]; 217 | v.z = pV->x * pM->mat[2] + pV->y * pM->mat[6] + pV->z * pM->mat[10] + pM->mat[14]; 218 | 219 | pOut->x = v.x; 220 | pOut->y = v.y; 221 | pOut->z = v.z; 222 | 223 | return pOut; 224 | } 225 | 226 | 227 | kmVec3* kmVec3Transform(kmVec3* pOut, const kmVec3* pV, const kmMat4* pM) 228 | { 229 | /* 230 | @deprecated Should intead use kmVec3MultiplyMat4 231 | */ 232 | return kmVec3MultiplyMat4(pOut, pV, pM); 233 | } 234 | 235 | kmVec3* kmVec3InverseTransform(kmVec3* pOut, const kmVec3* pVect, const kmMat4* pM) 236 | { 237 | kmVec3 v1, v2; 238 | 239 | v1.x = pVect->x - pM->mat[12]; 240 | v1.y = pVect->y - pM->mat[13]; 241 | v1.z = pVect->z - pM->mat[14]; 242 | 243 | v2.x = v1.x * pM->mat[0] + v1.y * pM->mat[1] + v1.z * pM->mat[2]; 244 | v2.y = v1.x * pM->mat[4] + v1.y * pM->mat[5] + v1.z * pM->mat[6]; 245 | v2.z = v1.x * pM->mat[8] + v1.y * pM->mat[9] + v1.z * pM->mat[10]; 246 | 247 | pOut->x = v2.x; 248 | pOut->y = v2.y; 249 | pOut->z = v2.z; 250 | 251 | return pOut; 252 | } 253 | 254 | kmVec3* kmVec3InverseTransformNormal(kmVec3* pOut, const kmVec3* pVect, const kmMat4* pM) 255 | { 256 | kmVec3 v; 257 | 258 | v.x = pVect->x * pM->mat[0] + pVect->y * pM->mat[1] + pVect->z * pM->mat[2]; 259 | v.y = pVect->x * pM->mat[4] + pVect->y * pM->mat[5] + pVect->z * pM->mat[6]; 260 | v.z = pVect->x * pM->mat[8] + pVect->y * pM->mat[9] + pVect->z * pM->mat[10]; 261 | 262 | pOut->x = v.x; 263 | pOut->y = v.y; 264 | pOut->z = v.z; 265 | 266 | return pOut; 267 | } 268 | 269 | 270 | kmVec3* kmVec3TransformCoord(kmVec3* pOut, const kmVec3* pV, const kmMat4* pM) 271 | { 272 | /* 273 | a = (Vx, Vy, Vz, 1) 274 | b = (a×M)T 275 | Out = 1⁄bw(bx, by, bz) 276 | */ 277 | 278 | kmVec4 v; 279 | kmVec4 inV; 280 | kmVec4Fill(&inV, pV->x, pV->y, pV->z, 1.0); 281 | 282 | kmVec4Transform(&v, &inV,pM); 283 | 284 | pOut->x = v.x / v.w; 285 | pOut->y = v.y / v.w; 286 | pOut->z = v.z / v.w; 287 | 288 | return pOut; 289 | } 290 | 291 | kmVec3* kmVec3TransformNormal(kmVec3* pOut, const kmVec3* pV, const kmMat4* pM) 292 | { 293 | /* 294 | a = (Vx, Vy, Vz, 0) 295 | b = (a×M)T 296 | Out = (bx, by, bz) 297 | */ 298 | /*Omits the translation, only scaling + rotating*/ 299 | kmVec3 v; 300 | 301 | v.x = pV->x * pM->mat[0] + pV->y * pM->mat[4] + pV->z * pM->mat[8]; 302 | v.y = pV->x * pM->mat[1] + pV->y * pM->mat[5] + pV->z * pM->mat[9]; 303 | v.z = pV->x * pM->mat[2] + pV->y * pM->mat[6] + pV->z * pM->mat[10]; 304 | 305 | pOut->x = v.x; 306 | pOut->y = v.y; 307 | pOut->z = v.z; 308 | 309 | return pOut; 310 | 311 | } 312 | 313 | /** 314 | * Scales a vector to length s. Does not normalize first, 315 | * you should do that! 316 | */ 317 | kmVec3* kmVec3Scale(kmVec3* pOut, const kmVec3* pIn, const kmScalar s) 318 | { 319 | pOut->x = pIn->x * s; 320 | pOut->y = pIn->y * s; 321 | pOut->z = pIn->z * s; 322 | 323 | return pOut; 324 | } 325 | 326 | /** 327 | * Returns KM_TRUE if the 2 vectors are approximately equal 328 | */ 329 | int kmVec3AreEqual(const kmVec3* p1, const kmVec3* p2) 330 | { 331 | if ((p1->x < (p2->x + kmEpsilon) && p1->x > (p2->x - kmEpsilon)) && 332 | (p1->y < (p2->y + kmEpsilon) && p1->y > (p2->y - kmEpsilon)) && 333 | (p1->z < (p2->z + kmEpsilon) && p1->z > (p2->z - kmEpsilon))) { 334 | return 1; 335 | } 336 | 337 | return 0; 338 | } 339 | 340 | /** 341 | * Assigns pIn to pOut. Returns pOut. If pIn and pOut are the same 342 | * then nothing happens but pOut is still returned 343 | */ 344 | kmVec3* kmVec3Assign(kmVec3* pOut, const kmVec3* pIn) { 345 | if (pOut == pIn) { 346 | return pOut; 347 | } 348 | 349 | pOut->x = pIn->x; 350 | pOut->y = pIn->y; 351 | pOut->z = pIn->z; 352 | 353 | return pOut; 354 | } 355 | 356 | /** 357 | * Sets all the elements of pOut to zero. Returns pOut. 358 | */ 359 | kmVec3* kmVec3Zero(kmVec3* pOut) { 360 | pOut->x = 0.0f; 361 | pOut->y = 0.0f; 362 | pOut->z = 0.0f; 363 | 364 | return pOut; 365 | } 366 | 367 | /** 368 | * Get the rotations that would make a (0,0,1) direction vector point in the same direction as this direction vector. 369 | * Useful for orienting vector towards a point. 370 | * 371 | * Returns a rotation vector containing the X (pitch) and Y (raw) rotations (in degrees) that when applied to a 372 | * +Z (e.g. 0, 0, 1) direction vector would make it point in the same direction as this vector. The Z (roll) rotation 373 | * is always 0, since two Euler rotations are sufficient to point in any given direction. 374 | * 375 | * Code ported from Irrlicht: http://irrlicht.sourceforge.net/ 376 | */ 377 | kmVec3* kmVec3GetHorizontalAngle(kmVec3* pOut, const kmVec3 *pIn) { 378 | const kmScalar z1 = sqrt(pIn->x * pIn->x + pIn->z * pIn->z); 379 | 380 | pOut->y = kmRadiansToDegrees(atan2(pIn->x, pIn->z)); 381 | if (pOut->y < 0) 382 | pOut->y += 360; 383 | if (pOut->y >= 360) 384 | pOut->y -= 360; 385 | 386 | pOut->x = kmRadiansToDegrees(atan2(z1, pIn->y)) - 90.0; 387 | if (pOut->x < 0) 388 | pOut->x += 360; 389 | if (pOut->x >= 360) 390 | pOut->x -= 360; 391 | 392 | return pOut; 393 | } 394 | 395 | /** 396 | * Builds a direction vector from input vector. 397 | * Input vector is assumed to be rotation vector composed from 3 Euler angle rotations, in degrees. 398 | * The forwards vector will be rotated by the input vector 399 | * 400 | * Code ported from Irrlicht: http://irrlicht.sourceforge.net/ 401 | */ 402 | kmVec3* kmVec3RotationToDirection(kmVec3* pOut, const kmVec3* pIn, const kmVec3* forwards) 403 | { 404 | const kmScalar xr = kmDegreesToRadians(pIn->x); 405 | const kmScalar yr = kmDegreesToRadians(pIn->y); 406 | const kmScalar zr = kmDegreesToRadians(pIn->z); 407 | const kmScalar cr = cos(xr), sr = sin(xr); 408 | const kmScalar cp = cos(yr), sp = sin(yr); 409 | const kmScalar cy = cos(zr), sy = sin(zr); 410 | 411 | const kmScalar srsp = sr*sp; 412 | const kmScalar crsp = cr*sp; 413 | 414 | const kmScalar pseudoMatrix[] = { 415 | (cp*cy), (cp*sy), (-sp), 416 | (srsp*cy-cr*sy), (srsp*sy+cr*cy), (sr*cp), 417 | (crsp*cy+sr*sy), (crsp*sy-sr*cy), (cr*cp) 418 | }; 419 | 420 | pOut->x = forwards->x * pseudoMatrix[0] + 421 | forwards->y * pseudoMatrix[3] + 422 | forwards->z * pseudoMatrix[6]; 423 | 424 | pOut->y = forwards->x * pseudoMatrix[1] + 425 | forwards->y * pseudoMatrix[4] + 426 | forwards->z * pseudoMatrix[7]; 427 | 428 | pOut->z = forwards->x * pseudoMatrix[2] + 429 | forwards->y * pseudoMatrix[5] + 430 | forwards->z * pseudoMatrix[8]; 431 | 432 | return pOut; 433 | } 434 | 435 | kmVec3* kmVec3ProjectOnToPlane(kmVec3* pOut, const kmVec3* point, const struct kmPlane* plane) { 436 | kmRay3 ray; 437 | kmVec3Assign(&ray.start, point); 438 | ray.dir.x = -plane->a; 439 | ray.dir.y = -plane->b; 440 | ray.dir.z = -plane->c; 441 | 442 | kmRay3IntersectPlane(pOut, &ray, plane); 443 | return pOut; 444 | } 445 | 446 | /** 447 | * Reflects a vector about a given surface normal. The surface normal is 448 | * assumed to be of unit length. 449 | */ 450 | kmVec3* kmVec3Reflect(kmVec3* pOut, const kmVec3* pIn, const kmVec3* normal) { 451 | kmVec3 tmp; 452 | kmVec3Scale(&tmp, normal, 2.0f * kmVec3Dot(pIn, normal)); 453 | kmVec3Subtract(pOut, pIn, &tmp); 454 | 455 | return pOut; 456 | } 457 | --------------------------------------------------------------------------------