softrend: Resembling a pixel pipeline, textures, sort, cull

- Basic pixel pipeline, a bit better triangle tests, specialized render handlers
- Textures w/ point filtering. Not very smart is it goes 32 -> 16 -> 32 bpp, but works.
- The texture cache is shared rather inelegantly w/ OpenGL one
- Culling
- PParam sorting (shared w/ GL)

The texturing and color blending paths are ugly and slow
This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2015-08-05 17:02:34 +02:00 committed by TwistedUmbrella
parent fcf273dd11
commit e6a9d3e661
4 changed files with 923 additions and 551 deletions

View File

@ -419,7 +419,7 @@ union FPU_SHAD_SCALE_type
#define FPU_SHAD_SCALE PvrReg(FPU_SHAD_SCALE_addr,FPU_SHAD_SCALE_type) // RW Intensity Volume mode
#define FPU_CULL_VAL PvrReg(FPU_CULL_VAL_addr,u32) // RW Comparison value for culling
#define FPU_CULL_VAL PvrReg(FPU_CULL_VAL_addr,f32) // RW Comparison value for culling
#define FPU_PARAM_CFG PvrReg(FPU_PARAM_CFG_addr,u32) // RW Parameter read control
#define HALF_OFFSET PvrReg(HALF_OFFSET_addr,u32) // RW Pixel sampling control
#define FPU_PERP_VAL PvrReg(FPU_PERP_VAL_addr,u32) // RW Comparison value for perpendicular polygons

View File

@ -100,8 +100,17 @@ struct gl_ctx
extern gl_ctx gl;
GLuint gl_GetTexture(TSP tsp,TCW tcw);
struct text_info {
u16* pdata;
u32 width;
u32 height;
u32 textype; // 0 565, 1 1555, 2 4444
};
text_info raw_GetTexture(TSP tsp, TCW tcw);
void CollectCleanup();
void DoCleanup();
void SortPParams();
void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt);
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,

View File

