Initial HECL-IR to GLSL implementation

This commit is contained in:
Jack Andersen 2015-11-10 13:17:53 -10:00
parent b4725c7d2e
commit cbb0951c09
6 changed files with 618 additions and 677 deletions

View File

@ -1,59 +1,36 @@
#ifndef HECLBACKEND_GLSL_HPP #ifndef HECLBACKEND_GLSL_HPP
#define HECLBACKEND_GLSL_HPP #define HECLBACKEND_GLSL_HPP
#include "Backend.hpp" #include "ProgrammableCommon.hpp"
#include <Athena/DNA.hpp>
#include <boo/graphicsdev/GL.hpp>
#include <stdint.h>
#include <stdlib.h>
#include <algorithm>
namespace HECL namespace HECL
{ {
namespace Backend namespace Backend
{ {
struct GLSL : IBackend struct GLSL : ProgrammableCommon
{ {
boo::BlendFactor m_blendSrc;
boo::BlendFactor m_blendDst;
std::string m_vertSource;
std::string m_fragSource;
size_t m_texSamplingCount = 0;
std::string m_texSamplings;
enum TexGenSrc
{
TG_POS,
TG_NRM,
TG_UV
};
struct TexCoordGen
{
TexGenSrc m_src;
int m_uvIdx = 0;
int m_mtx = -1;
std::string m_gameFunction;
std::vector<atVec4f> m_gameArgs;
};
std::vector<TexCoordGen> m_tcgs;
std::vector<size_t> m_texMtxRefs;
void reset(const IR& ir, Diagnostics& diag); void reset(const IR& ir, Diagnostics& diag);
std::string makeVert(const char* glslVer, unsigned col, unsigned uv, unsigned w,
unsigned skinSlots, unsigned texMtxs) const;
std::string makeFrag(const char* glslVer,
const char* lightingSource, const char* lightingEntry) const;
std::string makeFrag(const char* glslVer,
const char* lightingSource, const char* lightingEntry,
const char* postSource, const char* postEntry) const;
private: private:
unsigned addTexCoordGen(Diagnostics& diag, const SourceLocation& loc, std::string GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const;
TexGenSrc src, int uvIdx, int mtx); std::string GenerateVertToFragStruct() const;
std::string RecursiveTraceColor(const IR& ir, Diagnostics& diag, std::string GenerateVertUniformStruct(unsigned skinSlots, unsigned texMtxs) const;
const IR::Instruction& inst,
bool swizzleAlpha=false); std::string EmitVec3(const atVec4f& vec) const
std::string RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, {
const IR::Instruction& inst); return HECL::Format("vec3(%g,%g,%g)", vec.vec[0], vec.vec[1], vec.vec[2]);
unsigned RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, }
const IR::Instruction& inst,
int mtx); std::string EmitTexGenSource2(TexGenSrc src, int uvIdx) const;
std::string EmitTexGenSource4(TexGenSrc src, int uvIdx) const;
}; };
} }

View File

@ -0,0 +1,114 @@
#ifndef HECLBACKEND_PROGCOMMON_HPP
#define HECLBACKEND_PROGCOMMON_HPP
#include "Backend.hpp"
#include <Athena/DNA.hpp>
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
#include <stdint.h>
#include <stdlib.h>
#include <algorithm>
namespace HECL
{
namespace Backend
{
struct ProgrammableCommon : IBackend
{
std::string m_colorExpr;
std::string m_alphaExpr;
boo::BlendFactor m_blendSrc;
boo::BlendFactor m_blendDst;
bool m_lighting = false;
struct TexSampling
{
int mapIdx = -1;
int tcgIdx = -1;
};
std::vector<TexSampling> m_texSamplings;
enum TexGenSrc
{
TG_POS,
TG_NRM,
TG_UV
};
struct TexCoordGen
{
TexGenSrc m_src;
int m_uvIdx = 0;
int m_mtx = -1;
std::string m_gameFunction;
std::vector<atVec4f> m_gameArgs;
};
std::vector<TexCoordGen> m_tcgs;
std::vector<size_t> m_texMtxRefs;
void reset(const IR& ir, Diagnostics& diag, const char* backendName);
private:
unsigned addTexCoordGen(TexGenSrc src, int uvIdx, int mtx);
unsigned addTexSampling(unsigned mapIdx, unsigned tcgIdx);
std::string RecursiveTraceColor(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst);
std::string RecursiveTraceAlpha(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst);
unsigned RecursiveTraceTexGen(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst,
int mtx);
std::string EmitSamplingUse(unsigned samplingIdx) const
{
return HECL::Format("sampling%u", samplingIdx);
}
std::string EmitColorRegUse(unsigned idx) const
{
return HECL::Format("colorReg%u", idx);
}
std::string EmitLighting() const
{
return std::string("lighting");
}
virtual std::string EmitVec3(const atVec4f& vec) const=0;
std::string EmitVal(float val) const
{
return HECL::Format("%g", val);
}
std::string EmitAdd(const std::string& a, const std::string& b) const
{
return '(' + a + '+' + b + ')';
}
std::string EmitSub(const std::string& a, const std::string& b) const
{
return '(' + a + '-' + b + ')';
}
std::string EmitMult(const std::string& a, const std::string& b) const
{
return '(' + a + '*' + b + ')';
}
std::string EmitDiv(const std::string& a, const std::string& b) const
{
return '(' + a + '/' + b + ')';
}
std::string EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc,
const std::string& a, const atInt8 swiz[4]) const;
std::string EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc,
const std::string& a, const atInt8 swiz[4]) const;
};
}
}
#endif // HECLBACKEND_PROGCOMMON_HPP

