diff --git a/SMILEBASIC/SMILEBASIC.visualdproj b/SMILEBASIC/SMILEBASIC.visualdproj index 3263d9c..ea56b65 100644 --- a/SMILEBASIC/SMILEBASIC.visualdproj +++ b/SMILEBASIC/SMILEBASIC.visualdproj @@ -37,7 +37,7 @@ 0 0 0 - 0 + 1 0 0 0 @@ -72,7 +72,7 @@ 0 0 - + NDirectMode 0 0 0 diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index 8adaed0..53ec8f6 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -23,10 +23,17 @@ struct VMVariable this.index = index; } } +struct SourceLocation +{ + int line;//何行目 + int pos;//何文字目 + byte slot;//スロット +} class VM { DataTable globalDataTable; Code[] code; + SourceLocation[] location; int stacki; int pc; Value[] stack; @@ -742,7 +749,6 @@ class NewArray : Code break; default: throw new TypeMismatch(); - break; } vm.push(array); } @@ -885,7 +891,6 @@ class PopArray : Code //TODO:文字列の挙動 throw new TypeMismatch(); //array.stringValue[index[0]] = assign.stringValue[0]; - return; } throw new TypeMismatch(); } diff --git a/SMILEBASIC/bg.d b/SMILEBASIC/bg.d index effaa00..2e99c1a 100644 --- a/SMILEBASIC/bg.d +++ b/SMILEBASIC/bg.d @@ -44,7 +44,7 @@ class BG glScalef(1.0f / aspect, 1.0f, 1.0f); glRotatef(360 - r, 0.0f, 0.0f, 1.0f ); glScalef(scalex * aspect, scaley, 1f); - version(test) glRotatef(45f, 1f, 0f, 0.5f); + version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); //viewport //clipx,clipy glBegin(GL_QUADS); diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d index 6aa7798..a206ca7 100644 --- a/SMILEBASIC/builtinfunctions.d +++ b/SMILEBASIC/builtinfunctions.d @@ -228,6 +228,11 @@ class BuiltinFunction p.showGRP = showPage; p.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); + } static void BGMPLAY(PetitComputer p, int music) { } @@ -477,6 +482,9 @@ class BuiltinFunction { switch(va_args.length) { + case 0: + p.sprite.spdef();//初期化 + return; case 1://array { if(va_args[0].isNumberArray) @@ -557,6 +565,10 @@ class BuiltinFunction { p.sprite.sprot(i, rot); } + static void SPCOLOR(PetitComputer p, int id, int color) + { + p.sprite.spcolor(id, cast(uint)color); + } static void BGMSTOP(PetitComputer p) { writeln("NOTIMPL:BGMSTOP"); @@ -709,16 +721,46 @@ class BuiltinFunction static void EFCWET(Value[]) { } + static void COPY(PetitComputer p, Value[] rawargs) + { + auto args = retro(rawargs); + //文字列はリテラル渡すとType mismatch + if(args.length > 5 || args.length < 2 || !args[0].isArray) + { + throw new IllegalFunctionCall("COPY"); + } + //COPY string, string->文字列COPY + //COPY array, string->DATA COPY + Value dst = args[0]; + int dstoffset = 0; + int srcoffset = 0; + int len = dst.length;//省略時はコピー元の末尾まで + if(args[1].isString && !args[0].isString) + { + //DATAから + VM vm = p.vm; + vm.pushDataIndex(); + vm.restoreData(args[1].castString); + for(int i = 0; i < len; i++) + { + Value data = vm.readData(); + dst[dstoffset++] = data; + } + vm.popDataIndex(); + return; + } + throw new IllegalFunctionCall("COPY (Not implemented error)"); + } //alias void function(PetitComputer, Value[], Value[]) BuiltinFunc; static BuiltinFunction[wstring] builtinFunctions; static this() { foreach(name; __traits(derivedMembers, BuiltinFunction)) { - writeln(name); + //writeln(name); static if(/*__traits(isStaticFunction, __traits(getMember, BuiltinFunction, name)) && */name[0].isUpper) { - pragma(msg, AddFunc!(BuiltinFunction, name)); + //pragma(msg, AddFunc!(BuiltinFunction, name)); wstring suffix = ""; if(is(ReturnType!(__traits(getMember, BuiltinFunction, name)) == wstring)) { @@ -732,7 +774,7 @@ class BuiltinFunction IsVariadic!(BuiltinFunction, name), name, ); - writeln(AddFunc!(BuiltinFunction, name)); + //writeln(AddFunc!(BuiltinFunction, name)); } } } @@ -799,8 +841,7 @@ template AddFunc(T, string N) } else static if(is(ReturnType!(__traits(getMember, T, N)) == void)) { - - pragma(msg, GetArgumentCount!(T,N)); + //pragma(msg, GetArgumentCount!(T,N)); const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){/*if(ret.length != 0){throw new IllegalFunctionCall(\"" ~ N ~ "\");}*/" ~ OutArgsInit!(T,N) ~ N ~ "(" ~ AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N, ParameterTypeTuple!(__traits(getMember, T, N))) ~ ");}"; diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index b663172..fd6b133 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -148,7 +148,7 @@ class Compiler return ValueType.Integer; default: return ValueType.Double;//非DEFINT時 - return ValueType.Integer;//DEFINT時 + //return ValueType.Integer;//DEFINT時 } } Statements statements; diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index aa16c7d..6eb14f0 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -143,7 +143,7 @@ class Lexical wstring iden; for(;i < code.length;i++) { - c = cast(wchar)code[i].toUpper;; + c = cast(wchar)code[i].toUpper; if(!c.isAlpha() && !c.isDigit() && c != '_') { break; @@ -374,7 +374,7 @@ class Parser this.code = input; lex = new Lexical(input); } - const int opMax = 11; + const static int opMax = 11; int getOPRank(TokenType type) { switch(type) @@ -460,7 +460,6 @@ class Parser return - - -1; } } - break; case NodeType.Variable: return 100; case NodeType.CallFunction: diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d index d88c478..363dac9 100644 --- a/SMILEBASIC/petitcomputer.d +++ b/SMILEBASIC/petitcomputer.d @@ -10,10 +10,14 @@ import std.conv; import std.string; import std.c.stdio; import core.sync.mutex; -import otya.smilebasic.parser; import otya.smilebasic.sprite; import otya.smilebasic.error; import otya.smilebasic.bg; +import otya.smilebasic.parser; +const static rot_test_deg = 45f; +const static rot_test_x = 1f; +const static rot_test_y = 0f; +const static rot_test_z = 0f; enum Button { NONE = 0, @@ -185,6 +189,7 @@ class PetitComputer int foreColor; int backColor; byte attr; + int z; } SDL_Color PetitColor(ubyte r, ubyte g, ubyte b, ubyte a) { @@ -471,6 +476,149 @@ class PetitComputer } Mutex grpmutex; int displaynum; + 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); + } + int renderstartpos; void renderGraphic() { if(!drawMessageLength) return; @@ -480,20 +628,23 @@ class PetitComputer drawflag = true; //betuni kouzoutai demo sonnnani sokudo kawaranasasou auto len = drawMessageLength; - drawMessageLength = 0; - int s = 0; + 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_ALPHA_TEST); glDisable(GL_DEPTH_TEST); // //glAlphaFunc(GL_GEQUAL, 0.0); glViewport(0, 0, 512, 512); - for(int i = s; i < len; i++) + DrawType dt; + auto start = SDL_GetTicks(); + int i = s; + for(; i < len; i++) { DrawMessage dm = drawMessageQueue[i]; if(oldpage != dm.page) @@ -545,8 +696,37 @@ class PetitComputer } //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, buffer.ptr); + } + gpaintBuffer(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; default: } + dt = dm.type; + } + brk: + if(i == len) + { + renderstartpos = 0; + drawMessageLength = 0; + } + else + { + renderstartpos = s; } glBindFramebufferEXT(GL_FRAMEBUFFER, old); glEnable(GL_DEPTH_TEST); @@ -592,8 +772,10 @@ class PetitComputer return bg; } protected BG[4] bg; + bool quit; void render() { + buffer = new uint[512 * 512]; DerelictSDL2.load(); DerelictSDL2Image.load(); GRPF = createGRPF(fontFile); @@ -616,7 +798,7 @@ class PetitComputer buttonTable[SDL_SCANCODE_LEFT] = Button.LEFT; buttonTable[SDL_SCANCODE_RIGHT] = Button.RIGHT; buttonTable[SDL_SCANCODE_SPACE] = Button.A; - bool renderprofile;// = true; + bool renderprofile = true; try { version(Windows) @@ -629,6 +811,11 @@ class PetitComputer window = SDL_CreateWindow("SMILEBASIC", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 400, 240, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL); + scope(exit) + { + SDL_DestroyWindow(window); + SDL_Quit(); + } renderer = SDL_CreateRenderer(window, -1, 0); SDL_Event event; SDL_GLContext context; @@ -662,9 +849,9 @@ class PetitComputer //glEnable(GL_ALPHA_TEST); // sprite.spset(0, 0); // sprite.spofs(0, 9, 8); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glAlphaFunc(GL_GEQUAL, 0.5); + glAlphaFunc(GL_GEQUAL, 0.1f); glEnable(GL_ALPHA_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); while(true) { auto profile = SDL_GetTicks(); @@ -690,18 +877,23 @@ class PetitComputer } //描画の順位 //sprite>GRP>console>BG + glDisable(GL_BLEND); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_BLEND); version(test) glLoadIdentity(); - version(test) glRotatef(45f, 1f, 0f, 0.5f); + version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); if(xscreenmode == 1) { glViewport(0, 240, 400, 240); } - sprite.render(); + glEnable(GL_BLEND); if(xscreenmode == 1) { glViewport(0, 240, 400, 240); } + glEnable(GL_BLEND); + version(test) glLoadIdentity(); + version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); if(xscreenmode == 2) { renderGraphicPage(0, 320, 480); @@ -726,7 +918,7 @@ class PetitComputer glViewport(0, 240, 400, 240); } version(test) glLoadIdentity(); - version(test) glRotatef(45f, 1f, 0f, 0.5f); + version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); glBindTexture(GL_TEXTURE_2D, GRP[bgpage].glTexture); if(xscreenmode == 2) { @@ -752,12 +944,20 @@ class PetitComputer } } version(test) glLoadIdentity(); - version(test) glRotatef(45f, 1f, 0f, 0.5f); + version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); if(xscreenmode == 1) { glViewport(0, 240, 400, 240); } + //http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20081122 みたいな方法もあるけどとりあえず + //とりあえず一番楽な方法 + //これだと同一Zでスプライトが一番下に来てしまうのでZ値を補正する必要がある->やった + glEnable(GL_BLEND); + glDepthMask(GL_FALSE);//スプライト同士でのZバッファは半透明だと邪魔なので無効 + sprite.render();//Zソートすべき->やった->プチコンの挙動的に安定ソートか非安定ソートか + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); SDL_GL_SwapWindow(window); auto renderticks = (SDL_GetTicks() - profile); if(renderprofile) writeln(renderticks); @@ -766,8 +966,7 @@ class PetitComputer switch (event.type) { case SDL_QUIT: - SDL_DestroyWindow(window); - SDL_Quit(); + quit = true; return; case SDL_KEYUP: { @@ -806,22 +1005,9 @@ class PetitComputer break; } } - if(drawMessageLength) - { - //renderGraphic; - } - while(true) - { - long delay = (1000/60) - (cast(long)SDL_GetTicks() - profile); - if(delay > 0) - SDL_Delay(cast(uint)delay); - break; - if(delay < 0) break; - renderGraphic(); - SDL_Delay(1); - //if(delay > 0) - // SDL_Delay(cast(uint)delay); - } + long delay = (1000/60) - (cast(long)SDL_GetTicks() - profile); + if(delay > 0) + SDL_Delay(cast(uint)delay); } } catch(Throwable t) @@ -854,56 +1040,79 @@ class PetitComputer thread.start(); while(!buttonTable){} auto startTicks = SDL_GetTicks(); - //とりあえず - auto parser = new Parser( - //readText("./SYS/GAME6TALK.TXT").to!wstring - //readText("./SYS/GAME4SHOOTER.TXT").to!wstring - //readText("./SYS/GAME2RPG.TXT").to!wstring - //readText("./SYS/GAME1DOTRC.TXT").to!wstring - //readText(input("LOAD PROGRAM:", true).to!string).to!wstring - readText("./SYS/EX8TECDEMO.TXT").to!wstring - //readText("./SYS/EX1TEXT.TXT").to!wstring - //readText("FIZZBUZZ.TXT").to!wstring - //readText("TEST.TXT").to!wstring - /*"?ABS(-1) - LOCATE 0,10 - COLOR 5 - FOR I=0 TO 10 - ?I;\"!\",\"=\",FACT(I) - NEXT - DEF FACT(N) - IF N<=1 THEN RETURN 1 - RETURN N*FACT(N-1) - END"*/ - /* - `CLS : CL=0 : Z=0 - WHILE 1 - INC Z : IF Z>200 THEN Z=0 - FOR I=0 TO 15 - LOCATE 9,4+I,Z : COLOR (CL+I) MOD 16 - PRINT "★ 梅雨で雨が多い季節ですね ★" - NEXT - CL=(CL+1) MOD 16 - WEND`*/ - /* - `CLS : CL=0 - WHILE 1 - FOR I=0 TO 15 - LOCATE 9,4+I : COLOR (CL+I) MOD 16 - PRINT "Ё プチコン3ゴウ Ж" - NEXT - CL=(CL+1) MOD 16 : VSYNC 1 - WEND` - /* - `CLS : CL=0 - @LOOP - FOR I=0 TO 15 - LOCATE 9,4+I : COLOR (CL+I) MOD 16 - PRINT "Ё プチコン3ゴウ Ж" - NEXT - CL=(CL+1) MOD 16 : VSYNC 1 - GOTO @LOOP`*/ - ); + Parser parser; + //デバッグ用 + version(NDirectMode) + { + parser = new Parser( + //readText("./SYS/GAME6TALK.TXT").to!wstring + //readText("./SYS/GAME4SHOOTER.TXT").to!wstring + //readText("./SYS/GAME2RPG.TXT").to!wstring + //readText("./SYS/GAME1DOTRC.TXT").to!wstring + //readText(input("LOAD PROGRAM:", true).to!string).to!wstring + readText("./SYS/EX8TECDEMO.TXT").to!wstring + //readText("./SYS/EX1TEXT.TXT").to!wstring + //readText("FIZZBUZZ.TXT").to!wstring + //readText("TEST.TXT").to!wstring + /*"?ABS(-1) + LOCATE 0,10 + COLOR 5 + FOR I=0 TO 10 + ?I;\"!\",\"=\",FACT(I) + NEXT + DEF FACT(N) + IF N<=1 THEN RETURN 1 + RETURN N*FACT(N-1) + END"*/ + /* + `CLS : CL=0 : Z=0 + WHILE 1 + INC Z : IF Z>200 THEN Z=0 + FOR I=0 TO 15 + LOCATE 9,4+I,Z : COLOR (CL+I) MOD 16 + PRINT "★ 梅雨で雨が多い季節ですね ★" + NEXT + CL=(CL+1) MOD 16 + WEND`*/ + /* + `CLS : CL=0 + WHILE 1 + FOR I=0 TO 15 + LOCATE 9,4+I : COLOR (CL+I) MOD 16 + PRINT "Ё プチコン3ゴウ Ж" + NEXT + CL=(CL+1) MOD 16 : VSYNC 1 + WEND` + /* + `CLS : CL=0 + @LOOP + FOR I=0 TO 15 + LOCATE 9,4+I : COLOR (CL+I) MOD 16 + PRINT "Ё プチコン3ゴウ Ж" + NEXT + CL=(CL+1) MOD 16 : VSYNC 1 + GOTO @LOOP`*/ + ); + } + else + { + do + { + auto file = input("LOAD PROGRAM:", true).to!string; + try + { + parser = new Parser(readText(file).to!wstring); + } + catch(Throwable t) + { + writeln(t); + printConsole("can't open program \"", file, "\".\n"); + continue; + } + break; + } while(!quit); + } + if(quit) return; auto vm = parser.compile(); bool running = true; vm.init(this); @@ -915,11 +1124,12 @@ class PetitComputer //gfill(0, 78, 78, 40, 40, RGB(0, 255, 255)); //gbox(0, 78, 78, 40, 40, RGB(255, 255, 0)); int startcnt = SDL_GetTicks(); + float frame = 1000f / 60f; while (true) { uint elapse; startTicks = SDL_GetTicks(); - do + //do { try { @@ -956,14 +1166,24 @@ class PetitComputer { } } - elapse = SDL_GetTicks() - startTicks; - } while(elapse <= 1000 / 60); - maincnt = (SDL_GetTicks() - startcnt) / (1000 / 60); - vsyncCount++; - if(vsyncFrame <= vsyncCount) vsyncFrame = 0; + //elapse = SDL_GetTicks() - startTicks; + } //while(elapse <= 1000 / 60); + if(vsyncFrame) + { + SDL_Delay(cast(uint)(vsyncFrame * frame)); + vsyncFrame = 0; + } + maincnt = cast(int)((SDL_GetTicks() - startcnt) / frame); + if(quit) + { + quit = false; + break; + } + } + scope(exit) + { + writeln("quit"); } - SDL_DestroyWindow(window); - SDL_Quit(); } void clearKeyBuffer() { @@ -982,12 +1202,12 @@ class PetitComputer showCursor = true; int oldCSRX = this.CSRX; int oldCSRY = this.CSRY; - while(true) + while(!quit) { auto oldpos = keybufferpos; - while(oldpos == keybufferpos) + while(oldpos == keybufferpos && !quit) { - SDL_Delay(4);//適当 ストレスを感じないくらい + SDL_Delay(8);//適当 ストレスを感じないくらい } auto kbp = keybufferpos; auto len = kbp - oldpos; @@ -1088,6 +1308,7 @@ class PetitComputer BOX, CIRCLE, TRI, + PAINT, } struct DrawMessage { @@ -1159,6 +1380,10 @@ class PetitComputer { 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); + } int gprio; void renderGraphicPage(int display, float w, float h) { @@ -1261,15 +1486,16 @@ class PetitComputer { auto fore = consoleColorGL[console[y][x].foreColor]; auto rect = &fontTable[console[y][x].character]; + float z = console[y][x].z / 1025f; glColor4ubv(cast(ubyte*)&fore); glTexCoord2f((rect.x) / 512f - 1 , (rect.y + 8) / 512f - 1); - glVertex3f((x * 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0); + glVertex3f((x * 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, z); glTexCoord2f((rect.x) / 512f - 1, (rect.y) / 512f - 1); - glVertex3f((x * 8) / 200f - 1, 1 - (y * 8) / 120f, 0); + glVertex3f((x * 8) / 200f - 1, 1 - (y * 8) / 120f, z); glTexCoord2f((rect.x + 8) / 512f - 1, (rect.y) / 512f - 1); - glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8) / 120f, 0); + glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8) / 120f, z); glTexCoord2f((rect.x + 8) / 512f - 1, (rect.y +8) / 512f - 1); - glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0); + glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, z); } glEnd(); if(xscreenmode != 1) @@ -1310,15 +1536,16 @@ class PetitComputer { auto fore = consoleColorGL[consoleDisplay1[y][x].foreColor]; auto rect = &fontTable[consoleDisplay1[y][x].character]; + float z = consoleDisplay1[y][x].z / 1025f; glColor4ubv(cast(ubyte*)&fore); glTexCoord2f((rect.x) / 512f - 1 , (rect.y + 8) / 512f - 1); - glVertex3f((x * 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0); + glVertex3f((x * 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, z); glTexCoord2f((rect.x) / 512f - 1, (rect.y) / 512f - 1); - glVertex3f((x * 8) / 200f - 1, 1 - (y * 8) / 120f, 0); + glVertex3f((x * 8) / 200f - 1, 1 - (y * 8) / 120f, z); glTexCoord2f((rect.x + 8) / 512f - 1, (rect.y) / 512f - 1); - glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8) / 120f, 0); + glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8) / 120f, z); glTexCoord2f((rect.x + 8) / 512f - 1, (rect.y +8) / 512f - 1); - glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0); + glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, z); } glEnd(); // glFlush(); @@ -1330,6 +1557,7 @@ class PetitComputer printConsoleString(i.to!wstring); } } + byte consoleAttr; void printConsoleString(wstring text) { //consolem.lock(); @@ -1346,6 +1574,8 @@ class PetitComputer consoleC[CSRY][CSRX].character = c; consoleC[CSRY][CSRX].foreColor = consoleForeColor; consoleC[CSRY][CSRX].backColor = consoleBackColor; + consoleC[CSRY][CSRX].z = CSRZ; + consoleC[CSRY][CSRX].attr = consoleAttr; } CSRX++; if(CSRX >= consoleWidthC || c == '\n' || c == '\r') @@ -1361,7 +1591,7 @@ class PetitComputer consoleC[i] = consoleC[i + 1]; } consoleC[consoleHeightC - 1] = tmp; - tmp[] = ConsoleCharacter(0, consoleForeColor, consoleBackColor); + tmp[] = ConsoleCharacter(0, consoleForeColor, consoleBackColor, consoleAttr, CSRZ); //assert(console[0] != console[2]); CSRY = consoleHeightC - 1; } diff --git a/SMILEBASIC/sprite.d b/SMILEBASIC/sprite.d index aaa1f3e..5ba5035 100644 --- a/SMILEBASIC/sprite.d +++ b/SMILEBASIC/sprite.d @@ -143,7 +143,7 @@ struct SpriteData int defno; double x, y; int homex, homey; - double z;/*!*/ + int z;/*!*/ int u, v, w, h;//個々で保持してるみたい,SPSETをして後でSPDEFをしても変化しない uint color; double[8] var; @@ -152,8 +152,10 @@ struct SpriteData double scalex; double scaley; double r; - this(bool flag) + this(int id) { + this.id = id; + z = 0; define = false; } this(int id, int defno) @@ -237,9 +239,22 @@ struct SpriteData this.homey = s.hy; this.attr = s.a; } + double debugZ() + { + import std.stdio; + // writefln("sprite=%d, z=%f", id, z); + return z; + } + int opCmp(ref SpriteData spr) + { + import std.stdio; + writeln("WHAT!????"); + return 0; + } } class Sprite { + SpriteDef[] defSPDEFTable; SpriteDef[] SPDEFTable; SpriteData[] sprites; PetitComputer petitcom; @@ -248,13 +263,7 @@ class Sprite void initUVTable() { SPDEFTable = new SpriteDef[4096]; - //UVTable[] = SDL_Rect(0, 0, 16, 16);//Ichigo - for(int i = 0; i < 4096; i++) - { - SPDEFTable[i] = SpriteDef(0, 0, 16, 16, 0, 0, SpriteAttr.show); - } - SPDEFTable[4095] = SpriteDef(192, 480, 96, 32, 48, 16, SpriteAttr.show); - //UVTable[] = SDL_Rect(192, 480, 96, 32); + defSPDEFTable = new SpriteDef[4096]; import std.csv; import std.typecons;//I X Y W H HX HY ATTR import std.file; @@ -265,8 +274,13 @@ class Sprite auto csv = file.byLine.joiner("\n").csvReader!(Tuple!(int, "I", int, "X" ,int, "Y", int, "W", int, "H", int, "HX", int, "HY", int, "ATTR")); foreach(record; csv) { - SPDEFTable[record.I] = SpriteDef(record.X, record.Y, record.W, record.H, record.HX, record.HY, cast(SpriteAttr)record.ATTR); + defSPDEFTable[record.I] = SpriteDef(record.X, record.Y, record.W, record.H, record.HX, record.HY, cast(SpriteAttr)record.ATTR); } + spdef; + } + void spdef() + { + this.SPDEFTable[] = (this.defSPDEFTable)[]; } void spchr(int i, int d) { @@ -282,11 +296,24 @@ class Sprite this(PetitComputer petitcom) { sprites = new SpriteData[512]; - sprites[] = SpriteData(false); + zsortedSprites = new SpriteData*[512]; + for(int i = 0; i < sprites.length; i++) + { + zsortedSprites[i] = &sprites[i]; + sprites[i] = SpriteData(i); + } initUVTable; this.petitcom = petitcom; + list = new SpriteBucket[512]; + for(int i = 0; i < 512; i++) + { + list[i] = new SpriteBucket(); + } + buckets = new SpriteBucket[1024 + 256]; + listptr = list.ptr; + bucketsptr = buckets.ptr; } - void animation(ref SpriteData sprite) + void animation(SpriteData* sprite) { foreach(i, ref d; sprite.anim) { @@ -307,7 +334,7 @@ class Sprite sprite.y = data.data.y; break; case SpriteAnimTarget.Z: - sprite.z = data.data.z; + sprite.z = cast(int)data.data.z; break; case SpriteAnimTarget.UV: sprite.u = data.data.u; @@ -343,7 +370,7 @@ class Sprite sprite.y = data.old.y + ((data.data.y - data.old.y) / data.frame) * frame; break; case SpriteAnimTarget.Z: - sprite.z = data.old.z + ((data.data.z - data.old.z) / data.frame) * frame; + sprite.z = cast(int)(data.old.z + ((data.data.z - data.old.z) / data.frame) * frame); break; case SpriteAnimTarget.UV: sprite.u = data.old.u + ((data.data.u - data.old.u) / data.frame) * frame; @@ -388,8 +415,78 @@ class Sprite } bool lll; import std.algorithm; + SpriteData*[] zsortedSprites; + bool zChange; + class SpriteBucket + { + SpriteData* sprite; + SpriteBucket next; + SpriteBucket last; + } + SpriteBucket[] list; + SpriteBucket[] buckets; + SpriteBucket* listptr; + SpriteBucket* bucketsptr; void render() { + //とりあえずZ更新されたら描画時にまとめてソート + //thread safe..... + if(zChange) + { + + import std.range; + import std.algorithm; + zChange = false; + /*//TimSortImpl!(binaryFun!("a.z < b.z"), Range).sort(zsortedSprites, null); + try + { + sort!("a.z > b.z", SwapStrategy.stable)(zsortedSprites); + } + catch(Throwable t) + { + }//*/ + //バケットソートっぽい奴 + //基本的にほぼソートされてるので挿入ソートのほうが早そう + //std.algorithmソートだと例外出る + //m = 256+1024 + //n = 512 + import std.stdio; + //writeln("=============START=========="); + //writeln("sort"); + foreach(i, ref s; sprites) + { + //if(!s.define) continue; + auto zet = s.z + 256; + listptr[i].sprite = &s; + if(bucketsptr[zet]) + { + //listptr[i].next = bucketsptr[zet].last; + bucketsptr[zet].last.next = listptr[i]; + bucketsptr[zet].last = listptr[i]; + listptr[i].next = null; + } + else + { + bucketsptr[zet] = listptr[i].last = listptr[i]; + listptr[i].next = null; + } + } + int j; + foreach_reverse(i, b; buckets) + { + if(b) + { + while(b) + { + //writefln("z:%d, id:%d", b.sprite.z, b.sprite.id); + zsortedSprites[j] = b.sprite; + j++; + b = b.next; + } + bucketsptr[i] = null; + } + } + } float disw = 200f, dish = 120f, disw2 = 400f, dish2 = 240f; if(petitcom.xscreenmode == 2) { @@ -407,7 +504,7 @@ class Sprite // glDisable(GL_TEXTURE_2D); version(test) glLoadIdentity(); glLoadIdentity(); - foreach(i,ref sprite; sprites) + foreach(i, sprite; zsortedSprites) { if(i == spmax) { @@ -440,7 +537,7 @@ class Sprite int v = cast(int)sprite.v; int u2 = cast(int)sprite.u + sprite.w;//-1 int v2 = cast(int)sprite.v + sprite.h; - z = sprite.z / 1025f; + z = (sprite.z - 1) / 1025f;//スプライトの描画順が一番上だけどスプライトは最後に描画しないといけないのでZ - 1で一番上にする float flipx = cast(float)sprite.scalex, flipy = cast(float)sprite.scaley, flipx2 = x, flipy2 = y; if(sprite.attr & SpriteAttr.hflip) { @@ -452,7 +549,7 @@ class Sprite flipy = -flipy; flipy2 = y2 - cast(int)(sprite.homey * sprite.scaley); } - version(test) glRotatef(45f, 1f, 0f, 0.5f); + version(test) glRotatef(rot_test_deg, rot_test_x, rot_test_y, rot_test_z); glTranslatef((flipx2) / disw - 1, 1 - ((flipy2) / dish), 0); @@ -465,7 +562,7 @@ class Sprite glRotatef(360 - sprite.r, 0.0f, 0.0f, 1.0f ); glScalef(flipx * aspect, flipy, 1f); glBegin(GL_QUADS); - glColor3f(1.0, 1.0, 1.0); + glColor4ubv(cast(ubyte*)&sprite.color); if((sprite.attr& 0b111) == SpriteAttr.show) { glTexCoord2f(u / 512f - 1, v / 512f - 1); @@ -567,6 +664,7 @@ class Sprite sprites[id].x = x; sprites[id].y = y; sprites[id].z = z; + zChange = true; } void sphide(int id) { @@ -659,4 +757,9 @@ class Sprite i = spid(i); sprites[i].r = rot; } + void spcolor(int id, uint color) + { + id = spid(id); + sprites[id].color = petitcom.toGLColor(color); + } } diff --git a/SMILEBASIC/type.d b/SMILEBASIC/type.d index f15f454..9080bd7 100644 --- a/SMILEBASIC/type.d +++ b/SMILEBASIC/type.d @@ -117,6 +117,62 @@ struct Value return "default"; } } + @property int length() + { + switch(this.type) + { + case ValueType.String: + return cast(int)stringValue.length; + case ValueType.IntegerArray: + return cast(int)integerArray.length; + case ValueType.DoubleArray: + return cast(int)doubleArray.length; + case ValueType.StringArray: + return cast(int)stringArray.length; + default: + throw new TypeMismatch(); + } + } + void opIndexAssign(Value v, int i) + { + switch(this.type) + { + //とりあえず破壊的に書き換えた + //どのみちこれだと文字数を増やすことができないのでArray!wcharで管理させたい + case ValueType.String: + (cast(wchar[])stringValue)[i] = v.castString[0]; + break; + case ValueType.IntegerArray: + integerArray.array[i] = v.castInteger; + break; + case ValueType.DoubleArray: + doubleArray.array[i] = v.castDouble; + break; + case ValueType.StringArray: + stringArray.array[i] = v.castString; + break; + default: + throw new TypeMismatch(); + } + } + Value opIndex(int i) + { + switch(this.type) + { + //とりあえず破壊的に書き換えた + //どのみちこれだと文字数を増やすことができないのでArray!wcharで管理させたい + case ValueType.String: + return Value(stringValue[i]); + case ValueType.IntegerArray: + return Value(integerArray.array[i]); + case ValueType.DoubleArray: + return Value(doubleArray.array[i]); + case ValueType.StringArray: + return Value(stringArray.array[i]); + default: + throw new TypeMismatch(); + } + } } class Array(T) { @@ -138,6 +194,10 @@ class Array(T) } dimCount = 1; } + @property size_t length() + { + return array.length; + } this(int[] dim) { int len = 1;