Ejemplo n.º 1
0
        /// <summary>
        /// R_TextureAnimation
        /// Returns the proper texture for a given time and base texture
        /// </summary>
        private static texture_t TextureAnimation(texture_t t)
        {
            if (_CurrentEntity.frame != 0)
            {
                if (t.alternate_anims != null)
                {
                    t = t.alternate_anims;
                }
            }

            if (t.anim_total == 0)
            {
                return(t);
            }

            int reletive = (int)(client.cl.time * 10) % t.anim_total;
            int count    = 0;

            while (t.anim_min > reletive || t.anim_max <= reletive)
            {
                t = t.anim_next;
                if (t == null)
                {
                    sys.Error("R_TextureAnimation: broken cycle");
                }
                if (++count > 100)
                {
                    sys.Error("R_TextureAnimation: infinite cycle");
                }
            }

            return(t);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// R_RenderBrushPoly
        /// </summary>
        private static void RenderBrushPoly(msurface_t fa)
        {
            _BrushPolys++;

            if ((fa.flags & Surf.SURF_DRAWSKY) != 0)
            {   // warp texture, no lightmaps
                EmitBothSkyLayers(fa);
                return;
            }

            texture_t t = TextureAnimation(fa.texinfo.texture);

            Drawer.Bind(t.gl_texturenum);

            if ((fa.flags & Surf.SURF_DRAWTURB) != 0)
            {   // warp texture, no lightmaps
                EmitWaterPolys(fa);
                return;
            }

            if ((fa.flags & Surf.SURF_UNDERWATER) != 0)
            {
                DrawGLWaterPoly(fa.polys);
            }
            else
            {
                DrawGLPoly(fa.polys);
            }

            // add the poly to the proper lightmap chain

            fa.polys.chain = _LightMapPolys[fa.lightmaptexturenum];
            _LightMapPolys[fa.lightmaptexturenum] = fa.polys;

            // check for lightmap modification
            bool modified = false;

            for (int maps = 0; maps < bsp_file.MAXLIGHTMAPS && fa.styles[maps] != 255; maps++)
            {
                if (_LightStyleValue[fa.styles[maps]] != fa.cached_light[maps])
                {
                    modified = true;
                    break;
                }
            }

            if (modified ||
                fa.dlightframe == _FrameCount ||        // dynamic this frame
                fa.cached_dlight)                       // dynamic previously
            {
                if (_Dynamic.Value != 0)
                {
                    _LightMapModified[fa.lightmaptexturenum] = true;
                    UpdateRect(fa, ref _LightMapRectChange[fa.lightmaptexturenum]);
                    int offset = fa.lightmaptexturenum * _LightMapBytes * BLOCK_WIDTH * BLOCK_HEIGHT;
                    offset += fa.light_t * BLOCK_WIDTH * _LightMapBytes + fa.light_s * _LightMapBytes;
                    BuildLightMap(fa, new ByteArraySegment(_LightMaps, offset), BLOCK_WIDTH * _LightMapBytes);
                }
            }
        }
Ejemplo n.º 3
0
        static void DrawTextureChains()
        {
            if (_glTexSort.Value == 0)
            {
                DisableMultitexture();

                if (_SkyChain != null)
                {
                    DrawSkyChain(_SkyChain);
                    _SkyChain = null;
                }
                return;
            }
            Model world = Client.Cl.worldmodel;

            for (int i = 0; i < world.numtextures; i++)
            {
                texture_t t = world.textures[i];
                if (t == null)
                {
                    continue;
                }

                msurface_t s = t.texturechain;
                if (s == null)
                {
                    continue;
                }

                if (i == _SkyTextureNum)
                {
                    DrawSkyChain(s);
                }
                else if (i == _MirrorTextureNum && _MirrorAlpha.Value != 1.0f)
                {
                    MirrorChain(s);
                    continue;
                }
                else
                {
                    if ((s.flags & Surf.SURF_DRAWTURB) != 0 && _WaterAlpha.Value != 1.0f)
                    {
                        continue;   // draw translucent water later
                    }

                    for (; s != null; s = s.texturechain)
                    {
                        RenderBrushPoly(s);
                    }
                }

                t.texturechain = null;
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// R_TextureAnimation
        /// Returns the proper texture for a given time and base texture
        /// </summary>
        static texture_t TextureAnimation(texture_t t)
        {
            if (_CurrentEntity.frame != 0)
            {
                if (t.alternate_anims != null)
                    t = t.alternate_anims;
            }

            if (t.anim_total == 0)
                return t;

            int reletive = (int)(Client.cl.time * 10) % t.anim_total;
            int count = 0;
            while (t.anim_min > reletive || t.anim_max <= reletive)
            {
                t = t.anim_next;
                if (t == null)
                    Sys.Error("R_TextureAnimation: broken cycle");
                if (++count > 100)
                    Sys.Error("R_TextureAnimation: infinite cycle");
            }

            return t;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// R_DrawWaterSurfaces
        /// </summary>
        private static void DrawWaterSurfaces()
        {
            if (_WaterAlpha.Value == 1.0f && _glTexSort.Value != 0)
            {
                return;
            }

            //
            // go back to the world matrix
            //
            GL.LoadMatrix(ref _WorldMatrix);

            if (_WaterAlpha.Value < 1.0)
            {
                GL.Enable(EnableCap.Blend);
                GL.Color4(1, 1, 1, _WaterAlpha.Value);
                GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate);
            }

            if (_glTexSort.Value == 0)
            {
                if (_WaterChain == null)
                {
                    return;
                }

                for (msurface_t s = _WaterChain; s != null; s = s.texturechain)
                {
                    Drawer.Bind(s.texinfo.texture.gl_texturenum);
                    EmitWaterPolys(s);
                }
                _WaterChain = null;
            }
            else
            {
                for (int i = 0; i < client.cl.worldmodel.numtextures; i++)
                {
                    texture_t t = client.cl.worldmodel.textures[i];
                    if (t == null)
                    {
                        continue;
                    }

                    msurface_t s = t.texturechain;
                    if (s == null)
                    {
                        continue;
                    }

                    if ((s.flags & Surf.SURF_DRAWTURB) == 0)
                    {
                        continue;
                    }

                    // set modulate mode explicitly

                    Drawer.Bind(t.gl_texturenum);

                    for ( ; s != null; s = s.texturechain)
                    {
                        EmitWaterPolys(s);
                    }

                    t.texturechain = null;
                }
            }

            if (_WaterAlpha.Value < 1.0)
            {
                GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Replace);
                GL.Color4(1f, 1, 1, 1);
                GL.Disable(EnableCap.Blend);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// R_DrawSequentialPoly
        /// Systems that have fast state and texture changes can
        /// just do everything as it passes with no need to sort
        /// </summary>
        private static void DrawSequentialPoly(msurface_t s)
        {
            //
            // normal lightmaped poly
            //
            if ((s.flags & (Surf.SURF_DRAWSKY | Surf.SURF_DRAWTURB | Surf.SURF_UNDERWATER)) == 0)
            {
                RenderDynamicLightmaps(s);
                glpoly_t  p = s.polys;
                texture_t t = TextureAnimation(s.texinfo.texture);
                if (vid.glMTexable)
                {
                    // Binds world to texture env 0
                    Drawer.SelectTexture(MTexTarget.TEXTURE0_SGIS);
                    Drawer.Bind(t.gl_texturenum);
                    GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Replace);

                    // Binds lightmap to texenv 1
                    EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
                    Drawer.Bind(_LightMapTextures + s.lightmaptexturenum);
                    int i = s.lightmaptexturenum;
                    if (_LightMapModified[i])
                    {
                        CommitLightmap(i);
                    }

                    GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Blend);
                    GL.Begin(PrimitiveType.Polygon);
                    for (i = 0; i < p.numverts; i++)
                    {
                        float[] v = p.verts[i];
                        GL.MultiTexCoord2(TextureUnit.Texture0, v[3], v[4]);
                        GL.MultiTexCoord2(TextureUnit.Texture1, v[5], v[6]);
                        GL.Vertex3(v);
                    }
                    GL.End();
                    return;
                }
                else
                {
                    Drawer.Bind(t.gl_texturenum);
                    GL.Begin(PrimitiveType.Polygon);
                    for (int i = 0; i < p.numverts; i++)
                    {
                        float[] v = p.verts[i];
                        GL.TexCoord2(v[3], v[4]);
                        GL.Vertex3(v);
                    }
                    GL.End();

                    Drawer.Bind(_LightMapTextures + s.lightmaptexturenum);
                    GL.Enable(EnableCap.Blend);
                    GL.Begin(PrimitiveType.Polygon);
                    for (int i = 0; i < p.numverts; i++)
                    {
                        float[] v = p.verts[i];
                        GL.TexCoord2(v[5], v[6]);
                        GL.Vertex3(v);
                    }
                    GL.End();

                    GL.Disable(EnableCap.Blend);
                }

                return;
            }

            //
            // subdivided water surface warp
            //

            if ((s.flags & Surf.SURF_DRAWTURB) != 0)
            {
                DisableMultitexture();
                Drawer.Bind(s.texinfo.texture.gl_texturenum);
                EmitWaterPolys(s);
                return;
            }

            //
            // subdivided sky warp
            //
            if ((s.flags & Surf.SURF_DRAWSKY) != 0)
            {
                DisableMultitexture();
                Drawer.Bind(_SolidSkyTexture);
                _SpeedScale  = (float)host.RealTime * 8;
                _SpeedScale -= (int)_SpeedScale & ~127;

                EmitSkyPolys(s);

                GL.Enable(EnableCap.Blend);
                Drawer.Bind(_AlphaSkyTexture);
                _SpeedScale  = (float)host.RealTime * 16;
                _SpeedScale -= (int)_SpeedScale & ~127;

                EmitSkyPolys(s);

                GL.Disable(EnableCap.Blend);
                return;
            }

            //
            // underwater warped with lightmap
            //
            RenderDynamicLightmaps(s);
            if (vid.glMTexable)
            {
                texture_t t = TextureAnimation(s.texinfo.texture);
                Drawer.SelectTexture(MTexTarget.TEXTURE0_SGIS);
                Drawer.Bind(t.gl_texturenum);
                GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Replace);
                EnableMultitexture();
                Drawer.Bind(_LightMapTextures + s.lightmaptexturenum);
                int i = s.lightmaptexturenum;
                if (_LightMapModified[i])
                {
                    CommitLightmap(i);
                }

                GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Blend);
                GL.Begin(PrimitiveType.TriangleFan);
                glpoly_t p  = s.polys;
                float[]  nv = new float[3];
                for (i = 0; i < p.numverts; i++)
                {
                    float[] v = p.verts[i];
                    GL.MultiTexCoord2(TextureUnit.Texture0, v[3], v[4]);
                    GL.MultiTexCoord2(TextureUnit.Texture1, v[5], v[6]);

                    nv[0] = (float)(v[0] + 8 * Math.Sin(v[1] * 0.05 + host.RealTime) * Math.Sin(v[2] * 0.05 + host.RealTime));
                    nv[1] = (float)(v[1] + 8 * Math.Sin(v[0] * 0.05 + host.RealTime) * Math.Sin(v[2] * 0.05 + host.RealTime));
                    nv[2] = v[2];

                    GL.Vertex3(nv);
                }
                GL.End();
            }
            else
            {
                glpoly_t p = s.polys;

                texture_t t = TextureAnimation(s.texinfo.texture);
                Drawer.Bind(t.gl_texturenum);
                DrawGLWaterPoly(p);

                Drawer.Bind(_LightMapTextures + s.lightmaptexturenum);
                GL.Enable(EnableCap.Blend);
                DrawGLWaterPolyLightmap(p);
                GL.Disable(EnableCap.Blend);
            }
        }
