From de2eb1872714badda166445df005c7b4d8f34931 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 12:38:39 +0100 Subject: [PATCH] - added per-channel access for color variables. However, since they are locally stored in registers, it required a minor bit of fudging for this case. - make sure that a PFunction's implementation is always initialized before starting the code generator. --- src/dobjtype.cpp | 14 ++++++++++++++ src/dobjtype.h | 1 + src/namedef.h | 6 ++++++ src/scripting/codegeneration/codegen.cpp | 24 ++++++++++++++++++++++++ src/scripting/vm/vmbuilder.cpp | 2 ++ src/scripting/zscript/zcc_compile.cpp | 2 +- 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 965a0d8fd..e84504015 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -85,6 +85,7 @@ PStatePointer *TypeState; PStateLabel *TypeStateLabel; PStruct *TypeVector2; PStruct *TypeVector3; +PStruct *TypeColorStruct; PPointer *TypeNullPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -578,6 +579,19 @@ void PType::StaticInit() TypeTable.AddType(TypeStateLabel = new PStateLabel); TypeTable.AddType(TypeNullPtr = new PPointer); + TypeColorStruct = new PStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. +#ifdef __BIG_ENDIAN__ + TypeColorStruct->AddField(NAME_a, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_b, TypeUInt8); +#else + TypeColorStruct->AddField(NAME_b, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_a, TypeUInt8); +#endif + TypeVector2 = new PStruct(NAME_Vector2, nullptr); TypeVector2->AddField(NAME_X, TypeFloat64); TypeVector2->AddField(NAME_Y, TypeFloat64); diff --git a/src/dobjtype.h b/src/dobjtype.h index aeb042ebb..b8fc1cbf6 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -919,6 +919,7 @@ extern PSound *TypeSound; extern PColor *TypeColor; extern PStruct *TypeVector2; extern PStruct *TypeVector3; +extern PStruct *TypeColorStruct; extern PStatePointer *TypeState; extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; diff --git a/src/namedef.h b/src/namedef.h index d4206e2bb..0418e0f87 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -750,3 +750,9 @@ xx(A_FirePlasma) xx(A_FireBFG) xx(A_FireOldBFG) xx(A_FireRailgun) + +// color channels +xx(a) +xx(r) +xx(g) +xx(b) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 43d5f8174..c040403d8 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5652,6 +5652,10 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) SAFE_RESOLVE(Object, ctx); + // allow accessing the color chanels by mapping the type to a matching struct which defines them. + if (Object->ValueType == TypeColor) + Object->ValueType = TypeColorStruct; + if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Object->ValueType)->PointedType; @@ -6305,6 +6309,26 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) delete this; return locvar; } + else if (classx->ExprType == EFX_LocalVariable && classx->ValueType == TypeColorStruct) + { + // This needs special treatment because it'd require accessing the register via address. + // Fortunately this is the only place where this kind of access is ever needed so an explicit handling is acceptable. + int bits; + switch (membervar->SymbolName.GetIndex()) + { + case NAME_a: bits = 24; break; + case NAME_r: bits = 16; break; + case NAME_g: bits = 8; break; + case NAME_b: default: bits = 0; break; + } + classx->ValueType = TypeColor; // need to set it back. + FxExpression *x = classx; + if (bits > 0) x = new FxShift(TK_URShift, x, new FxConstant(bits, ScriptPosition)); + x = new FxBitOp('&', x, new FxConstant(255, ScriptPosition)); + classx = nullptr; + delete this; + return x->Resolve(ctx); + } else { if (!(classx->RequestAddress(ctx, &AddressWritable))) diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 3ccf67f95..04339f6eb 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -785,6 +785,8 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c it.StateIndex = stateindex; it.StateCount = statecount; it.Lump = lumpnum; + assert(it.Func->Variants.Size() == 1); + it.Func->Variants[0].Implementation = it.Function; // set prototype for named functions. if (it.Func->SymbolName != NAME_None) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index f2d847325..3d8cc18b5 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2272,7 +2272,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool auto code = ConvertAST(c->Type(), f->Body); if (code != nullptr) { - sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); } } }