/// <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); } } }
/// <summary> /// R_DrawSkyChain /// </summary> private static void DrawSkyChain(msurface_t s) { DisableMultitexture(); // used when gl_texsort is on Drawer.Bind(_SolidSkyTexture); _SpeedScale = (float)Host.RealTime * 8; _SpeedScale -= (int)_SpeedScale & ~127; for (msurface_t fa = s; fa != null; fa = fa.texturechain) { EmitSkyPolys(fa); } GL.Enable(EnableCap.Blend); Drawer.Bind(_AlphaSkyTexture); _SpeedScale = (float)Host.RealTime * 16; _SpeedScale -= (int)_SpeedScale & ~127; for (msurface_t fa = s; fa != null; fa = fa.texturechain) { EmitSkyPolys(fa); } GL.Disable(EnableCap.Blend); }
/// <summary> /// EmitBothSkyLayers /// Does a sky warp on the pre-fragmented glpoly_t chain /// This will be called for brushmodels, the world /// will have them chained together. /// </summary> private static void EmitBothSkyLayers(msurface_t fa) { DisableMultitexture(); Drawer.Bind(_SolidSkyTexture); _SpeedScale = (float)Host.RealTime * 8; _SpeedScale -= (int)_SpeedScale & ~127; EmitSkyPolys(fa); GL.Enable(EnableCap.Blend); Drawer.Bind(_AlphaSkyTexture); _SpeedScale = (float)Host.RealTime * 16; _SpeedScale -= (int)_SpeedScale & ~127; EmitSkyPolys(fa); GL.Disable(EnableCap.Blend); }
// R_InitParticleTexture static void InitParticleTexture() { _ParticleTexture = Drawer.GenerateTextureNumber();// texture_extension_number++; Drawer.Bind(_ParticleTexture); byte[,,] data = new byte[8, 8, 4]; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { data[y, x, 0] = 255; data[y, x, 1] = 255; data[y, x, 2] = 255; data[y, x, 3] = (byte)(_DotTexture[x, y] * 255); } } GL.TexImage2D(TextureTarget.Texture2D, 0, Drawer.AlphaFormat, 8, 8, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data); GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear); }
/// <summary> /// R_DrawParticles /// </summary> private static void DrawParticles() { Drawer.Bind(_ParticleTexture); GL.Enable(EnableCap.Blend); GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate); GL.Begin(BeginMode.Triangles); Vector3 up = Render.ViewUp * 1.5f; Vector3 right = Render.ViewRight * 1.5f; float frametime = (float)(Client.cl.time - Client.cl.oldtime); float time3 = frametime * 15; float time2 = frametime * 10; float time1 = frametime * 5; float grav = frametime * Server.Gravity * 0.05f; float dvel = 4 * frametime; while (true) { particle_t kill = _ActiveParticles; if (kill != null && kill.die < Client.cl.time) { _ActiveParticles = kill.next; kill.next = _FreeParticles; _FreeParticles = kill; continue; } break; } for (particle_t p = _ActiveParticles; p != null; p = p.next) { while (true) { particle_t kill = p.next; if (kill != null && kill.die < Client.cl.time) { p.next = kill.next; kill.next = _FreeParticles; _FreeParticles = kill; continue; } break; } // hack a scale up to keep particles from disapearing float scale = Vector3.Dot((p.org - Render.Origin), Render.ViewPn); if (scale < 20) { scale = 1; } else { scale = 1 + scale * 0.004f; } // Uze todo: check if this is correct uint color = Vid.Table8to24[(byte)p.color]; GL.Color4((byte)(color & 0xff), (byte)((color >> 8) & 0xff), (byte)((color >> 16) & 0xff), (byte)((color >> 24) & 0xff)); GL.TexCoord2(0f, 0); GL.Vertex3(p.org); GL.TexCoord2(1f, 0); Vector3 v = p.org + up * scale; GL.Vertex3(v); GL.TexCoord2(0f, 1); v = p.org + right * scale; GL.Vertex3(v); p.org += p.vel * frametime; switch (p.type) { case ptype_t.pt_static: break; case ptype_t.pt_fire: p.ramp += time1; if (p.ramp >= 6) { p.die = -1; } else { p.color = _Ramp3[(int)p.ramp]; } p.vel.Z += grav; break; case ptype_t.pt_explode: p.ramp += time2; if (p.ramp >= 8) { p.die = -1; } else { p.color = _Ramp1[(int)p.ramp]; } p.vel += p.vel * dvel; p.vel.Z -= grav; break; case ptype_t.pt_explode2: p.ramp += time3; if (p.ramp >= 8) { p.die = -1; } else { p.color = _Ramp2[(int)p.ramp]; } p.vel -= p.vel * frametime; p.vel.Z -= grav; break; case ptype_t.pt_blob: p.vel += p.vel * dvel; p.vel.Z -= grav; break; case ptype_t.pt_blob2: p.vel -= p.vel * dvel; p.vel.Z -= grav; break; case ptype_t.pt_grav: case ptype_t.pt_slowgrav: p.vel.Z -= grav; break; } } GL.End(); GL.Disable(EnableCap.Blend); GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Replace); }
/// <summary> /// R_BlendLightmaps /// </summary> private static void BlendLightmaps() { if (_FullBright.Value != 0) { return; } if (_glTexSort.Value == 0) { return; } GL.DepthMask(false); // don't bother writing Z if (Drawer.LightMapFormat == PixelFormat.Luminance) { GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor); } //else if (gl_lightmap_format == GL_INTENSITY) //{ // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // glColor4f(0, 0, 0, 1); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //} if (_LightMap.Value == 0) { GL.Enable(EnableCap.Blend); } for (int i = 0; i < MAX_LIGHTMAPS; i++) { glpoly_t p = _LightMapPolys[i]; if (p == null) { continue; } Drawer.Bind(_LightMapTextures + i); if (_LightMapModified[i]) { CommitLightmap(i); } for ( ; p != null; p = p.chain) { if ((p.flags & Surf.SURF_UNDERWATER) != 0) { DrawGLWaterPolyLightmap(p); } else { GL.Begin(PrimitiveType.Polygon); for (int j = 0; j < p.numverts; j++) { float[] v = p.verts[j]; GL.TexCoord2(v[5], v[6]); GL.Vertex3(v); } GL.End(); } } } GL.Disable(EnableCap.Blend); if (Drawer.LightMapFormat == PixelFormat.Luminance) { GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); } //else if (gl_lightmap_format == GL_INTENSITY) //{ // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // glColor4f(1, 1, 1, 1); //} GL.DepthMask(true); // back to normal Z buffering }
private static byte[] _LightMaps = new byte[4 * MAX_LIGHTMAPS * BLOCK_WIDTH * BLOCK_HEIGHT]; // lightmaps /// <summary> /// GL_BuildLightmaps /// Builds the lightmap texture with all the surfaces from all brush models /// </summary> private static void BuildLightMaps() { Array.Clear(_Allocated, 0, _Allocated.Length); //memset (allocated, 0, sizeof(allocated)); _FrameCount = 1; // no dlightcache if (_LightMapTextures == 0) { _LightMapTextures = Drawer.GenerateTextureNumberRange(MAX_LIGHTMAPS); } Drawer.LightMapFormat = PixelFormat.Luminance;// GL_LUMINANCE; // default differently on the Permedia if (Scr.IsPermedia) { Drawer.LightMapFormat = PixelFormat.Rgba; } if (common.HasParam("-lm_1")) { Drawer.LightMapFormat = PixelFormat.Luminance; } if (common.HasParam("-lm_a")) { Drawer.LightMapFormat = PixelFormat.Alpha; } //if (Common.HasParam("-lm_i")) // Drawer.LightMapFormat = PixelFormat.Intensity; //if (Common.HasParam("-lm_2")) // Drawer.LightMapFormat = PixelFormat.Rgba4; if (common.HasParam("-lm_4")) { Drawer.LightMapFormat = PixelFormat.Rgba; } switch (Drawer.LightMapFormat) { case PixelFormat.Rgba: _LightMapBytes = 4; break; //case PixelFormat.Rgba4: //_LightMapBytes = 2; //break; case PixelFormat.Luminance: //case PixelFormat.Intensity: case PixelFormat.Alpha: _LightMapBytes = 1; break; } for (int j = 1; j < QDef.MAX_MODELS; j++) { model_t m = client.cl.model_precache[j]; if (m == null) { break; } if (m.name != null && m.name.StartsWith("*")) { continue; } _CurrentVertBase = m.vertexes; _CurrentModel = m; for (int i = 0; i < m.numsurfaces; i++) { CreateSurfaceLightmap(m.surfaces[i]); if ((m.surfaces[i].flags & Surf.SURF_DRAWTURB) != 0) { continue; } if ((m.surfaces[i].flags & Surf.SURF_DRAWSKY) != 0) { continue; } BuildSurfaceDisplayList(m.surfaces[i]); } } if (_glTexSort.Value == 0) { Drawer.SelectTexture(MTexTarget.TEXTURE1_SGIS); } // // upload all lightmaps that were filled // GCHandle handle = GCHandle.Alloc(_LightMaps, GCHandleType.Pinned); try { IntPtr ptr = handle.AddrOfPinnedObject(); long lmAddr = ptr.ToInt64(); for (int i = 0; i < MAX_LIGHTMAPS; i++) { if (_Allocated[i, 0] == 0) { break; // no more used } _LightMapModified[i] = false; _LightMapRectChange[i].l = BLOCK_WIDTH; _LightMapRectChange[i].t = BLOCK_HEIGHT; _LightMapRectChange[i].w = 0; _LightMapRectChange[i].h = 0; Drawer.Bind(_LightMapTextures + i); Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear); long addr = lmAddr + i * BLOCK_WIDTH * BLOCK_HEIGHT * _LightMapBytes; GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormat)_LightMapBytes, BLOCK_WIDTH, BLOCK_HEIGHT, 0, Drawer.LightMapFormat, PixelType.UnsignedByte, new IntPtr(addr)); } } finally { handle.Free(); } if (_glTexSort.Value == 0) { Drawer.SelectTexture(MTexTarget.TEXTURE0_SGIS); } }
/// <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); } }
/// <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); } }
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); }