From fbd7471b0ea43b73c7940a90000238284d410ba6 Mon Sep 17 00:00:00 2001 From: otya128 Date: Sat, 3 Dec 2016 13:35:13 +0900 Subject: [PATCH] Extract graphic class --- SMILEBASIC/builtinfunctions.d | 38 +-- SMILEBASIC/draw.d | 103 -------- SMILEBASIC/graphic.d | 442 +++++++++++++++++++++++++++++++++ SMILEBASIC/petitcomputer.d | 452 +--------------------------------- SMILEBASIC/sprite.d | 2 +- 5 files changed, 475 insertions(+), 562 deletions(-) delete mode 100644 SMILEBASIC/draw.d create mode 100644 SMILEBASIC/graphic.d diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d index f89b56f..61676f5 100644 --- a/SMILEBASIC/builtinfunctions.d +++ b/SMILEBASIC/builtinfunctions.d @@ -299,58 +299,58 @@ class BuiltinFunction static void GCLS(PetitComputer p, DefaultValue!(int, false) color) { color.setDefaultValue(0); - p.gfill(p.useGRP, 0, 0, 511, 511, cast(int)color); + p.graphic.gfill(p.graphic.useGRP, 0, 0, 511, 511, cast(int)color); } static void GPSET(PetitComputer p, int x, int y, DefaultValue!(int, false) color) { - color.setDefaultValue(p.gcolor); - p.gpset(p.useGRP, x, y, cast(int)color); + color.setDefaultValue(p.graphic.gcolor); + p.graphic.gpset(p.graphic.useGRP, x, y, cast(int)color); } static void GLINE(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color) { - color.setDefaultValue(p.gcolor); - p.gline(p.useGRP, x, y, x2, y2, cast(int)color); + color.setDefaultValue(p.graphic.gcolor); + p.graphic.gline(p.graphic.useGRP, x, y, x2, y2, cast(int)color); } static void GBOX(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color) { - color.setDefaultValue(p.gcolor); - p.gbox(p.useGRP, x, y, x2, y2, cast(int)color); + color.setDefaultValue(p.graphic.gcolor); + p.graphic.gbox(p.graphic.useGRP, x, y, x2, y2, cast(int)color); } static void GFILL(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color) { - color.setDefaultValue(p.gcolor); - p.gfill(p.useGRP, x, y, x2, y2, cast(int)color); + color.setDefaultValue(p.graphic.gcolor); + p.graphic.gfill(p.graphic.useGRP, x, y, x2, y2, cast(int)color); } //X,Y,R[,COLOR] //X,Y,R,SR,ER[,COLOR] static void GCIRCLE(PetitComputer p, int x, int y, int r, DefaultValue!(int, false) color) { - color.setDefaultValue(p.gcolor); - p.gcircle(p.useGRP, x, y, r, 0, 360, 0, cast(int)color); + color.setDefaultValue(p.graphic.gcolor); + p.graphic.gcircle(p.graphic.useGRP, x, y, r, 0, 360, 0, cast(int)color); } static void GCIRCLE(PetitComputer p, int x, int y, int r, int sr, int er, DefaultValue!(int, false) flag, DefaultValue!(int, false) color) { - color.setDefaultValue(p.gcolor); + color.setDefaultValue(p.graphic.gcolor); flag.setDefaultValue(0); - p.gcircle(p.useGRP, x, y, r, sr, er, cast(int)flag, cast(int)color); + p.graphic.gcircle(p.graphic.useGRP, x, y, r, sr, er, cast(int)flag, cast(int)color); } static void GCOLOR(PetitComputer p, int color) { - p.gcolor = color; + p.graphic.gcolor = color; } static void GPRIO(PetitComputer p, int z) { - p.gprio = z; + p.graphic.gprio = z; } static void GPAGE(PetitComputer p, int showPage, int usePage) { - p.showGRP = showPage; - p.useGRP = usePage; + p.graphic.showGRP = showPage; + p.graphic.useGRP = usePage; } static void GPAINT(PetitComputer p, int x, int y, DefaultValue!(int, false) color, DefaultValue!(int, false) color2) { - color.setDefaultValue(p.gcolor); - p.gpaint(p.useGRP, x, y, cast(int)color); + color.setDefaultValue(p.graphic.gcolor); + p.graphic.gpaint(p.graphic.useGRP, x, y, cast(int)color); } static void BGMPLAY(PetitComputer p, int music) { diff --git a/SMILEBASIC/draw.d b/SMILEBASIC/draw.d deleted file mode 100644 index c00ce62..0000000 --- a/SMILEBASIC/draw.d +++ /dev/null @@ -1,103 +0,0 @@ -module otya.smilebasic.draw; -import otya.smilebasic.petitcomputer; -import derelict.opengl3.gl; -class Draw -{ - PetitComputer petitcom; - this(PetitComputer petitcom) - { - this.petitcom = petitcom; - } - - void gpset(int page, int x, int y, uint color) - { - color = PetitComputer.toGLColor(petitcom.GRP[page].textureFormat, color); - glBindTexture(GL_TEXTURE_2D, petitcom.GRP[page].glTexture); - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, 1, 1, petitcom.GRP[page].textureFormat, GL_UNSIGNED_BYTE, &color); - } - void gline(int page, int x, int y, int x2, int y2, uint color) - { - import std.math; - color = PetitComputer.toGLColor(petitcom.GRP[page].textureFormat, color); - glBindTexture(GL_TEXTURE_2D, petitcom.GRP[page].glTexture); - auto tf = petitcom.GRP[page].textureFormat; - 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; - while(true) - { - if(x < 0 || y < 0 || x >= 512 || y >= 512) break; - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, 1, 1, tf, GL_UNSIGNED_BYTE, &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 ; - } - } - } - uint[] graphicBuffer = new uint[512 * 512]; - void gfill(int page, int x, int y, int x2, int y2, uint color) - { - import std.algorithm; - import std.math; - if(x < 0 && x2 < 0 || y < 0 && y2 < 0) return; - if(x > 511 && x2 > 511 || y > 511 && y2 > 511) return; - //0<=x<512 - x = min(max(x, 0), 511); - y = min(max(y, 0), 511); - x2 = min(max(x2, 0), 511); - y2 = min(max(y2, 0), 511); - if(x2 < x) swap(x, x2); - if(y2 < y) swap(y, y2); - auto w = abs(x2 - x) + 1;//abs - auto h = abs(y2 - y) + 1; - auto size = w * h; - uint* pixels = graphicBuffer.ptr; - color = PetitComputer.toGLColor(petitcom.GRP[page].textureFormat, color); - for(int i = 0; i < size; i++) - { - pixels[i] = color; - } - glBindTexture(GL_TEXTURE_2D, petitcom.GRP[page].glTexture); - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, w, h, petitcom.GRP[page].textureFormat, GL_UNSIGNED_BYTE, pixels); - } - - void gbox(int page, int x, int y, int x2, int y2, uint color) - { - import std.algorithm; - import std.math; - if(x < 0 && x2 < 0 || y < 0 && y2 < 0) return; - if(x > 511 && x2 > 511 || y > 511 && y2 > 511) return; - //0<=x<512 - x = min(max(x, 0), 511); - y = min(max(y, 0), 511); - x2 = min(max(x2, 0), 511); - y2 = min(max(y2, 0), 511); - if(x2 < x) swap(x, x2); - if(y2 < y) swap(y, y2); - auto w = abs(x2 - x) + 1;//abs - auto h = abs(y2 - y) + 1; - auto size = max(w, h); - uint* pixels = graphicBuffer.ptr; - color = PetitComputer.toGLColor(petitcom.GRP[page].textureFormat, color); - for(int i = 0; i < size; i++) - { - pixels[i] = color; - } - glBindTexture(GL_TEXTURE_2D, petitcom.GRP[page].glTexture); - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, w, 1, petitcom.GRP[page].textureFormat, GL_UNSIGNED_BYTE, pixels); - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y2, w, 1, petitcom.GRP[page].textureFormat, GL_UNSIGNED_BYTE, pixels); - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, 1, h, petitcom.GRP[page].textureFormat, GL_UNSIGNED_BYTE, pixels); - glTexSubImage2D(GL_TEXTURE_2D , 0, x2, y, 1, h, petitcom.GRP[page].textureFormat, GL_UNSIGNED_BYTE, pixels); - } -} diff --git a/SMILEBASIC/graphic.d b/SMILEBASIC/graphic.d new file mode 100644 index 0000000..e88e17a --- /dev/null +++ b/SMILEBASIC/graphic.d @@ -0,0 +1,442 @@ +module otya.smilebasic.graphic; +import derelict.sdl2.sdl; +import derelict.sdl2.image; +import derelict.opengl3.gl; +import derelict.opengl3.gl3; +import otya.smilebasic.petitcomputer; + +class Graphic +{ + PetitComputer petitcom; + this(PetitComputer p) + { + petitcom = p; + //nnnue + paint.buffer = new uint[512 * 512]; + } + + bool visibleGRP = true; + private int[2] showPage = [0, 1]; + private int[2] usePage = [0, 1]; + @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; + struct 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 buff[MAXSIZE]; /* シード登録用バッファ */ + BufStr* sIdx, eIdx; /* buffの先頭・末尾ポインタ */ + uint point(int x, int y) + { + return buffer.ptr[x + y * 512]; + } + void pset(int x, int y, uint col) + { + buffer.ptr[x + y * 512] = 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, 512, h, tf, GL_UNSIGNED_BYTE, pixels + (dy * 512)); + // glDrawPixels(512, dy2, tf, GL_UNSIGNED_BYTE, buffer.ptr); + } + } + Paint paint; + void drawCircle(int x, int y, int r, int startr, int endr, int flag) + { + import std.math : sin, cos, PI; + int count = r; + glBegin(GL_LINE_LOOP); + for (int i = 0; i <= r; i++) + { + //float a = i * (360f / r); + glVertex2f(sin(cast(float)i / count * 2f * PI) * r + x, cos(cast(float)i / count * 2f * PI) * r + y); + } + glEnd(); + } + void draw() + { + if(!drawMessageLength) return; + drawflag = true; + //betuni kouzoutai demo sonnnani sokudo kawaranasasou + auto len = drawMessageLength; + int s = petitcom.renderstartpos; + GLint old; + auto a = &glBindFramebuffer; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old); + int oldpage = drawMessageQueue[0].page; + glBindFramebufferEXT(GL_FRAMEBUFFER, this.GRP[oldpage].buffer); + glDisable(GL_TEXTURE_2D); + glDisable(GL_ALPHA_TEST); + glDisable(GL_DEPTH_TEST); + + //glAlphaFunc(GL_GEQUAL, 0.0); + void chScreen(int x, int y, int w, int h) + { + glViewport(x, y, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, w, 0, h, -256, 1024);//wakaranai + } + chScreen(0, 0, 511, 511); + DrawType dt; + auto start = SDL_GetTicks(); + int i = s; + static const size = 255.5f; + for(; i < len; i++) + { + DrawMessage dm = drawMessageQueue[i]; + if(oldpage != dm.page) + { + oldpage = dm.page; + glBindFramebufferEXT(GL_FRAMEBUFFER, this.GRP[oldpage].buffer); + } + switch(dm.type) + { + case DrawType.PSET: + glBegin(GL_POINTS); + glColor4ubv(cast(ubyte*)&dm.color); + glVertex2f(dm.x, dm.y); + glEnd(); + break; + case DrawType.LINE: + { + glBegin(GL_LINES); + glColor4ubv(cast(ubyte*)&dm.color); + glVertex2f(dm.x, dm.y); + glVertex2f(dm.x2, dm.y2); + //glFlush(); + glEnd(); + } + break; + case DrawType.FILL: + { + glBegin(GL_QUADS); + glColor4ubv(cast(ubyte*)&dm.color); + glVertex2f(dm.x, dm.y); + glVertex2f(dm.x, dm.y2); + glVertex2f(dm.x2, dm.y2); + glVertex2f(dm.x2, dm.y); + glEnd(); + } + break; + case DrawType.BOX: + { + glBegin(GL_LINE_LOOP); + glColor4ubv(cast(ubyte*)&dm.color); + glVertex2f(dm.x, dm.y); + glVertex2f(dm.x, dm.y2); + glVertex2f(dm.x2, dm.y2); + glVertex2f(dm.x2, dm.y); + glEnd(); + } + break; + case DrawType.PAINT: + { + glBindTexture(GL_TEXTURE_2D, GRP[oldpage].glTexture); + if(dt != DrawType.PAINT) + { + glFinish(); + //glGetTexImage(GL_TEXTURE_2D,0,GRP[oldpage].textureFormat,GL_UNSIGNED_BYTE,buffer.ptr); + glReadPixels(0, 0, 512, 512, GRP[oldpage].textureFormat, GL_UNSIGNED_BYTE, paint.buffer.ptr); + } + paint.gpaintBuffer(paint.buffer.ptr, dm.x, dm.y, dm.color, GRP[oldpage].textureFormat); + //gpaintBufferExW(oldpage, dm.x, dm.y, dm.color); + if(SDL_GetTicks() - start >= 16 && i != len - 1) + { + s = i + 1; + goto brk; + } + } + break; + case DrawType.CIRCLE: + { + glColor4ubv(cast(ubyte*)&dm.color); + drawCircle(dm.x, dm.y, dm.circle.r, dm.circle.startr, dm.circle.endr, dm.circle.flag); + } + break; + default: + } + dt = dm.type; + } + brk: + if(i == len) + { + petitcom.renderstartpos = 0; + drawMessageLength = 0; + } + else + { + petitcom.renderstartpos = s; + } + glBindFramebufferEXT(GL_FRAMEBUFFER, old); + glEnable(GL_DEPTH_TEST); + drawflag = false; + glEnable(GL_ALPHA_TEST); + } + enum DrawType + { + CLEAR, + PSET, + LINE, + FILL, + BOX, + CIRCLE, + TRI, + PAINT, + } + struct Circle + { + short r, startr, endr; + short flag; + } + struct DrawMessage + { + DrawType type; + byte page; + short x; + short y; + uint color; + short x2; + short y2; + Circle circle; + // + } + static const int dmqqueuelen = 8192; + DrawMessage[] drawMessageQueue = new DrawMessage[dmqqueuelen]; + int drawMessageLength; + bool drawflag; + void sendDrawMessage(DrawMessage dm) + { + //grpmutex.lock(); + //scope(exit) + // grpmutex.unlock(); + if(drawMessageLength >= dmqqueuelen) + { + while(drawMessageLength) + { + SDL_Delay(1); + } + } + while(drawflag){} + dm.color = petitcom.toGLColor(this.GRP[0].textureFormat, dm.color & 0xFFF8F8F8); + drawMessageQueue[drawMessageLength] = dm; + drawMessageLength++; + } + void sendDrawMessage(DrawType type, byte page, short x, short y, uint color) + { + DrawMessage dm; + dm.type = type; + dm.page = page; + dm.x = x; + dm.y = y; + dm.color = color; + sendDrawMessage(dm); + } + void sendDrawMessage(DrawType type, byte page, short x, short y, short x2, short y2, uint color) + { + DrawMessage dm; + dm.type = type; + dm.page = page; + dm.x = x; + dm.y = y; + dm.x2 = x2; + dm.y2 = y2; + dm.color = color; + sendDrawMessage(dm); + } + //TODO:範囲チェック + void gpset(int page, int x, int y, uint color) + { + sendDrawMessage(DrawType.PSET, cast(byte)page, cast(short)x, cast(short)y, color); + } + void gline(int page, int x, int y, int x2, int y2, uint color) + { + sendDrawMessage(DrawType.LINE, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color); + } + void gbox(int page, int x, int y, int x2, int y2, uint color) + { + sendDrawMessage(DrawType.BOX, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color); + } + void gfill(int page, int x, int y, int x2, int y2, uint color) + { + sendDrawMessage(DrawType.FILL, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color); + } + void gpaint(int page, int x, int y, uint color) + { + sendDrawMessage(DrawType.PAINT, cast(byte)page, cast(short)x, cast(short)y, color); + } + void gcircle(int page, int x, int y, int r, int startr, int endr, int flag, uint color) + { + DrawMessage dm; + dm.page = cast(byte)page; + dm.x = cast(short)x; + dm.y = cast(short)y; + dm.circle.r = cast(short)r; + dm.circle.startr = cast(short)startr; + dm.circle.endr = cast(short)endr; + dm.circle.flag = cast(short)flag; + dm.color = color; + dm.type = DrawType.CIRCLE; + sendDrawMessage(dm); + } + int gprio; + void render(int display, float w, float h) + { + float z = gprio; + glColor3f(1.0, 1.0, 1.0); + glBindTexture(GL_TEXTURE_2D, GRP[showPage[display]].glTexture); + glEnable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + glTexCoord2f(0 / 512f - 1 , h / 512f - 1); + glVertex3f(0, h, z); + glTexCoord2f(0 / 512f - 1, 0 / 512f - 1); + glVertex3f(0, 0, z); + glTexCoord2f(w / 512f - 1, 0 / 512f - 1); + glVertex3f(w, 0, z); + glTexCoord2f(w / 512f - 1, h / 512f - 1); + glVertex3f(w, h, z); + glEnd(); + //glFlush(); + } +} diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d index 7e5ed9f..176aef9 100644 --- a/SMILEBASIC/petitcomputer.d +++ b/SMILEBASIC/petitcomputer.d @@ -17,6 +17,7 @@ import otya.smilebasic.bg; import otya.smilebasic.parser; import otya.smilebasic.project; import otya.smilebasic.console; +import otya.smilebasic.graphic; const static rot_test_deg = 45f; const static rot_test_x = 0f; const static rot_test_y = 1f; @@ -185,27 +186,6 @@ class PetitComputer return SDL_Color(r >> 5 << 5, g >> 5 << 5, b >> 5 << 5, a == 255 ? 255 : 0); } Button button; - bool visibleGRP = true; - private int[2] showPage = [0, 1]; - private int[2] usePage = [0, 1]; - @property int useGRP() - { - return usePage[displaynum]; - } - @property int showGRP() - { - return showPage[displaynum]; - } - @property void useGRP(int page) - { - usePage[displaynum] = page; - } - @property void showGRP(int page) - { - showPage[displaynum] = page; - } - uint gcolor = -1; - GraphicPage[] GRP; GraphicPage createGRPF(string file) { SDL_RWops* stream = SDL_RWFromFile(toStringz(file), toStringz("rb")); @@ -345,6 +325,7 @@ class PetitComputer vsyncCount = 0; vsyncFrame = f; } + Graphic graphic; Mutex keybuffermutex; int keybufferpos; int keybufferlen; @@ -386,152 +367,6 @@ class PetitComputer } Mutex grpmutex; int displaynum; - struct 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 buff[MAXSIZE]; /* シード登録用バッファ */ - BufStr* sIdx, eIdx; /* buffの先頭・末尾ポインタ */ - uint point(int x, int y) - { - return buffer.ptr[x + y * 512]; - } - void pset(int x, int y, uint col) - { - buffer.ptr[x + y * 512] = 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, 512, h, tf, GL_UNSIGNED_BYTE, pixels + (dy * 512)); - // glDrawPixels(512, dy2, tf, GL_UNSIGNED_BYTE, buffer.ptr); - } - } - Paint paint; int renderstartpos; void chScreen(int x, int y, int w, int h) { @@ -540,142 +375,6 @@ class PetitComputer glLoadIdentity(); glOrtho(0, w, h, 0, 1024, -2048); } - void drawCircle(int x, int y, int r, int startr, int endr, int flag) - { - import std.math : sin, cos, PI; - int count = r; - glBegin(GL_LINE_LOOP); - for (int i = 0; i <= r; i++) - { - //float a = i * (360f / r); - glVertex2f(sin(cast(float)i / count * 2f * PI) * r + x, cos(cast(float)i / count * 2f * PI) * r + y); - } - glEnd(); - } - void renderGraphic() - { - if(!drawMessageLength) return; - drawflag = true; - //betuni kouzoutai demo sonnnani sokudo kawaranasasou - auto len = drawMessageLength; - int s = renderstartpos; - GLint old; - auto a = & glBindFramebuffer; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old); - int oldpage = drawMessageQueue[0].page; - glBindFramebufferEXT(GL_FRAMEBUFFER, this.GRP[oldpage].buffer); - glDisable(GL_TEXTURE_2D); - glDisable(GL_ALPHA_TEST); - glDisable(GL_DEPTH_TEST); - - //glAlphaFunc(GL_GEQUAL, 0.0); - void chScreen(int x, int y, int w, int h) - { - glViewport(x, y, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, w, 0, h, -256, 1024);//wakaranai - } - chScreen(0, 0, 511, 511); - DrawType dt; - auto start = SDL_GetTicks(); - int i = s; - static const size = 255.5f; - for(; i < len; i++) - { - DrawMessage dm = drawMessageQueue[i]; - if(oldpage != dm.page) - { - oldpage = dm.page; - glBindFramebufferEXT(GL_FRAMEBUFFER, this.GRP[oldpage].buffer); - } - switch(dm.type) - { - case DrawType.PSET: - glBegin(GL_POINTS); - glColor4ubv(cast(ubyte*)&dm.color); - glVertex2f(dm.x, dm.y); - glEnd(); - //draw.gpset(dm.page, dm.x, dm.y ,dm.color); - break; - case DrawType.LINE: - { - glBegin(GL_LINES); - glColor4ubv(cast(ubyte*)&dm.color); - glVertex2f(dm.x, dm.y); - glVertex2f(dm.x2, dm.y2); - //glFlush(); - glEnd(); - } - //draw.gline(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color); - break; - case DrawType.FILL: - { - glBegin(GL_QUADS); - glColor4ubv(cast(ubyte*)&dm.color); - glVertex2f(dm.x, dm.y); - glVertex2f(dm.x, dm.y2); - glVertex2f(dm.x2, dm.y2); - glVertex2f(dm.x2, dm.y); - glEnd(); - } - //draw.gfill(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color); - break; - case DrawType.BOX: - { - glBegin(GL_LINE_LOOP); - glColor4ubv(cast(ubyte*)&dm.color); - glVertex2f(dm.x, dm.y); - glVertex2f(dm.x, dm.y2); - glVertex2f(dm.x2, dm.y2); - glVertex2f(dm.x2, dm.y); - glEnd(); - } - //draw.gbox(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color); - break; - case DrawType.PAINT: - { - glBindTexture(GL_TEXTURE_2D, GRP[oldpage].glTexture); - if(dt != DrawType.PAINT) - { - glFinish(); - //glGetTexImage(GL_TEXTURE_2D,0,GRP[oldpage].textureFormat,GL_UNSIGNED_BYTE,buffer.ptr); - glReadPixels(0, 0, 512, 512, GRP[oldpage].textureFormat, GL_UNSIGNED_BYTE, paint.buffer.ptr); - } - paint.gpaintBuffer(paint.buffer.ptr, dm.x, dm.y, dm.color, GRP[oldpage].textureFormat); - //gpaintBufferExW(oldpage, dm.x, dm.y, dm.color); - if(SDL_GetTicks() - start >= 16 && i != len - 1) - { - s = i + 1; - goto brk; - } - } - break; - case DrawType.CIRCLE: - { - glColor4ubv(cast(ubyte*)&dm.color); - drawCircle(dm.x, dm.y, dm.circle.r, dm.circle.startr, dm.circle.endr, dm.circle.flag); - } - break; - default: - } - dt = dm.type; - } - brk: - if(i == len) - { - renderstartpos = 0; - drawMessageLength = 0; - } - else - { - renderstartpos = s; - } - glBindFramebufferEXT(GL_FRAMEBUFFER, old); - glEnable(GL_DEPTH_TEST); - drawflag = false; - glEnable(GL_ALPHA_TEST); - } Button[] buttonTable; Sprite sprite; int xscreenmode = 0; @@ -721,19 +420,18 @@ class PetitComputer { try { - paint.buffer = new uint[512 * 512]; DerelictSDL2.load(); DerelictSDL2Image.load(); console.GRPF = createGRPF(fontFile); - GRP = new GraphicPage[6]; + graphic.GRP = new GraphicPage[6]; for(int i = 0; i < 4; i++) { - GRP[i] = createEmptyPage(); + graphic.GRP[i] = createEmptyPage(); } sppage = 4; - GRP[4] = createGRPF(spriteFile); + graphic.GRP[4] = createGRPF(spriteFile); bgpage = 5; - GRP[5] = createGRPF(BGFile); + graphic.GRP[5] = createGRPF(BGFile); SDL_Init(SDL_INIT_VIDEO); DerelictGL.load(); @@ -809,7 +507,7 @@ class PetitComputer } int loopcnt; DerelictGL3.reload(); - foreach(g; GRP) + foreach(g; graphic.GRP) { g.createTexture(renderer); g.createBuffer(); @@ -842,7 +540,7 @@ class PetitComputer } } glLoadIdentity(); - renderGraphic(); + graphic.draw(); chScreen(0, 0, 400, 240); if(xscreenmode == 1) { @@ -865,16 +563,16 @@ class PetitComputer } if(xscreenmode == 2) { - renderGraphicPage(0, 320, 480); + graphic.render(0, 320, 480); } else { - renderGraphicPage(0, 400, 240); + graphic.render(0, 400, 240); } if(xscreenmode == 1) { chScreen(40, 0, 320, 240); - renderGraphicPage(1, 320, 240); + graphic.render(1, 320, 240); chScreen(0, 240, 400, 240); } if(xscreenmode == 2) @@ -887,7 +585,7 @@ class PetitComputer } version(test) glLoadIdentity(); version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); - glBindTexture(GL_TEXTURE_2D, GRP[bgpage].glTexture); + glBindTexture(GL_TEXTURE_2D, graphic.GRP[bgpage].glTexture); if(xscreenmode == 2) { for(int i = 0; i < bgmax; i++) @@ -1030,6 +728,7 @@ class PetitComputer slot = new Slot[5]; keybuffer = new Key[128]; init(); + graphic = new Graphic(this); consolem = new Mutex(); keybuffermutex = new Mutex(); grpmutex = new Mutex(); @@ -1490,129 +1189,4 @@ class PetitComputer { return a << 24 | r << 16 | g << 8 | b; } - enum DrawType - { - CLEAR, - PSET, - LINE, - FILL, - BOX, - CIRCLE, - TRI, - PAINT, - } - struct Circle - { - short r, startr, endr; - short flag; - } - struct DrawMessage - { - DrawType type; - byte page; - short x; - short y; - uint color; - short x2; - short y2; - Circle circle; - // - } - static const int dmqqueuelen = 8192; - DrawMessage[] drawMessageQueue = new DrawMessage[dmqqueuelen]; - int drawMessageLength; - bool drawflag; - void sendDrawMessage(DrawMessage dm) - { - //grpmutex.lock(); - //scope(exit) - // grpmutex.unlock(); - if(drawMessageLength >= dmqqueuelen) - { - while(drawMessageLength) - { - SDL_Delay(1); - } - } - while(drawflag){} - dm.color = toGLColor(this.GRP[0].textureFormat, dm.color & 0xFFF8F8F8); - drawMessageQueue[drawMessageLength] = dm; - drawMessageLength++; - } - void sendDrawMessage(DrawType type, byte page, short x, short y, uint color) - { - DrawMessage dm; - dm.type = type; - dm.page = page; - dm.x = x; - dm.y = y; - dm.color = color; - sendDrawMessage(dm); - } - void sendDrawMessage(DrawType type, byte page, short x, short y, short x2, short y2, uint color) - { - DrawMessage dm; - dm.type = type; - dm.page = page; - dm.x = x; - dm.y = y; - dm.x2 = x2; - dm.y2 = y2; - dm.color = color; - sendDrawMessage(dm); - } - //TODO:範囲チェック - void gpset(int page, int x, int y, uint color) - { - sendDrawMessage(DrawType.PSET, cast(byte)page, cast(short)x, cast(short)y, color); - } - void gline(int page, int x, int y, int x2, int y2, uint color) - { - sendDrawMessage(DrawType.LINE, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color); - } - void gbox(int page, int x, int y, int x2, int y2, uint color) - { - sendDrawMessage(DrawType.BOX, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color); - } - void gfill(int page, int x, int y, int x2, int y2, uint color) - { - sendDrawMessage(DrawType.FILL, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color); - } - void gpaint(int page, int x, int y, uint color) - { - sendDrawMessage(DrawType.PAINT, cast(byte)page, cast(short)x, cast(short)y, color); - } - void gcircle(int page, int x, int y, int r, int startr, int endr, int flag, uint color) - { - DrawMessage dm; - dm.page = cast(byte)page; - dm.x = cast(short)x; - dm.y = cast(short)y; - dm.circle.r = cast(short)r; - dm.circle.startr = cast(short)startr; - dm.circle.endr = cast(short)endr; - dm.circle.flag = cast(short)flag; - dm.color = color; - dm.type = DrawType.CIRCLE; - sendDrawMessage(dm); - } - int gprio; - void renderGraphicPage(int display, float w, float h) - { - float z = gprio; - glColor3f(1.0, 1.0, 1.0); - glBindTexture(GL_TEXTURE_2D, GRP[showPage[display]].glTexture); - glEnable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - glTexCoord2f(0 / 512f - 1 , h / 512f - 1); - glVertex3f(0, h, z); - glTexCoord2f(0 / 512f - 1, 0 / 512f - 1); - glVertex3f(0, 0, z); - glTexCoord2f(w / 512f - 1, 0 / 512f - 1); - glVertex3f(w, 0, z); - glTexCoord2f(w / 512f - 1, h / 512f - 1); - glVertex3f(w, h, z); - glEnd(); - //glFlush(); - } } diff --git a/SMILEBASIC/sprite.d b/SMILEBASIC/sprite.d index 6cf9dee..2c4d14f 100644 --- a/SMILEBASIC/sprite.d +++ b/SMILEBASIC/sprite.d @@ -625,7 +625,7 @@ class Sprite dish2 = 480f; dis = -1; } - auto texture = petitcom.GRP[petitcom.sppage].glTexture; + auto texture = petitcom.graphic.GRP[petitcom.sppage].glTexture; float aspect = disw2 / dish2; float z = -0.01f; int spmax = petitcom.xscreenmode == 1 ? this.spmax : 512;//XSCREENが2,3じゃないと下画面は描画しない