1
0
Files
2017-07-28 23:08:09 +09:00

502 lines
15 KiB
D

module otya.smilebasic.bg;
import otya.smilebasic.petitcomputer;
import otya.smilebasic.error;
import otya.smilebasic.sprite;
import derelict.sdl2.sdl;
import derelict.opengl3.gl;
struct BGChip
{
int i;
int screenData()
{
return i;
}
void screenData(int a)
{
i = a;
}
}
//912枚まで描画されるみたい
//->899枚まで描画してその後は一番下のみ描画の様子
//縦から描画していそう
class BG
{
BGChip[16384] chip;
int offsetx, offsety, offsetz;
int clipx, clipy, clipx2, clipy2;
double scalex, scaley;
double r;
int homex, homey;
int width, height;
int rendermax = 899;
PetitComputer petitcom;
bool show;
int chipWidth = 16;
int chipHeight = 16;
int display;
int bgcolor;
this(PetitComputer pc)
{
chip[] = BGChip(0);
width = 25;
height = 35;
petitcom = pc;
scalex = 1;
scaley = 1;
r = 0;
show = true;
bgcolor = 0xffffffff;
initBGAnimationTable();
}
void render(int display, float disw, float dish)
{
animation();
if (!show)
return;
float aspect = disw / dish;
disw /= 2;
dish /= 2;
float z = offsetz;
{
ubyte r, g, b, a;
petitcom.RGBRead(bgcolor, r, g, b, a);
glColor4ub(r, g, b, 255);
}
petitcom.chRenderingDisplay(display, clipx, clipx, clipx2 - clipx + 1, clipy2 - clipy + 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(homex, homey, 0);
glScalef(scalex, scaley, 1f);
glRotatef( r, 0.0f, 0.0f, 1.0f );
glTranslatef(-offsetx, -offsety, z);
version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z);
//viewport
//clipx,clipy
int bgchipwidth = 512 / chipWidth;
int bgchipheight = 512 / chipHeight;
int bgchipwidth2 = petitcom.graphic.width / chipWidth;
int bgchipheight2 = petitcom.graphic.height / chipHeight;
int chipNumberMax = bgchipwidth * bgchipheight;
int chipNumberMax2 = bgchipwidth2 * bgchipheight2;
bool isHR = (petitcom.graphic.width > 512) || (petitcom.graphic.height > 512);
glBegin(GL_QUADS);
int rendercount = 0;
for(int x = 0; x < width; x++)
{
version(none)
{
for(int y = 0; y < height; y++){}
}
for(int y = height - 1; y >= 0; y--)//下から描画してるのか?
{
BGChip bgc = chip[x + y * width];
if(!bgc.i) continue;
int u = (bgc.i % bgchipwidth) * chipWidth;
int v = (bgc.i / bgchipheight) * chipHeight;
if (bgc.i >= chipNumberMax)
{
if (isHR)
{
if (bgc.i >= bgchipheight2 * bgchipwidth)
{
u += 512;
v %= petitcom.graphic.height;
}
}
else
{
u = ((bgc.i % chipNumberMax) % bgchipwidth) * chipWidth;
v = ((bgc.i % chipNumberMax) / bgchipheight) * chipHeight;
}
}
int u2 = u + chipWidth;
int v2 = v + chipHeight;
int w = chipWidth;
int h = chipHeight;
glTexCoord2f(u / (cast(float)petitcom.graphic.width) - 1 , v2 / (cast(float)petitcom.graphic.height) - 1);
glVertex3f((x * w), (y * h + h), 0);
glTexCoord2f(u / (cast(float)petitcom.graphic.width) - 1, v / (cast(float)petitcom.graphic.height) - 1);
glVertex3f((x * w), (y * h), 0);
glTexCoord2f(u2 / (cast(float)petitcom.graphic.width) - 1, v / (cast(float)petitcom.graphic.height) - 1);
glVertex3f((x * w + w), (y * h), 0);
glTexCoord2f(u2 / (cast(float)petitcom.graphic.width) - 1, v2 / (cast(float)petitcom.graphic.height) - 1);
glVertex3f((x * w + w), (y * h + h), 0);
rendercount++;
/*if(rendercount >= 899)
{
break;
}*/
}
}
glEnd();
glLoadIdentity();
}
void put(int x, int y, int screendata)
{
int i = screendata & 4095;
chip[x + y * width].i = i;
}
void clear()
{
chip[0 .. width * height] = BGChip(0);
}
void screen(int w, int h)
{
rot = 0;
scalex = 1;
scaley = 1;
homex = 0;
homey = 0;
chipWidth = 16;
chipHeight = 16;
offsetx = offsety = offsetz = 0;
//BGCLIP is not initialized
this.width = w;
this.height = h;
this.clear();
}
void ofs(int x, int y, int z)
{
this.offsetx = x;
this.offsety = y;
this.offsetz = z;
}
void clip(int x, int y, int x2, int y2)
{
import std.algorithm : swap;
if (x > x2)
{
swap(x, x2);
}
if (y > y2)
{
swap(y, y2);
}
this.clipx = x;
this.clipy = y;
this.clipx2 = x2;
this.clipy2 = y2;
}
void clip()
{
this.clipx = 0;
this.clipy = 0;
this.clipx2 = petitcom.currentDisplay.rect[display].w - 1;
this.clipy2 = petitcom.currentDisplay.rect[display].h - 1;
}
void home(int x, int y)
{
homex = x;
homey = y;
}
void scale(double x, double y)
{
this.scalex = x;
this.scaley = y;
}
void getScale(out double x, out double y)
{
x = this.scalex;
y = this.scaley;
}
void rot(int rot)
{
this.r = rot;
}
int rot()
{
return cast(int)r;
}
void fill(int x, int y, int x2, int y2, int screendata)
{
import std.algorithm;
int id = screendata & 4095;
if(x > x2) swap(x, x2);
if(y > y2) swap(y, y2);
for(; y <= y2; y++)
chip[x + y * width .. x2 + y * width + 1] = BGChip(id);
/*for(int i = x; i <= x2; i++)
{
chip[i + y * width].i = id;
}*/
}
void fill(int x, int y, int x2, int y2, ushort[] screendata)
{
import std.algorithm;
if(x > x2) swap(x, x2);
if(y > y2) swap(y, y2);
int index = 0;
if (screendata.length == 0)
{
fill(x, y, x2, y2, 0);
return;
}
for(; y <= y2; y++)
for(int i = x; i <= x2; i++)
{
chip[i + y * width] = BGChip(screendata[index] & 4095);
index = (index + 1) % cast(int)screendata.length;
}
}
int get(int x, int y, int flag)
{
if (flag)
{
return chip[x / chipWidth + y / chipHeight * width].screenData;
}
else
{
return chip[x + y * width].screenData;
}
}
void save(T)(int x, int y, int w, int h, T[] array)
if (is(T == int) || is(T == double))
{
int desti;
for (int i = x; i < x + w; i++)
{
for (int j = y; j < y + h; j++)
{
desti++;
int index = i + j * width;
if (index < 0)
continue;
array[desti - 1] = cast(int)chip[index].screenData;
}
}
}
void load(T)(int x, int y, int w, int h, T[] array, int charoff)
if (is(T == int) || is(T == double))
{
int srci;
for (int i = x; i < x + w; i++)
{
for (int j = y; j < y + h; j++)
{
srci++;
int index = i + j * width;
if (index < 0)
continue;
auto scr = cast(int)array[srci - 1];
auto chr = ((scr & 0xFFF) + charoff) & /*mask?*/0xFFF;
chip[index].screenData = (scr & 0xF000) | chr;
}
}
}
import otya.smilebasic.vm;
Callback callback;
public void color(int color)
{
this.bgcolor = color;
}
public int color()
{
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;
}
}
}
}
}
}