view src/dmcurves.c @ 2298:b5abfff07ca9

Add new DMGrowBuf helper functions dmGrowBufCopyOffsSize() and dmGrowBufConstCopyOffsSize().
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 04 Jul 2019 10:54:16 +0300
parents 7df95aefb9c6
children
line wrap: on
line source

/*
 * DMLib
 * -- Curve and spline functions
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2015 Tecnic Software productions (TNSP)
 */
#include "dmcurves.h"


void dmLerpInit(DMLerpContext *ctx, DMFloat start, DMFloat end, DMFloat nsteps)
{
    ctx->start = start;
    ctx->end = end;
    ctx->nsteps = nsteps;
}


DMFloat dmCatmullRom(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3)
{
    const DMFloat q = t * t;
    return (
        (2 * p1) +
        (-p0 + p2) * t +
        (2 * p0 - 5 * p1 + 4 * p2 - p3) * q +
        (   -p0 + 3 * p1 - 3 * p2 + p3) * q * t
        ) * 0.5f;
}


static inline const DMVector *dmSplineGetPoint(const DMVector *points, const int npoints, const int n)
{
    return (n < 0) ? &points[0] : ((n < npoints) ? &points[n] : &points[npoints - 1]);
}


int dmBSplineGenerate(const DMVector *points, const int npoints, const int slod,
    int (*callback)(void *data, const int ndst, const int nc, float x, float y, float z),
    void *data, const int ndst)
{
    int cv, j;

    for (cv = -3, j = 0; j != npoints + 1; j++, cv++)
    {
        // for each section of curve, draw 'lod' number of divisions
        int i;
        for (i = 0; i != slod; i++)
        {
            int ret;
            const float t = (float) i / slod;
            const float it = 1.0f - t;

            // Calculate blending functions for cubic bspline
            const float t2 = t * t;
            const float t3 = t2 * t;
            const float b0 = it * it * it / 6.0f;
            const float b1 = ( 3*t3 - 6*t2 + 4) / 6.0f;
            const float b2 = (-3*t3 + 3*t2 + 3*t + 1) / 6.0f;
            const float b3 = t3 / 6.0f;

            // Calculate coordinates of the curve point
            if ((ret = callback(data, ndst, j,
                b0 * dmSplineGetPoint(points, npoints, cv + 0)->x +
                b1 * dmSplineGetPoint(points, npoints, cv + 1)->x +
                b2 * dmSplineGetPoint(points, npoints, cv + 2)->x +
                b3 * dmSplineGetPoint(points, npoints, cv + 3)->x
                ,
                b0 * dmSplineGetPoint(points, npoints, cv + 0)->y +
                b1 * dmSplineGetPoint(points, npoints, cv + 1)->y +
                b2 * dmSplineGetPoint(points, npoints, cv + 2)->y +
                b3 * dmSplineGetPoint(points, npoints, cv + 3)->y
                ,
                b0 * dmSplineGetPoint(points, npoints, cv + 0)->z +
                b1 * dmSplineGetPoint(points, npoints, cv + 1)->z +
                b2 * dmSplineGetPoint(points, npoints, cv + 2)->z +
                b3 * dmSplineGetPoint(points, npoints, cv + 3)->z
                )) != DMERR_OK)
                return ret;
        }
    }

    return DMERR_OK;
}


/*
static int dmSplineAddGL(void *data, const int ndst, const int nc, float x, float y, float z)
{
    (void) data;
    glVertex3f(x, y, z);
    return DMERR_OK;
}


int dmGLBSpline(const DMVector *points, const int npoints, const int slod)
{
    // begin drawing our curve
    glBegin(GL_LINE_STRIP);

    return dmBSplineGenerate(points, npoints, slod, dmSplineAddGL, NULL, 0);

    // we need to specify the last point on the curve
    glVertex3fv(points[npoints - 1]);
    glEnd();
}
*/


static int dmSplineAddVector(void *data, const int ndst, const int nc, float x, float y, float z)
{
    if (nc < ndst)
    {
        DMVector **dst = (DMVector **) data;

        (*dst)->x = x;
        (*dst)->y = y;
        (*dst)->z = z;

        (*dst)++;
        return DMERR_OK;
    }
    else
        return DMERR_BOUNDS;
}


int dmBSplineGenerateArray(DMVector *dst, const int ndst, const DMVector *points, const int npoints, const int slod)
{
    return dmBSplineGenerate(points, npoints, slod, dmSplineAddVector, &dst, ndst);
}


int dmBSplineGenerateAlloc(DMVector **dst, int *ndst, const DMVector *points, const int npoints, const int slod)
{
    if (ndst == NULL || dst == NULL)
        return DMERR_NULLPTR;

    if ((*ndst = dmBSplineGetNPoints(npoints, slod)) <= 0)
        return DMERR_INVALID_DATA;

    if ((*dst = dmCalloc(*ndst, sizeof(DMVector))) == NULL)
        return DMERR_MALLOC;

    return dmBSplineGenerate(points, npoints, slod, dmSplineAddVector, *dst, *ndst);
}