mirror of https://github.com/AxioDL/metaforce.git
Initial HECL-IR to GLSL implementation
This commit is contained in:
parent
b4725c7d2e
commit
cbb0951c09
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -1,3 +1,4 @@
|
||||||
add_library(HECLBackend
|
add_library(HECLBackend
|
||||||
GX.cpp
|
GX.cpp
|
||||||
|
ProgrammableCommon.cpp
|
||||||
GLSL.cpp)
|
GLSL.cpp)
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue