Mercurial > hg > dmlib
view dmtimeline.c @ 510:43ea59887c69
Start work on making C64 formats encoding possible by changing DMDecodeOps
to DMEncDecOps and adding fields and op enums for custom encode functions, renaming,
etc. Split generic op sanity checking into a separate function in
preparation for its use in generic encoding function.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 19 Nov 2012 15:06:01 +0200 |
parents | 525f7af644c4 |
children | d4b84101e480 |
line wrap: on
line source
#include "dmengine.h" static BOOL dmLoadFloatValue(DMResource *res, DMFloat *val) { char tmp[DT_FLOAT_STORE_SIZE + 1]; if (!dmf_read_str(res, (Uint8 *) 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) { int point; 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 (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, (Uint8 *) &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, (Uint8 *) param->vstr, len)) return DMERR_FREAD; param->vstr[len] = 0; break; } return DMERR_OK; } static int dmLoadTimelineEvent(DMResource *res, DMTimelineEvent **pevent) { int param; 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, (Uint8 *) &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) { dmError("Invalid number of parameters, %d > %d ('%s' @ %d:%d)\n", hdr.nparams, DT_MAX_EFFECT_PARAMS, hdr.effectName, hdr.start, hdr.duration); return DMERR_INVALID_DATA; } event->start = hdr.start; event->duration = hdr.duration; event->nparams = hdr.nparams; event->effect = engineFindEffect(hdr.effectName, hdr.nparams); if (event->effect == NULL) { dmError("No matching registered effect found for '%s'.\n", hdr.effectName); return DMERR_INVALID_DATA; } event->params = dmCalloc(event->nparams, sizeof(DMTimelineEventParam)); if (event->params == NULL) { dmError("Could not allocate memory for timeline event parameters.\n"); return DMERR_MALLOC; } for (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 event, err; DMFTimelineTrack hdr; DMTimelineTrack *track; if ((*ptrack = track = dmMalloc0(sizeof(DMTimelineTrack))) == NULL) return DMERR_MALLOC; if (!dmf_read_str(res, (Uint8 *) &hdr.name, sizeof(hdr.name))) return DMERR_FREAD; hdr.enabled = dmfgetc(res); if (!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 (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 track, err; DMFTimeline hdr; DMTimeline *tl; if ((*ptl = tl = dmMalloc0(sizeof(DMTimeline))) == NULL) return DMERR_MALLOC; // Read and check header if (!dmf_read_str(res, (Uint8 *) &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, (Uint8 *) &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 (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) { int param; for (param = 0; param < event->nparams; param++) dmFreeTimelineEventParam(&(event->params[param])); dmFree(event->params); } } void dmFreeTimelineTrack(DMTimelineTrack *track) { if (track != NULL) { int event; dmFree(track->name); for (event = 0; event < track->nevents; event++) dmFreeTimelineEvent(track->events[event]); dmFree(track->events); dmFreeTimelinePoints(&(track->composite.points)); } } void dmFreeTimeline(DMTimeline *tl) { if (tl != NULL) { int i; for (i = 0; i < tl->ntracks; i++) dmFreeTimelineTrack(tl->tracks[i]); 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) { int group; for (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, SDL_Surface *screen, int time) { return DMERR_OK; }