View File

@ -1,3 +1,4 @@
add_library(HECLBackend add_library(HECLBackend
GX.cpp GX.cpp
ProgrammableCommon.cpp
GLSL.cpp) GLSL.cpp)

View File

@ -6,675 +6,207 @@ namespace HECL
namespace Backend namespace Backend
{ {
unsigned GLSL::addTexCoordGen(Diagnostics&, const SourceLocation&, std::string GLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const
TexGenSrc src, int uvIdx, int mtx)
{ {
for (unsigned i=0 ; i<m_tcgs.size() ; ++i) switch (src)
{ {
TexCoordGen& tcg = m_tcgs[i]; case TG_POS:
if (tcg.m_src == src && tcg.m_uvIdx == uvIdx && tcg.m_mtx == mtx) return "posIn.xy;\n";
return i; case TG_NRM:
return "normIn.xy;\n";
case TG_UV:
return HECL::Format("uvIn[%u]", uvIdx);
default: break;
} }
m_tcgs.emplace_back(); return std::string();
TexCoordGen& newTcg = m_tcgs.back();
newTcg.m_src = src;
newTcg.m_uvIdx = uvIdx;
newTcg.m_mtx = mtx;
return m_tcgs.size() - 1;
} }
unsigned GLSL::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, int mtx) std::string GLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const
{ {
if (inst.m_op != IR::OpCall) switch (src)
diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function");
const std::string& tcgName = inst.m_call.m_name;
if (!tcgName.compare("UV"))
{ {
if (inst.getChildCount() < 1) case TG_POS:
diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument"); return "vec4(posIn, 1.0);\n";
const IR::Instruction& idxInst = inst.getChildInst(ir, 0); case TG_NRM:
const atVec4f& idxImm = idxInst.getImmVec(); return "vec4(normIn, 1.0);\n";
return addTexCoordGen(diag, inst.m_loc, TG_UV, idxImm.vec[0], mtx); case TG_UV:
return HECL::Format("vec4(uvIn[%u], 0.0, 1.0)", uvIdx);
default: break;
} }
else if (!tcgName.compare("Normal")) return std::string();
return addTexCoordGen(diag, inst.m_loc, TG_NRM, 0, mtx);
else if (!tcgName.compare("View"))
return addTexCoordGen(diag, inst.m_loc, TG_POS, 0, mtx);
/* Otherwise treat as game-specific function */
const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0);
unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, m_texMtxRefs.size());
TexCoordGen& tcg = m_tcgs[idx];
m_texMtxRefs.push_back(idx);
tcg.m_gameFunction = tcgName;
tcg.m_gameArgs.clear();
for (int i=1 ; i<inst.getChildCount() ; ++i)
{
const IR::Instruction& ci = inst.getChildInst(ir, i);
tcg.m_gameArgs.push_back(ci.getImmVec());
}
return idx;
} }
#if 0 std::string GLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const
{
std::string retval =
"layout(location=0) in vec3 posIn;\n"
"layout(location=1) in vec3 normIn;\n";
std::string GLSL::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst) unsigned idx = 2;
if (col)
{ {
switch (inst.m_op) retval += HECL::Format("layout(location=%u) in vec4 colIn[%u];\n", idx, col);
{ idx += col;
case IR::OpCall:
{
const std::string& name = inst.m_call.m_name;
if (!name.compare("Texture"))
{
TEVStage& newStage = addTEVStage(diag, inst.m_loc);
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
const atVec4f& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.vec[0]);
if (mapIdx >)
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY);
return TraceResult(&newStage);
}
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().vec[0]);
if (swizzleAlpha)
m_aRegMask |= 1 << idx;
else
m_cRegMask |= 1 << idx;
return TraceResult(TevColorArg((swizzleAlpha ? CC_A0 : CC_C0) + idx * 2));
}
else if (!name.compare("Lighting"))
{
return TraceResult(swizzleAlpha ? CC_RASA : CC_RASC);
}
else
diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str());
break;
}
case IR::OpLoadImm:
{
const atVec4f& vec = inst.m_loadImm.m_immVec;
if (vec.vec[0] == 0.f && vec.vec[1] == 0.f && vec.vec[2] == 0.f)
return TraceResult(CC_ZERO);
else if (vec.vec[0] == 1.f && vec.vec[1] == 1.f && vec.vec[2] == 1.f)
return TraceResult(CC_ONE);
unsigned idx = addKColor(diag, inst.m_loc, vec);
return TraceResult(TevKColorSel(TEV_KCSEL_K0 + idx));
}
case IR::OpArithmetic:
{
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
TraceResult aTrace;
TraceResult bTrace;
if (aInst.m_op != IR::OpArithmetic && bInst.m_op == IR::OpArithmetic)
{
bTrace = RecursiveTraceColor(ir, diag, bInst);
aTrace = RecursiveTraceColor(ir, diag, aInst);
}
else
{
aTrace = RecursiveTraceColor(ir, diag, aInst);
bTrace = RecursiveTraceColor(ir, diag, bInst);
}
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage &&
getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage))
{
TraceResult tmp = aTrace;
aTrace = bTrace;
bTrace = tmp;
} }
TevKColorSel newKColor = TEV_KCSEL_1; if (uv)
if (aTrace.type == TraceResult::TraceTEVKColorSel &&
bTrace.type == TraceResult::TraceTEVKColorSel)
diag.reportBackendErr(inst.m_loc, "unable to handle 2 KColors in one stage");
else if (aTrace.type == TraceResult::TraceTEVKColorSel)
{ {
newKColor = aTrace.tevKColorSel; retval += HECL::Format("layout(location=%u) in vec2 uvIn[%u];\n", idx, uv);
aTrace.type = TraceResult::TraceTEVColorArg; idx += uv;
aTrace.tevColorArg = CC_KONST;
}
else if (bTrace.type == TraceResult::TraceTEVKColorSel)
{
newKColor = bTrace.tevKColorSel;
bTrace.type = TraceResult::TraceTEVColorArg;
bTrace.tevColorArg = CC_KONST;
} }
switch (op) if (w)
{ {
case ArithmeticOp::ArithmeticOpAdd: retval += HECL::Format("layout(location=%u) in vec4 weightIn[%u];\n", idx, w);
{
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a)
{
a->m_cRegOut = TEVLAZY;
b->m_color[3] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++;
}
else if (b == &m_tevs[m_tevCount-1] &&
a->m_texMapIdx == b->m_texMapIdx && a->m_texGenIdx == b->m_texGenIdx &&
a->m_color[3] == CC_ZERO && b->m_color[0] != CC_ZERO)
{
a->m_color[3] = b->m_color[0];
--m_tevCount;
return TraceResult(a);
}
else
b->m_color[3] = CC_CPREV;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
TEVStage* a = aTrace.tevStage;
if (a->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_color[3] = bTrace.tevColorArg;
a->m_kColor = newKColor;
return TraceResult(a);
}
else if (aTrace.type == TraceResult::TraceTEVColorArg &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* b = bTrace.tevStage;
if (b->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
b->m_color[3] = aTrace.tevColorArg;
b->m_kColor = newKColor;
return TraceResult(b);
}
break;
}
case ArithmeticOp::ArithmeticOpSubtract:
{
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a)
{
a->m_cRegOut = TEVLAZY;
b->m_color[3] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++;
}
else
b->m_color[3] = CC_CPREV;
b->m_cop = TEV_SUB;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
TEVStage* a = aTrace.tevStage;
if (a->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for subtract combine");
a->m_color[3] = bTrace.tevColorArg;
a->m_kColor = newKColor;
a->m_cop = TEV_SUB;
return TraceResult(a);
}
break;
}
case ArithmeticOp::ArithmeticOpMultiply:
{
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_color[2] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
if (b->m_prev != a)
{
a->m_cRegOut = TEVLAZY;
b->m_color[2] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++;
}
else
b->m_color[2] = CC_CPREV;
b->m_color[1] = b->m_color[0];
b->m_color[0] = CC_ZERO;
b->m_color[3] = CC_ZERO;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVColorArg &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = aTrace.tevColorArg;
stage.m_color[2] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVColorArg)
{
TEVStage* a = aTrace.tevStage;
if (a->m_color[1] != CC_ZERO)
{
if (a->m_cRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = CC_CPREV;
stage.m_color[2] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
a->m_color[1] = a->m_color[0];
a->m_color[0] = CC_ZERO;
a->m_color[2] = bTrace.tevColorArg;
a->m_kColor = newKColor;
return TraceResult(a);
}
else if (aTrace.type == TraceResult::TraceTEVColorArg &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* b = bTrace.tevStage;
if (b->m_color[1] != CC_ZERO)
{
if (b->m_cRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = aTrace.tevColorArg;
stage.m_color[2] = CC_CPREV;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
b->m_color[1] = b->m_color[0];
b->m_color[0] = CC_ZERO;
b->m_color[2] = bTrace.tevColorArg;
b->m_kColor = newKColor;
return TraceResult(b);
}
break;
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
} }
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage"); return retval;
}
case IR::OpSwizzle:
{
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 &&
inst.m_swizzle.m_idxs[2] == 3 && inst.m_swizzle.m_idxs[3] == -1)
{
const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpCall)
diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle");
return RecursiveTraceColor(ir, diag, cInst, true);
}
else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
}
default:
diag.reportBackendErr(inst.m_loc, "invalid color op");
} }
return TraceResult(); std::string GLSL::GenerateVertToFragStruct() const
{
std::string retval =
"struct VertToFrag\n"
"{\n"
" vec4 mvPos;\n"
" vec4 mvNorm;\n";
if (m_tcgs.size())
retval += HECL::Format(" vec2 tcgs[%u];\n", unsigned(m_tcgs.size()));
return retval + "};\n";
} }
std::string GLSL::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst) std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, unsigned texMtxs) const
{ {
switch (inst.m_op) if (skinSlots == 0)
{ skinSlots = 1;
case IR::OpCall: std::string retval = HECL::Format("struct HECLVertUniform\n"
{ "{\n"
const std::string& name = inst.m_call.m_name; " mat4 mv[%u];\n"
if (!name.compare("Texture")) " mat4 mvInv[%u];\n"
{ " mat4 proj;\n",
if (inst.getChildCount() < 2) skinSlots, skinSlots);
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments"); if (texMtxs)
retval += HECL::Format(" mat4 texMtxs[%u];\n", texMtxs);
const IR::Instruction& mapInst = inst.getChildInst(ir, 0); return retval + "};\n";
const atVec4f& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.vec[0]);
int foundStage = -1;
for (int i=0 ; i<int(m_tevCount) ; ++i)
{
TEVStage& testStage = m_tevs[i];
if (testStage.m_texMapIdx == mapIdx && i > m_alphaTraceStage)
{
foundStage = i;
break;
}
}
if (foundStage >= 0)
{
m_alphaTraceStage = foundStage;
TEVStage& stage = m_tevs[foundStage];
stage.m_alpha[0] = CA_TEXA;
return TraceResult(&stage);
}
TEVStage& newStage = addTEVStage(diag, inst.m_loc);
newStage.m_color[3] = CC_CPREV;
newStage.m_texMapIdx = mapIdx;
newStage.m_alpha[0] = CA_TEXA;
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY);
return TraceResult(&newStage);
}
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().vec[0]);
m_aRegMask |= 1 << idx;
return TraceResult(TevAlphaArg(CA_A0 + idx));
}
else if (!name.compare("Lighting"))
{
return TraceResult(CA_RASA);
}
else
diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str());
break;
}
case IR::OpLoadImm:
{
const atVec4f& vec = inst.m_loadImm.m_immVec;
if (vec.vec[0] == 0.f)
return TraceResult(CA_ZERO);
unsigned idx = addKAlpha(diag, inst.m_loc, vec.vec[0]);
return TraceResult(TevKAlphaSel(TEV_KASEL_K0_A + idx));
}
case IR::OpArithmetic:
{
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
TraceResult aTrace;
TraceResult bTrace;
if (aInst.m_op != IR::OpArithmetic && bInst.m_op == IR::OpArithmetic)
{
bTrace = RecursiveTraceAlpha(ir, diag, bInst);
aTrace = RecursiveTraceAlpha(ir, diag, aInst);
}
else
{
aTrace = RecursiveTraceAlpha(ir, diag, aInst);
bTrace = RecursiveTraceAlpha(ir, diag, bInst);
}
TevKAlphaSel newKAlpha = TEV_KASEL_1;
if (aTrace.type == TraceResult::TraceTEVKAlphaSel &&
bTrace.type == TraceResult::TraceTEVKAlphaSel)
diag.reportBackendErr(inst.m_loc, "unable to handle 2 KAlphas in one stage");
else if (aTrace.type == TraceResult::TraceTEVKAlphaSel)
{
newKAlpha = aTrace.tevKAlphaSel;
aTrace.type = TraceResult::TraceTEVAlphaArg;
aTrace.tevAlphaArg = CA_KONST;
}
else if (bTrace.type == TraceResult::TraceTEVKAlphaSel)
{
newKAlpha = bTrace.tevKAlphaSel;
bTrace.type = TraceResult::TraceTEVAlphaArg;
bTrace.tevAlphaArg = CA_KONST;
}
switch (op)
{
case ArithmeticOp::ArithmeticOpAdd:
{
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a)
{
a->m_aRegOut = TEVLAZY;
b->m_alpha[3] = CA_LAZY;
if (a->m_lazyAOutIdx != -1)
b->m_lazyAInIdx = a->m_lazyAOutIdx;
else
{
b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++;
}
}
else
b->m_alpha[3] = CA_APREV;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVAlphaArg)
{
TEVStage* a = aTrace.tevStage;
if (a->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_alpha[3] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha;
return TraceResult(a);
}
else if (aTrace.type == TraceResult::TraceTEVAlphaArg &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* b = bTrace.tevStage;
if (b->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
b->m_alpha[3] = aTrace.tevAlphaArg;
b->m_kAlpha = newKAlpha;
return TraceResult(b);
}
break;
}
case ArithmeticOp::ArithmeticOpSubtract:
{
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_aop != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
if (b->m_prev != a)
{
a->m_aRegOut = TEVLAZY;
b->m_alpha[3] = CA_LAZY;
if (a->m_lazyAOutIdx != -1)
b->m_lazyAInIdx = a->m_lazyAOutIdx;
else
{
b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++;
}
}
else
b->m_alpha[3] = CA_APREV;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVAlphaArg)
{
TEVStage* a = aTrace.tevStage;
if (a->m_aop != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
if (a->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_alpha[3] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha;
return TraceResult(a);
}
break;
}
case ArithmeticOp::ArithmeticOpMultiply:
{
if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_alpha[2] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
if (b->m_prev != a)
{
a->m_aRegOut = TEVLAZY;
b->m_alpha[2] = CA_LAZY;
b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++;
}
else
b->m_alpha[2] = CA_APREV;
b->m_alpha[1] = b->m_alpha[0];
b->m_alpha[0] = CA_ZERO;
b->m_alpha[3] = CA_ZERO;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::TraceTEVAlphaArg &&
bTrace.type == TraceResult::TraceTEVAlphaArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[3] = CC_CPREV;
stage.m_alpha[1] = aTrace.tevAlphaArg;
stage.m_alpha[2] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
else if (aTrace.type == TraceResult::TraceTEVStage &&
bTrace.type == TraceResult::TraceTEVAlphaArg)
{
TEVStage* a = aTrace.tevStage;
if (a->m_alpha[1] != CA_ZERO)
{
if (a->m_aRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_alpha[1] = CA_APREV;
stage.m_alpha[2] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
a->m_alpha[1] = a->m_alpha[0];
a->m_alpha[0] = CA_ZERO;
a->m_alpha[2] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha;
return TraceResult(a);
}
else if (aTrace.type == TraceResult::TraceTEVAlphaArg &&
bTrace.type == TraceResult::TraceTEVStage)
{
TEVStage* b = bTrace.tevStage;
if (b->m_alpha[1] != CA_ZERO)
{
if (b->m_aRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_alpha[1] = aTrace.tevAlphaArg;
stage.m_alpha[2] = CA_APREV;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
b->m_alpha[1] = b->m_alpha[0];
b->m_alpha[0] = CA_ZERO;
b->m_alpha[2] = bTrace.tevAlphaArg;
b->m_kAlpha = newKAlpha;
return TraceResult(b);
}
break;
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage");
}
case IR::OpSwizzle:
{
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 &&
inst.m_swizzle.m_idxs[2] == 3 && inst.m_swizzle.m_idxs[3] == -1)
{
const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpCall)
diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle");
return RecursiveTraceAlpha(ir, diag, cInst);
}
else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
}
default:
diag.reportBackendErr(inst.m_loc, "invalid alpha op");
}
return TraceResult();
} }
void GLSL::reset(const IR& ir, Diagnostics& diag) void GLSL::reset(const IR& ir, Diagnostics& diag)
{ {
diag.setBackend("GLSL"); /* Common programmable interpretation */
m_vertSource.clear(); ProgrammableCommon::reset(ir, diag, "GLSL");
m_fragSource.clear(); }
/* Final instruction is the root call by hecl convention */ std::string GLSL::makeVert(const char* glslVer, unsigned col, unsigned uv, unsigned w,
const IR::Instruction& rootCall = ir.m_instructions.back(); unsigned skinSlots, unsigned texMtxs) const
bool doAlpha = false;
if (!rootCall.m_call.m_name.compare("HECLOpaque"))
{ {
m_blendSrc = boo::BlendFactorOne; std::string retval = std::string(glslVer) + "\n" +
m_blendDst = boo::BlendFactorZero; GenerateVertInStruct(col, uv, w) + "\n" +
} GenerateVertToFragStruct() + "\n" +
else if (!rootCall.m_call.m_name.compare("HECLAlpha")) GenerateVertUniformStruct(skinSlots, texMtxs) +
"layout(location=0) uniform HECLVertUniform vu;\n"
"out VertToFrag vtf;\n\n"
"void main()\n{\n";
if (skinSlots)
{ {
m_blendSrc = boo::BlendFactorSrcAlpha; /* skinned */
m_blendDst = boo::BlendFactorInvSrcAlpha; retval += " vec4 posAccum = vec4(0.0,0.0,0.0,0.0);\n"
doAlpha = true; " vec4 normAccum = vec4(0.0,0.0,0.0,0.0);\n";
} for (int i=0 ; i<skinSlots ; ++i)
else if (!rootCall.m_call.m_name.compare("HECLAdditive")) retval += HECL::Format(" posAccum += (vu.mv[%u] * vec4(posIn, 1.0)) * weightIn[%u][%u]\n"
{ " normAccum += (vu.mvInv[%u] * vec4(normIn, 1.0)) * weightIn[%u][%u]\n",
m_blendSrc = boo::BlendFactorSrcAlpha; i, i/4, i%4, i, i/4, i%4);
m_blendDst = boo::BlendFactorOne; retval += HECL::Format(" posAccum /= %u;\n"
doAlpha = true; " normAccum /= %u;\n",
skinSlots, skinSlots);
retval += " posAccum[3] = 1.0\n"
" vtf.mvPos = posAccum;\n"
" vtf.mvNorm = vec4(normalize(normAccum.xyz), 0.0);\n"
" gl_Position = vu.proj * posAccum;\n";
} }
else else
{ {
diag.reportBackendErr(rootCall.m_loc, "GLSL backend doesn't handle '%s' root", /* non-skinned */
rootCall.m_call.m_name.c_str()); retval += " vtf.mvPos = vu.mv[0] * vec4(posIn, 1.0);\n"
return; " vtf.mvNorm = vu.mvInv[0] * vec4(normIn, 0.0)\n"
" gl_Position = vu.proj * vtf.mvPos;\n";
} }
/* Follow Color Chain */ int tcgIdx = 0;
const IR::Instruction& colorRoot = for (const TexCoordGen& tcg : m_tcgs)
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
RecursiveTraceColor(ir, diag, colorRoot);
/* Follow Alpha Chain */
if (doAlpha)
{ {
const IR::Instruction& alphaRoot = if (tcg.m_mtx < 0)
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1)); retval += HECL::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx,
RecursiveTraceAlpha(ir, diag, alphaRoot); EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
} else
retval += HECL::Format(" vtf.tcgs[%u] = (vu.texMtxs[%u] * %s).xy;\n", tcgIdx, tcg.m_mtx,
EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str());
++tcgIdx;
} }
#endif return retval + "}\n";
}
std::string GLSL::makeFrag(const char* glslVer,
const char* lightingSource, const char* lightingEntry) const
{
std::string lightingSrc;
if (lightingSource)
lightingSrc = lightingSource;
std::string retval = std::string(glslVer) + "\n" +
GenerateVertToFragStruct() +
"\nlayout(location=0) out vec4 colorOut;\n"
"in VertToFrag vtf;\n\n" + lightingSrc +
"\nvoid main()\n{\n";
if (m_lighting)
{
if (lightingEntry)
retval += HECL::Format(" vec4 lighting = %s();\n", lightingEntry);
else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
}
if (m_alphaExpr.size())
retval += " colorOut = vec4(" + m_colorExpr + ", " + m_alphaExpr + ");\n";
else
retval += " colorOut = vec4(" + m_colorExpr + ", 1.0);\n";
return retval + "};\n";
}
std::string GLSL::makeFrag(const char* glslVer,
const char* lightingSource, const char* lightingEntry,
const char* postSource, const char* postEntry) const
{
std::string lightingSrc;
if (lightingSource)
lightingSrc = lightingSource;
std::string retval = std::string(glslVer) + "\n" +
GenerateVertToFragStruct() +
"\nlayout(location=0) out vec4 colorOut;\n"
"in VertToFrag vtf;\n\n" + lightingSrc + "\n" + std::string(postSource) +
"\nvoid main()\n{\n";
if (m_lighting)
{
if (lightingEntry)
retval += HECL::Format(" vec4 lighting = %s();\n", lightingEntry);
else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
}
if (m_alphaExpr.size())
retval += " colorOut = " + std::string(postEntry) + "(vec4(" + m_colorExpr + ", " + m_alphaExpr + "));\n";
else
retval += " colorOut = " + std::string(postEntry) + "(vec4(" + m_colorExpr + ", 1.0));\n";
return retval + "};\n";
}
} }
} }

