From c23568709680c3122aba0e114be0146088242f7f Mon Sep 17 00:00:00 2001 From: otya128 Date: Sat, 22 Jul 2017 14:34:07 +0900 Subject: [PATCH] Implement BGANIM? --- SMILEBASIC/bg.d | 206 ++++++++++++++++++++++++++++++++++ SMILEBASIC/builtinfunctions.d | 48 ++++++++ SMILEBASIC/sprite.d | 67 +++++++++++ 3 files changed, 321 insertions(+) diff --git a/SMILEBASIC/bg.d b/SMILEBASIC/bg.d index 756816a..f91e58f 100644 --- a/SMILEBASIC/bg.d +++ b/SMILEBASIC/bg.d @@ -1,6 +1,7 @@ module otya.smilebasic.bg; import otya.smilebasic.petitcomputer; import otya.smilebasic.error; +import otya.smilebasic.sprite; import derelict.sdl2.sdl; import derelict.opengl3.gl; @@ -46,9 +47,11 @@ class BG r = 0; show = true; bgcolor = 0xffffffff; + initBGAnimationTable(); } void render(int display, float disw, float dish) { + animation(); if (!show) return; float aspect = disw / dish; @@ -292,4 +295,207 @@ class BG { return this.bgcolor; } + bool isAnim; + SpriteAnimData[][SpriteAnimTarget.V + 1] anim; + int[SpriteAnimTarget.V + 1] animindex; + int[SpriteAnimTarget.V + 1] animloop; + int[SpriteAnimTarget.V + 1] animloopcnt; + void setAnimation(SpriteAnimData[] anim, SpriteAnimTarget sat, int loop) + { + this.anim[sat] = null; + if(loop < 0) + { + throw new IllegalFunctionCall("BGANIM"); + } + animloop[sat] = loop; + animloopcnt[sat] = 0; + animindex[sat] = 0; + this.anim[sat] = anim; + isAnim = true; + } + + + + void bganim(wstring target, double[] data) + { + static import std.uni; + bool relative = false; + if(target[$ - 1..$] == "+") + { + target = target[0..$-1]; + relative = true; + } + target = std.uni.toUpper(target); + if (!(target in bgAnimTarget)) + throw new IllegalFunctionCall("BGANIM"); + auto tgete = bgAnimTarget[target]; + bganim(tgete | (relative ? SpriteAnimTarget.relative : cast(SpriteAnimTarget)0), data); + + } + SpriteAnimTarget[wstring] bgAnimTarget; + void initBGAnimationTable() + { + bgAnimTarget = [ + "XY": SpriteAnimTarget.XY, + "Z": SpriteAnimTarget.Z, + "R": SpriteAnimTarget.R, + "S": SpriteAnimTarget.S, + "C": SpriteAnimTarget.C, + "V": SpriteAnimTarget.V, + ]; + } + SpriteAnimTarget getBGAnimTarget(wstring target) + { + bool relative = false; + if(target[$ - 1..$] == "+") + { + target = target[0..$-1]; + relative = true; + } + return bgAnimTarget[target] | (relative ? SpriteAnimTarget.relative : cast(SpriteAnimTarget)0); + } + void animation(SpriteAnimData* data, SpriteAnimTarget target) + { + if (!animationEnabled) + return; + auto frame = data.elapse; + if(frame == 1) + { + if(!data.interpolation) + { + switch(target) + { + case SpriteAnimTarget.XY: + offsetx = cast(int)data.data.x; + offsety = cast(int)data.data.y; + break; + case SpriteAnimTarget.Z: + offsetz = cast(int)data.data.z; + break; + case SpriteAnimTarget.R: + r = data.data.r; + break; + case SpriteAnimTarget.S: + scalex = data.data.scalex; + scaley = data.data.scaley; + break; + case SpriteAnimTarget.C: + break; + case SpriteAnimTarget.V: + break; + default: + break; + } + } + } + if(data.interpolation) + { + //線形補完する奴 + switch(target) + { + case SpriteAnimTarget.XY: + offsetx = cast(int)(data.old.x + ((data.data.x - data.old.x) / data.frame) * frame); + offsety = cast(int)(data.old.y + ((data.data.y - data.old.y) / data.frame) * frame); + break; + case SpriteAnimTarget.Z: + offsetz = cast(int)(data.old.z + ((data.data.z - data.old.z) / data.frame) * frame); + break; + case SpriteAnimTarget.R: + r = data.old.r + ((data.data.r - data.old.r) / data.frame) * frame; + break; + case SpriteAnimTarget.S: + scalex = data.old.scalex + ((data.data.scalex - data.old.scalex) / data.frame) * frame; + scaley = data.old.scaley + ((data.data.scaley - data.old.scaley) / data.frame) * frame; + break; + case SpriteAnimTarget.C: + break; + case SpriteAnimTarget.V: + break; + default: + break; + } + } + } + + void animation() + { + if (!animationEnabled) + return; + foreach(i, ref d; anim) + { + if(!d) continue;//未定義 + SpriteAnimTarget target = cast(SpriteAnimTarget)i; + int index = animindex[i]; + SpriteAnimData* data = &d[index]; + data.elapse = data.elapse + 1; + auto frame = data.elapse; + animation(data, target); + if(frame >= data.frame) + { + animindex[i] = (animindex[i] + 1) % cast(int)d.length; + data.elapse = 0; + if(animloop[i] == 0) + { + continue; + } + if(!animindex[i]) + { + animloop[i]++; + if(animloop[i] >= animloopcnt[i]) + { + anim[i] = null; + continue; + } + } + continue; + } + } + } + bool animationEnabled = true; + void bganim(SpriteAnimTarget target, double[] data) + { + synchronized (this) + { + bool relative; + if(SpriteAnimTarget.relative & target) + { + relative = true; + target ^= SpriteAnimTarget.relative; + } + int animcount = cast(int)data.length / ((target == SpriteAnimTarget.XY || target == SpriteAnimTarget.UV) ? 3 : 2); + SpriteAnimData[] animdata = new SpriteAnimData[animcount]; + int j; + int loop = 1; + SpriteAnimData* old; + for(int i = 0; i < data.length;) + { + i = animdata[j].load(i, this, target, data, old, relative); + old = &animdata[j++]; + if(data.length - i == 1) + { + //loop + loop = cast(int)data[i]; + break; + } + } + setAnimation(animdata, target, loop); + if(animdata[0].frame == 1) + { + animindex[target]++; + animation(&animdata[0], target); + if(animcount == 1) + { + if(loop > 1 || loop == 0) + { + animindex[target] = 0; + animloopcnt[target]++; + } + else + { + anim[target] = null; + } + } + } + } + } } diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d index cbcb684..601cb82 100644 --- a/SMILEBASIC/builtinfunctions.d +++ b/SMILEBASIC/builtinfunctions.d @@ -1790,6 +1790,54 @@ class BuiltinFunction if(args[1].isNumber) p.sprite.spanim(no, cast(SpriteAnimTarget)(args[1].castInteger), animdata); } + + static void BGANIM(PetitComputer p, Value[] va_args) + { + //TODO:配列 + auto args = retro(va_args); + int no = args[0].castInteger; + if (!p.isValidLayer(no)) + { + throw new OutOfRange(smilebasicFunctionName, 1); + } + double[] animdata; + if(args[2].isString) + { + VM vm = p.vm; + vm.restoreData(args[2].castDString); + int keyframe = vm.readData.castInteger; + auto target = p.getBG(no).getBGAnimTarget(args[1].castDString); + int item = 2; + if((target & 7) == SpriteAnimTarget.XY || (target & 7) == SpriteAnimTarget.UV) item++; + animdata = new double[item * keyframe + 1]; + int j; + for(int i = 0; i < keyframe; i++) + { + animdata[j] = vm.readData.castDouble; + animdata[j + 1] = vm.readData.castDouble; + if(item == 3) + animdata[j + 2] = vm.readData.castDouble; + j += item; + } + if(args.length > 3) + animdata[j] = args[3].castInteger; + else + animdata[j] = 1;//loop count + } + else + { + int i; + animdata = new double[args.length - 2]; + foreach(a; args[2..$]) + { + animdata[i++] = a.castDouble; + } + } + if(args[1].isString) + p.getBG(no).bganim(args[1].castDString, animdata); + if(args[1].isNumber) + p.getBG(no).bganim(cast(SpriteAnimTarget)(args[1].castInteger), animdata); + } static void SPDEF(PetitComputer p, int id, out int U, out int V) { if (!p.sprite.isValidDef(id)) diff --git a/SMILEBASIC/sprite.d b/SMILEBASIC/sprite.d index 9c766a8..ce09e0b 100644 --- a/SMILEBASIC/sprite.d +++ b/SMILEBASIC/sprite.d @@ -160,6 +160,73 @@ struct SpriteAnimData } return i; } + + import otya.smilebasic.bg; + int load(int i, BG bg, SpriteAnimTarget target, double[] data, SpriteAnimData* old, bool r) + { + relative = r; + this.frame = cast(int)data[i]; + if(this.frame < 0) + { + this.frame = -this.frame; + interpolation = true; + } + if(this.frame == 0) + { + throw new IllegalFunctionCall("BGANIM"); + } + i++; + switch(target) + { + case SpriteAnimTarget.XY: + this.data.x = cast(int)data[i++]; + this.data.y = cast(int)data[i++]; + if (relative) + { + this.data.x += bg.offsetx; + this.data.y += bg.offsety; + } + this.old.x = old ? old.data.x : bg.offsetx; + this.old.y = old ? old.data.y : bg.offsety; + break; + case SpriteAnimTarget.Z: + this.data.z = cast(int)data[i++]; + if (relative) + { + this.data.z += bg.offsetz; + } + this.old.z = old ? old.data.z : bg.offsetz; + break; + case SpriteAnimTarget.R: + this.data.r = data[i++]; + if (relative) + { + this.data.r += bg.r; + } + this.old.r = old ? old.data.r : bg.r; + break; + case SpriteAnimTarget.S: + this.data.scalex = data[i++]; + this.data.scaley = data[i++]; + if (relative) + { + this.data.scalex += bg.scalex; + this.data.scaley += bg.scaley; + } + this.old.scalex = old ? old.data.scalex : bg.scalex; + this.old.scaley = old ? old.data.scaley : bg.scaley; + break; + case SpriteAnimTarget.C: + this.data.c = cast(uint)data[i++]; + break; + case SpriteAnimTarget.V: + this.data.var = data[i++]; + break; + default: + throw new IllegalFunctionCall("BGANIM"); + } + return i; + } } struct SpriteDef {