/*
**  LLVM code generated drawers
**  Copyright (c) 2016 Magnus Norddahl
**
**  This software is provided 'as-is', without any express or implied
**  warranty.  In no event will the authors be held liable for any damages
**  arising from the use of this software.
**
**  Permission is granted to anyone to use this software for any purpose,
**  including commercial applications, and to alter it and redistribute it
**  freely, subject to the following restrictions:
**
**  1. The origin of this software must not be misrepresented; you must not
**     claim that you wrote the original software. If you use this software
**     in a product, an acknowledgment in the product documentation would be
**     appreciated but is not required.
**  2. Altered source versions must be plainly marked as such, and must not be
**     misrepresented as being the original software.
**  3. This notice may not be removed or altered from any source distribution.
**
*/

#include "precomp.h"
#include "timestamp.h"
#include "llvmdrawers.h"
#include "exception.h"

LLVMDrawers::LLVMDrawers(const std::string &triple, const std::string &cpuName, const std::string &features, const std::string namePostfix) : mNamePostfix(namePostfix)
{
	mProgram.CreateModule();

	CodegenDrawColumn("FillColumn", DrawColumnVariant::Fill);
	CodegenDrawColumn("FillColumnAdd", DrawColumnVariant::FillAdd);
	CodegenDrawColumn("FillColumnAddClamp", DrawColumnVariant::FillAddClamp);
	CodegenDrawColumn("FillColumnSubClamp", DrawColumnVariant::FillSubClamp);
	CodegenDrawColumn("FillColumnRevSubClamp", DrawColumnVariant::FillRevSubClamp);
	CodegenDrawColumn("DrawColumn", DrawColumnVariant::Draw);
	CodegenDrawColumn("DrawColumnAdd", DrawColumnVariant::DrawAdd);
	CodegenDrawColumn("DrawColumnShaded", DrawColumnVariant::DrawShaded);
	CodegenDrawColumn("DrawColumnAddClamp", DrawColumnVariant::DrawAddClamp);
	CodegenDrawColumn("DrawColumnSubClamp", DrawColumnVariant::DrawSubClamp);
	CodegenDrawColumn("DrawColumnRevSubClamp", DrawColumnVariant::DrawRevSubClamp);
	CodegenDrawColumn("DrawColumnTranslated", DrawColumnVariant::DrawTranslated);
	CodegenDrawColumn("DrawColumnTlatedAdd", DrawColumnVariant::DrawTlatedAdd);
	CodegenDrawColumn("DrawColumnAddClampTranslated", DrawColumnVariant::DrawAddClampTranslated);
	CodegenDrawColumn("DrawColumnSubClampTranslated", DrawColumnVariant::DrawSubClampTranslated);
	CodegenDrawColumn("DrawColumnRevSubClampTranslated", DrawColumnVariant::DrawRevSubClampTranslated);
	CodegenDrawSpan("DrawSpan", DrawSpanVariant::Opaque);
	CodegenDrawSpan("DrawSpanMasked", DrawSpanVariant::Masked);
	CodegenDrawSpan("DrawSpanTranslucent", DrawSpanVariant::Translucent);
	CodegenDrawSpan("DrawSpanMaskedTranslucent", DrawSpanVariant::MaskedTranslucent);
	CodegenDrawSpan("DrawSpanAddClamp", DrawSpanVariant::AddClamp);
	CodegenDrawSpan("DrawSpanMaskedAddClamp", DrawSpanVariant::MaskedAddClamp);
	CodegenDrawWall("vlinec1", DrawWallVariant::Opaque);
	CodegenDrawWall("mvlinec1", DrawWallVariant::Masked);
	CodegenDrawWall("tmvline1_add", DrawWallVariant::Add);
	CodegenDrawWall("tmvline1_addclamp", DrawWallVariant::AddClamp);
	CodegenDrawWall("tmvline1_subclamp", DrawWallVariant::SubClamp);
	CodegenDrawWall("tmvline1_revsubclamp", DrawWallVariant::RevSubClamp);
	CodegenDrawSky("DrawSky1", DrawSkyVariant::Single);
	CodegenDrawSky("DrawDoubleSky1", DrawSkyVariant::Double);
	for (int i = 0; i < NumTriBlendModes(); i++)
	{
		CodegenDrawTriangle("TriDraw8_" + std::to_string(i), (TriBlendMode)i, false, false);
		CodegenDrawTriangle("TriDraw32_" + std::to_string(i), (TriBlendMode)i, true, false);
		CodegenDrawTriangle("TriFill8_" + std::to_string(i), (TriBlendMode)i, false, true);
		CodegenDrawTriangle("TriFill32_" + std::to_string(i), (TriBlendMode)i, true, true);
	}

	ObjectFile = mProgram.GenerateObjectFile(triple, cpuName, features);
}