@ -69,6 +69,8 @@ struct TextureCacheData
TCW tcw;
GLuint texID; //gl texture
u16* pData;
int tex_type;
u32 Lookups;
@ -122,10 +124,18 @@ struct TextureCacheData
}
//Create GL texture from tsp/tcw
void Create()
void Create(bool isGL)
{
//ask GL for texture ID
if (isGL) {
glGenTextures(1, &texID);
}
else {
texID = 0;
}
pData = 0;
tex_type = 0;
//Reset state info ..
Lookups=0;
@ -141,6 +151,7 @@ struct TextureCacheData
w=8<<tsp.TexU; //tex width
h=8<<tsp.TexV; //tex height
if (texID) {
//bind texture to set modes
glBindTexture(GL_TEXTURE_2D, texID);
@ -166,6 +177,7 @@ struct TextureCacheData
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, (tcw.MipMapped && settings.rend.UseMipmaps)?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
}
//PAL texture
if (tex->bpp==4)
@ -286,21 +298,43 @@ struct TextureCacheData
//lock the texture to detect changes in it
lock_block = libCore_vramlock_Lock(sa_tex,sa+size-1,this);
if (texID) {
//upload to OpenGL !
glBindTexture(GL_TEXTURE_2D, texID);
GLuint comps=textype==GL_UNSIGNED_SHORT_5_6_5?GL_RGB:GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0,comps , w, h, 0, comps, textype, temp_tex_buffer);
if (tcw.MipMapped && settings.rend.UseMipmaps)
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
if (textype == GL_UNSIGNED_SHORT_5_6_5)
tex_type = 0;
else if (textype == GL_UNSIGNED_SHORT_5_5_5_1)
tex_type = 1;
else if (textype == GL_UNSIGNED_SHORT_4_4_4_4)
tex_type = 2;
if (pData) {
free(pData);
}
pData = (u16*)malloc(w * h * 2);
memcpy(pData, temp_tex_buffer, w * h * 2);
}
}
//true if : dirty or paletted texture and revs don't match
bool NeedsUpdate() { return (dirty) || (pal_table_rev!=0 && *pal_table_rev!=pal_local_rev); }
void Delete()
{
if (pData) {
free(pData);
pData = 0;
}
if (texID) {
glDeleteTextures(1, &texID);
}
if (lock_block)
libCore_vramlock_Unlock_block(lock_block);
lock_block=0;
@ -414,7 +448,7 @@ GLuint gl_GetTexture(TSP tsp, TCW tcw)
tf->tsp=tsp;
tf->tcw=tcw;
tf->Create();
tf->Create(true);
}
//update if needed
@ -428,6 +462,52 @@ GLuint gl_GetTexture(TSP tsp, TCW tcw)
return tf->texID;
}
text_info raw_GetTexture(TSP tsp, TCW tcw)
{
text_info rv = { 0 };
//lookup texture
TextureCacheData* tf;
//= TexCache.Find(tcw.full,tsp.full);
u64 key = ((u64)tcw.full << 32) | tsp.full;
TexCacheIter tx = TexCache.find(key);
if (tx != TexCache.end())
{
tf = &tx->second;
}
else //create if not existing
{
TextureCacheData tfc = { 0 };
TexCache[key] = tfc;
tx = TexCache.find(key);
tf = &tx->second;
tf->tsp = tsp;
tf->tcw = tcw;
tf->Create(false);
}
//update if needed
if (tf->NeedsUpdate())
tf->Update();
//update state for opts/stuff
tf->Lookups++;
//return gl texture
rv.height = tf->h;
rv.width = tf->w;
rv.pdata = tf->pData;
rv.textype = tf->tex_type;
return rv;
}
void CollectCleanup() {
vector<u64> list;

View File

@ -19,21 +19,9 @@
BITMAPINFOHEADER bi = { sizeof(BITMAPINFOHEADER), 0, 0, 1, 32, BI_RGB };
struct softrend : Renderer
{
virtual bool Process(TA_context* ctx) {
//disable RTTs for now ..
if (ctx->rend.isRTT)
return false;
#include "rend/gles/gles.h"
ctx->rend_inuse.Lock();
ctx->MarkRend();
if (!ta_parse_vdrc(ctx))
return false;
return true;
}
u32 decoded_colors[3][65536];
DECL_ALIGN(32) u32 render_buffer[640 * 480 * 2 * 4]; //Color + depth
DECL_ALIGN(32) u32 pixels[640 * 480 * 4];
@ -203,12 +191,18 @@ struct softrend : Renderer
PlaneStepper ZUV;
PlaneStepper Col;
void Setup(const Vertex &v1, const Vertex &v2, const Vertex &v3, int minx, int miny, int q)
void Setup(PolyParam* pp, text_info* texture, const Vertex &v1, const Vertex &v2, const Vertex &v3, int minx, int miny, int q)
{
u32 w = 0, h = 0;
if (texture) {
w = texture->width;
h = texture->height;
}
ZUV.Setup(v1, v2, v3, minx, miny, q,
v1.z, v2.z, v3.z,
v1.u, v2.u, v3.u,
v1.v, v2.v, v3.v,
v1.u * w, v2.u * w, v3.u * w,
v1.v * h, v2.v * h, v3.v * h,
0, -1, 1);
Col.Setup(v1, v2, v3, minx, miny, q,
@ -223,10 +217,26 @@ struct softrend : Renderer
IPs __declspec(align(64)) ip;
#define TPL_DECL_pixel template<bool useoldmsk, bool alpha_blend, bool pp_UseAlpha, bool pp_Texture, bool pp_IgnoreTexA, int pp_ShadInstr, bool pp_Offset >
#define TPL_DECL_triangle template<bool alpha_blend, bool pp_UseAlpha, bool pp_Texture, bool pp_IgnoreTexA, int pp_ShadInstr, bool pp_Offset >
#define TPL_PRMS_pixel(useoldmsk) <useoldmsk, alpha_blend, pp_UseAlpha, pp_Texture, pp_IgnoreTexA, pp_ShadInstr, pp_Offset >
#define TPL_PRMS_triangle <alpha_blend, pp_UseAlpha, pp_Texture, pp_IgnoreTexA, pp_ShadInstr, pp_Offset >
template<bool useoldmsk, bool alpha_blend>
__forceinline void PixelFlush(__m128 x, __m128 y, u8* cb, __m128 oldmask)
//<alpha_blend, pp_UseAlpha, pp_Texture, pp_IgnoreTexA, pp_ShadInstr, pp_Offset >
typedef void(*RendtriangleFn)(PolyParam* pp, int vertex_offset, const Vertex &v1, const Vertex &v2, const Vertex &v3, u32* colorBuffer);
RendtriangleFn RendtriangleFns[2][2][2][2][4][2];
__m128i const_setAlpha = { 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000 };
__m128i shuffle_alpha = {
0x0E, 0x80, 0x0E, 0x80, 0x0E, 0x80, 0x0E, 0x80,
0x06, 0x80, 0x06, 0x80, 0x06, 0x80, 0x06, 0x80
};
TPL_DECL_pixel
static void PixelFlush(PolyParam* pp, text_info* texture, __m128 x, __m128 y, u8* cb, __m128 oldmask)
{
x = _mm_shuffle_ps(x, x, 0);
__m128 invW = ip.ZUV.Ip(x, y);
@ -259,19 +269,121 @@ struct softrend : Renderer
__m128 c = ip.Col.InStep(b);
__m128 d = ip.Col.InStep(c);
__m128i ui = _mm_cvttps_epi32(u);
__m128i vi = _mm_cvttps_epi32(v);
//(int)v<<x+(int)u
__m128i textadr = _mm_add_epi32(_mm_slli_epi32(vi, 8), ui);//texture addresses ! 4x of em !
//we need :
__m128i ab = _mm_packs_epi32(_mm_cvttps_epi32(a), _mm_cvttps_epi32(b));
__m128i cd = _mm_packs_epi32(_mm_cvttps_epi32(c), _mm_cvttps_epi32(d));
rv = _mm_packus_epi16(ab, cd);
//rv = _mm_xor_si128(rv,textadr);
if (!pp_UseAlpha) {
rv = _mm_or_si128(rv, const_setAlpha);
}
if (pp_Texture) {
__m128i ui = _mm_cvttps_epi32(u);
__m128i vi = _mm_cvttps_epi32(v);
//(int)v<<x+(int)u
__m128i textadr = _mm_add_epi32(_mm_slli_epi32(vi, 16), ui);//texture addresses ! 4x of em !
__m128i textel;
for (int i = 0; i < 4; i++) {
u32 u = textadr.m128i_i16[i * 2 + 0];
u32 v = textadr.m128i_i16[i * 2 + 1];
u32 textel_size = 2;
u %= texture->width;
v %= texture->height;
u32 pixel = decoded_colors[texture->textype][texture->pdata[(u + v * texture->width)]];
textel.m128i_i32[i] = pixel;
}
if (pp_IgnoreTexA) {
textel = _mm_or_si128(textel, const_setAlpha);
}
if (pp_ShadInstr == 0){
//color.rgb = texcol.rgb;
//color.a = texcol.a;
rv = textel;
}
else if (pp_ShadInstr == 1) {
//color.rgb *= texcol.rgb;
//color.a = texcol.a;
//color.a = 1
rv = _mm_or_si128(rv, const_setAlpha);
//color *= texcol
__m128i lo_rv = _mm_cvtepu8_epi16(rv);
__m128i hi_rv = _mm_cvtepu8_epi16(_mm_shuffle_epi32(rv, _MM_SHUFFLE(1, 0, 3, 2)));
__m128i lo_fb = _mm_cvtepu8_epi16(textel);
__m128i hi_fb = _mm_cvtepu8_epi16(_mm_shuffle_epi32(textel, _MM_SHUFFLE(1, 0, 3, 2)));
lo_rv = _mm_mullo_epi16(lo_rv, lo_fb);
hi_rv = _mm_mullo_epi16(hi_rv, hi_fb);
rv = _mm_packus_epi16(_mm_srli_epi16(lo_rv, 8), _mm_srli_epi16(hi_rv, 8));
}
else if (pp_ShadInstr == 2) {
//color.rgb=mix(color.rgb,texcol.rgb,texcol.a);
// a bit wrong atm, as it also mixes alphas
__m128i lo_rv = _mm_cvtepu8_epi16(rv);
__m128i hi_rv = _mm_cvtepu8_epi16(_mm_shuffle_epi32(rv, _MM_SHUFFLE(1, 0, 3, 2)));
__m128i lo_fb = _mm_cvtepu8_epi16(textel);
__m128i hi_fb = _mm_cvtepu8_epi16(_mm_shuffle_epi32(textel, _MM_SHUFFLE(1, 0, 3, 2)));
__m128i lo_rv_alpha = _mm_shuffle_epi8(lo_fb, shuffle_alpha);
__m128i hi_rv_alpha = _mm_shuffle_epi8(hi_fb, shuffle_alpha);
__m128i lo_fb_alpha = _mm_sub_epi16(_mm_set1_epi16(255), lo_rv_alpha);
__m128i hi_fb_alpha = _mm_sub_epi16(_mm_set1_epi16(255), hi_rv_alpha);
lo_rv = _mm_mullo_epi16(lo_rv, lo_rv_alpha);
hi_rv = _mm_mullo_epi16(hi_rv, hi_rv_alpha);
lo_fb = _mm_mullo_epi16(lo_fb, lo_fb_alpha);
hi_fb = _mm_mullo_epi16(hi_fb, hi_fb_alpha);
rv = _mm_packus_epi16(_mm_srli_epi16(_mm_adds_epu16(lo_rv, lo_fb), 8), _mm_srli_epi16(_mm_adds_epu16(hi_rv, hi_fb), 8));
}
else if (pp_ShadInstr == 3) {
//color*=texcol
__m128i lo_rv = _mm_cvtepu8_epi16(rv);
__m128i hi_rv = _mm_cvtepu8_epi16(_mm_shuffle_epi32(rv, _MM_SHUFFLE(1, 0, 3, 2)));
__m128i lo_fb = _mm_cvtepu8_epi16(textel);
__m128i hi_fb = _mm_cvtepu8_epi16(_mm_shuffle_epi32(textel, _MM_SHUFFLE(1, 0, 3, 2)));
lo_rv = _mm_mullo_epi16(lo_rv, lo_fb);
hi_rv = _mm_mullo_epi16(hi_rv, hi_fb);
rv = _mm_packus_epi16(_mm_srli_epi16(lo_rv, 8), _mm_srli_epi16(hi_rv, 8));
}
if (pp_Offset) {
//add offset
}
//textadr = _mm_add_epi32(textadr, _mm_setr_epi32(tex_addr, tex_addr, tex_addr, tex_addr));
//rv = textel; // _mm_xor_si128(rv, textadr);
}
}
//__m128i rv=ip.col;//_mm_xor_si128(_mm_cvtps_epi32(_mm_mul_ps(x,Z.c)),_mm_cvtps_epi32(y));
@ -287,10 +399,6 @@ struct softrend : Renderer
}
}
#else
static __m128i shuffle_alpha = {
0x0E, 0x80, 0x0E, 0x80, 0x0E, 0x80, 0x0E, 0x80,
0x06, 0x80, 0x06, 0x80, 0x06, 0x80, 0x06, 0x80
};
__m128i lo_rv = _mm_cvtepu8_epi16(rv);
@ -329,10 +437,17 @@ struct softrend : Renderer
*zb = invW;
*(__m128i*)cb = rv;
}
//u32 nok,fok;
template <bool alpha_blend>
void Rendtriangle(PolyParam* pp, int vertex_offset, const Vertex &v1, const Vertex &v2, const Vertex &v3, u32* colorBuffer)
TPL_DECL_triangle
static void Rendtriangle(PolyParam* pp, int vertex_offset, const Vertex &v1, const Vertex &v2, const Vertex &v3, u32* colorBuffer)
{
text_info texture = { 0 };
if (pp_Texture) {
texture = raw_GetTexture(pp->tsp, pp->tcw);
}
const int stride = 640 * 4;
//Plane equation
@ -449,7 +564,7 @@ struct softrend : Renderer
u8* cb_y = (u8*)colorBuffer;
cb_y += miny*stride + minx*(q * 4);
ip.Setup(v1, v2, v3, minx, miny, q);
ip.Setup(pp, &texture, v1, v2, v3, minx, miny, q);
__m128 y_ps = _mm_broadcast_float(miny);
__m128 minx_ps = _mm_load_scaled_float(minx - q, 1);
static __declspec(align(16)) float ones_ps[4] = { 1, 1, 1, 1 };
@ -488,7 +603,7 @@ struct softrend : Renderer
__m128 yl_ps = y_ps;
for (int iy = q; iy > 0; iy--)
{
PixelFlush<false, alpha_blend>(x_ps, yl_ps, cb_x, x_ps);
PixelFlush TPL_PRMS_pixel(false) (pp, &texture, x_ps, yl_ps, cb_x, x_ps);
yl_ps = _mm_add_ps(yl_ps, *(__m128*)ones_ps);
cb_x += sizeof(__m128);
}
@ -523,7 +638,7 @@ struct softrend : Renderer
int msk = _mm_movemask_ps((__m128&)a);
if (msk != 0)
{
PixelFlush<true, alpha_blend>(x_ps, yl_ps, cb_x, *(__m128*)&a);
PixelFlush TPL_PRMS_pixel(true) (pp, &texture, x_ps, yl_ps, cb_x, *(__m128*)&a);
}
yl_ps = _mm_add_ps(yl_ps, *(__m128*)ones_ps);
@ -556,6 +671,25 @@ struct softrend : Renderer
}
}
struct softrend : Renderer
{
virtual bool Process(TA_context* ctx) {
//disable RTTs for now ..
if (ctx->rend.isRTT)
return false;
ctx->rend_inuse.Lock();
ctx->MarkRend();
if (!ta_parse_vdrc(ctx))
return false;
return true;
}
template <bool alpha_blend>
void RenderParamList(List<PolyParam>* param_list) {
@ -572,8 +706,10 @@ struct softrend : Renderer
u16* poly_idx = &idx[params[i].first];
for (int v = 0; v < vertex_count; v++) {
////<alpha_blend, pp_UseAlpha, pp_Texture, pp_IgnoreTexA, pp_ShadInstr, pp_Offset >
RendtriangleFn fn = RendtriangleFns[alpha_blend][params[i].tsp.UseAlpha][params[i].pcw.Texture][params[i].tsp.IgnoreTexA][params[i].tsp.ShadInstr][params[i].pcw.Offset];
Rendtriangle<alpha_blend>(&params[i], v, verts[poly_idx[v]], verts[poly_idx[v + 1]], verts[poly_idx[v + 2]], render_buffer);
fn(&params[i], v, verts[poly_idx[v]], verts[poly_idx[v + 1]], verts[poly_idx[v + 2]], render_buffer);
}
}
}
@ -588,6 +724,9 @@ struct softrend : Renderer
RenderParamList<false>(&pvrrc.global_param_op);
RenderParamList<false>(&pvrrc.global_param_pt);
if (pvrrc.isAutoSort)
SortPParams();
RenderParamList<true>(&pvrrc.global_param_tr);
@ -628,6 +767,150 @@ struct softrend : Renderer
holdBMP = (HBITMAP)SelectObject(hmem, hBMP);
ReleaseDC(hWnd, hdc);
#define REP_16(x) ((x)* 16 + (x))
#define REP_32(x) ((x)* 8 + (x)/4)
#define REP_64(x) ((x)* 4 + (x)/16)
for (int c = 0; c < 65536; c++) {
//565
decoded_colors[0][c] = 0xFF000000 | (REP_32((c >> 11) % 32) << 16) | (REP_64((c >> 5) % 64) << 8) | (REP_32((c >> 0) % 32) << 0);
//1555
decoded_colors[1][c] = ((c >> 0) % 2 * 255 << 24) | (REP_32((c >> 10) % 32) << 16) | (REP_32((c >> 5) % 32) << 8) | (REP_32((c >> 1) % 32) << 0);
//4444
decoded_colors[2][c] = (REP_16((c >> 0) % 16) << 24) | (REP_16((c >> 12) % 16) << 16) | (REP_16((c >> 8) % 16) << 8) | (REP_16((c >> 4) % 16) << 0);
}
{
RendtriangleFns[0][0][1][0][0][0] = &Rendtriangle<0, 0, 1, 0, 0, 0>;
RendtriangleFns[0][0][1][0][0][1] = &Rendtriangle<0, 0, 1, 0, 0, 1>;
RendtriangleFns[0][0][1][0][1][0] = &Rendtriangle<0, 0, 1, 0, 1, 0>;
RendtriangleFns[0][0][1][0][1][1] = &Rendtriangle<0, 0, 1, 0, 1, 1>;
RendtriangleFns[0][0][1][0][2][0] = &Rendtriangle<0, 0, 1, 0, 2, 0>;
RendtriangleFns[0][0][1][0][2][1] = &Rendtriangle<0, 0, 1, 0, 2, 1>;
RendtriangleFns[0][0][1][0][3][0] = &Rendtriangle<0, 0, 1, 0, 3, 0>;
RendtriangleFns[0][0][1][0][3][1] = &Rendtriangle<0, 0, 1, 0, 3, 1>;
RendtriangleFns[0][0][1][1][0][0] = &Rendtriangle<0, 0, 1, 1, 0, 0>;
RendtriangleFns[0][0][1][1][0][1] = &Rendtriangle<0, 0, 1, 1, 0, 1>;
RendtriangleFns[0][0][1][1][1][0] = &Rendtriangle<0, 0, 1, 1, 1, 0>;
RendtriangleFns[0][0][1][1][1][1] = &Rendtriangle<0, 0, 1, 1, 1, 1>;
RendtriangleFns[0][0][1][1][2][0] = &Rendtriangle<0, 0, 1, 1, 2, 0>;
RendtriangleFns[0][0][1][1][2][1] = &Rendtriangle<0, 0, 1, 1, 2, 1>;
RendtriangleFns[0][0][1][1][3][0] = &Rendtriangle<0, 0, 1, 1, 3, 0>;
RendtriangleFns[0][0][1][1][3][1] = &Rendtriangle<0, 0, 1, 1, 3, 1>;
RendtriangleFns[0][0][0][0][0][0] = &Rendtriangle<0, 0, 0, 0, 0, 0>;
RendtriangleFns[0][0][0][0][0][1] = &Rendtriangle<0, 0, 0, 0, 0, 1>;
RendtriangleFns[0][0][0][0][1][0] = &Rendtriangle<0, 0, 0, 0, 1, 0>;
RendtriangleFns[0][0][0][0][1][1] = &Rendtriangle<0, 0, 0, 0, 1, 1>;
RendtriangleFns[0][0][0][0][2][0] = &Rendtriangle<0, 0, 0, 0, 2, 0>;
RendtriangleFns[0][0][0][0][2][1] = &Rendtriangle<0, 0, 0, 0, 2, 1>;
RendtriangleFns[0][0][0][0][3][0] = &Rendtriangle<0, 0, 0, 0, 3, 0>;
RendtriangleFns[0][0][0][0][3][1] = &Rendtriangle<0, 0, 0, 0, 3, 1>;
RendtriangleFns[0][0][0][1][0][0] = &Rendtriangle<0, 0, 0, 1, 0, 0>;
RendtriangleFns[0][0][0][1][0][1] = &Rendtriangle<0, 0, 0, 1, 0, 1>;
RendtriangleFns[0][0][0][1][1][0] = &Rendtriangle<0, 0, 0, 1, 1, 0>;
RendtriangleFns[0][0][0][1][1][1] = &Rendtriangle<0, 0, 0, 1, 1, 1>;
RendtriangleFns[0][0][0][1][2][0] = &Rendtriangle<0, 0, 0, 1, 2, 0>;
RendtriangleFns[0][0][0][1][2][1] = &Rendtriangle<0, 0, 0, 1, 2, 1>;
RendtriangleFns[0][0][0][1][3][0] = &Rendtriangle<0, 0, 0, 1, 3, 0>;
RendtriangleFns[0][0][0][1][3][1] = &Rendtriangle<0, 0, 0, 1, 3, 1>;
RendtriangleFns[0][1][1][0][0][0] = &Rendtriangle<0, 1, 1, 0, 0, 0>;
RendtriangleFns[0][1][1][0][0][1] = &Rendtriangle<0, 1, 1, 0, 0, 1>;
RendtriangleFns[0][1][1][0][1][0] = &Rendtriangle<0, 1, 1, 0, 1, 0>;
RendtriangleFns[0][1][1][0][1][1] = &Rendtriangle<0, 1, 1, 0, 1, 1>;
RendtriangleFns[0][1][1][0][2][0] = &Rendtriangle<0, 1, 1, 0, 2, 0>;
RendtriangleFns[0][1][1][0][2][1] = &Rendtriangle<0, 1, 1, 0, 2, 1>;
RendtriangleFns[0][1][1][0][3][0] = &Rendtriangle<0, 1, 1, 0, 3, 0>;
RendtriangleFns[0][1][1][0][3][1] = &Rendtriangle<0, 1, 1, 0, 3, 1>;
RendtriangleFns[0][1][1][1][0][0] = &Rendtriangle<0, 1, 1, 1, 0, 0>;
RendtriangleFns[0][1][1][1][0][1] = &Rendtriangle<0, 1, 1, 1, 0, 1>;
RendtriangleFns[0][1][1][1][1][0] = &Rendtriangle<0, 1, 1, 1, 1, 0>;
RendtriangleFns[0][1][1][1][1][1] = &Rendtriangle<0, 1, 1, 1, 1, 1>;
RendtriangleFns[0][1][1][1][2][0] = &Rendtriangle<0, 1, 1, 1, 2, 0>;
RendtriangleFns[0][1][1][1][2][1] = &Rendtriangle<0, 1, 1, 1, 2, 1>;
RendtriangleFns[0][1][1][1][3][0] = &Rendtriangle<0, 1, 1, 1, 3, 0>;
RendtriangleFns[0][1][1][1][3][1] = &Rendtriangle<0, 1, 1, 1, 3, 1>;
RendtriangleFns[0][1][0][0][0][0] = &Rendtriangle<0, 1, 0, 0, 0, 0>;
RendtriangleFns[0][1][0][0][0][1] = &Rendtriangle<0, 1, 0, 0, 0, 1>;
RendtriangleFns[0][1][0][0][1][0] = &Rendtriangle<0, 1, 0, 0, 1, 0>;
RendtriangleFns[0][1][0][0][1][1] = &Rendtriangle<0, 1, 0, 0, 1, 1>;
RendtriangleFns[0][1][0][0][2][0] = &Rendtriangle<0, 1, 0, 0, 2, 0>;
RendtriangleFns[0][1][0][0][2][1] = &Rendtriangle<0, 1, 0, 0, 2, 1>;
RendtriangleFns[0][1][0][0][3][0] = &Rendtriangle<0, 1, 0, 0, 3, 0>;
RendtriangleFns[0][1][0][0][3][1] = &Rendtriangle<0, 1, 0, 0, 3, 1>;
RendtriangleFns[0][1][0][1][0][0] = &Rendtriangle<0, 1, 0, 1, 0, 0>;
RendtriangleFns[0][1][0][1][0][1] = &Rendtriangle<0, 1, 0, 1, 0, 1>;
RendtriangleFns[0][1][0][1][1][0] = &Rendtriangle<0, 1, 0, 1, 1, 0>;
RendtriangleFns[0][1][0][1][1][1] = &Rendtriangle<0, 1, 0, 1, 1, 1>;
RendtriangleFns[0][1][0][1][2][0] = &Rendtriangle<0, 1, 0, 1, 2, 0>;
RendtriangleFns[0][1][0][1][2][1] = &Rendtriangle<0, 1, 0, 1, 2, 1>;
RendtriangleFns[0][1][0][1][3][0] = &Rendtriangle<0, 1, 0, 1, 3, 0>;
RendtriangleFns[0][1][0][1][3][1] = &Rendtriangle<0, 1, 0, 1, 3, 1>;
RendtriangleFns[1][0][1][0][0][0] = &Rendtriangle<1, 0, 1, 0, 0, 0>;
RendtriangleFns[1][0][1][0][0][1] = &Rendtriangle<1, 0, 1, 0, 0, 1>;
RendtriangleFns[1][0][1][0][1][0] = &Rendtriangle<1, 0, 1, 0, 1, 0>;
RendtriangleFns[1][0][1][0][1][1] = &Rendtriangle<1, 0, 1, 0, 1, 1>;
RendtriangleFns[1][0][1][0][2][0] = &Rendtriangle<1, 0, 1, 0, 2, 0>;
RendtriangleFns[1][0][1][0][2][1] = &Rendtriangle<1, 0, 1, 0, 2, 1>;
RendtriangleFns[1][0][1][0][3][0] = &Rendtriangle<1, 0, 1, 0, 3, 0>;
RendtriangleFns[1][0][1][0][3][1] = &Rendtriangle<1, 0, 1, 0, 3, 1>;
RendtriangleFns[1][0][1][1][0][0] = &Rendtriangle<1, 0, 1, 1, 0, 0>;
RendtriangleFns[1][0][1][1][0][1] = &Rendtriangle<1, 0, 1, 1, 0, 1>;
RendtriangleFns[1][0][1][1][1][0] = &Rendtriangle<1, 0, 1, 1, 1, 0>;
RendtriangleFns[1][0][1][1][1][1] = &Rendtriangle<1, 0, 1, 1, 1, 1>;
RendtriangleFns[1][0][1][1][2][0] = &Rendtriangle<1, 0, 1, 1, 2, 0>;
RendtriangleFns[1][0][1][1][2][1] = &Rendtriangle<1, 0, 1, 1, 2, 1>;
RendtriangleFns[1][0][1][1][3][0] = &Rendtriangle<1, 0, 1, 1, 3, 0>;
RendtriangleFns[1][0][1][1][3][1] = &Rendtriangle<1, 0, 1, 1, 3, 1>;
RendtriangleFns[1][0][0][0][0][0] = &Rendtriangle<1, 0, 0, 0, 0, 0>;
RendtriangleFns[1][0][0][0][0][1] = &Rendtriangle<1, 0, 0, 0, 0, 1>;
RendtriangleFns[1][0][0][0][1][0] = &Rendtriangle<1, 0, 0, 0, 1, 0>;
RendtriangleFns[1][0][0][0][1][1] = &Rendtriangle<1, 0, 0, 0, 1, 1>;
RendtriangleFns[1][0][0][0][2][0] = &Rendtriangle<1, 0, 0, 0, 2, 0>;
RendtriangleFns[1][0][0][0][2][1] = &Rendtriangle<1, 0, 0, 0, 2, 1>;
RendtriangleFns[1][0][0][0][3][0] = &Rendtriangle<1, 0, 0, 0, 3, 0>;
RendtriangleFns[1][0][0][0][3][1] = &Rendtriangle<1, 0, 0, 0, 3, 1>;
RendtriangleFns[1][0][0][1][0][0] = &Rendtriangle<1, 0, 0, 1, 0, 0>;
RendtriangleFns[1][0][0][1][0][1] = &Rendtriangle<1, 0, 0, 1, 0, 1>;
RendtriangleFns[1][0][0][1][1][0] = &Rendtriangle<1, 0, 0, 1, 1, 0>;
RendtriangleFns[1][0][0][1][1][1] = &Rendtriangle<1, 0, 0, 1, 1, 1>;
RendtriangleFns[1][0][0][1][2][0] = &Rendtriangle<1, 0, 0, 1, 2, 0>;
RendtriangleFns[1][0][0][1][2][1] = &Rendtriangle<1, 0, 0, 1, 2, 1>;
RendtriangleFns[1][0][0][1][3][0] = &Rendtriangle<1, 0, 0, 1, 3, 0>;
RendtriangleFns[1][0][0][1][3][1] = &Rendtriangle<1, 0, 0, 1, 3, 1>;
RendtriangleFns[1][1][1][0][0][0] = &Rendtriangle<1, 1, 1, 0, 0, 0>;
RendtriangleFns[1][1][1][0][0][1] = &Rendtriangle<1, 1, 1, 0, 0, 1>;
RendtriangleFns[1][1][1][0][1][0] = &Rendtriangle<1, 1, 1, 0, 1, 0>;
RendtriangleFns[1][1][1][0][1][1] = &Rendtriangle<1, 1, 1, 0, 1, 1>;
RendtriangleFns[1][1][1][0][2][0] = &Rendtriangle<1, 1, 1, 0, 2, 0>;
RendtriangleFns[1][1][1][0][2][1] = &Rendtriangle<1, 1, 1, 0, 2, 1>;
RendtriangleFns[1][1][1][0][3][0] = &Rendtriangle<1, 1, 1, 0, 3, 0>;
RendtriangleFns[1][1][1][0][3][1] = &Rendtriangle<1, 1, 1, 0, 3, 1>;
RendtriangleFns[1][1][1][1][0][0] = &Rendtriangle<1, 1, 1, 1, 0, 0>;
RendtriangleFns[1][1][1][1][0][1] = &Rendtriangle<1, 1, 1, 1, 0, 1>;
RendtriangleFns[1][1][1][1][1][0] = &Rendtriangle<1, 1, 1, 1, 1, 0>;
RendtriangleFns[1][1][1][1][1][1] = &Rendtriangle<1, 1, 1, 1, 1, 1>;
RendtriangleFns[1][1][1][1][2][0] = &Rendtriangle<1, 1, 1, 1, 2, 0>;
RendtriangleFns[1][1][1][1][2][1] = &Rendtriangle<1, 1, 1, 1, 2, 1>;
RendtriangleFns[1][1][1][1][3][0] = &Rendtriangle<1, 1, 1, 1, 3, 0>;
RendtriangleFns[1][1][1][1][3][1] = &Rendtriangle<1, 1, 1, 1, 3, 1>;
RendtriangleFns[1][1][0][0][0][0] = &Rendtriangle<1, 1, 0, 0, 0, 0>;
RendtriangleFns[1][1][0][0][0][1] = &Rendtriangle<1, 1, 0, 0, 0, 1>;
RendtriangleFns[1][1][0][0][1][0] = &Rendtriangle<1, 1, 0, 0, 1, 0>;
RendtriangleFns[1][1][0][0][1][1] = &Rendtriangle<1, 1, 0, 0, 1, 1>;
RendtriangleFns[1][1][0][0][2][0] = &Rendtriangle<1, 1, 0, 0, 2, 0>;
RendtriangleFns[1][1][0][0][2][1] = &Rendtriangle<1, 1, 0, 0, 2, 1>;
RendtriangleFns[1][1][0][0][3][0] = &Rendtriangle<1, 1, 0, 0, 3, 0>;
RendtriangleFns[1][1][0][0][3][1] = &Rendtriangle<1, 1, 0, 0, 3, 1>;
RendtriangleFns[1][1][0][1][0][0] = &Rendtriangle<1, 1, 0, 1, 0, 0>;
RendtriangleFns[1][1][0][1][0][1] = &Rendtriangle<1, 1, 0, 1, 0, 1>;
RendtriangleFns[1][1][0][1][1][0] = &Rendtriangle<1, 1, 0, 1, 1, 0>;
RendtriangleFns[1][1][0][1][1][1] = &Rendtriangle<1, 1, 0, 1, 1, 1>;
RendtriangleFns[1][1][0][1][2][0] = &Rendtriangle<1, 1, 0, 1, 2, 0>;
RendtriangleFns[1][1][0][1][2][1] = &Rendtriangle<1, 1, 0, 1, 2, 1>;
RendtriangleFns[1][1][0][1][3][0] = &Rendtriangle<1, 1, 0, 1, 3, 0>;
RendtriangleFns[1][1][0][1][3][1] = &Rendtriangle<1, 1, 0, 1, 3, 1>;
}
return true;
}