Ejemplo n.º 7
0
        // R_InitTextures
        public static void InitTextures()
        {
            // create a simple checkerboard texture for the default
            _NoTextureMip = new texture_t();
            _NoTextureMip.pixels = new byte[16 * 16 + 8 * 8 + 4 * 4 + 2 * 2];
            _NoTextureMip.width = _NoTextureMip.height = 16;
            int offset = 0;
            _NoTextureMip.offsets[0] = offset;
            offset += 16 * 16;
            _NoTextureMip.offsets[1] = offset;
            offset += 8 * 8;
            _NoTextureMip.offsets[2] = offset;
            offset += 4 * 4;
            _NoTextureMip.offsets[3] = offset;

            byte[] dest = _NoTextureMip.pixels;
            for (int m = 0; m < 4; m++)
            {
                offset = _NoTextureMip.offsets[m];
                for (int y = 0; y < (16 >> m); y++)
                    for (int x = 0; x < (16 >> m); x++)
                    {
                        if ((y < (8 >> m)) ^ (x < (8 >> m)))
                            dest[offset] = 0;
                        else
                            dest[offset] = 0xff;

                        offset++;
                    }
            }
        }
Ejemplo n.º 8
0
        static msurface_t _WarpFace; // used by SubdivideSurface()

        #endregion Fields

        #region Methods

        /// <summary>
        /// R_InitSky
        /// called at level load
        /// A sky texture is 256*128, with the right side being a masked overlay
        /// </summary>
        public static void InitSky(texture_t mt)
        {
            byte[] src = mt.pixels;
            int offset = mt.offsets[0];

            // make an average value for the back to avoid
            // a fringe on the top level
            const int size = 128 * 128;
            uint[] trans = new uint[size];
            uint[] v8to24 = Vid.Table8to24;
            int r = 0;
            int g = 0;
            int b = 0;
            Union4b rgba = Union4b.Empty;
            for (int i=0 ; i<128 ; i++)
                for (int j=0 ; j<128 ; j++)
                {
                    int p = src[offset + i*256 + j + 128];
                    rgba.ui0 = v8to24[p];
                    trans[(i * 128) + j] = rgba.ui0;
                    r += rgba.b0;
                    g += rgba.b1;
                    b += rgba.b2;
                }

            rgba.b0 = (byte)(r / size);
            rgba.b1 = (byte)(g / size);
            rgba.b2 = (byte)(b / size);
            rgba.b3 = 0;

            uint transpix = rgba.ui0;

            if (_SolidSkyTexture == 0)
                _SolidSkyTexture = Drawer.GenerateTextureNumber();
            Drawer.Bind (_SolidSkyTexture );
            GL.TexImage2D(TextureTarget.Texture2D, 0, Drawer.SolidFormat, 128, 128, 0, PixelFormat.Rgba, PixelType.UnsignedByte, trans);
            Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear);

            for (int i=0 ; i<128 ; i++)
                for (int j=0 ; j<128 ; j++)
                {
                    int p = src[offset + i*256 + j];
                    if (p == 0)
                        trans[(i*128) + j] = transpix;
                    else
                        trans[(i*128) + j] = v8to24[p];
                }

            if (_AlphaSkyTexture == 0)
                _AlphaSkyTexture = Drawer.GenerateTextureNumber();
            Drawer.Bind(_AlphaSkyTexture);
            GL.TexImage2D(TextureTarget.Texture2D, 0, Drawer.AlphaFormat, 128, 128, 0, PixelFormat.Rgba, PixelType.UnsignedByte, trans);
            Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear);
        }
