Newer
Older
Import / research / 3d-experiments / Framework / Maths.h
//  BlockyFroggy
//  Copyright © 2017 John Ryland.
//  All rights reserved.
#pragma once
#ifndef MATHS_H
#define MATHS_H


#include <cmath>
#include <random>
#define restrict  __restrict


namespace Math
{
  float dotProduct(const float *v1, const float *v2, int stride1 = 1, int stride2 = 1, int count = 4);
  void crossProduct(float *restrict out, const float *restrict v1, const float *restrict v2);
  void transformVector(float *restrict vout, const float *restrict m, const float *restrict vin);
  void normalizeVector(float *vInOut, int count = 4);

  // Functions to make a new matrix
  void makeIdentityMatrix4x4(float* out);
  void makePerspectiveMatrix4x4(float* out, float a_fov, float a_aspect, float a_near, float a_far);
  void makeOrthographicMatrix4x4(float* out, float , float , float, float, float a_near, float a_far);
  void translationRotationScaleToMatrix4x4(float *restrict out, const float *restrict translate, const float *restrict rot, float uniformScale);
  void quatToMatrix4x4(float *restrict out, const float *restrict a_quat);

  // Apply transfomations to a matrix (pass in an identity matrix if need to make a matrix)
  void translateMatrix4x4(float *restrict inOut, const float *restrict vec3);
  void scaleMatrix4x4(float *restrict inOut, const float *restrict vec3);
  void rotateMatrix4x4(float *restrict inOut, const float *restrict vec3);
  void quatRotateMatrix4x4(float *restrict inOut, const float *restrict a_quat);  // quaternion

  void translateMatrix4x4(float* inOut, float x, float y, float z);
  void scaleMatrix4x4(float* inOut, float x, float y, float z);
  void rotateMatrix4x4(float* inOut, float x, float y, float z);

  // If apply rotation about an arbitary axis at a time (vec3 is the direction about which to rotate around)
  void rotateAxisMatrix4x4(float *restrict inOut, float radians, const float *restrict vec3);
  void rotateAxisMatrix4x4(float* inOut, float rad, float x, float y, float z);

  // Helpers
  void multiplyMatrix4x4(float *restrict out, const float *restrict m1, const float *restrict m2);
  bool matrix4x4ToNormalMatrix3x3(float *restrict out, const float *restrict m);
  bool inverseMatrix4x4(float *restrict out, const float *restrict m);
  void transposeMatrix4x4(float *restrict out, const float *restrict m);

  // Unit conversion helpers
  float degreesToRadians(float degrees);
  float radiansToDegrees(float radians);

  // Camera helpers
  void makeCameraMatrix(float *restrict out, float fov, float aspect, const float restrict translate[3], const float restrict rotate[3], float scale, bool ortho);
  void extractClipPlanes(float restrict clipPlanes[6][4], const float *restrict m);
  bool isClipped(float clipPlanes[6][4], float x, float y, float z, float w, float h, float d);
  void calcFrustum(float restrict frustumPts[8][4], const float *restrict m);
  
  template <typename T>
  inline T lerp(T t0, T t1, float ratio)
  {
    return t0 + ratio * (t1 - t0);
  }

  template <typename T>
  inline T clamp(T t, T t1, T t2)
  {
    T max = t > t1 ? t : t1;
    return max > t2 ? t2 : max;
  }

/*
  template <typename T>
  inline T floor2(T t1, T t2) {
    // 0.5 -> 0.0      -0.5 -> -1.0
    return T(int(((t1 - ((t2+1)>>1))/t2)));
  }
*/

  // different result to x%y, result here should always be positive
  template <typename T>
  T modulus(T x, T y)
  {
    // return x - y * ((x-y+T(1))/y);
    return x - y * int(floor(float(x)/y)); // inefficient at the moment, probably can do much better if test and use something like the floor2 function above
  }

  // different results to fmod, this function matches what glsl shaders mod function does
  // this is important for predicting where a model will be rendered when allowing the vertex shader
  // to wrap positions
  template <typename T>
  float modulus(float x, float y)
  {
    return x - y * floor(x/y);
  }

  class RandomNumberGenerator
  {
    public:
      RandomNumberGenerator() : gen(rd()) {}
      template <typename T>
      T generate(T min = 0, T max = std::numeric_limits<T>::max())
      {
        std::uniform_int_distribution<T> dis(min, max);
        return dis(gen);
      }
    private:
      std::random_device rd;
      std::mt19937 gen;
  };
}


#endif // MATHS_H