void LLVMDrawers::CodegenDrawColumn(const char *name, DrawColumnVariant variant)
{
	llvm::IRBuilder<> builder(mProgram.context());
	SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder);

	SSAFunction function(name + mNamePostfix);
	function.add_parameter(GetDrawColumnArgsStruct(mProgram.context()));
	function.add_parameter(GetWorkerThreadDataStruct(mProgram.context()));
	function.create_public();

	DrawColumnCodegen codegen;
	codegen.Generate(variant, function.parameter(0), function.parameter(1));

	builder.CreateRetVoid();

	if (llvm::verifyFunction(*function.func))
		throw Exception("verifyFunction failed for CodegenDrawColumn()");
}

void LLVMDrawers::CodegenDrawSpan(const char *name, DrawSpanVariant variant)
{
	llvm::IRBuilder<> builder(mProgram.context());
	SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder);

	SSAFunction function(name + mNamePostfix);
	function.add_parameter(GetDrawSpanArgsStruct(mProgram.context()));
	function.create_public();

	DrawSpanCodegen codegen;
	codegen.Generate(variant, function.parameter(0));

	builder.CreateRetVoid();

	if (llvm::verifyFunction(*function.func))
		throw Exception("verifyFunction failed for CodegenDrawSpan()");
}

void LLVMDrawers::CodegenDrawWall(const char *name, DrawWallVariant variant)
{
	llvm::IRBuilder<> builder(mProgram.context());
	SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder);

	SSAFunction function(name + mNamePostfix);
	function.add_parameter(GetDrawWallArgsStruct(mProgram.context()));
	function.add_parameter(GetWorkerThreadDataStruct(mProgram.context()));
	function.create_public();

	DrawWallCodegen codegen;
	codegen.Generate(variant, function.parameter(0), function.parameter(1));

	builder.CreateRetVoid();

	if (llvm::verifyFunction(*function.func))
		throw Exception("verifyFunction failed for CodegenDrawWall()");
}

void LLVMDrawers::CodegenDrawSky(const char *name, DrawSkyVariant variant)
{
	llvm::IRBuilder<> builder(mProgram.context());
	SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder);

	SSAFunction function(name + mNamePostfix);
	function.add_parameter(GetDrawSkyArgsStruct(mProgram.context()));
	function.add_parameter(GetWorkerThreadDataStruct(mProgram.context()));
	function.create_public();

	DrawSkyCodegen codegen;
	codegen.Generate(variant, function.parameter(0), function.parameter(1));

	builder.CreateRetVoid();

	if (llvm::verifyFunction(*function.func))
		throw Exception("verifyFunction failed for CodegenDrawSky()");
}

void LLVMDrawers::CodegenDrawTriangle(const std::string &name, TriBlendMode blendmode, bool truecolor, bool colorfill)
{
	llvm::IRBuilder<> builder(mProgram.context());
	SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder);

	SSAFunction function(name + mNamePostfix);
	function.add_parameter(GetTriDrawTriangleArgs(mProgram.context()));
	function.add_parameter(GetWorkerThreadDataStruct(mProgram.context()));
	function.create_public();

	DrawTriangleCodegen codegen;
	codegen.Generate(blendmode, truecolor, colorfill, function.parameter(0), function.parameter(1));

	builder.CreateRetVoid();

	if (llvm::verifyFunction(*function.func))
		throw Exception("verifyFunction failed for CodegenDrawTriangle()");
}

llvm::Type *LLVMDrawers::GetDrawColumnArgsStruct(llvm::LLVMContext &context)
{
	if (DrawColumnArgsStruct)
		return DrawColumnArgsStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // uint32_t *dest;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // const uint32_t *source;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // const uint32_t *source2;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // uint8_t *colormap;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // uint8_t *translation;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // const uint32_t *basecolors;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t pitch;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t count;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t dest_y;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t iscale;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t texturefracx;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t textureheight;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t texturefrac;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t light;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t color;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t srccolor;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t srcalpha;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t destalpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t desaturate;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t flags;
	DrawColumnArgsStruct = llvm::StructType::create(context, elements, "DrawColumnArgs", false)->getPointerTo();
	return DrawColumnArgsStruct;
}