Ejemplo n.º 9
0
        static msurface_t _WarpFace; // used by SubdivideSurface()


        /// <summary>
        /// R_InitSky
        /// called at level load
        /// A sky texture is 256*128, with the right side being a masked overlay
        /// </summary>
        public static void InitSky(texture_t mt)
        {
            byte[] src    = mt.pixels;
            int    offset = mt.offsets[0];

            // make an average value for the back to avoid
            // a fringe on the top level
            const int size = 128 * 128;

            uint[]  trans  = new uint[size];
            uint[]  v8to24 = Vid.Table8to24;
            int     r      = 0;
            int     g      = 0;
            int     b      = 0;
            Union4b rgba   = Union4b.Empty;

            for (int i = 0; i < 128; i++)
            {
                for (int j = 0; j < 128; j++)
                {
                    int p = src[offset + i * 256 + j + 128];
                    rgba.ui0             = v8to24[p];
                    trans[(i * 128) + j] = rgba.ui0;
                    r += rgba.b0;
                    g += rgba.b1;
                    b += rgba.b2;
                }
            }

            rgba.b0 = (byte)(r / size);
            rgba.b1 = (byte)(g / size);
            rgba.b2 = (byte)(b / size);
            rgba.b3 = 0;

            uint transpix = rgba.ui0;

            if (_SolidSkyTexture == 0)
            {
                _SolidSkyTexture = Drawer.GenerateTextureNumber();
            }

            Drawer.Bind(_SolidSkyTexture);
            GL.TexImage2D(TextureTarget.Texture2D, 0, Drawer.SolidFormat, 128, 128, 0, PixelFormat.Rgba, PixelType.UnsignedByte, trans);
            Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear);

            for (int i = 0; i < 128; i++)
            {
                for (int j = 0; j < 128; j++)
                {
                    int p = src[offset + i * 256 + j];
                    if (p == 0)
                    {
                        trans[(i * 128) + j] = transpix;
                    }
                    else
                    {
                        trans[(i * 128) + j] = v8to24[p];
                    }
                }
            }

            if (_AlphaSkyTexture == 0)
            {
                _AlphaSkyTexture = Drawer.GenerateTextureNumber();
            }

            Drawer.Bind(_AlphaSkyTexture);
            GL.TexImage2D(TextureTarget.Texture2D, 0, Drawer.AlphaFormat, 128, 128, 0, PixelFormat.Rgba, PixelType.UnsignedByte, trans);
            Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Mod_LoadTextures
        /// </summary>
        static void LoadTextures(ref lump_t l)
        {
            if (l.filelen == 0)
            {
                _LoadModel.textures = null;
                return;
            }

            dmiptexlump_t m = Sys.BytesToStructure<dmiptexlump_t>(_ModBase, l.fileofs);// (dmiptexlump_t *)(mod_base + l.fileofs);

            m.nummiptex = Common.LittleLong(m.nummiptex);

            int[] dataofs = new int[m.nummiptex];

            Buffer.BlockCopy(_ModBase, l.fileofs + dmiptexlump_t.SizeInBytes, dataofs, 0, dataofs.Length * sizeof(int));

            _LoadModel.numtextures = m.nummiptex;
            _LoadModel.textures = new texture_t[m.nummiptex]; // Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);

            for (int i = 0; i < m.nummiptex; i++)
            {
                dataofs[i] = Common.LittleLong(dataofs[i]);
                if (dataofs[i] == -1)
                    continue;

                int mtOffset = l.fileofs + dataofs[i];
                miptex_t mt = Sys.BytesToStructure<miptex_t>(_ModBase, mtOffset); //mt = (miptex_t *)((byte *)m + m.dataofs[i]);
                mt.width = (uint)Common.LittleLong((int)mt.width);
                mt.height = (uint)Common.LittleLong((int)mt.height);
                for (int j = 0; j < BspFile.MIPLEVELS; j++)
                    mt.offsets[j] = (uint)Common.LittleLong((int)mt.offsets[j]);

                if ((mt.width & 15) != 0 || (mt.height & 15) != 0)
                    Sys.Error("Texture {0} is not 16 aligned", mt.name);

                int pixels = (int)(mt.width * mt.height / 64 * 85);
                texture_t tx = new texture_t();// Hunk_AllocName(sizeof(texture_t) + pixels, loadname);
                _LoadModel.textures[i] = tx;

                tx.name = Common.GetString(mt.name);//   memcpy (tx->name, mt->name, sizeof(tx.name));
                tx.width = mt.width;
                tx.height = mt.height;
                for (int j = 0; j < BspFile.MIPLEVELS; j++)
                    tx.offsets[j] = (int)mt.offsets[j] - miptex_t.SizeInBytes;
                // the pixels immediately follow the structures
                tx.pixels = new byte[pixels];
                Buffer.BlockCopy(_ModBase, mtOffset + miptex_t.SizeInBytes, tx.pixels, 0, pixels);

                if (tx.name != null && tx.name.StartsWith("sky"))// !Q_strncmp(mt->name,"sky",3))
                    Render.InitSky(tx);
                else
                {
                    tx.gl_texturenum = Drawer.LoadTexture(tx.name, (int)tx.width, (int)tx.height,
                        new ByteArraySegment(tx.pixels), true, false);
                }
            }

            //
            // sequence the animations
            //
            texture_t[] anims = new texture_t[10];
            texture_t[] altanims = new texture_t[10];

            for (int i = 0; i < m.nummiptex; i++)
            {
                texture_t tx = _LoadModel.textures[i];
                if (tx == null || !tx.name.StartsWith("+"))// [0] != '+')
                    continue;
                if (tx.anim_next != null)
                    continue;	// allready sequenced

                // find the number of frames in the animation
                Array.Clear(anims, 0, anims.Length);
                Array.Clear(altanims, 0, altanims.Length);

                int max = tx.name[1];
                int altmax = 0;
                if (max >= 'a' && max <= 'z')
                    max -= 'a' - 'A';
                if (max >= '0' && max <= '9')
                {
                    max -= '0';
                    altmax = 0;
                    anims[max] = tx;
                    max++;
                }
                else if (max >= 'A' && max <= 'J')
                {
                    altmax = max - 'A';
                    max = 0;
                    altanims[altmax] = tx;
                    altmax++;
                }
                else
                    Sys.Error("Bad animating texture {0}", tx.name);

                for (int j = i + 1; j < m.nummiptex; j++)
                {
                    texture_t tx2 = _LoadModel.textures[j];
                    if (tx2 == null || !tx2.name.StartsWith("+"))// tx2->name[0] != '+')
                        continue;
                    if (String.Compare(tx2.name, 2, tx.name, 2, Math.Min(tx.name.Length, tx2.name.Length)) != 0)// strcmp (tx2->name+2, tx->name+2))
                        continue;

                    int num = tx2.name[1];
                    if (num >= 'a' && num <= 'z')
                        num -= 'a' - 'A';
                    if (num >= '0' && num <= '9')
                    {
                        num -= '0';
                        anims[num] = tx2;
                        if (num + 1 > max)
                            max = num + 1;
                    }
                    else if (num >= 'A' && num <= 'J')
                    {
                        num = num - 'A';
                        altanims[num] = tx2;
                        if (num + 1 > altmax)
                            altmax = num + 1;
                    }
                    else
                        Sys.Error("Bad animating texture {0}", tx2.name);
                }

                // link them all together
                for (int j = 0; j < max; j++)
                {
                    texture_t tx2 = anims[j];
                    if (tx2 == null)
                        Sys.Error("Missing frame {0} of {1}", j, tx.name);
                    tx2.anim_total = max * ANIM_CYCLE;
                    tx2.anim_min = j * ANIM_CYCLE;
                    tx2.anim_max = (j + 1) * ANIM_CYCLE;
                    tx2.anim_next = anims[(j + 1) % max];
                    if (altmax != 0)
                        tx2.alternate_anims = altanims[0];
                }
                for (int j = 0; j < altmax; j++)
                {
                    texture_t tx2 = altanims[j];
                    if (tx2 == null)
                        Sys.Error("Missing frame {0} of {1}", j, tx2.name);
                    tx2.anim_total = altmax * ANIM_CYCLE;
                    tx2.anim_min = j * ANIM_CYCLE;
                    tx2.anim_max = (j + 1) * ANIM_CYCLE;
                    tx2.anim_next = altanims[(j + 1) % altmax];
                    if (max != 0)
                        tx2.alternate_anims = anims[0];
                }
            }
        }