Mercurial > hg > dmlib
view src/dmtimeline.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 | 28fe5b0925dc |
children | 7190f4fbc0dd |
line wrap: on
line source
/* * dmlib * -- Timeline file loading and timeline processing/execution * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2012-2015 Tecnic Software productions (TNSP) */ #include "dmengine.h" static BOOL dmLoadFloatValue(DMResource *res, DMFloat *val) { char tmp[DT_FLOAT_STORE_SIZE + 1]; if (!dmf_read_str(res, &tmp, DT_FLOAT_STORE_SIZE)) return FALSE; tmp[DT_FLOAT_STORE_SIZE] = 0; *val = atof(tmp); return TRUE; } static int dmLoadTimelinePoints(DMResource *res, DMTimelinePoints *points, int type) { Uint32 npoints; // Get number of points if (!dmf_read_le32(res, &npoints)) return DMERR_FREAD; // Calculate and allocate space points->npoints = npoints; points->nallocated = ((npoints / 16) + 1) * 16; points->points = dmCalloc(points->nallocated, sizeof(DMTimelinePoint)); if (points->points == NULL) return DMERR_MALLOC; // Read points for (int point = 0; point < points->npoints; point++) { DMTimelinePoint *pt = &(points->points[point]); Uint32 ptype, ptime; if (!dmf_read_le32(res, &ptype) || !dmf_read_le32(res, &ptime)) return DMERR_FREAD; switch (type) { case EFPT_INT: { Uint32 tmp; if (!dmf_read_le32(res, &tmp)) return DMERR_FREAD; pt->vint = tmp; } break; case EFPT_FLOAT: if (!dmLoadFloatValue(res, &pt->vfloat)) return DMERR_FREAD; break; case EFPT_VECTOR: if (!dmLoadFloatValue(res, &pt->vector.x) || !dmLoadFloatValue(res, &pt->vector.y) || !dmLoadFloatValue(res, &pt->vector.z) || !dmLoadFloatValue(res, &pt->vector.W)) return DMERR_FREAD; break; case EFPT_MATRIX: { int x, y; for (y = 0; y < DM_MATRIX_SIZE; y++) for (x = 0; x < DM_MATRIX_SIZE; x++) { if (!dmLoadFloatValue(res, &(pt->matrix.m[y][x]))) return DMERR_FREAD; } } break; } pt->type = ptype; pt->time = ptime; } return DMERR_OK; } static int dmLoadTimelineEventParam(DMResource *res, DMTimelineEventParam *param) { int err; DMFTimelineEventParam hdr; Uint16 len; if (!dmf_read_str(res, &hdr.name, sizeof(hdr.name)) || !dmf_read_le32(res, &hdr.type)) return DMERR_FREAD; hdr.name[sizeof(hdr.name) - 1] = 0; param->name = dm_strdup(hdr.name); param->type = hdr.type; switch (param->type) { case EFPT_INT: case EFPT_FLOAT: case EFPT_VECTOR: case EFPT_MATRIX: if ((err = dmLoadTimelinePoints(res, ¶m->pts, param->type)) != DMERR_OK) return err; break; case EFPT_STRING: if (!dmf_read_le16(res, &len)) return DMERR_FREAD; param->vstr = dmMalloc((unsigned int)len + 1); if (!dmf_read_str(res, param->vstr, len)) return DMERR_FREAD; param->vstr[len] = 0; break; } return DMERR_OK; } static int dmLoadTimelineEvent(DMResource *res, DMTimelineEvent **pevent) { DMFTimelineEvent hdr; DMTimelineEvent *event; if ((*pevent = event = dmMalloc0(sizeof(DMTimelineEvent))) == NULL) return DMERR_MALLOC; // Get basic event data if (!dmf_read_le32(res, &hdr.start) || !dmf_read_le32(res, &hdr.duration) || !dmf_read_str(res, &hdr.effectName, sizeof(hdr.effectName)) || !dmf_read_le32(res, &hdr.nparams)) return DMERR_FREAD; hdr.effectName[sizeof(hdr.effectName) - 1] = 0; if (hdr.nparams > DT_MAX_EFFECT_PARAMS) { return dmError(DMERR_INVALID_DATA, "Invalid number of parameters, %d > %d ('%s' @ %d:%d)\n", hdr.nparams, DT_MAX_EFFECT_PARAMS, hdr.effectName, hdr.start, hdr.duration); } event->start = hdr.start; event->duration = hdr.duration; event->nparams = hdr.nparams; event->effect = engineFindEffect(hdr.effectName, hdr.nparams); if (event->effect == NULL) { return dmError(DMERR_INVALID_DATA, "No matching registered effect found for '%s'.\n", hdr.effectName); } event->params = dmCalloc(event->nparams, sizeof(DMTimelineEventParam)); if (event->params == NULL) { return dmError(DMERR_MALLOC, "Could not allocate memory for timeline event parameters.\n"); } for (int param = 0; param < event->nparams; param++) { int err; if ((err = dmLoadTimelineEventParam(res, &(event->params[param]))) != DMERR_OK) return err; } return DMERR_OK; } static int dmLoadTimelineCurve(DMResource *res, DMTimelineCurve *curve) { int err; curve->enabled = dmfgetc(res); if ((err = dmLoadTimelinePoints(res, &(curve->points), EFPT_FLOAT)) != DMERR_OK) return err; return DMERR_OK; } static int dmLoadTimelineTrack(DMResource *res, DMTimelineTrack **ptrack) { int err; DMFTimelineTrack hdr; DMTimelineTrack *track; if ((*ptrack = track = dmMalloc0(sizeof(DMTimelineTrack))) == NULL) return DMERR_MALLOC; if (!dmf_read_le32(res, &hdr.index) || !dmf_read_le32(res, &hdr.layer) || !dmf_read_str(res, &hdr.name, sizeof(hdr.name)) || !dmf_read_byte(res, &hdr.enabled) || !dmf_read_le32(res, &hdr.nevents)) return DMERR_FREAD; if (hdr.nevents >= 4096) return DMERR_INVALID_DATA; if ((track->events = dmCalloc(hdr.nevents, sizeof(DMTimelineEvent *))) == NULL) return DMERR_MALLOC; hdr.name[sizeof(hdr.name) - 1] = 0; track->name = dm_strdup(hdr.name); track->enabled = hdr.enabled; track->nevents = hdr.nevents; for (int event = 0; event < track->nevents; event++) { if ((err = dmLoadTimelineEvent(res, &(track->events[event]))) != DMERR_OK) return err; } if ((err = dmLoadTimelineCurve(res, &(track->composite))) != DMERR_OK) return err; return DMERR_OK; } int dmLoadTimeline(DMResource *res, DMTimeline **ptl) { int err; DMFTimeline hdr; DMTimeline *tl; if ((*ptl = tl = dmMalloc0(sizeof(DMTimeline))) == NULL) return DMERR_MALLOC; // Read and check header if (!dmf_read_str(res, &hdr.magic, sizeof(hdr.magic))) return DMERR_FREAD; if (memcmp(hdr.magic, DT_MAGIC_ID, sizeof(hdr.magic)) != 0) return DMERR_INVALID_DATA; if (!dmf_read_str(res, &hdr.name, sizeof(hdr.name)) || !dmf_read_le32(res, &hdr.ntracks) || !dmf_read_le32(res, &hdr.duration)) return DMERR_FREAD; if (hdr.ntracks >= 64) return DMERR_INVALID_DATA; // Allocate track pointers tl->tracks = (DMTimelineTrack **) dmCalloc(hdr.ntracks, sizeof(DMTimelineTrack *)); if (tl->tracks == NULL) return DMERR_MALLOC; // Copy rest hdr.name[sizeof(hdr.name) - 1] = 0; tl->name = dm_strdup(hdr.name); tl->duration = hdr.duration; tl->ntracks = hdr.ntracks; // Read tracks for (int track = 0; track < tl->ntracks; track++) { if ((err = dmLoadTimelineTrack(res, &(tl->tracks[track]))) != DMERR_OK) return err; } return DMERR_OK; } void dmFreeTimelinePoints(DMTimelinePoints *points) { dmFree(points->points); points->points = NULL; points->npoints = points->nallocated = 0; } void dmFreeTimelineEventParam(DMTimelineEventParam *param) { dmFree(param->name); dmFree(param->vstr); dmFreeTimelinePoints(&(param->pts)); } void dmFreeTimelineEvent(DMTimelineEvent *event) { if (event != NULL) { for (int param = 0; param < event->nparams; param++) dmFreeTimelineEventParam(&(event->params[param])); dmFree(event->params); } } void dmFreeTimelineTrack(DMTimelineTrack *track) { if (track != NULL) { dmFree(track->name); for (int event = 0; event < track->nevents; event++) dmFreeTimelineEvent(track->events[event]); dmFree(track->events); dmFreeTimelinePoints(&(track->composite.points)); } } void dmFreeTimeline(DMTimeline *tl) { if (tl != NULL) { for (int track = 0; track < tl->ntracks; track++) dmFreeTimelineTrack(tl->tracks[track]); dmFree(tl->tracks); dmFree(tl->name); } } static void dmFreePreparedEventGroup(DMPreparedEventGroup *group) { if (group != NULL) { dmFree(group->events); dmFree(group); } } void dmFreePreparedTimelineData(DMPreparedTimeline *ptl) { if (ptl != NULL) { for (int group = 0; group < ptl->ngroups; group++) { dmFreePreparedEventGroup(ptl->groups[group]); ptl->groups[group] = NULL; } dmFree(ptl->groups); ptl->groups = NULL; } } /* Prepare a loaded timeline for execution. Creates the "stacked" structure * of timeline data for efficient rendering. */ int dmAddSplitPreparedEventGroup(DMPreparedEventGroup **groups, DMTimelineTrack *track, DMTimelineEvent *event) { DMPreparedEventGroup *node; for (node = *groups; node != NULL; node = node->next) { } return DMERR_OK; } int dmPrepareTimeline(DMTimeline *tl, DMPreparedTimeline *ptl) { int group, ntrack, event, err; DMPreparedEventGroup *groups = NULL, *node; // Free previous data dmFreePreparedTimelineData(ptl); // Process tracks for (ntrack = 0; ntrack < tl->ntracks; ntrack++) { DMTimelineTrack *track = tl->tracks[ntrack]; for (event = 0; event < track->nevents; event++) { if ((err = dmAddSplitPreparedEventGroup(&groups, track, track->events[event])) != DMERR_OK) return err; } } // Compute number of groups ptl->ngroups = 0; for (node = groups; node != NULL; node = node->next) ptl->ngroups++; // Allocate linear array for fast access ptl->groups = dmMalloc(sizeof(DMPreparedEventGroup) * ptl->ngroups); if (ptl->groups == NULL) return DMERR_MALLOC; // Store pointers in the array for (group = 0, node = groups; node != NULL; node = node->next) ptl->groups[group++] = node; return DMERR_OK; } /* Seeks to specified position in the timeline. The execution function * only handles monotonously increasing time, going backwards will not work * there correctly, thus to seek freely this function must be used. */ int dmSeekTimeline(DMPreparedTimeline *tl, int time) { return DMERR_OK; } /* "Executes", or rather renders a frame on the specified timeline position. */ int dmExecuteTimeline(DMPreparedTimeline *tl, DMEngineData *engine, int time) { return DMERR_OK; }