1
0
Files
otyaSMILEBASIC/SMILEBASIC/graphic.d
2016-12-18 17:40:59 +09:00

1186 lines
34 KiB
D

module otya.smilebasic.graphic;
import derelict.sdl2.sdl;
import derelict.sdl2.image;
import derelict.opengl3.gl;
import derelict.opengl3.gl3;
import otya.smilebasic.petitcomputer;
import std.string;
class Graphic
{
PetitComputer petitcom;
int width;
int height;
this(PetitComputer p)
{
petitcom = p;
paint = new Paint();
width = 512;
height = 512;
//nnnue
paint.buffer = new uint[width * height];
}
int GRPFWidth, GRPFHeight;
void setSize(int w, int h)
{
width = w;
height = h;
}
void getSize(out int w, out int h)
{
w = width;
h = height;
}
void initGraphicPages()
{
if (GRP.length == 0)
{
GRP = new GraphicPage[6];
}
for(int i = 0; i < 4; i++)
{
GRP[i] = createEmptyPage();
}
GRP[4] = createGRPF(petitcom.spriteFile);
GRP[5] = createGRPF(petitcom.BGFile);
}
GraphicPage createGRPF(string file)
{
SDL_RWops* stream = SDL_RWFromFile(toStringz(file), toStringz("rb"));
auto src = IMG_Load_RW(stream, 0);
SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);//0xff000000, 0x00ff0000, 0x0000ff00, 0xFF);
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = surface.w;
rect.h = surface.h;
// SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
// SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_BLEND);
ubyte sr, sg, sb, sa;
SDL_GetRGBA((cast(uint*)src.pixels)[0], src.format, &sr, &sg, &sb, &sa);
auto color = SDL_MapRGBA(surface.format, sr, sg, sb, sa);
SDL_SetColorKey(src, SDL_TRUE, (cast(uint*)src.pixels)[0]);
//SDL_SetColorKey(surface, SDL_TRUE, color);
int i = SDL_BlitSurface(src, &rect, surface, &rect);
auto srcpixels = (cast(uint*)src.pixels);
auto pixels = (cast(uint*)surface.pixels);
auto aaa = surface.format.Amask;
//surface.format.Amask = 0xFF;
for(int x = 0; x < surface.w; x++)
{
for(int y = 0; y < surface.h; y++)
{
ubyte r, g, b, a;
SDL_GetRGBA(*pixels, surface.format, &r, &g, &b, &a);
if(r == sr && g == sg && b == sb)
{
r = 0;
g = 0;
b = 0;
a = 0;
*pixels = 0;
*pixels = SDL_MapRGBA(surface.format, r, g, b, a);
}
pixels++;
}
}
SDL_RWclose(stream);
SDL_FreeSurface(src);
return new GraphicPage(surface);
}
GraphicPage createEmptyPage()
{
auto surface = SDL_CreateRGBSurface(0, width, height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
auto pixels = (cast(uint*)surface.pixels);
for(int x = 0; x < surface.w; x++)
{
for(int y = 0; y < surface.h; y++)
{
ubyte r, g, b, a;
SDL_GetRGBA(*pixels, surface.format, &r, &g, &b, &a);
{
r = 0;
g = 0;
b = 0;
a = 0;
*pixels = 0;
*pixels = SDL_MapRGBA(surface.format, r, g, b, a);
}
pixels++;
}
}
return new GraphicPage(surface);
}
bool[2] visibles = [true, true];
protected int[2] showPage = [0, 1];
protected int[2] usePage = [0, 1];
bool visible()
{
return visibles[petitcom.displaynum];
}
void visible(bool value)
{
visibles[petitcom.displaynum] = value;
}
@property int useGRP()
{
return usePage[petitcom.displaynum];
}
@property int showGRP()
{
return showPage[petitcom.displaynum];
}
@property void useGRP(int page)
{
usePage[petitcom.displaynum] = page;
}
@property void showGRP(int page)
{
showPage[petitcom.displaynum] = page;
}
uint gcolor = -1;
GraphicPage[] GRP;
GraphicPage[] oldGRP;
class Paint
{
uint[] buffer;
static const MAXSIZE = 1024; /* バッファサイズ */
/* 画面サイズは 1024 X 1024 とする */
static const MINX = 0;
static const MINY = 0;
static const MAXX = 511;
static const MAXY = 511;
struct BufStr {
int lx; /* 領域右端のX座標 */
int rx; /* 領域右端のX座標 */
int y; /* 領域のY座標 */
int oy; /* 親ラインのY座標 */
};
BufStr[MAXSIZE] buff; /* シード登録用バッファ */
BufStr* sIdx, eIdx; /* buffの先頭・末尾ポインタ */
uint point(int x, int y)
{
return buffer.ptr[x + y * width];
}
void pset(int x, int y, uint col)
{
buffer.ptr[x + y * width] = col;
}
/*
scanLine : 線分からシードを探索してバッファに登録する
int lx, rx : 線分のX座標の範囲
int y : 線分のY座標
int oy : 親ラインのY座標
unsigned int col : 領域色
*/
void scanLine( int lx, int rx, int y, int oy, uint col )
{
while ( lx <= rx ) {
/* 非領域色を飛ばす */
for ( ; lx < rx ; lx++ )
if ( point( lx, y ) == col ) break;
if ( point( lx, y ) != col ) break;
eIdx.lx = lx;
/* 領域色を飛ばす */
for ( ; lx <= rx ; lx++ )
if ( point( lx, y ) != col ) break;
eIdx.rx = lx - 1;
eIdx.y = y;
eIdx.oy = oy;
if ( ++eIdx == &buff.ptr[MAXSIZE] )
eIdx = buff.ptr;
}
}
/*
paint : 塗り潰し処理(高速版)
int x, y : 開始座標
unsigned int paintCol : 塗り潰す時の色(描画色)
*/
void paint( int x, int y, uint paintCol , out int dx, out int dy, out int dx2, out int dy2)
{
int lx, rx; /* 塗り潰す線分の両端のX座標 */
int ly; /* 塗り潰す線分のY座標 */
int oy; /* 親ラインのY座標 */
int i;
uint col = point( x, y ); /* 閉領域の色(領域色) */
dx = int.max, dy = int.max, dx2 = int.min, dy2 = int.min;
if ( col == paintCol ) return; /* 領域色と描画色が等しければ処理不要 */
sIdx = buff.ptr;
eIdx = buff.ptr + 1;
sIdx.lx = sIdx.rx = x;
sIdx.y = sIdx.oy = y;
do {
lx = sIdx.lx;
rx = sIdx.rx;
ly = sIdx.y;
oy = sIdx.oy;
int lxsav = lx - 1;
int rxsav = rx + 1;
if ( ++sIdx == &buff.ptr[MAXSIZE] ) sIdx = buff.ptr;
/* 処理済のシードなら無視 */
if ( point( lx, ly ) != col )
continue;
/* 右方向の境界を探す */
while ( rx < MAXX ) {
if ( point( rx + 1, ly ) != col ) break;
rx++;
}
/* 左方向の境界を探す */
while ( lx > MINX ) {
if ( point( lx - 1, ly ) != col ) break;
lx--;
}
import std.algorithm;
dy = min(dy, ly);
dy2 = max(dy2, ly);
dx = min(dx, lx);
dx2 = max(dx2, rx);
//
/* lx-rxの線分を描画 */
for ( i = lx; i <= rx; i++ ) pset( i, ly, paintCol );
/* 真上のスキャンラインを走査する */
if ( ly - 1 >= MINY ) {
if ( ly - 1 == oy ) {
scanLine( lx, lxsav, ly - 1, ly, col );
scanLine( rxsav, rx, ly - 1, ly, col );
} else {
scanLine( lx, rx, ly - 1, ly, col );
}
}
/* 真下のスキャンラインを走査する */
if ( ly + 1 <= MAXY ) {
if ( ly + 1 == oy ) {
scanLine( lx, lxsav, ly + 1, ly, col );
scanLine( rxsav, rx, ly + 1, ly, col );
} else {
scanLine( lx, rx, ly + 1, ly, col );
}
}
} while ( sIdx != eIdx );
}
void gpaintBuffer(uint* pixels, int x, int y, uint color, GLenum tf)
{
int dx, dy, dx2, dy2;
paint(x, y, color, dx, dy, dx2, dy2);
if(dx == int.max) return;
int h = dy2 - dy;
//glTexSubImage2D(GL_TEXTURE_2D , 0, 0, dy, width, h, tf, GL_UNSIGNED_BYTE, pixels + (dy * width));
glDrawPixels(512, dy2, tf, GL_UNSIGNED_BYTE, buffer.ptr);
}
}
Paint paint;
abstract void initVM();
abstract void display(int display);
abstract void updateVM();
abstract void gpset(int page, int x, int y, uint color);
abstract void gline(int page, int x, int y, int x2, int y2, uint color);
abstract void gbox(int page, int x, int y, int x2, int y2, uint color);
abstract void gfill(int page, int x, int y, int x2, int y2, uint color);
abstract void gcls(int page, uint color);
abstract void gpaint(int page, int x, int y, uint color);
abstract void gcircle(int page, int x, int y, int r, uint color);
abstract void gcircle(int page, int x, int y, int r, int startr, int endr, int flag, uint color);
abstract void gputchr(int page, int x, int y, int text, int scalex, int scaley, uint color);
abstract void gputchr(int page, int x, int y, wstring text, int scalex, int scaley, uint color);
abstract int gspoit(int page, int x, int y);
abstract void gsave(int savepage, int x, int y, int w, int h, double[] array, int flag);
abstract void gsave(int savepage, int x, int y, int w, int h, int[] array, int flag);
abstract void gload(int x, int y, int w, int h, int[] array, int flag, int copymode);
abstract void gload(int x, int y, int w, int h, double[] array, int flag, int copymode);
void gloadPalette(T, T2)(int x, int y, int w, int h, T[] array, T2[] palette, int copymode)
if ((is(T == int) || is(T == double)) && (is(T2 == int) || is(T2 == double)))
{
if (cast(GraphicFBO)this)
{
GraphicFBO gfbo = (cast(GraphicFBO)this);
gfbo.gloadPalette(x, y, w, h, array, palette, copymode);
}
}
int[2] gprios = [511, 511];
@property ref gprio()
{
return gprios[petitcom.displaynum];
}
@property void gprio(int value)
{
gprios[petitcom.displaynum] = value;
}
void render()
{
for (int i = 0; i < petitcom.currentDisplay.rect.length; i++)
{
render(i, petitcom.currentDisplay.rect[i].w, petitcom.currentDisplay.rect[i].h);
}
}
void render(int display, int w, int h)
{
if (!visibles[display])
return;
petitcom.chRenderingDisplay(display);
float z = gprios[display];
glColor3f(1.0, 1.0, 1.0);
glBindTexture(GL_TEXTURE_2D, GRP[showPage[display]].glTexture);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
int x1 = displayArea[display].x;
int y1 = displayArea[display].y;
int x2 = x1 + displayArea[display].w;
int y2 = y1 + displayArea[display].h;
glTexCoord2f(x1 / (cast(float)width) - 1 , y2 / (cast(float)height) - 1);
glVertex3f(x1, y2, z);
glTexCoord2f(x1 / (cast(float)width) - 1, y1 / (cast(float)height) - 1);
glVertex3f(x1, y1, z);
glTexCoord2f(x2 / (cast(float)width) - 1, y1 / (cast(float)height) - 1);
glVertex3f(x2, y1, z);
glTexCoord2f(x2 / (cast(float)width) - 1, y2 / (cast(float)height) - 1);
glVertex3f(x2, y2, z);
glEnd();
//glFlush();
}
SDL_Rect[2] writeArea;
SDL_Rect[2] displayArea;
void clip(bool clipmode)
{
if (clipmode)
{
clip(clipmode, 0, 0, width, height);
}
else
{
clip(clipmode, 0, 0, petitcom.currentScreenWidth, petitcom.currentScreenHeight);
}
}
void clip(bool clipmode, int x, int y, int w, int h)
{
if (clipmode)
{
writeArea[petitcom.displaynum].x = x;
writeArea[petitcom.displaynum].y = y;
writeArea[petitcom.displaynum].w = w;
writeArea[petitcom.displaynum].h = h;
this.display(petitcom.displaynum);
}
else
{
displayArea[petitcom.displaynum] = SDL_Rect(x, y, w, h);
}
}
static int ARGB32ToRGBA16Color(int argb32)
{
auto a = (argb32 & 0xFF000000) >> 24;
auto r = (argb32 & 0x00FF0000) >> 16;
auto g = (argb32 & 0x0000FF00) >> 8;
auto b = (argb32 & 0x000000FF);
return (a == 255) | r >> 3 << 11 | g >> 3 << 6 | b >> 3 << 1;
}
static int RGBA16ToARGB32Color(int rgba16)
{
auto a = (rgba16 & 0b0000000000000001) == 1 ? 0xFF000000 : 0;
auto r = (rgba16 & 0b1111100000000000) >> 11;
auto g = (rgba16 & 0b0000011111000000) >> 6;
auto b = (rgba16 & 0b0000000000111110) >> 1;
return a | r << 19 | g << 11 | b << 3;
}
}
class GraphicFBO : Graphic
{
this(PetitComputer p)
{
super(p);
}
override void initGraphicPages()
{
foreach(g; GRP)
{
if (g.glTexture)
g.deleteGL();
}
super.initGraphicPages();
foreach(g; GRP)
{
g.createTexture(petitcom.renderer, petitcom.textureScaleMode);
g.createBuffer();
}
}
override @property void useGRP(int page)
{
super.useGRP = page;
glBindFramebufferEXT(GL_FRAMEBUFFER, this.GRP[page].buffer);
}
override @property int useGRP()
{
return super.useGRP;
}
//(x+r,y):0°
//(x,y+r):90°
void drawCircle(int x, int y, int r, int startr, int endr, int flag)
{
import std.math : sin, cos, PI;
import std.algorithm.comparison : min;
int count = min(r, 1000);
if (flag)
{
glBegin(GL_LINE_LOOP);
glVertex2i(x, y);
}
else
{
glBegin(GL_LINE_STRIP);
}
startr = startr % 360;
endr = endr % 360;
if (startr > endr)
{
endr += 360;
}
for (int i = 0; i <= r; i++)
{
//float a = i * (360f / count);
float angle = (cast(float)i / count) * ((endr - startr) / 180f) * PI + (startr / 180f * PI);
glVertex2f(cos(angle) * r + x, sin(angle) * r + y);
}
glEnd();
}
void drawCircle(int x, int y, int r)
{
import std.math : sin, cos, PI;
import std.algorithm.comparison : min;
int count = min(r, 1000);
glBegin(GL_LINE_STRIP);
for (int i = 0; i <= r; i++)
{
//float a = i * (360f / r);
float angle = cast(float)i / count * 2f * PI;
glVertex2f(cos(angle) * r + x, sin(angle) * r + y);
}
glEnd();
}
void drawText(wstring text)
{
int x;
foreach (c; text)
{
drawCharacter(x, 0, c);
x += 8;
}
}
void drawCharacter(int x, int y, wchar character)
{
auto rect = petitcom.console.fontTable[character];
float tx1 = (rect.x) / (cast(float)GRPFWidth) - 1;
float ty1 = (rect.y + 8) / (cast(float)GRPFHeight) - 1;
float tx2 = (rect.x + 8) / (cast(float)GRPFWidth) - 1;
float ty2 = (rect.y) / (cast(float)GRPFHeight) - 1;
glTexCoord2f(tx1 , ty1);
glVertex3i(x, y + 8, 0);
glTexCoord2f(tx1, ty2);
glVertex3i(x, y, 0);
glTexCoord2f(tx2, ty2);
glVertex3i(x + 8, y, 0);
glTexCoord2f(tx2, ty1);
glVertex3i(x + 8, y + 8, 0);
}
override void initVM()
{
SDL_GL_MakeCurrent(petitcom.window, petitcom.contextVM);
glAlphaFunc(GL_GEQUAL, 0.1f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_DEPTH_TEST);
}
int drc = 0;
override void display(int display)
{
void chScreen(int x, int y, int w, int h)
{
glViewport(x, y, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(x, x + w - 1, y, y + h - 1, -256, 1024);//wakaranai
}
chScreen(writeArea[display].x, writeArea[display].y, writeArea[display].w, writeArea[display].h);
glBindFramebufferEXT(GL_FRAMEBUFFER, this.GRP[usePage[display]].buffer);
}
bool flushRequired;
override void updateVM()
{
if (drc)
glFlush();
drc = 0;
}
uint convertColor(uint color)
{
return petitcom.toGLColor(this.GRP[0].textureFormat, color & 0xFFF8F8F8);
}
override void gpset(int page, int x, int y, uint color)
{
color = convertColor(color);
glBegin(GL_POINTS);
glColor4ubv(cast(ubyte*)&color);
glVertex2f(x, y);
glEnd();
drc++;
}
override void gline(int page, int x, int y, int x2, int y2, uint color)
{
color = convertColor(color);
glBegin(GL_LINES);
glColor4ubv(cast(ubyte*)&color);
glVertex2f(x, y);
glVertex2f(x2, y2);
glEnd();
drc++;
}
override void gbox(int page, int x, int y, int x2, int y2, uint color)
{
color = convertColor(color);
glBegin(GL_LINE_LOOP);
glColor4ubv(cast(ubyte*)&color);
glVertex2f(x, y);
glVertex2f(x, y2);
glVertex2f(x2, y2);
glVertex2f(x2, y);
glEnd();
drc++;
}
override void gfill(int page, int x, int y, int x2, int y2, uint color)
{
color = convertColor(color);
glBegin(GL_QUADS);
glColor4ubv(cast(ubyte*)&color);
glVertex2f(x, y);
glVertex2f(x, y2);
glVertex2f(x2, y2);
glVertex2f(x2, y);
glEnd();
drc++;
}
override void gcls(int page, uint color)
{
gfill(page, 0, 0, width - 1, height - 1, color);
}
override void gpaint(int page, int x, int y, uint color)
{
color = convertColor(color);
updateVM();
//glGetTexImage(GL_TEXTURE_2D,0,GRP[oldpage].textureFormat,GL_UNSIGNED_BYTE,buffer.ptr);
glReadPixels(0, 0, width, height, GRP[useGRP].textureFormat, GL_UNSIGNED_BYTE, paint.buffer.ptr);
paint.gpaintBuffer(paint.buffer.ptr, x, y, color, GRP[useGRP].textureFormat);
}
override void gcircle(int page, int x, int y, int r, uint color)
{
color = convertColor(color);
glColor4ubv(cast(ubyte*)&color);
drawCircle(x, y, r);
drc++;
}
override void gcircle(int page, int x, int y, int r, int startr, int endr, int flag, uint color)
{
color = convertColor(color);
glColor4ubv(cast(ubyte*)&color);
drawCircle(x, y, r, startr, endr, flag);
drc++;
}
override void gputchr(int page, int x, int y, int text, int scalex, int scaley, uint color)
{
import std.conv : to;
gputchr(page, x, y, (cast(wchar)text).to!wstring, scalex, scaley, color);
}
override void gputchr(int page, int x, int y, wstring text, int scalex, int scaley, uint color)
{
color = convertColor(color);
glColor4ubv(cast(ubyte*)&color);
glEnable(GL_TEXTURE_2D);
glEnable(GL_ALPHA_TEST);
glBindTexture(GL_TEXTURE_2D, petitcom.console.GRPF.glTexture);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(x, y, 0);
glScalef(scalex, scaley, 1);
glBegin(GL_QUADS);
drawText(text);
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
drc++;
}
override int gspoit(int page, int x, int y)
{
int ui;
//flush
//if (drc)
// glFinish();
//drc = 0;
glReadPixels(x, y, 1, 1, GRP[page].textureFormat, GL_UNSIGNED_BYTE, &ui);
return ui;
}
override void gsave(int savepage, int x, int y, int w, int h, double[] array, int flag)
{
if (w * h > array.length)
return;
gsave(savepage, x, y, w, h, cast(int[])paint.buffer, flag);
for (int i = 0; i < array.length; i++)
{
array[i] = cast(double)cast(int)paint.buffer[i];
}
}
override void gsave(int savepage, int x, int y, int w, int h, int[] array, int flag)
{
if (w * h > array.length)
return;
auto oldPage = useGRP;
if (savepage == -1)
{
glBindFramebufferEXT(GL_FRAMEBUFFER, petitcom.console.GRPF.buffer);
}
else
{
useGRP = savepage;
}
scope (exit)
{
useGRP = oldPage;
}
//endian?
if (false && flag)//0=32bit
{
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, array.ptr);
}
else
{
glReadPixels(x, y, w, h, GL_BGRA, GL_UNSIGNED_BYTE, array.ptr);
}
if (flag)
{
//ARRRRRGGGGGBBBBB
for (int i = 0; i < array.length; i++)
{
array[i] = ARGB32ToRGBA16Color(array[i]);
}
}
}
override void gload(int x, int y, int w, int h, int[] array, int flag, int copymode)
{
if (w * h > array.length)
return;
if (!copymode)
{
glEnable(GL_ALPHA_TEST);
}
glRasterPos2i(x, y);
//convertColor
if (flag)
{
//ARRRRRGGGGGBBBBB
for (int i = 0; i < array.length; i++)
{
paint.buffer[i] = RGBA16ToARGB32Color(array[i]);
}
glDrawPixels(w , h , GL_BGRA , GL_UNSIGNED_BYTE , paint.buffer.ptr);
}
else
{
glDrawPixels(w , h , GL_BGRA , GL_UNSIGNED_BYTE , array.ptr);
}
if (!copymode)
{
glDisable(GL_ALPHA_TEST);
}
}
override void gload(int x, int y, int w, int h, double[] array, int flag, int copymode)
{
for (int i = 0; i < array.length; i++)
{
paint.buffer[i] = cast(int)array[i];
}
gload(x, y, w, h, cast(int[])paint.buffer, flag, copymode);
}
void gloadPalette(T, T2)(int x, int y, int w, int h, T[] array, T2[] palette, int copymode)
if ((is(T == int) || is(T == double)) && (is(T2 == int) || is(T2 == double)))
{
for (int i = 0; i < array.length; i++)
{
paint.buffer[i] = cast(int)palette[cast(int)array[i]];
}
gload(x, y, w, h, cast(int[])paint.buffer, 0, copymode);
}
}
class Graphic2 : Graphic
{
this(PetitComputer p)
{
super(p);
}
override void initGraphicPages()
{
foreach(g; GRP)
{
if (g.glTexture)
g.deleteGL();
}
super.initGraphicPages();
foreach(g; GRP)
{
g.createTexture(petitcom.renderer, petitcom.textureScaleMode);
}
}
override void initVM()
{
SDL_GL_MakeCurrent(petitcom.window, petitcom.contextVM);
glAlphaFunc(GL_GEQUAL, 0.1f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_DEPTH_TEST);
}
int olddisplay;
override void display(int display)
{
if (df)
{
glBindTexture(GL_TEXTURE_2D, this.GRP[usePage[olddisplay]].glTexture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
df = false;
}
olddisplay = display;
buffer = cast(int*)this.GRP[usePage[display]].surface.pixels;
}
bool df;
void updateTexture()
{
glBindTexture(GL_TEXTURE_2D, this.GRP[useGRP].glTexture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
}
override void updateVM()
{
if (df)
{
updateTexture;
df = false;
}
}
int* buffer;
override @property void useGRP(int page)
{
updateVM;
super.useGRP(page);
buffer = cast(int*)this.GRP[useGRP].surface.pixels;
}
override @property int useGRP()
{
return super.useGRP;
}
override void gpset(int page, int x, int y, uint color)
{
auto wa = writeArea[petitcom.displaynum];
int cx2 = wa.x + wa.w;
int cy2 = wa.y + wa.h;
if (x >= wa.x && y >= wa.y && x < cx2 && y < cy2)
{
buffer[y * width + x] = color;
}
df = true;
}
import std.math;
override void gline(int page, int x, int y, int x2, int y2, uint color)
{
int dx = abs(x2 - x);
int dy = abs(y2 - y);
int sx, sy;
if (x < x2)
sx = 1;
else
sx = -1;
if (y < y2)
sy = 1;
else
sy = -1;
int err = dx - dy;
auto wa = writeArea[petitcom.displaynum];
int cx2 = wa.x + wa.w;
int cy2 = wa.y + wa.h;
while (true)
{
if (x >= wa.x && y >= wa.y && x < cx2 && y < cy2)
buffer[y * width + x] = color;
if (x == x2 && y == y2) break;
int e2 = 2 * err;
if (e2 > -dy)
{
err = err - dy;
x = x + sx;
}
if (e2 < dx)
{
err = err + dx;
y = y + sy;
}
}
df = true;
}
override void gbox(int page, int x, int y, int x2, int y2, uint color)
{
int sx, sy, ex, ey;
if (x > x2)
{
sx = x2;
ex = x;
}
else
{
sx = x;
ex = x2;
}
if (y > y2)
{
sy = y2;
ey = y;
}
else
{
sy = y;
ey = y2;
}
auto wa = writeArea[petitcom.displaynum];
int cx2 = wa.x + wa.w - 1;
int cy2 = wa.y + wa.h - 1;
void drawLine1(int y)
{
for (int x = sx; x <= ex; x++)
{
if (x >= wa.x && y >= wa.y && x < cx2 && y < cy2)
buffer[y * height + x] = color;
}
}
drawLine1(sy);
drawLine1(ey);
void drawLine2(int x)
{
for (int y = sy; y <= ey; y++)
{
if (x >= wa.x && y >= wa.y && x < cx2 && y < cy2)
buffer[y * width + x] = color;
}
}
drawLine2(ex);
drawLine2(sx);
df = true;
}
override void gfill(int page, int x, int y, int x2, int y2, uint color)
{
int sx, sy, ex, ey;
if (x > x2)
{
sx = x2;
ex = x;
}
else
{
sx = x;
ex = x2;
}
if (y > y2)
{
sy = y2;
ey = y;
}
else
{
sy = y;
ey = y2;
}
auto wa = writeArea[petitcom.displaynum];
int cx2 = wa.x + wa.w - 1;
int cy2 = wa.y + wa.h - 1;
//clipping
if (wa.x > sx)
{
if (wa.x > ex)
{
return;
}
sx = wa.x;
}
if (cx2 < ex)
{
if (cx2 < sx)
{
return;
}
ex = cx2;
}
if (wa.y > sy)
{
if (wa.y > ey)
{
return;
}
sy = wa.y;
}
if (cy2 < ey)
{
if (cy2 < sy)
{
return;
}
ey = cy2;
}
for (y = sy; y <= ey; y++)
{
(buffer + y * width + sx)[0..(ex - sx + 1)] = color;
}
df = true;
}
override void gcls(int page, uint color)
{
gfill(page, 0, 0, width - 1, height - 1, color);
}
override void gpaint(int page, int x, int y, uint color)
{
}
override void gcircle(int page, int x, int y, int r, uint color)
{
}
override void gcircle(int page, int x, int y, int r, int startr, int endr, int flag, uint color)
{
}
override void gputchr(int page, int x, int y, int text, int scalex, int scaley, uint color)
{
drawCharacter(x, y, scalex, scaley, color, cast(wchar)text);
df = true;
}
int mulColor(int color, int color2)
{
ubyte r1, g1, b1, a1;
ubyte r2, g2, b2, a2;
PetitComputer.RGBRead(color, r1, g1, b1, a1);
PetitComputer.RGBRead(color2, r2, g2, b2, a2);
r1 = cast(ubyte)((r1 * r2) / 255);
g1 = cast(ubyte)((g1 * g2) / 255);
b1 = cast(ubyte)((b1 * b2) / 255);
if (a2 && a1)
a1 = 255;
else
a1 = 0;
return PetitComputer.RGB(a1, r1, g1, b1);
}
bool clipXYWH(SDL_Rect wa, int x, int y, int w, int h, out int sx, out int sy, out int w2, out int h2)
{
int cx2 = wa.x + wa.w;
int cy2 = wa.y + wa.h;
w2 = w;
h2 = h;
//clipping
if (wa.x > x)
{
sx = wa.x - x;
w2 -= sx;
if (sx >= w)
{
return true;
}
}
if (wa.w + wa.x < x + sx + w2)
{
w2 = w2 - ((x + sx + w2) - (wa.w + wa.x));
if (w < 1)
{
return true;
}
}
if (wa.y > y)
{
sy = wa.y - y;
h2 -= sy;
if (sy >= h)
{
return true;
}
}
if (wa.h < h2)
{
h2 = h2 - ((y + sy + h2) - (wa.h + wa.y));
if (h < 1)
{
return true;
}
}
return false;
}
void drawCharacter(int x, int y, int scalex, int scaley, uint color, immutable wchar c)
{
auto rect = petitcom.console.fontTable[c];
int[8 * 8] font;
auto wa = writeArea[petitcom.displaynum];
int cx2 = wa.x + wa.w;
int cy2 = wa.y + wa.h;
int sx, sy, w = rect.w * scalex, h = rect.h * scaley;
//clipping
if (wa.x > x)
{
sx = wa.x - x;
w -= sx;
if (sx >= rect.w)
{
return;
}
}
if (wa.w + wa.x < x + sx + w)
{
w = w - ((x + sx + w) - (wa.w + wa.x));
if (w < 1)
{
return;
}
}
if (wa.y > y)
{
sy = wa.y - y;
h -= sy;
if (sy >= rect.h)
{
return;
}
}
if (wa.h < h)
{
h = h - ((y + sy + h) - (wa.h + wa.y));
if (h < 1)
{
return;
}
}
int* grpfbuffer = cast(int*)petitcom.console.GRPF.surface.pixels;
if (scalex == 1 && scaley == 1)
{
for (int i = sy; i < sy + h; i ++)
{
for (int j = sx; j < sx + w; j++)
{
font[i * 8 + j] = mulColor(grpfbuffer[rect.x + j + (rect.y + i) * GRPFWidth], color);
}
}
for (int iy = sy; iy < sy + h; iy++)
{
for (int ix = sx; ix < sx + w; ix++)
{
if (font[iy * 8 + ix] >> 24/*is trans*/)
{
(buffer + (y + iy) * width + x + ix)[0] = font[iy * 8 + ix];
}
}
}
return;
}
for (int i = sy / scaley; i < (sy + h) / scaley; i ++)
{
for (int j = sx / scalex; j < (sx + w) / scalex; j++)
{
font[i * 8 + j] = mulColor(grpfbuffer[rect.x + j + (rect.y + i) * GRPFWidth], color);
}
}
for (int iy = sy; iy < sy + h; iy++)
{
for (int ix = sx; ix < sx + w; ix++)
{
if (font[iy / scaley * 8 + ix / scalex] >> 24/*is trans*/)
{
(buffer + (y + iy) * width + x + ix)[0] = font[iy / scaley * 8 + ix / scaley];
}
}
}
}
override void gputchr(int page, int x, int y, wstring text, int scalex, int scaley, uint color)
{
foreach (i, c; text)
{
drawCharacter(x + scalex * cast(int)i * 8, y, scalex, scaley, color, c);
}
df = true;
}
override int gspoit(int page, int x, int y)
{
return buffer[y * height + x];
}
void gsaveTempl(T)(int x, int y, int w, int h, T[] array, int flag)
{
int arrayH = h, arrayW = w;
int sx, sy;
for (int iy = sy; iy < h; iy++)
{
for (int ix = sx; ix < w; ix++)
{
if (x >= 0 && y >= 0 && x < width && y < height)
{
auto c = *(buffer + (iy + y) * width + (x + ix));
array[iy * arrayW + ix] = flag ? ARGB32ToRGBA16Color(c) : c;
}
else
array[iy * arrayW + ix] = 0;
}
}
}
override void gsave(int savepage, int x, int y, int w, int h, double[] array, int flag)
{
gsaveTempl(x, y, w, h, array, flag);
}
override void gsave(int savepage, int x, int y, int w, int h, int[] array, int flag)
{
gsaveTempl(x, y, w, h, array, flag);
}
override void gload(int x, int y, int w, int h, int[] array, int flag, int copymode)
{
}
override void gload(int x, int y, int w, int h, double[] array, int flag, int copymode)
{
}
}