WIP multi-shader support, see details:
- picasso now accepts several input files, which are each compiled into DVLE objects inside the .shbin - Uniform allocation is shared amongst all DVLEs. - Constant allocation is private to each DVLE. - Header file generation is temporarily disabled. - New directives: .nodvle Disables the generation of a DVLE object for the current input file. This allows sharing code amongst shaders. .entry entryName Specifies the name of the entrypoint procedure of the current DVLE. By default it's 'main'.
This commit is contained in:
parent
b250513be0
commit
e152f4e626
@ -2,7 +2,7 @@
|
|||||||
# Process this file with autoconf to produce a configure script.
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([picasso],[1.0.0],[fincs.alt1@gmail.com])
|
AC_INIT([picasso],[2.0.0],[fincs.alt1@gmail.com])
|
||||||
AC_CONFIG_SRCDIR([source/picasso_frontend.cpp])
|
AC_CONFIG_SRCDIR([source/picasso_frontend.cpp])
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([1.10])
|
AM_INIT_AUTOMAKE([1.10])
|
||||||
|
102
source/picasso.h
102
source/picasso.h
@ -58,10 +58,13 @@ enum
|
|||||||
COND_UNK2,
|
COND_UNK2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Global data
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Output buffer
|
||||||
typedef std::vector<u32> outputBufType;
|
typedef std::vector<u32> outputBufType;
|
||||||
typedef outputBufType::iterator outputBufIter;
|
typedef outputBufType::iterator outputBufIter;
|
||||||
|
|
||||||
extern bool g_isGeoShader;
|
|
||||||
extern outputBufType g_outputBuf;
|
extern outputBufType g_outputBuf;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -87,6 +90,7 @@ struct StackEntry
|
|||||||
extern StackEntry g_stack[MAX_STACK];
|
extern StackEntry g_stack[MAX_STACK];
|
||||||
extern int g_stackPos;
|
extern int g_stackPos;
|
||||||
|
|
||||||
|
// Operand descriptor stuff.
|
||||||
#define MAX_OPDESC 128
|
#define MAX_OPDESC 128
|
||||||
extern int g_opdescTable[MAX_OPDESC];
|
extern int g_opdescTable[MAX_OPDESC];
|
||||||
extern int g_opdeskMasks[MAX_OPDESC]; // used to keep track of used bits
|
extern int g_opdeskMasks[MAX_OPDESC]; // used to keep track of used bits
|
||||||
@ -106,10 +110,45 @@ struct Uniform
|
|||||||
int type;
|
int type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// List of uniforms
|
||||||
#define MAX_UNIFORM 0x60
|
#define MAX_UNIFORM 0x60
|
||||||
extern Uniform g_uniformTable[MAX_UNIFORM];
|
extern Uniform g_uniformTable[MAX_UNIFORM];
|
||||||
extern int g_uniformCount;
|
extern int g_uniformCount;
|
||||||
|
|
||||||
|
struct DVLEData; // Forward declaration
|
||||||
|
|
||||||
|
typedef std::pair<size_t, size_t> procedure; // position, size
|
||||||
|
typedef std::pair<size_t, std::string> relocation; // position, name
|
||||||
|
|
||||||
|
typedef std::map<std::string, procedure> procTableType;
|
||||||
|
typedef std::map<std::string, size_t> labelTableType;
|
||||||
|
typedef std::map<std::string, int> aliasTableType;
|
||||||
|
typedef std::vector<relocation> relocTableType;
|
||||||
|
typedef std::list<DVLEData> dvleTableType;
|
||||||
|
|
||||||
|
typedef procTableType::iterator procTableIter;
|
||||||
|
typedef labelTableType::iterator labelTableIter;
|
||||||
|
typedef aliasTableType::iterator aliasTableIter;
|
||||||
|
typedef relocTableType::iterator relocTableIter;
|
||||||
|
typedef dvleTableType::iterator dvleTableIter;
|
||||||
|
|
||||||
|
extern procTableType g_procTable;
|
||||||
|
extern dvleTableType g_dvleTable;
|
||||||
|
extern relocTableType g_procRelocTable;
|
||||||
|
extern int g_totalDvleCount;
|
||||||
|
|
||||||
|
// The following are cleared before each file is processed
|
||||||
|
extern labelTableType g_labels;
|
||||||
|
extern relocTableType g_labelRelocTable;
|
||||||
|
extern aliasTableType g_aliases;
|
||||||
|
|
||||||
|
int AssembleString(char* str, const char* initialFilename);
|
||||||
|
int RelocateProduct(void);
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Local data
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
OUTTYPE_POS = 0,
|
OUTTYPE_POS = 0,
|
||||||
@ -123,10 +162,6 @@ enum
|
|||||||
OUTTYPE_VIEW,
|
OUTTYPE_VIEW,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_OUTPUT 8
|
|
||||||
extern u64 g_outputTable[MAX_OUTPUT];
|
|
||||||
extern int g_outputCount;
|
|
||||||
|
|
||||||
struct Constant
|
struct Constant
|
||||||
{
|
{
|
||||||
int regId;
|
int regId;
|
||||||
@ -138,33 +173,32 @@ struct Constant
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_CONSTANT 0x60
|
struct DVLEData
|
||||||
extern Constant g_constantTable[MAX_CONSTANT];
|
|
||||||
extern int g_constantCount;
|
|
||||||
extern size_t g_constantSize;
|
|
||||||
|
|
||||||
struct Relocation
|
|
||||||
{
|
{
|
||||||
size_t instPos;
|
// General config
|
||||||
const char* target;
|
std::string filename;
|
||||||
bool isProc;
|
std::string entrypoint;
|
||||||
|
size_t entryStart, entryEnd;
|
||||||
|
bool nodvle, isGeoShader;
|
||||||
|
|
||||||
|
// Uniforms
|
||||||
|
Uniform uniformTable[MAX_UNIFORM];
|
||||||
|
int uniformCount;
|
||||||
|
size_t symbolSize;
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
#define MAX_CONSTANT 0x60
|
||||||
|
Constant constantTable[MAX_CONSTANT];
|
||||||
|
int constantCount;
|
||||||
|
size_t constantSize;
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
#define MAX_OUTPUT 8
|
||||||
|
u64 outputTable[MAX_OUTPUT];
|
||||||
|
int outputCount;
|
||||||
|
|
||||||
|
DVLEData(const char* filename) :
|
||||||
|
filename(filename), entrypoint("main"),
|
||||||
|
nodvle(false), isGeoShader(false),
|
||||||
|
uniformCount(0), symbolSize(0), constantCount(0), constantSize(0), outputCount(0) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::pair<size_t, size_t> procedure; // position, size
|
|
||||||
|
|
||||||
typedef std::map<std::string, procedure> procTableType;
|
|
||||||
typedef std::map<std::string, size_t> labelTableType;
|
|
||||||
typedef std::map<std::string, int> aliasTableType;
|
|
||||||
typedef std::vector<Relocation> relocTableType;
|
|
||||||
|
|
||||||
typedef procTableType::iterator procTableIter;
|
|
||||||
typedef labelTableType::iterator labelTableIter;
|
|
||||||
typedef aliasTableType::iterator aliasTableIter;
|
|
||||||
typedef relocTableType::iterator relocTableIter;
|
|
||||||
|
|
||||||
extern procTableType g_procTable;
|
|
||||||
extern labelTableType g_labels;
|
|
||||||
extern aliasTableType g_aliases;
|
|
||||||
extern relocTableType g_relocs;
|
|
||||||
|
|
||||||
int AssembleString(char* str, const char* initialFilename);
|
|
||||||
|
@ -19,21 +19,63 @@ int g_opdescMasks[MAX_OPDESC];
|
|||||||
|
|
||||||
Uniform g_uniformTable[MAX_UNIFORM];
|
Uniform g_uniformTable[MAX_UNIFORM];
|
||||||
int g_uniformCount;
|
int g_uniformCount;
|
||||||
static int fvecUnifPos = 0x20;
|
|
||||||
static int ivecUnifPos = 0x80;
|
|
||||||
static int boolUnifPos = 0x88;
|
|
||||||
|
|
||||||
Constant g_constantTable[MAX_CONSTANT];
|
class UniformAlloc
|
||||||
int g_constantCount;
|
{
|
||||||
size_t g_constantSize;
|
int start, end, bound, tend;
|
||||||
|
public:
|
||||||
|
UniformAlloc(int start, int end) : start(start), end(end), bound(end), tend(end) { }
|
||||||
|
void ClearLocal(void) { end = tend; }
|
||||||
|
int AllocGlobal(int size)
|
||||||
|
{
|
||||||
|
if ((start+size) > bound) return -1;
|
||||||
|
int ret = start;
|
||||||
|
start += size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int AllocLocal(int size)
|
||||||
|
{
|
||||||
|
int pos = end - size;
|
||||||
|
if (pos < start) return -1;
|
||||||
|
bound = pos < bound ? pos : bound;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
u64 g_outputTable[MAX_OUTPUT];
|
static UniformAlloc fvecAlloc(0x20, 0x80), ivecAlloc(0x80, 0x84), boolAlloc(0x88, 0x98);
|
||||||
int g_outputCount;
|
|
||||||
|
|
||||||
procTableType g_procTable;
|
procTableType g_procTable;
|
||||||
|
dvleTableType g_dvleTable;
|
||||||
|
relocTableType g_procRelocTable;
|
||||||
|
int g_totalDvleCount;
|
||||||
|
|
||||||
labelTableType g_labels;
|
labelTableType g_labels;
|
||||||
|
relocTableType g_labelRelocTable;
|
||||||
aliasTableType g_aliases;
|
aliasTableType g_aliases;
|
||||||
relocTableType g_relocs;
|
|
||||||
|
static DVLEData* curDvle;
|
||||||
|
|
||||||
|
static void ClearStatus(void)
|
||||||
|
{
|
||||||
|
fvecAlloc.ClearLocal();
|
||||||
|
ivecAlloc.ClearLocal();
|
||||||
|
boolAlloc.ClearLocal();
|
||||||
|
g_labels.clear();
|
||||||
|
g_labelRelocTable.clear();
|
||||||
|
g_aliases.clear();
|
||||||
|
curDvle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DVLEData* GetDvleData(void)
|
||||||
|
{
|
||||||
|
if (!curDvle)
|
||||||
|
{
|
||||||
|
g_dvleTable.push_back( DVLEData(curFile) );
|
||||||
|
curDvle = &g_dvleTable.back();
|
||||||
|
g_totalDvleCount ++;
|
||||||
|
}
|
||||||
|
return curDvle;
|
||||||
|
}
|
||||||
|
|
||||||
static char* mystrtok_pos;
|
static char* mystrtok_pos;
|
||||||
static char* mystrtok(char* str, const char* delim)
|
static char* mystrtok(char* str, const char* delim)
|
||||||
@ -126,13 +168,15 @@ static int parseInt(char* pos, int& out, long long min, long long max)
|
|||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
static int ProcessCommand(const char* cmd);
|
static int ProcessCommand(const char* cmd);
|
||||||
static int FixupRelocations();
|
static int FixupLabelRelocations();
|
||||||
|
|
||||||
int AssembleString(char* str, const char* initialFilename)
|
int AssembleString(char* str, const char* initialFilename)
|
||||||
{
|
{
|
||||||
curFile = initialFilename;
|
curFile = initialFilename;
|
||||||
curLine = 1;
|
curLine = 1;
|
||||||
|
|
||||||
|
ClearStatus();
|
||||||
|
|
||||||
int nextLineIncr = 0;
|
int nextLineIncr = 0;
|
||||||
char* nextStr = NULL;
|
char* nextStr = NULL;
|
||||||
for (; str; str = nextStr, curLine += nextLineIncr)
|
for (; str; str = nextStr, curLine += nextLineIncr)
|
||||||
@ -192,35 +236,55 @@ int AssembleString(char* str, const char* initialFilename)
|
|||||||
if (g_stackPos)
|
if (g_stackPos)
|
||||||
return throwError("unclosed block(s)\n");
|
return throwError("unclosed block(s)\n");
|
||||||
|
|
||||||
safe_call(FixupRelocations());
|
safe_call(FixupLabelRelocations());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FixupRelocations()
|
int FixupLabelRelocations()
|
||||||
{
|
{
|
||||||
for (relocTableIter it = g_relocs.begin(); it != g_relocs.end(); ++it)
|
for (relocTableIter it = g_labelRelocTable.begin(); it != g_labelRelocTable.end(); ++it)
|
||||||
{
|
{
|
||||||
Relocation& r = *it;
|
relocation& r = *it;
|
||||||
u32& inst = BUF[r.instPos];
|
u32& inst = BUF[r.first];
|
||||||
if (r.isProc)
|
labelTableIter lbl = g_labels.find(r.second);
|
||||||
{
|
if (lbl == g_labels.end())
|
||||||
procTableIter proc = g_procTable.find(r.target);
|
return throwError("label '%s' is undefined\n", r.second.c_str());
|
||||||
if (proc == g_procTable.end())
|
u32 dst = lbl->second;
|
||||||
return throwError("procedure '%s' is undefined\n", r.target);
|
inst &= ~(0xFFF << 10);
|
||||||
u32 dst = proc->second.first;
|
inst |= dst << 10;
|
||||||
u32 num = proc->second.second;
|
}
|
||||||
inst &= ~0x3FFFFF;
|
return 0;
|
||||||
inst |= num | (dst << 10);
|
}
|
||||||
} else
|
|
||||||
{
|
int RelocateProduct()
|
||||||
labelTableIter lbl = g_labels.find(r.target);
|
{
|
||||||
if (lbl == g_labels.end())
|
for (relocTableIter it = g_procRelocTable.begin(); it != g_procRelocTable.end(); ++it)
|
||||||
return throwError("label '%s' is undefined\n", r.target);
|
{
|
||||||
u32 dst = lbl->second;
|
relocation& r = *it;
|
||||||
inst &= ~(0xFFF << 10);
|
u32& inst = BUF[r.first];
|
||||||
inst |= dst << 10;
|
procTableIter proc = g_procTable.find(r.second);
|
||||||
}
|
if (proc == g_procTable.end())
|
||||||
|
return throwError("procedure '%s' is undefined\n", r.second.c_str());
|
||||||
|
u32 dst = proc->second.first;
|
||||||
|
u32 num = proc->second.second;
|
||||||
|
inst &= ~0x3FFFFF;
|
||||||
|
inst |= num | (dst << 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_totalDvleCount == 0)
|
||||||
|
return throwError("no DVLEs can be generated from the given input file(s)\n");
|
||||||
|
|
||||||
|
for (dvleTableIter it = g_dvleTable.begin(); it != g_dvleTable.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->nodvle) continue;
|
||||||
|
curFile = it->filename.c_str();
|
||||||
|
curLine = 1;
|
||||||
|
procTableIter mainIt = g_procTable.find(it->entrypoint);
|
||||||
|
if (mainIt == g_procTable.end())
|
||||||
|
return throwError("entrypoint '%s' is undefined\n", it->entrypoint.c_str());
|
||||||
|
it->entryStart = mainIt->second.first;
|
||||||
|
it->entryEnd = it->entryStart + mainIt->second.second;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -422,12 +486,16 @@ static int parseSwizzling(const char* b)
|
|||||||
return out<<1;
|
return out<<1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int maskFromSwizzling(int sw)
|
static int maskFromSwizzling(int sw, bool reverse = true)
|
||||||
{
|
{
|
||||||
sw >>= 1; // get rid of negation bit
|
sw >>= 1; // get rid of negation bit
|
||||||
int out = 0;
|
int out = 0;
|
||||||
for (int i = 0; i < 4; i ++)
|
for (int i = 0; i < 4; i ++)
|
||||||
out |= BIT(3-((sw>>(i*2))&3));
|
{
|
||||||
|
int bitid = (sw>>(i*2))&3;
|
||||||
|
if (reverse) bitid = 3 - bitid;
|
||||||
|
out |= BIT(bitid);
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,10 +909,10 @@ DEF_COMMAND(formatsetemit)
|
|||||||
safe_call(parseSetEmitFlags(flagStr, isPrim, isInv));
|
safe_call(parseSetEmitFlags(flagStr, isPrim, isInv));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("%s:%02X vtx%d, %s, %s\n", cmdName, opcode, vtxId, isPrim?"true":"false", isInv=?"true":"false");
|
printf("%s:%02X vtx%d, %s, %s\n", cmdName, opcode, vtxId, isPrim?"true":"false", isInv?"true":"false");
|
||||||
#endif
|
#endif
|
||||||
BUF.push_back(FMT_OPCODE(opcode) | ((u32)isInv<<22) | ((u32)isPrim<<23) | (vtxId<<24));
|
BUF.push_back(FMT_OPCODE(opcode) | ((u32)isInv<<22) | ((u32)isPrim<<23) | (vtxId<<24));
|
||||||
g_isGeoShader = true;
|
GetDvleData()->isGeoShader = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -856,11 +924,7 @@ DEF_COMMAND(formatcall)
|
|||||||
|
|
||||||
ARG_TARGET(procName);
|
ARG_TARGET(procName);
|
||||||
|
|
||||||
Relocation r;
|
g_procRelocTable.push_back( std::make_pair(BUF.size(), procName) );
|
||||||
r.instPos = BUF.size();
|
|
||||||
r.target = procName;
|
|
||||||
r.isProc = true;
|
|
||||||
g_relocs.push_back(r);
|
|
||||||
|
|
||||||
BUF.push_back(FMT_OPCODE(opcode));
|
BUF.push_back(FMT_OPCODE(opcode));
|
||||||
|
|
||||||
@ -919,11 +983,8 @@ DEF_COMMAND(format2)
|
|||||||
|
|
||||||
ARG_TARGET(targetName);
|
ARG_TARGET(targetName);
|
||||||
|
|
||||||
Relocation r;
|
relocTableType& rt = opcode==MAESTRO_CALLC ? g_procRelocTable : g_labelRelocTable;
|
||||||
r.instPos = BUF.size();
|
rt.push_back( std::make_pair(BUF.size(), targetName) );
|
||||||
r.target = targetName;
|
|
||||||
r.isProc = opcode==MAESTRO_CALLC;
|
|
||||||
g_relocs.push_back(r);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("%s:%02X %s, %s\n", cmdName, opcode, condExp, targetName);
|
printf("%s:%02X %s, %s\n", cmdName, opcode, condExp, targetName);
|
||||||
@ -971,11 +1032,8 @@ DEF_COMMAND(format3)
|
|||||||
|
|
||||||
ARG_TARGET(targetName);
|
ARG_TARGET(targetName);
|
||||||
|
|
||||||
Relocation r;
|
relocTableType& rt = opcode==MAESTRO_CALLU ? g_procRelocTable : g_labelRelocTable;
|
||||||
r.instPos = BUF.size();
|
rt.push_back( std::make_pair(BUF.size(), targetName) );
|
||||||
r.target = targetName;
|
|
||||||
r.isProc = opcode==MAESTRO_CALLU;
|
|
||||||
g_relocs.push_back(r);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("%s:%02X d%02X, %s\n", cmdName, opcode, regId, targetName);
|
printf("%s:%02X d%02X, %s\n", cmdName, opcode, regId, targetName);
|
||||||
@ -1185,21 +1243,20 @@ DEF_DIRECTIVE(alias)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int& getAllocVar(int type, int& bound)
|
static inline UniformAlloc& getAlloc(int type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case UTYPE_FVEC: bound = 0x80; return fvecUnifPos;
|
case UTYPE_FVEC: return fvecAlloc;
|
||||||
case UTYPE_IVEC: bound = 0x84; return ivecUnifPos;
|
case UTYPE_IVEC: return ivecAlloc;
|
||||||
case UTYPE_BOOL: bound = 0x98; return boolUnifPos;
|
case UTYPE_BOOL: return boolAlloc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_DIRECTIVE(uniform)
|
DEF_DIRECTIVE(uniform)
|
||||||
{
|
{
|
||||||
int bound;
|
UniformAlloc& alloc = getAlloc(dirParam);
|
||||||
int& uniformPos = getAllocVar(dirParam, bound);
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -1222,19 +1279,55 @@ DEF_DIRECTIVE(uniform)
|
|||||||
}
|
}
|
||||||
if (!validateIdentifier(argText))
|
if (!validateIdentifier(argText))
|
||||||
return throwError("invalid uniform name: %s\n", argText);
|
return throwError("invalid uniform name: %s\n", argText);
|
||||||
if ((uniformPos+uSize) >= bound)
|
|
||||||
return throwError("not enough uniform registers: %s[%d]\n", argText, uSize);
|
|
||||||
if (g_uniformCount == MAX_UNIFORM)
|
|
||||||
return throwError("too many uniforms: %s[%d]\n", argText, uSize);
|
|
||||||
if (g_aliases.find(argText) != g_aliases.end())
|
if (g_aliases.find(argText) != g_aliases.end())
|
||||||
return duplicateIdentifier(argText);
|
return duplicateIdentifier(argText);
|
||||||
|
|
||||||
|
int uniformPos = -1;
|
||||||
|
|
||||||
|
// Find the uniform in the table
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < g_uniformCount; i ++)
|
||||||
|
{
|
||||||
|
Uniform& uniform = g_uniformTable[i];
|
||||||
|
if (uniform.name == argText)
|
||||||
|
{
|
||||||
|
if (uniform.type != dirParam)
|
||||||
|
return throwError("mismatched uniform type: %s\n", argText);
|
||||||
|
if (uniform.size != uSize)
|
||||||
|
return throwError("uniform '%s' previously declared as having size %d\n", argText, uniform.size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not found, create it
|
||||||
|
if (i == g_uniformCount && uniformPos < 0)
|
||||||
|
{
|
||||||
|
if (g_uniformCount == MAX_UNIFORM)
|
||||||
|
return throwError("too many global uniforms: %s\n", argText);
|
||||||
|
|
||||||
|
uniformPos = alloc.AllocGlobal(uSize);
|
||||||
|
if (uniformPos < 0)
|
||||||
|
return throwError("not enough uniform space: %s[%d]\n", argText, uSize);
|
||||||
|
}
|
||||||
|
|
||||||
Uniform& uniform = g_uniformTable[g_uniformCount++];
|
Uniform& uniform = g_uniformTable[g_uniformCount++];
|
||||||
uniform.name = argText;
|
uniform.name = argText;
|
||||||
uniform.pos = uniformPos;
|
uniform.pos = uniformPos;
|
||||||
uniform.size = uSize;
|
uniform.size = uSize;
|
||||||
uniform.type = dirParam;
|
uniform.type = dirParam;
|
||||||
uniformPos += uSize;
|
uniformPos += uSize;
|
||||||
|
|
||||||
|
if (*argText != '_')
|
||||||
|
{
|
||||||
|
DVLEData* dvle = GetDvleData();
|
||||||
|
|
||||||
|
// Add the uniform to the table
|
||||||
|
if (dvle->uniformCount == MAX_UNIFORM)
|
||||||
|
return throwError("too many referenced uniforms: %s\n", argText);
|
||||||
|
dvle->uniformTable[dvle->uniformCount++] = uniform; // Copy constructor
|
||||||
|
dvle->symbolSize += strlen(argText)+1;
|
||||||
|
}
|
||||||
|
|
||||||
g_aliases.insert( std::pair<std::string,int>(argText, uniform.pos | (DEFAULT_OPSRC<<8)) );
|
g_aliases.insert( std::pair<std::string,int>(argText, uniform.pos | (DEFAULT_OPSRC<<8)) );
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -1246,8 +1339,8 @@ DEF_DIRECTIVE(uniform)
|
|||||||
|
|
||||||
DEF_DIRECTIVE(const)
|
DEF_DIRECTIVE(const)
|
||||||
{
|
{
|
||||||
int bound;
|
DVLEData* dvle = GetDvleData();
|
||||||
int& uniformPos = getAllocVar(dirParam, bound);
|
UniformAlloc& alloc = getAlloc(dirParam);
|
||||||
|
|
||||||
NEXT_ARG_CPAREN(constName);
|
NEXT_ARG_CPAREN(constName);
|
||||||
NEXT_ARG(arg0Text);
|
NEXT_ARG(arg0Text);
|
||||||
@ -1260,14 +1353,18 @@ DEF_DIRECTIVE(const)
|
|||||||
*parenPos = 0;
|
*parenPos = 0;
|
||||||
arg3Text = trim_whitespace(arg3Text);
|
arg3Text = trim_whitespace(arg3Text);
|
||||||
|
|
||||||
if (g_constantCount == MAX_CONSTANT || uniformPos>=bound)
|
|
||||||
return throwError("not enough space for constant\n");
|
|
||||||
|
|
||||||
if (g_aliases.find(constName) != g_aliases.end())
|
if (g_aliases.find(constName) != g_aliases.end())
|
||||||
return duplicateIdentifier(constName);
|
return duplicateIdentifier(constName);
|
||||||
|
|
||||||
Constant& ct = g_constantTable[g_constantCount++];
|
int uniformPos = alloc.AllocLocal(1);
|
||||||
ct.regId = uniformPos++;
|
if (uniformPos < 0)
|
||||||
|
return throwError("not enough space for local constant '%s'\n", constName);
|
||||||
|
|
||||||
|
if (dvle->constantCount == MAX_CONSTANT)
|
||||||
|
return throwError("too many local constants\n");
|
||||||
|
|
||||||
|
Constant& ct = dvle->constantTable[dvle->constantCount++];
|
||||||
|
ct.regId = uniformPos;
|
||||||
ct.type = dirParam;
|
ct.type = dirParam;
|
||||||
if (dirParam == UTYPE_FVEC)
|
if (dirParam == UTYPE_FVEC)
|
||||||
{
|
{
|
||||||
@ -1275,14 +1372,14 @@ DEF_DIRECTIVE(const)
|
|||||||
ct.fparam[1] = atof(arg1Text);
|
ct.fparam[1] = atof(arg1Text);
|
||||||
ct.fparam[2] = atof(arg2Text);
|
ct.fparam[2] = atof(arg2Text);
|
||||||
ct.fparam[3] = atof(arg3Text);
|
ct.fparam[3] = atof(arg3Text);
|
||||||
g_constantSize += 4 + 4*4;
|
dvle->constantSize += 4 + 4*4;
|
||||||
} else if (dirParam == UTYPE_IVEC)
|
} else if (dirParam == UTYPE_IVEC)
|
||||||
{
|
{
|
||||||
ct.iparam[0] = atoi(arg0Text) & 0xFF;
|
ct.iparam[0] = atoi(arg0Text) & 0xFF;
|
||||||
ct.iparam[1] = atoi(arg1Text) & 0xFF;
|
ct.iparam[1] = atoi(arg1Text) & 0xFF;
|
||||||
ct.iparam[2] = atoi(arg2Text) & 0xFF;
|
ct.iparam[2] = atoi(arg2Text) & 0xFF;
|
||||||
ct.iparam[3] = atoi(arg3Text) & 0xFF;
|
ct.iparam[3] = atoi(arg3Text) & 0xFF;
|
||||||
g_constantSize += 4 + 4;
|
dvle->constantSize += 4 + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_aliases.insert( std::pair<std::string,int>(constName, ct.regId | (DEFAULT_OPSRC<<8)) );
|
g_aliases.insert( std::pair<std::string,int>(constName, ct.regId | (DEFAULT_OPSRC<<8)) );
|
||||||
@ -1321,6 +1418,8 @@ static int parseOutType(const char* text)
|
|||||||
|
|
||||||
DEF_DIRECTIVE(out)
|
DEF_DIRECTIVE(out)
|
||||||
{
|
{
|
||||||
|
DVLEData* dvle = GetDvleData();
|
||||||
|
|
||||||
NEXT_ARG_SPC(outName);
|
NEXT_ARG_SPC(outName);
|
||||||
NEXT_ARG_SPC(outType);
|
NEXT_ARG_SPC(outType);
|
||||||
ENSURE_NO_MORE_ARGS();
|
ENSURE_NO_MORE_ARGS();
|
||||||
@ -1337,28 +1436,54 @@ DEF_DIRECTIVE(out)
|
|||||||
if (sw < 0)
|
if (sw < 0)
|
||||||
return throwError("invalid output mask: %s\n", dotPos);
|
return throwError("invalid output mask: %s\n", dotPos);
|
||||||
}
|
}
|
||||||
int mask = maskFromSwizzling(sw);
|
int mask = maskFromSwizzling(sw, false);
|
||||||
int type = parseOutType(outType);
|
int type = parseOutType(outType);
|
||||||
if (type < 0)
|
if (type < 0)
|
||||||
return throwError("invalid output type: %s\n", outType);
|
return throwError("invalid output type: %s\n", outType);
|
||||||
|
|
||||||
if (g_outputCount==MAX_OUTPUT)
|
if (dvle->outputCount==MAX_OUTPUT)
|
||||||
return throwError("too many outputs\n");
|
return throwError("too many outputs\n");
|
||||||
|
|
||||||
if (g_aliases.find(outName) != g_aliases.end())
|
if (g_aliases.find(outName) != g_aliases.end())
|
||||||
return duplicateIdentifier(outName);
|
return duplicateIdentifier(outName);
|
||||||
|
|
||||||
int oid = g_outputCount;
|
int oid = dvle->outputCount;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("output %s <- o%d (%d:%X)\n", outName, oid, type, mask);
|
printf("output %s <- o%d (%d:%X)\n", outName, oid, type, mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
g_outputTable[g_outputCount++] = OUTPUT_MAKE(type, oid, mask);
|
dvle->outputTable[dvle->outputCount++] = OUTPUT_MAKE(type, oid, mask);
|
||||||
g_aliases.insert( std::pair<std::string,int>(outName, oid | (sw<<8)) );
|
g_aliases.insert( std::pair<std::string,int>(outName, oid | (sw<<8)) );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEF_DIRECTIVE(entry)
|
||||||
|
{
|
||||||
|
DVLEData* dvle = GetDvleData();
|
||||||
|
|
||||||
|
NEXT_ARG_SPC(entrypoint);
|
||||||
|
ENSURE_NO_MORE_ARGS();
|
||||||
|
|
||||||
|
if (!validateIdentifier(entrypoint))
|
||||||
|
return throwError("invalid identifier: %s\n", entrypoint);
|
||||||
|
|
||||||
|
dvle->entrypoint = entrypoint;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_DIRECTIVE(nodvle)
|
||||||
|
{
|
||||||
|
DVLEData* dvle = GetDvleData();
|
||||||
|
ENSURE_NO_MORE_ARGS();
|
||||||
|
|
||||||
|
if (!dvle->nodvle)
|
||||||
|
{
|
||||||
|
dvle->nodvle = true;
|
||||||
|
g_totalDvleCount --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const cmdTableType dirTable[] =
|
static const cmdTableType dirTable[] =
|
||||||
{
|
{
|
||||||
DEC_DIRECTIVE(proc),
|
DEC_DIRECTIVE(proc),
|
||||||
@ -1371,6 +1496,8 @@ static const cmdTableType dirTable[] =
|
|||||||
DEC_DIRECTIVE2(constf, const, UTYPE_FVEC),
|
DEC_DIRECTIVE2(constf, const, UTYPE_FVEC),
|
||||||
DEC_DIRECTIVE2(consti, const, UTYPE_IVEC),
|
DEC_DIRECTIVE2(consti, const, UTYPE_IVEC),
|
||||||
DEC_DIRECTIVE(out),
|
DEC_DIRECTIVE(out),
|
||||||
|
DEC_DIRECTIVE(entry),
|
||||||
|
DEC_DIRECTIVE(nodvle),
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,44 +33,49 @@ int usage(const char* prog)
|
|||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage:\n\n"
|
"Usage:\n\n"
|
||||||
"%s shbinFile vshFile [hFile]\n", prog);
|
"%s output.shbin input1.pica input2.pica ...\n", prog);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (argc < 3 || argc > 4)
|
if (argc < 3)
|
||||||
return usage(argv[0]);
|
return usage(argv[0]);
|
||||||
|
|
||||||
char* shbinFile = argv[1];
|
char* shbinFile = argv[1];
|
||||||
char* vshFile = argv[2];
|
//char* hFile = argc > 3 ? argv[3] : NULL;
|
||||||
char* hFile = argc > 3 ? argv[3] : NULL;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
FixMinGWPath(shbinFile);
|
FixMinGWPath(shbinFile);
|
||||||
FixMinGWPath(vshFile);
|
//FixMinGWPath(hFile);
|
||||||
FixMinGWPath(hFile);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char* sourceCode = StringFromFile(vshFile);
|
int rc = 0;
|
||||||
if (!sourceCode)
|
for (int i = 2; i < argc; i ++)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Cannot open input file!\n");
|
char* vshFile = argv[i];
|
||||||
return 1;
|
|
||||||
|
#ifdef WIN32
|
||||||
|
FixMinGWPath(vshFile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char* sourceCode = StringFromFile(vshFile);
|
||||||
|
if (!sourceCode)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "error: cannot open input file: %s\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = AssembleString(sourceCode, vshFile);
|
||||||
|
free(sourceCode);
|
||||||
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = AssembleString(sourceCode, vshFile);
|
rc = RelocateProduct();
|
||||||
free(sourceCode);
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
procTableIter mainIt = g_procTable.find("main");
|
|
||||||
if (mainIt == g_procTable.end())
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Error: main proc not defined\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileClass f(shbinFile, "wb");
|
FileClass f(shbinFile, "wb");
|
||||||
|
|
||||||
if (f.openerror())
|
if (f.openerror())
|
||||||
@ -79,54 +84,39 @@ int main(int argc, char* argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 progSize = g_outputBuf.size();
|
||||||
|
u32 dvlpSize = 10*4 + progSize*4 + g_opdescCount*8;
|
||||||
|
|
||||||
|
// Write DVLB header
|
||||||
f.WriteWord(0x424C5644); // DVLB
|
f.WriteWord(0x424C5644); // DVLB
|
||||||
f.WriteWord(1); // 1 DVLE
|
f.WriteWord(g_totalDvleCount); // Number of DVLEs
|
||||||
f.WriteWord(3*4 + 0x28); // offset to DVLE
|
|
||||||
|
|
||||||
u32 dvlpStart = f.Tell();
|
// Calculate and write DVLE offsets
|
||||||
u32 shaderSize = g_outputBuf.size();
|
u32 curOff = 2*4 + g_totalDvleCount*4 + dvlpSize;
|
||||||
u32 paramStart = 0x28 + 0x40;
|
for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end(); ++dvle)
|
||||||
|
{
|
||||||
|
if (dvle->nodvle) continue;
|
||||||
|
f.WriteWord(curOff);
|
||||||
|
curOff += 16*4; // Header
|
||||||
|
curOff += dvle->constantSize;
|
||||||
|
curOff += dvle->outputCount*8;
|
||||||
|
curOff += dvle->uniformCount*8;
|
||||||
|
curOff += dvle->symbolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write DVLP header
|
||||||
f.WriteWord(0x504C5644); // DVLP
|
f.WriteWord(0x504C5644); // DVLP
|
||||||
f.WriteWord(0); // version
|
f.WriteWord(0); // version
|
||||||
f.WriteWord(paramStart); // offset to shader binary blob
|
f.WriteWord(10*4); // offset to shader binary blob
|
||||||
f.WriteWord(shaderSize); // size of shader binary blob
|
f.WriteWord(progSize); // size of shader binary blob
|
||||||
paramStart += shaderSize*4;
|
f.WriteWord(10*4 + progSize*4); // offset to opdesc table
|
||||||
f.WriteWord(paramStart); // offset to opdesc table
|
|
||||||
f.WriteWord(g_opdescCount); // number of opdescs
|
f.WriteWord(g_opdescCount); // number of opdescs
|
||||||
paramStart += g_opdescCount*8;
|
f.WriteWord(dvlpSize); // offset to symtable (TODO)
|
||||||
f.WriteWord(paramStart); // offset to symtable (TODO)
|
|
||||||
f.WriteWord(0); // ????
|
f.WriteWord(0); // ????
|
||||||
f.WriteWord(0); // ????
|
f.WriteWord(0); // ????
|
||||||
f.WriteWord(0); // ????
|
f.WriteWord(0); // ????
|
||||||
|
|
||||||
u32 dvleStart = f.Tell();
|
|
||||||
paramStart -= dvleStart - dvlpStart;
|
|
||||||
|
|
||||||
f.WriteWord(0x454C5644); // DVLE
|
|
||||||
f.WriteHword(0); // padding?
|
|
||||||
f.WriteHword(g_isGeoShader ? 1 : 0); // Shader type
|
|
||||||
f.WriteWord(mainIt->second.first); // offset to main
|
|
||||||
f.WriteWord(mainIt->second.first+mainIt->second.second); // offset to end of main
|
|
||||||
f.WriteWord(0); // ???
|
|
||||||
f.WriteWord(0); // ???
|
|
||||||
f.WriteWord(paramStart); // offset to constant table
|
|
||||||
f.WriteWord(g_constantCount); // size of constant table
|
|
||||||
paramStart += g_constantSize;
|
|
||||||
f.WriteWord(paramStart); // offset to label table (TODO)
|
|
||||||
f.WriteWord(0); // size of label table (TODO)
|
|
||||||
f.WriteWord(paramStart); // offset to output table
|
|
||||||
f.WriteWord(g_outputCount); // size of output table
|
|
||||||
paramStart += g_outputCount*8;
|
|
||||||
f.WriteWord(paramStart); // offset to uniform table
|
|
||||||
f.WriteWord(g_uniformCount); // size of uniform table
|
|
||||||
paramStart += g_uniformCount*8;
|
|
||||||
f.WriteWord(paramStart); // offset to symbol table
|
|
||||||
u32 temp = f.Tell();
|
|
||||||
f.WriteWord(0); // size of symbol table
|
|
||||||
|
|
||||||
// Write program
|
// Write program
|
||||||
//for (u32 p : g_outputBuf)
|
|
||||||
for (outputBufIter it = g_outputBuf.begin(); it != g_outputBuf.end(); ++it)
|
for (outputBufIter it = g_outputBuf.begin(); it != g_outputBuf.end(); ++it)
|
||||||
f.WriteWord(*it);
|
f.WriteWord(*it);
|
||||||
|
|
||||||
@ -134,53 +124,77 @@ int main(int argc, char* argv[])
|
|||||||
for (int i = 0; i < g_opdescCount; i ++)
|
for (int i = 0; i < g_opdescCount; i ++)
|
||||||
f.WriteDword(g_opdescTable[i]);
|
f.WriteDword(g_opdescTable[i]);
|
||||||
|
|
||||||
// Write constants
|
// Write DVLEs
|
||||||
for (int i = 0; i < g_constantCount; i ++)
|
for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end(); ++dvle)
|
||||||
{
|
{
|
||||||
Constant& ct = g_constantTable[i];
|
if (dvle->nodvle) continue;
|
||||||
f.WriteHword(ct.type);
|
curOff = 16*4;
|
||||||
if (ct.type == UTYPE_FVEC)
|
|
||||||
|
f.WriteWord(0x454C5644); // DVLE
|
||||||
|
f.WriteHword(0); // padding?
|
||||||
|
f.WriteHword(dvle->isGeoShader ? 1 : 0); // Shader type
|
||||||
|
f.WriteWord(dvle->entryStart); // offset to main
|
||||||
|
f.WriteWord(dvle->entryEnd); // offset to end of main
|
||||||
|
f.WriteWord(0); // ???
|
||||||
|
f.WriteWord(0); // ???
|
||||||
|
f.WriteWord(curOff); // offset to constant table
|
||||||
|
f.WriteWord(dvle->constantCount); // size of constant table
|
||||||
|
curOff += dvle->constantSize;
|
||||||
|
f.WriteWord(curOff); // offset to label table (TODO)
|
||||||
|
f.WriteWord(0); // size of label table (TODO)
|
||||||
|
f.WriteWord(curOff); // offset to output table
|
||||||
|
f.WriteWord(dvle->outputCount); // size of output table
|
||||||
|
curOff += dvle->outputCount*8;
|
||||||
|
f.WriteWord(curOff); // offset to uniform table
|
||||||
|
f.WriteWord(dvle->uniformCount); // size of uniform table
|
||||||
|
curOff += dvle->uniformCount*8;
|
||||||
|
f.WriteWord(curOff); // offset to symbol table
|
||||||
|
u32 temp = f.Tell();
|
||||||
|
f.WriteWord(dvle->symbolSize); // size of symbol table
|
||||||
|
|
||||||
|
// Write constants
|
||||||
|
for (int i = 0; i < dvle->constantCount; i ++)
|
||||||
{
|
{
|
||||||
f.WriteHword(ct.regId-0x20);
|
Constant& ct = dvle->constantTable[i];
|
||||||
for (int j = 0; j < 4; j ++)
|
f.WriteHword(ct.type);
|
||||||
f.WriteWord(f32tof24(ct.fparam[j]));
|
if (ct.type == UTYPE_FVEC)
|
||||||
} else if (ct.type == UTYPE_IVEC)
|
{
|
||||||
|
f.WriteHword(ct.regId-0x20);
|
||||||
|
for (int j = 0; j < 4; j ++)
|
||||||
|
f.WriteWord(f32tof24(ct.fparam[j]));
|
||||||
|
} else if (ct.type == UTYPE_IVEC)
|
||||||
|
{
|
||||||
|
f.WriteHword(ct.regId-0x80);
|
||||||
|
for (int j = 0; j < 4; j ++)
|
||||||
|
f.WriteByte(ct.iparam[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write outputs
|
||||||
|
for (int i = 0; i < dvle->outputCount; i ++)
|
||||||
|
f.WriteDword(dvle->outputTable[i]);
|
||||||
|
|
||||||
|
// Write uniforms
|
||||||
|
size_t sp = 0;
|
||||||
|
for (int i = 0; i < dvle->uniformCount; i ++)
|
||||||
{
|
{
|
||||||
f.WriteHword(ct.regId-0x80);
|
Uniform& u = dvle->uniformTable[i];
|
||||||
for (int j = 0; j < 4; j ++)
|
size_t l = u.name.length()+1;
|
||||||
f.WriteByte(ct.iparam[j]);
|
f.WriteWord(sp); sp += l;
|
||||||
|
f.WriteHword(u.pos-0x10);
|
||||||
|
f.WriteHword(u.pos+u.size-1-0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write symbols
|
||||||
|
for (int i = 0; i < dvle->uniformCount; i ++)
|
||||||
|
{
|
||||||
|
std::string& u = dvle->uniformTable[i].name;
|
||||||
|
size_t l = u.length()+1;
|
||||||
|
f.WriteRaw(u.c_str(), l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write outputs
|
#if 0
|
||||||
for (int i = 0; i < g_outputCount; i ++)
|
|
||||||
f.WriteDword(g_outputTable[i]);
|
|
||||||
|
|
||||||
// Write uniforms
|
|
||||||
size_t sp = 0;
|
|
||||||
for (int i = 0; i < g_uniformCount; i ++)
|
|
||||||
{
|
|
||||||
Uniform& u = g_uniformTable[i];
|
|
||||||
size_t l = u.name.length()+1;
|
|
||||||
f.WriteWord(sp); sp += l;
|
|
||||||
f.WriteHword(u.pos-0x10);
|
|
||||||
f.WriteHword(u.pos+u.size-1-0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write size of symbol table
|
|
||||||
u32 temp2 = f.Tell();
|
|
||||||
f.Seek(temp, SEEK_SET);
|
|
||||||
f.WriteWord(sp);
|
|
||||||
f.Seek(temp2, SEEK_SET);
|
|
||||||
|
|
||||||
// Write symbols
|
|
||||||
for (int i = 0; i < g_uniformCount; i ++)
|
|
||||||
{
|
|
||||||
std::string& u = g_uniformTable[i].name;
|
|
||||||
size_t l = u.length()+1;
|
|
||||||
f.WriteRaw(u.c_str(), l);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hFile)
|
if (hFile)
|
||||||
{
|
{
|
||||||
FILE* f2 = fopen(hFile, "w");
|
FILE* f2 = fopen(hFile, "w");
|
||||||
@ -213,6 +227,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
fclose(f2);
|
fclose(f2);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user