llvm::Type *LLVMDrawers::GetDrawSpanArgsStruct(llvm::LLVMContext &context)
{
	if (DrawSpanArgsStruct)
		return DrawSpanArgsStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // uint8_t *destorg;
	elements.push_back(llvm::Type::getInt8PtrTy(context)); // const uint32_t *source;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t destpitch;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xfrac;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t yfrac;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xstep;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t ystep;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t x1;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t x2;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t y;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xbits;
	elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t ybits;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t light;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t srcalpha;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t destalpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t desaturate;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t flags;
	elements.push_back(llvm::Type::getFloatTy(context)); // float viewpos_x;
	elements.push_back(llvm::Type::getFloatTy(context)); // float step_viewpos_x;
	elements.push_back(GetTriLightStruct(context));      // TriLight *dynlights;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t num_dynlights;
	DrawSpanArgsStruct = llvm::StructType::create(context, elements, "DrawSpanArgs", false)->getPointerTo();
	return DrawSpanArgsStruct;
}

llvm::Type *LLVMDrawers::GetDrawWallArgsStruct(llvm::LLVMContext &context)
{
	if (DrawWallArgsStruct)
		return DrawWallArgsStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt8PtrTy(context));
	for (int i = 0; i < 8; i++)
		elements.push_back(llvm::Type::getInt8PtrTy(context));
	for (int i = 0; i < 25; i++)
		elements.push_back(llvm::Type::getInt32Ty(context));
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t desaturate;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t flags;
	elements.push_back(llvm::Type::getFloatTy(context)); // float z;
	elements.push_back(llvm::Type::getFloatTy(context)); // float step_z;
	elements.push_back(GetTriLightStruct(context));      // TriLight *dynlights;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t num_dynlights;

	DrawWallArgsStruct = llvm::StructType::create(context, elements, "DrawWallArgs", false)->getPointerTo();
	return DrawWallArgsStruct;
}

llvm::Type *LLVMDrawers::GetDrawSkyArgsStruct(llvm::LLVMContext &context)
{
	if (DrawSkyArgsStruct)
		return DrawSkyArgsStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt8PtrTy(context));
	for (int i = 0; i < 8; i++)
		elements.push_back(llvm::Type::getInt8PtrTy(context));
	for (int i = 0; i < 15; i++)
		elements.push_back(llvm::Type::getInt32Ty(context));
	DrawSkyArgsStruct = llvm::StructType::create(context, elements, "DrawSkyArgs", false)->getPointerTo();
	return DrawSkyArgsStruct;
}

llvm::Type *LLVMDrawers::GetWorkerThreadDataStruct(llvm::LLVMContext &context)
{
	if (WorkerThreadDataStruct)
		return WorkerThreadDataStruct;

	std::vector<llvm::Type *> elements;
	for (int i = 0; i < 4; i++)
		elements.push_back(llvm::Type::getInt32Ty(context));
	elements.push_back(llvm::Type::getInt8PtrTy(context));
	elements.push_back(GetTriFullSpanStruct(context));
	elements.push_back(GetTriPartialBlockStruct(context));
	for (int i = 0; i < 4; i++)
		elements.push_back(llvm::Type::getInt32Ty(context));
	WorkerThreadDataStruct = llvm::StructType::create(context, elements, "ThreadData", false)->getPointerTo();
	return WorkerThreadDataStruct;
}

llvm::Type *LLVMDrawers::GetTriLightStruct(llvm::LLVMContext &context)
{
	if (TriLightStruct)
		return TriLightStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt32Ty(context));
	for (int i = 0; i < 4; i++)
		elements.push_back(llvm::Type::getFloatTy(context));
	TriLightStruct = llvm::StructType::create(context, elements, "TriLight", false)->getPointerTo();
	return TriLightStruct;
}

llvm::Type *LLVMDrawers::GetTriVertexStruct(llvm::LLVMContext &context)
{
	if (TriVertexStruct)
		return TriVertexStruct;

	std::vector<llvm::Type *> elements;
	for (int i = 0; i < 4 + TriVertex::NumVarying; i++)
		elements.push_back(llvm::Type::getFloatTy(context));
	TriVertexStruct = llvm::StructType::create(context, elements, "TriVertex", false)->getPointerTo();
	return TriVertexStruct;
}

