Mercurial > hg > dmlib
view src/dmtimeline.c @ 2416:377e96524145
Added signature for changeset a2c565ae8098
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 14 Jan 2020 02:10:09 +0200 |
parents | 7190f4fbc0dd |
children | 9807ae37ad69 |
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) { (void) groups; (void) track; (void) 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) { (void) tl; (void) time; return DMERR_OK; } /* "Executes", or rather renders a frame on the specified timeline position. */ int dmExecuteTimeline(DMPreparedTimeline *tl, DMEngineData *engine, int time) { (void) tl; (void) engine; (void) time; return DMERR_OK; }