wip update.
[AROS.git] / workbench / classes / datatypes / animation / animationbuffer.c
blob0a0361ed62344abce8c08a76c1d906d9d62cd2b6
1 /*
2 Copyright © 2015-2016, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #ifndef DEBUG
7 # define DEBUG 0
8 #endif
9 #include <aros/debug.h>
11 #include <clib/alib_protos.h>
12 #include <proto/exec.h>
13 #include <proto/dos.h>
14 #include <proto/intuition.h>
15 #include <proto/utility.h>
16 #include <proto/realtime.h>
18 #include <intuition/gadgetclass.h>
19 #include <libraries/realtime.h>
20 #include <gadgets/tapedeck.h>
22 #include "animationclass.h"
24 void FreeBufferSignals(struct ProcessPrivate *priv)
26 D(bug("[animation.datatype/BUFFER]: %s()\n", __func__);)
28 if (priv->pp_BufferFill != -1)
29 FreeSignal(priv->pp_BufferFill);
30 if (priv->pp_BufferPurge != -1)
31 FreeSignal(priv->pp_BufferPurge);
32 if (priv->pp_BufferEnable != -1)
33 FreeSignal(priv->pp_BufferEnable);
34 if (priv->pp_BufferDisable != -1)
35 FreeSignal(priv->pp_BufferDisable);
38 BOOL AllocBufferSignals(struct ProcessPrivate *priv)
40 D(bug("[animation.datatype/BUFFER]: %s()\n", __func__);)
42 if ((priv->pp_BufferEnable = AllocSignal(-1)) != -1)
44 D(bug("[animation.datatype/BUFFER]: %s: allocated enable signal (%x)\n", __func__, priv->pp_BufferEnable);)
45 if ((priv->pp_BufferDisable = AllocSignal(-1)) != -1)
47 D(bug("[animation.datatype/BUFFER]: %s: allocated disable signal (%x)\n", __func__, priv->pp_BufferDisable);)
48 if ((priv->pp_BufferFill = AllocSignal(-1)) != -1)
50 D(bug("[animation.datatype/BUFFER]: %s: allocated fill signal (%x)\n", __func__, priv->pp_BufferFill);)
51 if ((priv->pp_BufferPurge = AllocSignal(-1)) != -1)
53 D(bug("[animation.datatype/BUFFER]: %s: allocated purge signal (%x)\n", __func__, priv->pp_BufferPurge);)
55 priv->pp_BufferSigMask = (1 << priv->pp_BufferEnable) | (1 << priv->pp_BufferDisable) | (1 << priv->pp_BufferFill) | (1 << priv->pp_BufferPurge);
57 D(bug("[animation.datatype/BUFFER]: %s: signal mask (%x)\n", __func__, priv->pp_BufferSigMask);)
59 return TRUE;
64 return FALSE;
67 struct AnimFrame *NextToBuffer(struct ProcessPrivate *priv, struct AnimFrame *newFrame)
69 struct AnimFrame *startFrame, *prevFrame;
70 BOOL loop = FALSE;
72 DFRAMES("[animation.datatype/BUFFER]: %s()\n", __PRETTY_FUNCTION__)
74 ObtainSemaphoreShared(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
76 if ((startFrame = priv->pp_BufferFirst) == NULL)
77 prevFrame = (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames;
78 else
79 prevFrame = startFrame;
81 findprevframe:
82 while ((prevFrame->af_Node.ln_Succ) && (prevFrame->af_Node.ln_Succ->ln_Succ) &&
83 ((prevFrame == (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames) ||
84 (NODEID(prevFrame->af_Node.ln_Succ) == (NODEID(prevFrame) + 1))))
86 prevFrame = (struct AnimFrame *)prevFrame->af_Node.ln_Succ;
89 if (NODEID(prevFrame) == (priv->pp_Data->ad_FrameData.afd_Frames - 1))
91 prevFrame = (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames;
92 if (!loop)
94 loop = TRUE;
95 goto findprevframe;
99 if (prevFrame != (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames)
101 startFrame = prevFrame;
102 newFrame->af_Frame.alf_Frame = NODEID(prevFrame) + 1;
104 else
105 newFrame->af_Frame.alf_Frame = 0;
107 NODEID(newFrame) = (UWORD) newFrame->af_Frame.alf_Frame;
108 newFrame->af_Frame.alf_TimeStamp = newFrame->af_Frame.alf_Frame;
109 priv->pp_BufferFirst = startFrame;
111 ReleaseSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
113 return startFrame;
116 BOOL DoFramePurge(struct Animation_Data *animd, struct AnimFrame *purgeFrame)
118 UWORD dispplayedframe = animd->ad_FrameData.afd_FrameCurrent;
120 if ((purgeFrame->af_Frame.alf_BitMap != animd->ad_FrameBM) &&
121 (purgeFrame != animd->ad_ProcessData->pp_PlaybackFrame) &&
122 (purgeFrame != animd->ad_ProcessData->pp_BufferFirst) &&
123 (NODEID(purgeFrame) != dispplayedframe) &&
124 (NODEID(purgeFrame) != 0))
126 if ((NODEID(purgeFrame) > (dispplayedframe + animd->ad_ProcessData->pp_BufferFrames)) ||
127 (NODEID(purgeFrame) < dispplayedframe))
129 if ((dispplayedframe > (animd->ad_FrameData.afd_Frames - animd->ad_ProcessData->pp_BufferFrames)) &&
130 (NODEID(purgeFrame) < (animd->ad_ProcessData->pp_BufferFrames - (animd->ad_FrameData.afd_Frames - dispplayedframe))))
131 return FALSE;
133 return TRUE;
137 return FALSE;
141 Process to handle loading/discarding (buffering) of animation frames
142 realtime.library player & playback thread will signal us when needed.
145 AROS_UFH3(void, bufferProc,
146 AROS_UFHA(STRPTR, argPtr, A0),
147 AROS_UFHA(ULONG, argSize, D0),
148 AROS_UFHA(struct ExecBase *, SysBase, A6))
150 AROS_USERFUNC_INIT
152 struct Task *thisTask = FindTask(NULL);
153 struct ProcessPrivate *priv = thisTask->tc_UserData;
154 struct AnimFrame *curFrame = NULL, *startFrame;
155 ULONG signal, bufferstep;
157 D(bug("[animation.datatype/BUFFER]: %s()\n", __func__);)
159 if (priv)
162 bug("[animation.datatype/BUFFER] %s: private data @ 0x%p\n", __func__, priv);
163 bug("[animation.datatype/BUFFER] %s: dt obj @ 0x%p, instance data @ 0x%p\n", __func__, priv->pp_Object, priv->pp_Data);
166 priv->pp_BufferFirst = NULL;
167 priv->pp_BufferSpecific = -1;
168 priv->pp_BufferLevel = 0;
169 priv->pp_BufferFlags |= PRIVPROCF_RUNNING;
171 if (AllocBufferSignals(priv))
173 D(bug("[animation.datatype/BUFFER]: %s: entering main loop ...\n", __func__);)
175 bufferstep = priv->pp_Data->ad_BufferStep;
177 while (TRUE)
179 priv->pp_BufferFlags &= ~PRIVPROCF_ACTIVE;
181 if ((priv->pp_BufferFlags & PRIVPROCF_ENABLED) &&
182 ((bufferstep >= 1) || (priv->pp_BufferLevel < priv->pp_BufferFrames)) &&
183 (priv->pp_BufferLevel < priv->pp_Data->ad_FrameData.afd_Frames))
185 D(bug("[animation.datatype/BUFFER]: %s: %d:%d\n", __func__, priv->pp_BufferLevel, priv->pp_BufferFrames);)
186 signal = (1 << priv->pp_BufferFill);
188 else
190 bufferstep = priv->pp_Data->ad_BufferStep;
191 D(bug("[animation.datatype/BUFFER]: %s: waiting ...\n", __func__);)
192 signal = Wait(priv->pp_BufferSigMask | SIGBREAKF_CTRL_C);
195 D(bug("[animation.datatype/BUFFER]: %s: signalled (%08x)\n", __func__, signal);)
197 if (signal & SIGBREAKF_CTRL_C)
198 break;
200 if (signal & (1 << priv->pp_BufferEnable))
201 priv->pp_BufferFlags |= PRIVPROCF_ENABLED;
202 else if (signal & (1 << priv->pp_BufferDisable))
203 priv->pp_BufferFlags &= ~PRIVPROCF_ENABLED;
205 if ((priv->pp_BufferFlags & PRIVPROCF_ENABLED) &&
206 (signal & (1 <<priv->pp_BufferPurge)) &&
207 (priv->pp_BufferFrames < priv->pp_Data->ad_FrameData.afd_Frames))
209 struct AnimFrame *purgeFrame = NULL, *tmpFrame = NULL;
211 D(bug("[animation.datatype/BUFFER]: %s: Purging Frames...\n", __func__);)
212 if (AttemptSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock))
214 D(bug("[animation.datatype/BUFFER]: %s: locked frame list...\n", __func__);)
215 ForeachNodeSafe(&priv->pp_Data->ad_FrameData.afd_AnimFrames, purgeFrame, tmpFrame)
217 if (DoFramePurge(priv->pp_Data, (struct AnimFrame *)purgeFrame))
219 D(bug("[animation.datatype/BUFFER]: %s: unloading frame #%d\n", __func__, NODEID(purgeFrame));)
221 freeFrame(priv->pp_Data, purgeFrame);
223 purgeFrame->af_Frame.MethodID = ADTM_UNLOADFRAME;
224 DoMethodA(priv->pp_Object, (Msg)&purgeFrame->af_Frame);
226 D(bug("[animation.datatype/BUFFER]: %s: freeing frame @0x%p\n", __func__, purgeFrame);)
227 Remove(&purgeFrame->af_Node);
228 FreeMem(purgeFrame, sizeof(struct AnimFrame));
230 priv->pp_BufferLevel--;
233 ReleaseSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
237 if ((priv->pp_BufferFlags & PRIVPROCF_ENABLED) &&
238 (signal & (1 <<priv->pp_BufferFill)))
240 D(bug("[animation.datatype/BUFFER]: %s: Loading Frames...\n", __func__);)
242 priv->pp_BufferFlags |= PRIVPROCF_ACTIVE;
244 if ((priv->pp_BufferFrames > priv->pp_BufferLevel) &&
245 (priv->pp_BufferLevel < priv->pp_Data->ad_FrameData.afd_Frames))
247 if ((curFrame) ||
248 ((curFrame = AllocMem(sizeof(struct AnimFrame), MEMF_ANY|MEMF_CLEAR)) != NULL))
250 curFrame->af_Frame.MethodID = ADTM_LOADFRAME;
252 if (!(priv->pp_BufferFirst) && (priv->pp_BufferSpecific != -1))
254 curFrame->af_Frame.alf_Frame = priv->pp_BufferSpecific;
255 priv->pp_BufferSpecific = -1;
257 ObtainSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
258 startFrame = (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames;
259 while ((startFrame->af_Node.ln_Succ) &&
260 (startFrame->af_Node.ln_Succ->ln_Succ) &&
261 (NODEID(startFrame->af_Node.ln_Succ) < priv->pp_BufferSpecific))
263 startFrame = (struct AnimFrame *)startFrame->af_Node.ln_Succ;
266 if (startFrame == (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames)
267 startFrame = NULL;
268 priv->pp_BufferFirst = startFrame;
269 ReleaseSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
271 NODEID(curFrame) = (UWORD) curFrame->af_Frame.alf_Frame;
272 curFrame->af_Frame.alf_TimeStamp = curFrame->af_Frame.alf_Frame;
274 else
276 startFrame = NextToBuffer(priv, curFrame);
280 bug("[animation.datatype/BUFFER]: %s: Loading Frame #%d (AnimFrame @ 0x%p)\n", __func__, curFrame->af_Frame.alf_Frame, curFrame);
281 bug("[animation.datatype/BUFFER]: %s: startFrame @ 0x%p\n", __func__, startFrame);
284 if (DoMethodA(priv->pp_Object, (Msg)&curFrame->af_Frame))
286 priv->pp_BufferLevel++;
288 bug("[animation.datatype/BUFFER]: %s: Loaded! bitmap @ %p\n", __func__, curFrame->af_Frame.alf_BitMap);
289 bug("[animation.datatype/BUFFER]: %s: frame #%d. stamp %d\n", __func__, curFrame->af_Frame.alf_Frame, curFrame->af_Frame.alf_TimeStamp);
290 bug("[animation.datatype/BUFFER]: %s: bitmap @ %p\n", __func__, curFrame->af_Frame.alf_BitMap);
293 ObtainSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
294 Insert(&priv->pp_Data->ad_FrameData.afd_AnimFrames, &curFrame->af_Node, &startFrame->af_Node);
295 if (startFrame == priv->pp_BufferFirst)
297 if (NODEID(curFrame) < (priv->pp_Data->ad_FrameData.afd_Frames - 1))
299 priv->pp_BufferFirst = curFrame;
300 while ((priv->pp_BufferFirst->af_Node.ln_Succ) &&
301 (priv->pp_BufferFirst->af_Node.ln_Succ->ln_Succ) &&
302 (NODEID(priv->pp_BufferFirst->af_Node.ln_Succ) == (NODEID(priv->pp_BufferFirst) + 1)))
304 priv->pp_BufferFirst = (struct AnimFrame *)priv->pp_BufferFirst->af_Node.ln_Succ;
307 if ((priv->pp_BufferFirst) &&
308 (NODEID(priv->pp_BufferFirst) == (priv->pp_Data->ad_FrameData.afd_Frames - 1)))
309 priv->pp_BufferFirst = NULL;
311 ReleaseSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
313 cacheFrame(priv->pp_Data, curFrame);
315 curFrame = NULL;
317 else
319 curFrame->af_Frame.MethodID = ADTM_UNLOADFRAME;
320 DoMethodA(priv->pp_Object, (Msg)&curFrame->af_Frame);
325 if (bufferstep > 0)
326 bufferstep--;
328 SetTaskPri((struct Task *)priv->pp_Data->ad_PlayerProc, 0);
331 FreeBufferSignals(priv);
333 priv->pp_BufferFlags &= ~PRIVPROCF_RUNNING;
334 priv->pp_Data->ad_BufferProc = NULL;
336 D(bug("[animation.datatype/BUFFER]: %s: exiting ...\n", __func__);)
338 return;
340 AROS_USERFUNC_EXIT