llvm::Type *LLVMDrawers::GetTriMatrixStruct(llvm::LLVMContext &context)
{
	if (TriMatrixStruct)
		return TriMatrixStruct;

	std::vector<llvm::Type *> elements;
	for (int i = 0; i < 4 * 4; i++)
		elements.push_back(llvm::Type::getFloatTy(context));
	TriMatrixStruct = llvm::StructType::create(context, elements, "TriMatrix", false)->getPointerTo();
	return TriMatrixStruct;
}

llvm::Type *LLVMDrawers::GetTriUniformsStruct(llvm::LLVMContext &context)
{
	if (TriUniformsStruct)
		return TriUniformsStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t light;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t subsectorDepth;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t color;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t srcalpha;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t destalpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_alpha;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_red;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_green;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_blue;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t desaturate;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t flags;
	elements.push_back(GetTriMatrixStruct(context));     // TriMatrix objectToClip
	TriUniformsStruct = llvm::StructType::create(context, elements, "TriUniforms", false)->getPointerTo();
	return TriUniformsStruct;
}

llvm::Type *LLVMDrawers::GetTriFullSpanStruct(llvm::LLVMContext &context)
{
	if (TriFullSpanStruct)
		return TriFullSpanStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint32_t X;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint32_t Y;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t Length;
	TriFullSpanStruct = llvm::StructType::create(context, elements, "TriFullSpan", false)->getPointerTo();
	return TriFullSpanStruct;
}

llvm::Type *LLVMDrawers::GetTriPartialBlockStruct(llvm::LLVMContext &context)
{
	if (TriPartialBlockStruct)
		return TriPartialBlockStruct;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint32_t X;
	elements.push_back(llvm::Type::getInt16Ty(context)); // uint32_t Y;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t Mask0;
	elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t Mask1;
	TriPartialBlockStruct = llvm::StructType::create(context, elements, "TriPartialBlock", false)->getPointerTo();
	return TriPartialBlockStruct;
}

llvm::Type *LLVMDrawers::GetTriDrawTriangleArgs(llvm::LLVMContext &context)
{
	if (TriDrawTriangleArgs)
		return TriDrawTriangleArgs;

	std::vector<llvm::Type *> elements;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // uint8_t *dest;
	elements.push_back(llvm::Type::getInt32Ty(context));    // int32_t pitch;
	elements.push_back(GetTriVertexStruct(context)); // TriVertex *v1;
	elements.push_back(GetTriVertexStruct(context)); // TriVertex *v2;
	elements.push_back(GetTriVertexStruct(context)); // TriVertex *v3;
	elements.push_back(llvm::Type::getInt32Ty(context));    // int32_t clipleft;
	elements.push_back(llvm::Type::getInt32Ty(context));    // int32_t clipright;
	elements.push_back(llvm::Type::getInt32Ty(context));    // int32_t cliptop;
	elements.push_back(llvm::Type::getInt32Ty(context));    // int32_t clipbottom;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // const uint8_t *texturePixels;
	elements.push_back(llvm::Type::getInt32Ty(context));    // uint32_t textureWidth;
	elements.push_back(llvm::Type::getInt32Ty(context));    // uint32_t textureHeight;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // const uint8_t *translation;
	elements.push_back(GetTriUniformsStruct(context)); // const TriUniforms *uniforms;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // uint8_t *stencilValues;
	elements.push_back(llvm::Type::getInt32PtrTy(context)); // uint32_t *stencilMasks;
	elements.push_back(llvm::Type::getInt32Ty(context));    // int32_t stencilPitch;
	elements.push_back(llvm::Type::getInt8Ty(context));     // uint8_t stencilTestValue;
	elements.push_back(llvm::Type::getInt8Ty(context));     // uint8_t stencilWriteValue;
	elements.push_back(llvm::Type::getInt32PtrTy(context)); // uint32_t *subsectorGBuffer;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // const uint8_t *colormaps;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // const uint8_t *RGB256k;
	elements.push_back(llvm::Type::getInt8PtrTy(context));  // const uint8_t *BaseColors;
	TriDrawTriangleArgs = llvm::StructType::create(context, elements, "TriDrawTriangle", false)->getPointerTo();
	return TriDrawTriangleArgs;
}