view src/dmcurves.c @ 1785:86d10d5d4915

Fix case where DMGrowBuf is growing backwards and needs to be reallocated in dmGrowBufRealloc() and the data is moved to the "end" of the newly grown buffer. Previously we used clrsize as data size, but that is (in retrospect) obviously incorrect. Use old buffer size instead.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 13 Jun 2018 01:39:06 +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);
}