/// <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 < BspFile.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); } } }
/// <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); }
static void DrawTextureChains() { if (_glTexSort.Value == 0) { DisableMultitexture(); if (_SkyChain != null) { DrawSkyChain(_SkyChain); _SkyChain = null; } return; } model_t 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; } }
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); }
/// <summary> /// R_DrawWaterSurfaces /// </summary> 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); } }
/// <summary> /// R_DrawSequentialPoly /// Systems that have fast state and texture changes can /// just do everything as it passes with no need to sort /// </summary> 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); } }