diff --git a/SMILEBASIC/SMILEBASIC.visualdproj b/SMILEBASIC/SMILEBASIC.visualdproj index c6cfc95..b555c07 100644 --- a/SMILEBASIC/SMILEBASIC.visualdproj +++ b/SMILEBASIC/SMILEBASIC.visualdproj @@ -207,11 +207,13 @@ + + diff --git a/SMILEBASIC/TEST.txt b/SMILEBASIC/TEST.txt index 8fa3d34..93b7e9f 100644 --- a/SMILEBASIC/TEST.txt +++ b/SMILEBASIC/TEST.txt @@ -1,3 +1,15 @@ +GOSUB@A +GOTO@B +'A=SIN(B) +'?Y2,SIN(DAY * 2 * 3.141 / BDAY),LINEH,LINEC +@A +Y2 = LINEC - SIN(DAY * 2 * 3 / BDAY) * LINEH +RETURN +@B +?DATE$, TIME$ +DTREAD "2014/10/12" OUT Y,M,D +?Y,M,D +?SIN(1) 'COMMENT' ASSERT__ 1, "TRUE" A$="A" @@ -80,14 +92,18 @@ DEF ONGOSUBTEST @4 END @DATA_1 -DATA "A",1,2,3,4 +DIM ARY[2] +DATA "A",1,2,3,4,5 READ DATA$,_1,_2 READ _3,_4 +READ ARY[_1] ASSERT__ DATA$=="A", "DATA" ASSERT__ _1==1, "DATA" ASSERT__ _2==2, "DATA" ASSERT__ _3==3, "DATA" ASSERT__ _4==4, "DATA" +ASSERT__ ARY[1]==5, "DATA" +?ARY[_1] INPUT$="HELLO" INPUT INPUT$,IN ?INPUT$,IN diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index af5bd36..dd2adca 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -4,6 +4,7 @@ import otya.smilebasic.token; import otya.smilebasic.error; import otya.smilebasic.compiler; import otya.smilebasic.petitcomputer; +import otya.smilebasic.systemvariable; import std.uni; import std.utf; import std.conv; @@ -17,6 +18,10 @@ struct VMVariable this.index = index; this.type = type; } + this(int index) + { + this.index = index; + } } class VM { @@ -38,7 +43,8 @@ class VM this.globalTable = globalTable; foreach(wstring k, VMVariable v ; globalTable) { - this.global[v.index] = Value(v.type); + if(v.index >= 0) + this.global[v.index] = Value(v.type); } this.functions = functions; this.globalDataTable = gdt; @@ -889,10 +895,16 @@ class CallBuiltinFunction : Code else { arg = vm.stack[vm.stacki - argcount..vm.stacki]; - result = vm.stack[vm.stacki - argcount..vm.stacki - argcount + outcount];//雑; + result = vm.stack[vm.stacki/* - argcount */+ 1..vm.stacki + 1/* - argcount */+ outcount];//雑; } func.func(vm.petitcomputer, arg, result); - vm.stacki -= func.argments.length - outcount; + vm.stacki -= func.argments.length;// - outcount; + ////vm.stacki += outcount; + //vm.stacki = old; + for(int i = 0; i < result.length; i++) + { + vm.push(result[i]); + } } } class IncCodeG : Code @@ -1139,3 +1151,29 @@ class ReadCode : Code } } } +class PushSystemVariable : Code +{ + SystemVariable var; + this(SystemVariable var) + { + this.var = var; + } + override void execute(VM vm) + { + vm.push(var.value); + } +} +class PopSystemVariable : Code +{ + SystemVariable var; + this(SystemVariable var) + { + this.var = var; + } + override void execute(VM vm) + { + Value v; + vm.pop(v); + var.value = v; + } +} diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d index eae277b..752262b 100644 --- a/SMILEBASIC/builtinfunctions.d +++ b/SMILEBASIC/builtinfunctions.d @@ -15,12 +15,12 @@ struct DefaultValue(T, bool skippable = true) { T value; bool isDefault; - this(int v, bool f) + this(T v, bool f) { value = v; isDefault = f; } - this(int v) + this(T v) { value = v; isDefault = false; @@ -67,6 +67,10 @@ class BuiltinFunction return a < 0 ? -a : a; }*/ static double function(double) ABS = &abs!double; + static double SIN(double arg1) + { + return sin(arg1); + } //static ABS = function double(double x) => abs(this.result == ValueType.Double ? 1 : 0); static void LOCATE(PetitComputer p, DefaultValue!int x, DefaultValue!int y, DefaultValue!(int, false) z) { @@ -115,16 +119,84 @@ class BuiltinFunction static void DISPLAY(PetitComputer p, DefaultValue!(int, false) display) { } - static void GCLS(PetitComputer p, DefaultValue!(int, false) display) + static void GCLS(PetitComputer p, DefaultValue!(int, false) color) { + color.setDefaultValue(p.gcolor); + p.gfill(p.useGRP, 0, 0, 511, 511, cast(int)color); } static void GPSET(PetitComputer p, int x, int y, DefaultValue!(int, false) color) { - //p.gpset(p.useGRP, x, y, ); + color.setDefaultValue(p.gcolor); + p.gpset(p.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); + } + 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); + } + 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); + } + static void GCOLOR(PetitComputer p, int color) + { + p.gcolor = color; } static void BEEP(PetitComputer p, DefaultValue!(int, false) display) { } + static int RGB(int R, int G, int B, DefaultValue!(int, false) _) + { + if(!_.isDefault) + { + //やや強引なオーバーロード + return PetitComputer.RGB(cast(ubyte)R, cast(ubyte)G, cast(ubyte)B, cast(ubyte)_); + } + return PetitComputer.RGB(cast(ubyte)R, cast(ubyte)G, cast(ubyte)B); + } + static int RND(int max) + { + import std.random; + return uniform(0, max - 1); + } + static void DTREAD(DefaultValue!(wstring, false) date, out int Y, out int M, out int D/*W*/) + { + import std.datetime; + auto currentTime = Clock.currTime(); + if(date.isDefault) + { + Y = currentTime.year; + M = currentTime.month; + D = currentTime.day; + } + else + { + import std.format; + auto v = date.value; + formattedRead(v, "%d/%d/%d", &Y, &M, &D); + } + } + //hairetuha? + static int LEN(wstring str) + { + return str.length; + } + static double VAL(wstring str) + { + double val = str.to!double; + return val; + } + static wstring MID(wstring str, int i, int len) + { + //挙動未定 + return str[i..i + len]; + } //alias void function(PetitComputer, Value[], Value[]) BuiltinFunc; static BuiltinFunction[wstring] builtinFunctions; static this() @@ -134,7 +206,13 @@ class BuiltinFunction writeln(name); static if(/*__traits(isStaticFunction, __traits(getMember, BuiltinFunction, name)) && */name[0].isUpper) { - builtinFunctions[name] = new BuiltinFunction( + pragma(msg, AddFunc!(BuiltinFunction, name)); + wstring suffix = ""; + if(is(ReturnType!(__traits(getMember, BuiltinFunction, name)) == wstring)) + { + suffix = "$"; + } + builtinFunctions[name ~ suffix] = new BuiltinFunction( GetFunctionParamType!(BuiltinFunction, name), GetFunctionReturnType!(BuiltinFunction, name), mixin(AddFunc!(BuiltinFunction, name)), @@ -179,6 +257,10 @@ template GetFunctionReturnType(T, string N) { enum GetFunctionReturnType = ValueType.Void; } + else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring)) + { + enum GetFunctionReturnType = ValueType.String; + } else { enum GetFunctionReturnType = ValueType.Void; @@ -190,12 +272,22 @@ template AddFunc(T, string N) static if(is(ReturnType!(__traits(getMember, T, N)) == double) || is(ReturnType!(__traits(getMember, T, N)) == int)) { const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall();}ret[0] = Value(" ~ N ~ "(" ~ - AddFuncArg!(ParameterTypeTuple!(__traits(getMember, T, N)).length - 1, 0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}"; + AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N + , ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}"; } else static if(is(ReturnType!(__traits(getMember, T, N)) == void)) { - const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 0){throw new IllegalFunctionCall();}" ~ N ~ "(" ~ - AddFuncArg!(ParameterTypeTuple!(__traits(getMember, T, N)).length - 1, 0, 0, ParameterTypeTuple!(__traits(getMember, 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();}*/" ~ 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))) ~ ");}"; + } + else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring)) + { + const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall();}ret[0] = Value(" ~ N ~ "(" ~ + AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N + , ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}"; } else { @@ -217,6 +309,20 @@ DefaultValue!(int, false) fromIntToSkip(Value v) else return DefaultValue!(int, false)(true); } +DefaultValue!wstring fromStringToDefault(Value v) +{ + if(v.type == ValueType.String) + return DefaultValue!wstring(v.castString()); + else + return DefaultValue!wstring(true); +} +DefaultValue!(wstring, false) fromStringToSkip(Value v) +{ + if(v.type == ValueType.String) + return DefaultValue!(wstring, false)(v.castString()); + else + return DefaultValue!(wstring, false)(true); +} template GetFunctionParamType(T, string N) { enum GetFunctionParamType = mixin("[" ~ Array!(ParameterTypeTuple!(__traits(getMember, T, N))) ~ "]"); @@ -249,6 +355,14 @@ template GetFunctionParamType(T, string N) { const string arg = "ValueType.Integer, true"; } + else static if(is(P[0] == DefaultValue!(wstring))) + { + const string arg = "ValueType.String, false"; + } + else static if(is(P[0] == DefaultValue!(wstring, false))) + { + const string arg = "ValueType.String, true"; + } else static if(is(P[0] == PetitComputer)) { static if(P.length != 0) @@ -271,42 +385,71 @@ template GetFunctionParamType(T, string N) } } } -template AddFuncArg(int L, int N, int M, P...) +template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...) { enum I = L - N; + enum storage = ParameterStorageClassTuple!(__traits(getMember, T, NAME))[M]; static if(is(P[0] == double)) { enum add = 1; + enum outadd = 0; const string arg = "arg[" ~ I.to!string ~ "].castDouble"; } else static if(is(P[0] == PetitComputer)) { enum add = 0; + enum outadd = 0; const string arg = "p"; } else static if(is(P[0] == int)) { - enum add = 1; - const string arg = "arg[" ~ I.to!string ~ "].castInteger"; + static if(storage & ParameterStorageClass.out_) + { + enum add = 0; + enum outadd = 1; + const string arg = "ret[" ~ O.to!string ~ "].integerValue"; + } + else + { + enum add = 1; + enum outadd = 0; + const string arg = "arg[" ~ I.to!string ~ "].castInteger"; + } } else static if(is(P[0] == wstring)) { enum add = 1; + enum outadd = 0; const string arg = "arg[" ~ I.to!string ~ "].castString"; } else static if(is(P[0] == DefaultValue!int)) { enum add = 1; + enum outadd = 0; const string arg = "fromIntToDefault(arg[" ~ I.to!string ~ "])"; } else static if(is(P[0] == DefaultValue!(int, false))) { enum add = 1; + enum outadd = 0; const string arg = "fromIntToSkip(arg[" ~ I.to!string ~ "])"; } + else static if(is(P[0] == DefaultValue!wstring)) + { + enum add = 1; + enum outadd = 0; + const string arg = "fromStringToDefault(arg[" ~ I.to!string ~ "])"; + } + else static if(is(P[0] == DefaultValue!(wstring, false))) + { + enum add = 1; + enum outadd = 0; + const string arg = "fromStringToSkip(arg[" ~ I.to!string ~ "])"; + } else { enum add = 1; + enum outadd = 0; static assert(false, "Invalid type"); const string arg = ""; } @@ -316,6 +459,62 @@ template AddFuncArg(int L, int N, int M, P...) } else { - const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, P[1..$]); + const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, O + outadd, T, NAME, P[1..$]); + } +} +template OutArgsInit(T, string N, int I = 0, int J = 0) +{ + enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I]; + alias param = ParameterTypeTuple!(__traits(getMember, T, N)); + static if(tuple & ParameterStorageClass.out_) + { + enum add = 1; + enum ret1 = "ret[" ~ J.to!string ~ "].type = "; + static if(is(param[I] == int)) + { + enum ret2 = "ValueType.Integer;"; + } + enum result = ret1 ~ ret2; + } + else + { + enum add = 0; + enum result = ""; + } + static if(param.length > I + 1) + { + enum OutArgsInit = result ~ OutArgsInit!(T, N, I + 1, J + add); + } + else + { + enum OutArgsInit = result; + } +} +template GetArgumentCount(T, string N, int I = 0) +{ + enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I]; + alias param = ParameterTypeTuple!(__traits(getMember, T, N)); + static if(is(param[I] == PetitComputer)) + { + enum add = 0 + 1; + } + else + { + static if(tuple & ParameterStorageClass.out_) + { + enum add = 0; + } + else + { + enum add = 1; + } + } + static if(param.length > I + 1) + { + enum GetArgumentCount = add + GetArgumentCount!(T, N, I + 1); + } + else + { + enum GetArgumentCount = add; } } diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 1f82eff..13f2331 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -4,6 +4,7 @@ import otya.smilebasic.token; import otya.smilebasic.vm; import otya.smilebasic.type; import otya.smilebasic.error; +import otya.smilebasic.systemvariable; import std.stdio; class Scope { @@ -145,6 +146,7 @@ class Compiler case '%': return ValueType.Integer; default: + return ValueType.Double;//非DEFINT時 return ValueType.Integer;//DEFINT時 } } @@ -153,8 +155,13 @@ class Compiler { this.statements = statements; code = new Code[0]; + global["DATE$"] = VMVariable(-1); + sysVariable["DATE$"] = new Date(); + global["TIME$"] = VMVariable(-1); + sysVariable["TIME$"] = new Time(); } + SystemVariable[wstring] sysVariable; Code[] code; VMVariable[wstring] global; int[wstring] globalLabel; @@ -176,6 +183,19 @@ class Compiler { code ~= new PopG(ind); } + SystemVariable getSystemVariable(wstring name) + { + auto var = sysVariable.get(name, null); + return var; + } + void genCodePushSysVar(wstring name) + { + code ~= new PushSystemVariable(getSystemVariable(name)); + } + void genCodePopSysVar(wstring name) + { + code ~= new PopSystemVariable(getSystemVariable(name)); + } void genCodePushVar(wstring name, Scope sc) { auto global = hasGlobalVarIndex(name); @@ -186,6 +206,11 @@ class Compiler } if(global) { + if(global < 0) + { + genCodePushSysVar(name); + return; + } code ~= new PushG(global); return; } @@ -201,6 +226,11 @@ class Compiler } if(global) { + if(global < 0) + { + genCodePopSysVar(name); + return; + } code ~= new PopG(global); return; } @@ -371,13 +401,17 @@ class Compiler case NodeType.CallFunction: { auto func = cast(CallFunction)exp; + writeln(func.name); auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null); if(bfun) { - auto k = bfun.argments.length - func.args.length; - foreach(l;0..k) + if(bfun.argments.length >= func.args.length) { - genCodeImm(Value(ValueType.Void)); + auto k = bfun.argments.length - func.args.length; + foreach(l;0..k) + { + genCodeImm(Value(ValueType.Void)); + } } } foreach_reverse(Expression i ; func.args) @@ -418,10 +452,11 @@ class Compiler case NodeType.Variable: { auto var = cast(Variable)expr; - int index; - bool local; - getVarIndex(var.name, sc, index, local); - genCode(local ? new PopL(index) : new PopG(index)); + genCodePopVar(var.name, sc); + //int index; + //bool local; + //getVarIndex(var.name, sc, index, local); + //genCode(local ? new PopL(index) : new PopG(index)); } break; case NodeType.BinaryOperator: diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 1c34387..36c52d7 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -5,6 +5,7 @@ import otya.smilebasic.node; import otya.smilebasic.compiler; import std.ascii; import std.stdio; +import std.conv; class Lexical { TokenType[] table; @@ -60,6 +61,7 @@ class Lexical reserved["DIM"] = TokenType.Var; reserved["DEF"] = TokenType.Def; reserved["OUT"] = TokenType.Out; + reserved["out"] = TokenType.Out;//ekkitou reserved["WHILE"] = TokenType.While; reserved["WEND"] = TokenType.WEnd; reserved["INC"] = TokenType.Inc; @@ -69,6 +71,8 @@ class Lexical reserved["RESTORE"] = TokenType.Restore; reserved["ON"] = TokenType.On; reserved["INPUT"] = TokenType.Input; + reserved["TRUE"] = TokenType.True; + reserved["FALSE"] = TokenType.False; reserved.rehash(); line = 1; } @@ -103,19 +107,34 @@ class Lexical token = Token(TokenType.NewLine); break; } - if(c.isDigit()) + if(c.isDigit() || c == '.') { - int num; + bool dot; + int start = i; + double num; for(;i < code.length;i++) { c = code[i]; - if(!c.isDigit()) + if(c == '.') + { + if(dot) break; + dot = true; + } + if(!c.isDigit() && c != '.') { break; } - num = num * 10 + (c - '0'); } - token = Token(TokenType.Integer, Value(num)); + wstring numstr = code[start..i]; + num = numstr.to!double; + if(num <= int.max && num >= int.min && !dot) + { + token = Token(TokenType.Integer, Value(cast(int)num)); + } + else + { + token = Token(TokenType.Integer, Value(num)); + } break; } if(c.isAlpha() || c == '_') @@ -138,6 +157,17 @@ class Lexical else//変数が予約語であることはありえない { auto r = reserved.get(iden, TokenType.Unknown); + //TRUE/FALSEは3.1でもDATAに使える定数 + if(r == TokenType.True) + { + token = Token(TokenType.Integer, Value(1)); + break; + } + if(r == TokenType.False) + { + token = Token(TokenType.Integer, Value(0)); + break; + } if(r != TokenType.Unknown) { token = Token(r); @@ -628,6 +658,20 @@ class Parser } } lex.popFront(); + auto token = lex.front; + if(token.type == TokenType.Iden) + { + //NEXT I[,J[,K...]]プチコン3号だと無視 + lex.popFront(); + token = lex.front; + while(token.type == TokenType.Comma) + { + lex.popFront(); + token = lex.front; + if(token.type != TokenType.Iden) break; + lex.popFront(); + } + } return statements; } Statements whileStatements() @@ -655,6 +699,7 @@ class Parser { auto token = lex.front(); Statement node = null; + writeln(token.type); switch(token.type) { case TokenType.Print: @@ -694,6 +739,7 @@ class Parser if(expr) func.addArg(expr); } + if(lex.front().type == TokenType.Out) break; if(lex.front().type != TokenType.Comma) break; lex.popFront(); } @@ -753,8 +799,7 @@ class Parser node = if_(); return node; case TokenType.For: - node = forStatement(); - break; + return forStatement(); case TokenType.Return: lex.popFront(); if(isFuncReturnExpr) diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d index 51faf7e..f7d2929 100644 --- a/SMILEBASIC/petitcomputer.d +++ b/SMILEBASIC/petitcomputer.d @@ -123,6 +123,8 @@ class PetitComputer ConsoleCharacter[][] console; bool visibleGRP = true; int showGRP; + int useGRP; + uint gcolor; GraphicPage[] GRP; GraphicPage GRPF; GraphicPage[] GRPFColor; @@ -261,6 +263,19 @@ class PetitComputer } return new GraphicPage(surface); } + GraphicPage createEmptyPage() + { + auto surface = SDL_CreateRGBSurface(0, 512, 512, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0xff); + auto pixels = (cast(uint*)surface.pixels); + for(int x = 0; x < surface.w; x++) + { + for(int y = 0; y < surface.h; y++) + { + *pixels++ = 0; + } + } + return new GraphicPage(surface); + } struct Point { int x, y; @@ -382,7 +397,7 @@ class PetitComputer GRP = new GraphicPage[6]; for(int i = 0; i < 4; i++) { - GRP[i] = new GraphicPage(SDL_CreateRGBSurface(0, 512, 512, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0xff)); + GRP[i] = createEmptyPage(); } GRP[4] = createGRPF(spriteFile); GRP[5] = createGRPF(BGFile); @@ -431,9 +446,43 @@ class PetitComputer keybufferlen = keybuffer.length; keybufferpos = (keybufferpos + 1) % keybuffer.length; } + Mutex grpmutex; + otya.smilebasic.draw.Draw draw; + void renderGraphic() + { + //grpmutex.lock(); + //scope(exit) + // grpmutex.unlock(); + drawflag = true; + //betuni kouzoutai demo sonnnani sokudo kawaranasasou + auto len = drawMessageLength; + drawMessageLength = 0; + for(int i = 0; i < len; i++) + { + DrawMessage dm = drawMessageQueue[i]; + switch(dm.type) + { + case DrawType.PSET: + draw.gpset(dm.page, dm.x, dm.y ,dm.color); + break; + case DrawType.LINE: + draw.gline(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color); + break; + case DrawType.FILL: + draw.gfill(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color); + break; + case DrawType.BOX: + draw.gbox(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color); + break; + default: + } + } + drawflag = false; + + } void render() { - bool renderprofile = true; + bool renderprofile; try { version(Windows) @@ -471,8 +520,12 @@ class PetitComputer g.createTexture(renderer); } //GRP[0] = GRPF; - gpset(0, 10, 10, 0xFF00FF00); - gline(0, 0, 0, 399, 239, RGB(0, 255, 0)); + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glAlphaFunc(GL_GEQUAL, 0.5); + glEnable(GL_ALPHA_TEST); + draw = new otya.smilebasic.draw.Draw(this); while(true) { auto profile = SDL_GetTicks(); @@ -486,9 +539,10 @@ class PetitComputer loopcnt = 0; } } + renderGraphic(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - //renderConsoleGL(); renderGraphicPage(); + renderConsoleGL(); SDL_GL_SwapWindow(window); auto renderticks = (SDL_GetTicks() - profile); if(renderprofile) writeln(renderticks); @@ -528,9 +582,18 @@ class PetitComputer break; } } - long delay = (1000/60) - cast(long)(SDL_GetTicks() - profile); - if(delay > 0) - SDL_Delay(cast(uint)delay); + 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); + } } } catch(Throwable t) @@ -553,11 +616,13 @@ class PetitComputer consolem = new Mutex(); keybuffermutex = new Mutex(); + grpmutex = new Mutex(); core.thread.Thread thread = new core.thread.Thread(&render); thread.start(); auto startTicks = SDL_GetTicks(); //とりあえず - auto parser = new Parser(readText(input("LOAD PROGRAM:", true).to!string).to!wstring + auto parser = new Parser(readText("./SYS/EX5BIORHYTHM.TXT").to!wstring + //readText(input("LOAD PROGRAM:", true).to!string).to!wstring //readText("./SYS/EX1TEXT.TXT").to!wstring //readText("FIZZBUZZ.TXT").to!wstring //readText("TEST.TXT").to!wstring @@ -603,6 +668,10 @@ class PetitComputer auto vm = parser.compile(); bool running = true; vm.init(this); + gpset(0, 10, 10, 0xFF00FF00); + gline(0, 0, 0, 399, 239, RGB(0, 255, 0)); + gfill(0, 78, 78, 40, 40, RGB(0, 255, 255)); + gbox(0, 78, 78, 40, 40, RGB(255, 255, 0)); while (true) { uint elapse; @@ -712,7 +781,7 @@ class PetitComputer bool animationCursor; Mutex consolem; //プチコン内部表現はRGB5_A1 - uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a) + static uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a) { if(format == GL_BGRA) { @@ -724,7 +793,7 @@ class PetitComputer } throw new Exception("unsuport enviroment"); } - uint toGLColor(GLenum format, uint petitcolor) + static uint toGLColor(GLenum format, uint petitcolor) { if(format == GL_BGRA) { @@ -737,7 +806,7 @@ class PetitComputer throw new Exception("unsuport enviroment"); } //プチコンと違って[A,]R,G,Bじゃない - void RGBRead(uint color, out ubyte r, out ubyte g, out ubyte b, out ubyte a) + static void RGBRead(uint color, out ubyte r, out ubyte g, out ubyte b, out ubyte a) { //エンディアン関係ない a = color >> 24; @@ -745,62 +814,107 @@ class PetitComputer g = color >> 8 & 0xFF; b = color& 0xFF; } - uint RGB(ubyte r, ubyte g, ubyte b) + static uint RGB(ubyte r, ubyte g, ubyte b) { return 0xFF000000 | r << 16 | g << 8 | b; } - uint RGB(ubyte a, ubyte r, ubyte g, ubyte b) + static uint RGB(ubyte a, ubyte r, ubyte g, ubyte b) { return a << 24 | r << 16 | g << 8 | b; } + enum DrawType + { + CLEAR, + PSET, + LINE, + FILL, + BOX, + CIRCLE, + TRI, + } + struct DrawMessage + { + DrawType type; + byte page; + short x; + short y; + short x2; + short y2; + uint color; + // + } + static const int dmqqueuelen = 8192; + DrawMessage[] drawMessageQueue = new DrawMessage[dmqqueuelen]; + int drawMessageLength; + bool drawflag; + void sendDrawMessage(DrawType type, byte page, short x, short y, uint color) + { + //grpmutex.lock(); + //scope(exit) + // grpmutex.unlock(); + if(drawMessageLength >= dmqqueuelen) + { + while(drawMessageLength) + { + SDL_Delay(1); + } + } + while(drawflag){} + drawMessageQueue[drawMessageLength].type = type; + drawMessageQueue[drawMessageLength].page = page; + drawMessageQueue[drawMessageLength].x = x; + drawMessageQueue[drawMessageLength].y = y; + drawMessageQueue[drawMessageLength].color = color; + drawMessageLength++; + } + void sendDrawMessage(DrawType type, byte page, short x, short y, short x2, short y2, uint color) + { + grpmutex.lock(); + scope(exit) + grpmutex.unlock(); + drawMessageQueue[drawMessageLength].type = type; + drawMessageQueue[drawMessageLength].page = page; + drawMessageQueue[drawMessageLength].x = x; + drawMessageQueue[drawMessageLength].y = y; + drawMessageQueue[drawMessageLength].x2 = x2; + drawMessageQueue[drawMessageLength].y2 = y2; + drawMessageQueue[drawMessageLength].color = color; + drawMessageLength++; + } + //TODO:範囲チェック void gpset(int page, int x, int y, uint color) { - color = toGLColor(GRP[page].textureFormat, color); - glBindTexture(GL_TEXTURE_2D, GRP[page].glTexture); - glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, 1, 1, GRP[page].textureFormat, GL_UNSIGNED_BYTE, &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) { - import std.math; - 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) - { - gpset(page, x, y, 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 ; - } - } + 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 renderGraphicPage() { + float z = 0.01f; glColor3f(1.0, 1.0, 1.0); glBindTexture(GL_TEXTURE_2D, GRP[showGRP].glTexture); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f(0 / 512f - 1 , 240 / 512f - 1); - glVertex3f(0 / 200f - 1, 1 - 240 / 120f, 0); + glVertex3f(0 / 200f - 1, 1 - 240 / 120f, z); glTexCoord2f(0 / 512f - 1, 0 / 512f - 1); - glVertex3f(0 / 200f - 1, 1 - 0 / 120f, 0); + glVertex3f(0 / 200f - 1, 1 - 0 / 120f, z); glTexCoord2f(400 / 512f - 1, 0 / 512f - 1); - glVertex3f(400 / 200f - 1, 1 - 0 / 120f, 0); + glVertex3f(400 / 200f - 1, 1 - 0 / 120f, z); glTexCoord2f(400 / 512f - 1, 240 / 512f - 1); - glVertex3f(400 / 200f - 1, 1 - 240 / 120f, 0); + glVertex3f(400 / 200f - 1, 1 - 240 / 120f, z); glEnd(); - glFlush(); + //glFlush(); } void renderConsoleGL() { @@ -829,8 +943,6 @@ class PetitComputer } glEnd(); glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glAlphaFunc(GL_GEQUAL, 0.5); //glEnable(GL_ALPHA_TEST); @@ -851,7 +963,7 @@ class PetitComputer glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0); } glEnd(); - glFlush(); + // glFlush(); } void printConsole(T...)(T args) { diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index ae207a5..8c88da1 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -63,6 +63,8 @@ enum TokenType Restore, On, Input, + True, + False, } struct Token