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) { } }