View File

@ -0,0 +1,316 @@
#include "HECL/Backend/ProgrammableCommon.hpp"
#include <map>
namespace HECL
{
namespace Backend
{
unsigned ProgrammableCommon::addTexCoordGen(TexGenSrc src, int uvIdx, int mtx)
{
for (unsigned i=0 ; i<m_tcgs.size() ; ++i)
{
TexCoordGen& tcg = m_tcgs[i];
if (tcg.m_src == src && tcg.m_uvIdx == uvIdx && tcg.m_mtx == mtx)
return i;
}
m_tcgs.emplace_back();
TexCoordGen& newTcg = m_tcgs.back();
newTcg.m_src = src;
newTcg.m_uvIdx = uvIdx;
newTcg.m_mtx = mtx;
return m_tcgs.size() - 1;
}
unsigned ProgrammableCommon::addTexSampling(unsigned mapIdx, unsigned tcgIdx)
{
for (unsigned i=0 ; i<m_texSamplings.size() ; ++i)
{
TexSampling& samp = m_texSamplings[i];
if (samp.mapIdx == mapIdx && samp.tcgIdx == tcgIdx)
return i;
}
m_texSamplings.emplace_back();
TexSampling& samp = m_texSamplings.back();
samp.mapIdx = mapIdx;
samp.tcgIdx = tcgIdx;
return m_texSamplings.size() - 1;
}
unsigned ProgrammableCommon::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst, int mtx)
{
if (inst.m_op != IR::OpCall)
diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function");
const std::string& tcgName = inst.m_call.m_name;
if (!tcgName.compare("UV"))
{
if (inst.getChildCount() < 1)
diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument");
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
const atVec4f& idxImm = idxInst.getImmVec();
return addTexCoordGen(TG_UV, idxImm.vec[0], mtx);
}
else if (!tcgName.compare("Normal"))
return addTexCoordGen(TG_NRM, -1, mtx);
else if (!tcgName.compare("View"))
return addTexCoordGen(TG_POS, -1, mtx);
/* Otherwise treat as game-specific function */
const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0);
unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, m_texMtxRefs.size());
TexCoordGen& tcg = m_tcgs[idx];
m_texMtxRefs.push_back(idx);
tcg.m_gameFunction = tcgName;
tcg.m_gameArgs.clear();
for (int i=1 ; i<inst.getChildCount() ; ++i)
{
const IR::Instruction& ci = inst.getChildInst(ir, i);
tcg.m_gameArgs.push_back(ci.getImmVec());
}
return idx;
}
std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst)
{
switch (inst.m_op)
{
case IR::OpCall:
{
const std::string& name = inst.m_call.m_name;
if (!name.compare("Texture"))
{
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
const atVec4f& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.vec[0]);
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1);
return EmitSamplingUse(addTexSampling(mapIdx, texGenIdx));
}
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().vec[0]);
return EmitColorRegUse(idx);
}
else if (!name.compare("Lighting"))
{
m_lighting = true;
return EmitLighting();
}
else
diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str());
break;
}
case IR::OpLoadImm:
{
const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVec3(vec);
}
case IR::OpArithmetic:
{
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceColor(ir, diag, aInst);
std::string bTrace = RecursiveTraceColor(ir, diag, bInst);
switch (op)
{
case ArithmeticOp::ArithmeticOpAdd:
{
return EmitAdd(aTrace, bTrace);
}
case ArithmeticOp::ArithmeticOpSubtract:
{
return EmitSub(aTrace, bTrace);
}
case ArithmeticOp::ArithmeticOpMultiply:
{
return EmitMult(aTrace, bTrace);
}
case ArithmeticOp::ArithmeticOpDivide:
{
return EmitDiv(aTrace, bTrace);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
}
case IR::OpSwizzle:
{
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceColor(ir, diag, aInst);
return EmitSwizzle3(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid color op");
}
return std::string();
}
std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag,
const IR::Instruction& inst)
{
switch (inst.m_op)
{
case IR::OpCall:
{
const std::string& name = inst.m_call.m_name;
if (!name.compare("Texture"))
{
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
const atVec4f& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.vec[0]);
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1);
return EmitSamplingUse(addTexSampling(mapIdx, texGenIdx));
}
else if (!name.compare("ColorReg"))
{
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().vec[0]);
return EmitColorRegUse(idx);
}
else if (!name.compare("Lighting"))
{
m_lighting = true;
return EmitLighting();
}
else
diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str());
break;
}
case IR::OpLoadImm:
{
const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVal(vec.vec[0]);
}
case IR::OpArithmetic:
{
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst);
std::string bTrace = RecursiveTraceAlpha(ir, diag, bInst);
switch (op)
{
case ArithmeticOp::ArithmeticOpAdd:
{
return EmitAdd(aTrace, bTrace);
}
case ArithmeticOp::ArithmeticOpSubtract:
{
return EmitSub(aTrace, bTrace);
}
case ArithmeticOp::ArithmeticOpMultiply:
{
return EmitMult(aTrace, bTrace);
}
case ArithmeticOp::ArithmeticOpDivide:
{
return EmitDiv(aTrace, bTrace);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
}
case IR::OpSwizzle:
{
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst);
return EmitSwizzle1(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid alpha op");
}
return std::string();
}
void ProgrammableCommon::reset(const IR& ir, Diagnostics& diag, const char* backendName)
{
diag.setBackend(backendName);
/* Final instruction is the root call by hecl convention */
const IR::Instruction& rootCall = ir.m_instructions.back();
bool doAlpha = false;
if (!rootCall.m_call.m_name.compare("HECLOpaque"))
{
m_blendSrc = boo::BlendFactorOne;
m_blendDst = boo::BlendFactorZero;
}
else if (!rootCall.m_call.m_name.compare("HECLAlpha"))
{
m_blendSrc = boo::BlendFactorSrcAlpha;
m_blendDst = boo::BlendFactorInvSrcAlpha;
doAlpha = true;
}
else if (!rootCall.m_call.m_name.compare("HECLAdditive"))
{
m_blendSrc = boo::BlendFactorSrcAlpha;
m_blendDst = boo::BlendFactorOne;
doAlpha = true;
}
else
{
diag.reportBackendErr(rootCall.m_loc, "%s backend doesn't handle '%s' root",
backendName, rootCall.m_call.m_name.c_str());
return;
}
/* Follow Color Chain */
const IR::Instruction& colorRoot =
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
m_colorExpr = RecursiveTraceColor(ir, diag, colorRoot);
/* Follow Alpha Chain */
if (doAlpha)
{
const IR::Instruction& alphaRoot =
ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
m_alphaExpr = RecursiveTraceAlpha(ir, diag, alphaRoot);
}
}
static const char SWIZZLE_CHARS[] = "rgba";
std::string ProgrammableCommon::EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc,
const std::string& a, const atInt8 swiz[4]) const
{
std::string retval = a + '.';
for (int i=0 ; i<3 ; ++i)
{
if (swiz[i] < 0 || swiz[i] > 3)
diag.reportBackendErr(loc, "unable to use swizzle as RGB value");
retval += SWIZZLE_CHARS[swiz[i]];
}
return retval;
}
std::string ProgrammableCommon::EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc,
const std::string& a, const atInt8 swiz[4]) const
{
std::string retval = a + '.';
if (swiz[0] < 0 || swiz[0] > 3)
diag.reportBackendErr(loc, "unable to use swizzle as Alpha value");
retval += SWIZZLE_CHARS[swiz[0]];
return retval;
}
}
}

View File

@ -16,6 +16,7 @@ add_library(HECLCommon
../include/HECL/HECL.hpp ../include/HECL/HECL.hpp
../include/HECL/Backend/Backend.hpp ../include/HECL/Backend/Backend.hpp
../include/HECL/Backend/GX.hpp ../include/HECL/Backend/GX.hpp
../include/HECL/Backend/ProgrammableCommon.hpp
../include/HECL/Backend/GLSL.hpp ../include/HECL/Backend/GLSL.hpp
../include/HECL/Frontend.hpp ../include/HECL/Frontend.hpp
../include/HECL/Database.hpp ../include/HECL/Database.hpp