1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498:
| using System; using System.Collections.Generic; using System.Text;
using Fetze.Module; using Fetze.Utility; using Fetze.Module.ZweiDeXT.Shader; using Clr = Fetze.Utility.Color;
namespace ZweiDe_Application { public sealed class Light { private static List<Reciever> recievers = new List<Reciever>(); private static List<Reciever> recieversH = new List<Reciever>(); private static List<Reciever> recieversV = new List<Reciever>(); private static List<Source> lights = new List<Source>(); private static ZweiDe.Texture lightMap = null; private static ZweiDe.Texture whiteTex = null; private static Clr.RGBA ambient = new Clr.RGBA(128, 128, 128, 255); private static float ambientIntensity = 1.0f; private static bool hdrEnabled = true; private static bool normEnabled = true;
public static Clr.RGBA AmbientLight { get { return Light.ambient; } set { Light.ambient = value; } } public static float AmbientIntensity { get { return Light.ambientIntensity; } set { Light.ambientIntensity = value; } } public static bool HDREnabled { get { return Light.hdrEnabled; } set { if (Light.hdrEnabled != value) { Light.hdrEnabled = value; Light.lightMap = null; } } } public static bool NormalMapsEnabled { get { return Light.normEnabled; } set { Light.normEnabled = value; } }
public static ZweiDe.Texture Lightmap { get { return Light.lightMap; } }
#region Default lightmap shader private static Shader.Program shLightmapDefault = new Shader.Program( new Shader.Vertex[] { Shader.Vertex.Load( new string[] { "uniform vec3 lightPos;", "varying vec3 lightVec;", "void main()", "{", "\tlightVec = lightPos - gl_Vertex.xyz;", "\tgl_Position = ftransform();", "\tgl_TexCoord[0] = gl_MultiTexCoord0;", "\tgl_FrontColor = gl_Color;", "}"} ) }, new Shader.Fragment[] { Shader.Fragment.Load( new string[] { "uniform sampler2D normal;", "uniform float lightRange;", "varying vec3 lightVec;", "void main()", "{", "\tvec4 texClr = texture2D(normal, gl_TexCoord[0].st);", "\tfloat distCoeff = 1.0 - clamp(length(lightVec) / lightRange, 0.0, 1.0);", "\tfloat lightVal = ", "\tdot(2.0 * (texClr.xyz - 0.5), normalize(lightVec)) *", "\tdistCoeff * distCoeff;", "\tgl_FragColor = vec4(gl_Color.xyz * lightVal, texClr.w);", "}"} ) }); private static Shader.Program shLightmapConv = new Shader.Program( new Shader.Vertex[0], new Shader.Fragment[] { Shader.Fragment.Load( new string[] { "uniform sampler2D tex;", "uniform float mult;", "uniform float bias;", "void main()", "{", "\tgl_FragColor = gl_Color * (texture2D(tex, gl_TexCoord[0].st) + bias) * mult;", "}"} ) }); #endregion
public sealed class Reciever { private bool vertical = false; private ZweiDe.Texture normalTex = null; private Vector2D pos = new Vector2D();
public bool IsVertical { get { return this.vertical; } } public ZweiDe.Texture NormalmapTex { get { return this.normalTex; } } public Vector2D Pos { get { return this.pos; } }
public Reciever(ZweiDe.Texture normTex, double xPos, double yPos, bool vertical) { this.vertical = vertical; this.pos = new Vector2D(xPos, yPos); this.normalTex = normTex; Light.recievers.Add(this); if (vertical) Light.recieversV.Add(this); else Light.recieversH.Add(this); } public void Dispose() { Light.recievers.Remove(this); if (this.vertical) Light.recieversV.Remove(this); else Light.recieversH.Remove(this); this.normalTex = null; }
public void SetPosition(double x, double y) { this.pos.x = x; this.pos.y = y; } public void SetNormalmapTex(ZweiDe.Texture tex) { this.normalTex = tex; }
internal void Draw( float xOffset, float yOffset, float minX, float minY, float maxX, float maxY) { Point<float> posTemp; posTemp.x = (float)this.pos.x - this.normalTex.Handle.x - xOffset; posTemp.y = (float)this.pos.y - this.normalTex.Handle.y - yOffset; Rect<float> texCoord; texCoord.x = Math.Max(0.0f, minX - posTemp.x); texCoord.y = Math.Max(0.0f, minY - posTemp.y); texCoord.w = this.normalTex.Width - Math.Max(0.0f, posTemp.x + this.normalTex.Width - maxX) - texCoord.x; texCoord.h = this.normalTex.Height - Math.Max(0.0f, posTemp.y + this.normalTex.Height - maxY) - texCoord.y; ZweiDe.DrawTexturePart( this.normalTex, Math.Max(posTemp.x, minX), Math.Max(posTemp.y, minY), texCoord.x, texCoord.y, texCoord.w, texCoord.h); } }
public sealed class Source { private bool disabled = false; private Vector3D pos = new Vector3D(); private float range = 250.0f; private float intensity = 1.0f; private Clr.RGBA clr = new Clr.RGBA(255, 255, 255, 255); private Shader.Program shLightmap = Light.shLightmapDefault; internal ZweiDe.Texture texTemp = null;
public Vector3D Pos { get { return this.pos; } } public float Range { get { return this.range; } } public float FlatRange { get { return (float)Math.Sqrt(this.range * this.range - this.pos.z * this.pos.z); } } public float Intensity { get { return this.intensity; } } public Clr.RGBA Color { get { return this.clr; } } public Shader.Program LightmapShader { get { return this.shLightmap; } }
public bool Disabled { get { return this.disabled; } set { this.disabled = value; } }
static Source() { Light.shLightmapDefault.Compile(); Light.shLightmapConv.Compile(); } public Source(double x, double y, double z) { this.pos = new Vector3D(x, y, z); this.UpdateTempTex(); Light.lights.Add(this); } public Source() : this(0, 0, 0) {} public void Dispose() { Light.lights.Remove(this); this.shLightmap = null; }
private void UpdateTempTex() { if (this.texTemp == null) { this.texTemp = ZweiDe.Texture.Create(ZweiDe.WindowSize.x, ZweiDe.WindowSize.y); this.texTemp.CreateRenderBuffer(ZweiDe.Texture.TexFlag.None); int width = (int)Math.Ceiling(this.range * 2.0f); int height = ZweiDe.WindowSize.y; int oglWidth; int oglHeight; int maxSize = ZweiDe.Texture.GetMaxSize(); if (width < 1) width = 1; if (height < 1) height = 1; if (width > maxSize) width = maxSize; if (height > maxSize) height = maxSize; if (this.texTemp != null) { oglWidth = this.texTemp.OglWidth; oglHeight = this.texTemp.OglHeight; } else { oglWidth = 0; oglHeight = 0; } if (this.texTemp == null || width > oglWidth) { if (this.texTemp != null) { this.texTemp.Dispose(); this.texTemp = null; } this.texTemp = ZweiDe.Texture.Create(width, height); this.texTemp.CreateRenderBuffer(ZweiDe.Texture.TexFlag.None); } else { this.texTemp.ForceBoundaries(width, height, (float)width / (float)oglWidth, (float)height / (float)oglHeight); } } }
public void SetPosition(double x, double y, double z) { this.pos.x = x; this.pos.y = y; this.pos.z = z; } public void SetRange(float range) { if (this.range != range) { this.range = range; this.UpdateTempTex(); } } public void SetIntensity(float intensity) { this.intensity = intensity; } public void SetColor(byte r, byte g, byte b) { this.clr.r = r; this.clr.g = g; this.clr.b = b; } public void SetShader(Shader.Program shader) { this.shLightmap = shader; }
internal Rect<int> UpdateLmTex(float xOffset, float yOffset) { if (this.disabled) return new Rect<int>(0, 0, -1, -1); Rect<int> litArea = new Rect<int>(ZweiDe.WindowSize.x, ZweiDe.WindowSize.y, 0, 0); ZweiDe.BlendMode blendB4 = ZweiDe.DrawBlend; Clr.RGBA clrB4 = ZweiDe.DrawColor; Shader.Program shB4 = Shader.Program.CurrentBound; if (shB4 != this.shLightmap) Shader.Program.Bind(this.shLightmap);
this.texTemp.BindRenderBuffer(); ZweiDe.Cls(); xOffset += (float)Math.Round(this.pos.x - this.range);
ZweiDe.SetBlend(ZweiDe.BlendMode.Alpha); ZweiDe.SetColor(this.clr.r, this.clr.g, this.clr.b, this.clr.a); Shader.Program.SetUniform("lightRange", this.range);
Rect<float> minmax; int drawCount; float hRangeTemp = this.FlatRange; if (this.pos.z < this.range && this.pos.z >= 0.0f) { Shader.Program.SetUniform("lightPos", (float)this.pos.x - xOffset, (float)this.pos.y - yOffset, (float)this.pos.z); minmax = new Rect<float>( Math.Max(0.0f, (float)this.pos.x - xOffset - hRangeTemp), Math.Max(0.0f, (float)this.pos.y - yOffset - hRangeTemp), Math.Min(ZweiDe.WindowSize.x, (float)this.pos.x - xOffset + hRangeTemp), Math.Min(ZweiDe.WindowSize.y, (float)this.pos.y - yOffset + hRangeTemp)); drawCount = 0; for (int i = 0; i < Light.recieversH.Count; i++) { if (Light.recieversH[i].Pos.x - Light.recieversH[i].NormalmapTex.Handle.x - xOffset > minmax.w) continue; if (Light.recieversH[i].Pos.y - Light.recieversH[i].NormalmapTex.Handle.y - yOffset > minmax.h) continue; if (Light.recieversH[i].Pos.x - Light.recieversH[i].NormalmapTex.Handle.x - xOffset + Light.recieversH[i].NormalmapTex.Width < minmax.x) continue; if (Light.recieversH[i].Pos.y - Light.recieversH[i].NormalmapTex.Handle.y - yOffset + Light.recieversH[i].NormalmapTex.Height < minmax.y) continue; Light.recieversH[i].Draw( xOffset, yOffset, minmax.x, minmax.y, minmax.w, minmax.h); drawCount++; } if (drawCount > 0) { litArea.x = Math.Min(litArea.x, (int)minmax.x); litArea.y = Math.Min(litArea.y, (int)minmax.y); litArea.w = Math.Max(litArea.w, (int)minmax.w); litArea.h = Math.Max(litArea.h, (int)minmax.h); } } minmax = new Rect<float>( Math.Max(0.0f, (float)this.pos.x - xOffset - hRangeTemp), Math.Max(0.0f, (float)this.pos.y - yOffset - this.range), Math.Min(ZweiDe.WindowSize.x, (float)this.pos.x - xOffset + hRangeTemp), Math.Min(ZweiDe.WindowSize.y, (float)this.pos.y - yOffset + this.range)); drawCount = 0; for (int i = 0; i < Light.recieversV.Count; i++) { if (Light.recieversV[i].Pos.x - Light.recieversV[i].NormalmapTex.Handle.x - xOffset > minmax.w) continue; if (Light.recieversV[i].Pos.y - Light.recieversV[i].NormalmapTex.Handle.y - yOffset > minmax.h) continue; if (Light.recieversV[i].Pos.x - Light.recieversV[i].NormalmapTex.Handle.x - xOffset + Light.recieversV[i].NormalmapTex.Width < minmax.x) continue; if (Light.recieversV[i].Pos.y - Light.recieversV[i].NormalmapTex.Handle.y - yOffset + Light.recieversV[i].NormalmapTex.Height < minmax.y) continue; Shader.Program.SetUniform("lightPos", (float)this.pos.x - xOffset, (float)-this.pos.z - yOffset + (float)Light.recieversV[i].Pos.y, (float)this.pos.y - (float)Light.recieversV[i].Pos.y); Light.recieversV[i].Draw( xOffset, yOffset, minmax.x, 0, minmax.w, ZweiDe.WindowSize.y); drawCount++; } if (drawCount > 0) { litArea.y = Math.Min(litArea.y, 0); litArea.h = Math.Max(litArea.h, ZweiDe.WindowSize.y); } ZweiDe.SetBlend(blendB4); ZweiDe.SetColor(clrB4.r, clrB4.g, clrB4.b, clrB4.a);
this.texTemp.UnbindRenderBuffer(); if (shB4 != this.shLightmap) Shader.Program.Bind(shB4);
litArea.w -= litArea.x; litArea.h -= litArea.y; return litArea; } }
public static void UpdateLightmap(float xOffset, float yOffset) { ZweiDe.Cls(ZweiDe.ClsMode.Accum | ZweiDe.ClsMode.Color);
if (Light.lightMap == null) { Light.lightMap = ZweiDe.Texture.Create(ZweiDe.WindowSize.x, ZweiDe.WindowSize.y); if (Light.hdrEnabled) Light.lightMap.CreateRenderBuffer(ZweiDe.Texture.TexFlag.None, false, true); else Light.lightMap.CreateRenderBuffer(ZweiDe.Texture.TexFlag.None, false, false); }
Rect<int> litArea; for (int i = 0; i < Light.lights.Count; i++) { litArea = Light.lights[i].UpdateLmTex(xOffset, yOffset); }
Clr.RGBA clsclrB4 = ZweiDe.ClsColor; ZweiDe.ClsColor = new Clr.RGBA(0, 0, 0, 255); Light.lightMap.BindRenderBuffer(); ZweiDe.Cls(); if (Light.hdrEnabled) ZweiDe.SetBlend(ZweiDe.BlendMode.TotalAdd); else ZweiDe.SetBlend(ZweiDe.BlendMode.Light); ZweiDe.BlendMode blendB4 = ZweiDe.DrawBlend;
if (Light.hdrEnabled) { Shader.Program.Bind(Light.shLightmapConv); Shader.Program.SetUniform("mult", 0.01f * Light.ambientIntensity); Shader.Program.SetUniform("bias", 0.0f); } Clr.RGBA clrB4 = ZweiDe.DrawColor; ZweiDe.SetColor(ambient.r, ambient.g, ambient.b, Light.hdrEnabled ? (byte)255 : (byte)(255.0f * Math.Min(1.0f, Math.Max(0.0f, Light.ambientIntensity)))); if (Light.hdrEnabled) { if (Light.whiteTex == null) { Light.whiteTex = ZweiDe.Pixmap.Create(1, 1, new byte[] {255, 255, 255, 255}).ToTexture(ZweiDe.Texture.TexFlag.EdgeClamp, true); } ZweiDe.DrawTextureArea(Light.whiteTex, 0, 0, ZweiDe.WindowSize.x, ZweiDe.WindowSize.y, false); ZweiDe.SetColor(clrB4.r, clrB4.g, clrB4.b, clrB4.a); } else { ZweiDe.DrawRect(0, 0, ZweiDe.WindowSize.x, ZweiDe.WindowSize.y); }
for (int i = 0; i < Light.lights.Count; i++) { if (Light.lights[i].Disabled) continue; if (Light.hdrEnabled) Shader.Program.SetUniform("mult", 0.01f * Light.lights[i].Intensity); else ZweiDe.SetColor(255, 255, 255, (byte)(255.0f * Math.Min(1.0f, Math.Max(0.0f, Light.lights[i].Intensity)))); ZweiDe.DrawTexture( Light.lights[i].texTemp, (float)Math.Round(Light.lights[i].Pos.x - Light.lights[i].Range), 0); } if (!Light.hdrEnabled) ZweiDe.SetColor(clrB4.r, clrB4.g, clrB4.b, clrB4.a);
if (Light.hdrEnabled) Shader.Program.Bind(null); Light.lightMap.UnbindRenderBuffer(); ZweiDe.ClsColor = clsclrB4;
ZweiDe.SetBlend(blendB4); } public static void ApplyLightmap() { ZweiDe.BlendMode blendB4 = ZweiDe.DrawBlend; if (Light.hdrEnabled) Shader.Program.Bind(Light.shLightmapConv);
ZweiDe.SetBlend(ZweiDe.BlendMode.Shade); if (Light.hdrEnabled) Shader.Program.SetUniform("mult", 100.0f); ZweiDe.DrawTexture(Light.lightMap, 0, 0); if (Light.hdrEnabled) { ZweiDe.SetBlend(ZweiDe.BlendMode.SoftLight); Shader.Program.SetUniform("bias", -0.01f); ZweiDe.DrawTexture(Light.lightMap, 0, 0); ZweiDe.SetBlend(ZweiDe.BlendMode.Light); Shader.Program.SetUniform("bias", -0.02f); ZweiDe.DrawTexture(Light.lightMap, 0, 0);
Shader.Program.Bind(null); } ZweiDe.SetBlend(blendB4); } } } |