using System.ComponentModel; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using skyscraper5.Skyscraper.Plugins; using Color = System.Drawing.Color; namespace skyscraper8.UI.MonoGame.Screenhacks { [PluginPriority(2)] [DisplayName("Substrate")] internal class _2_Substrate : Processing, IScreenhack { int dimx = 250; int dimy = 250; int num = 0; int maxnum = 100; // grid of cracks int[] cgrid; Crack[] cracks; // color parameters int maxpal = 512; int numpal = 0; private Color[] goodcolor; // sand painters SandPainter[] sands; private void Begin() { // erase crack grid for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { cgrid[y * dimx + x] = 10001; } } // make random crack seeds for (int k = 0; k < 16; k++) { int i = (Random(dimx * dimy - 1)); cgrid[i] = (Random(360)); } // make just three cracks num = 0; for (int k = 0; k < 3; k++) { MakeCrack(); } //Background(Color.FromArgb(255, 255, 255, 255)); } private void MakeCrack() { if (num < maxnum) { // make a new crack instance cracks[num] = new Crack(this); num++; } } private void TakeColor() { uint[] srcArrays = { 0x201F21, 0x262C2E, 0x352626, 0x372B27, 0x302C2E, 0x392B2D, 0x323229, 0x3F3229, 0x38322E, 0x2E333D, 0x333A3D, 0x473329, 0x40392C, 0x40392E, 0x47402C, 0x47402E, 0x4E402C, 0x4F402E, 0x4E4738, 0x584037, 0x65472D, 0x6D5D3D, 0x745530, 0x755532, 0x745D32, 0x746433, 0x7C6C36, 0x523152, 0x444842, 0x4C5647, 0x655D45, 0x6D5D44, 0x6C5D4E, 0x746C43, 0x7C6C42, 0x7C6C4B, 0x6B734B, 0x73734B, 0x7B7B4A, 0x6B6C55, 0x696D5E, 0x7B6C5D, 0x6B7353, 0x6A745D, 0x727B52, 0x7B7B52, 0x57746E, 0x687466, 0x9C542B, 0x9D5432, 0x9D5B35, 0x936B36, 0xAA7330, 0xC45A27, 0xD95223, 0xD85A20, 0xDB5A23, 0xE57037, 0x836C4B, 0x8C6B4B, 0x82735C, 0x937352, 0x817B63, 0x817B6D, 0x927B63, 0xD9893B, 0xE49832, 0xDFA133, 0xE5A037, 0xF0AB3B, 0x8A8A59, 0xB29A58, 0x89826B, 0x9A8262, 0x888B7C, 0x909A7A, 0xA28262, 0xA18A69, 0xA99968, 0x99A160, 0x99A168, 0xCA8148, 0xEB8D43, 0xC29160, 0xC29168, 0xD1A977, 0xC9B97F, 0xF0E27B, 0x9F928B, 0xC0B999, 0xE6B88F, 0xC8C187, 0xE0C886, 0xF2CC85, 0xF5DA83, 0xECDE9D, 0xF5D294, 0xF5DA94, 0xF4E784, 0xF4E18A, 0xF4E193, 0xE7D8A7, 0xF1D4A5, 0xF1DCA5, 0xF4DBAD, 0xF1DCAE, 0xF4DBB5, 0xF5DBBD, 0xF4E2AD, 0xF5E9AD, 0xF4E3BE, 0xF5EABE, 0xF7F0B6, 0xD9D1C1, 0xE0D0C0, 0xE7D8C0, 0xF1DDC6, 0xE8E1C0, 0xF3EDC7, 0xF6ECCE, 0xF8F2C7, 0xEFEFD0, 0 }; for (int i = 0; i < srcArrays.Length; i++) { srcArrays[i] |= 0xff000000; goodcolor[i] = Color.FromArgb((int)srcArrays[i]); } numpal = srcArrays.Length; } class Crack { private readonly _2_Substrate _parent; private float x, y, t; private SandPainter sp; public Crack(_2_Substrate parent) { _parent = parent; FindStart(); sp = new SandPainter(_parent); } private void FindStart() { // pick random point int px = 0; int py = 0; // shift until crack is found bool found = false; int timeout = 0; while ((!found) || (timeout++ > 1000)) { px = (_parent.Random(_parent.dimx)); py = (_parent.Random(_parent.dimy)); if (_parent.cgrid[py * _parent.dimx + px] < 10000) { found = true; } } if (found) { // start crack int a = _parent.cgrid[py * _parent.dimx + px]; if (_parent.Random(100) < 50) { a -= 90 + (int)(_parent.Random(-2.0f, 2.1f)); } else { a += 90 + (int)(_parent.Random(-2.0f, 2.1f)); } StartCrack(px, py, a); } else { //println("timeout: "+timeout); } } private void StartCrack(int X, int Y, int T) { x = X; y = Y; t = T; //%360; x += 0.61f * (float)Math.Cos(t * Math.PI / 180.0); y += 0.61f * (float)Math.Sin(t * Math.PI / 180.0); } public void Move() { // continue cracking x += 0.42f * (float)Math.Cos(t * Math.PI / 180); y += 0.42f * (float)Math.Sin(t * Math.PI / 180); // bound check float z = 0.33f; int cx = (int)(x + _parent.Random(-z, z)); // add fuzz int cy = (int)(y + _parent.Random(-z, z)); // draw sand painter RegionColor(); // draw black crack _parent.Stroke(0.0f, 85.0f); _parent.Point(x + _parent.Random(-z, z), y + _parent.Random(-z, z)); if ((cx >= 0) && (cx < _parent.dimx) && (cy >= 0) && (cy < _parent.dimy)) { // safe to check if ((_parent.cgrid[cy * _parent.dimx + cx] > 10000) || (Math.Abs(_parent.cgrid[cy * _parent.dimx + cx] - t) < 5)) { // continue cracking _parent.cgrid[cy * _parent.dimx + cx] = (int)(t); } else if (Math.Abs(_parent.cgrid[cy * _parent.dimx + cx] - t) > 2) { // crack encountered (not self), stop cracking FindStart(); _parent.MakeCrack(); } } else { // out of bounds, stop cracking FindStart(); _parent.MakeCrack(); } } private void RegionColor() { // start checking one step away float rx = x; float ry = y; bool openspace = true; // find extents of open space while (openspace) { // move perpendicular to crack rx += 0.81f * (float)Math.Sin(t * Math.PI / 180.0); ry -= 0.81f * (float)Math.Cos(t * Math.PI / 180.0); int cx = (int)(rx); int cy = (int)(ry); if ((cx >= 0) && (cx < _parent.dimx) && (cy >= 0) && (cy < _parent.dimy)) { // safe to check if (_parent.cgrid[cy * _parent.dimx + cx] > 10000) { // space is open } else { openspace = false; } } else { openspace = false; } } // draw sand painter sp.Render(rx, ry, x, y); } } class SandPainter { private readonly _2_Substrate _parent; public SandPainter(_2_Substrate _parent) { this._parent = _parent; c = _parent.SomeColor(); g = _parent.Random(0.01f, 0.1f); } private Color c; private float g; public void Render(float x, float y, float ox, float oy) { // modulate gain g += _parent.Random(-0.050f, 0.050f); float maxg = 1.0f; if (g < 0) g = 0; if (g > maxg) g = maxg; // calculate grains by distance //int grains = (int)(Math.Sqrt((ox-x)*(ox-x)+(oy-y)*(oy-y))); int grains = 64; // lay down grains of sand (transparent pixels) float w = g / (grains - 1); for (int i = 0; i < grains; i++) { float a = 0.1f - i / (grains * 10.0f); _parent.Stroke(c.R, c.G, c.B, a * 256); _parent.Point(ox + (x - ox) * (float)Math.Sin(Math.Sin(i * w)), oy + (y - oy) * (float)Math.Sin(Math.Sin(i * w))); } } } private Color SomeColor() { if (rng == null) rng = new Random(); return goodcolor[rng.Next(numpal)]; } public void Draw(GameTime gameTime, SpriteBatch spriteBatch, Rectangle windowBounds) { for (int n = 0; n < num; n++) { cracks[n].Move(); } texture.SetData(textureColors); spriteBatch.Draw(texture, windowBounds, Microsoft.Xna.Framework.Color.White); } private Texture2D texture; private Microsoft.Xna.Framework.Color[] textureColors; private int screenWidth, screenHeight; public void SetGraphicsDevice(GraphicsDevice graphicsDevice, Rectangle presentationParametersBounds) { screenWidth = presentationParametersBounds.Width; screenHeight = presentationParametersBounds.Height; texture = new Texture2D(graphicsDevice, presentationParametersBounds.Width, presentationParametersBounds.Height); textureColors = new Microsoft.Xna.Framework.Color[presentationParametersBounds.Width * presentationParametersBounds.Height]; texture.GetData(textureColors); for (int i = 0; i < textureColors.Length; i++) { textureColors[i] = Microsoft.Xna.Framework.Color.White; } goodcolor = new Color[maxpal]; //Background(Color.FromArgb(255, 255, 255, 255)); TakeColor(); dimx = presentationParametersBounds.Width; dimy = presentationParametersBounds.Height; cgrid = new int[dimx * dimy]; cracks = new Crack[maxnum]; Begin(); } public void Dispose() { } protected override void Point(float x, float y) { int ix = (int)x; int iy = (int)y; if (y < 0) return; if (y >= screenHeight) return; if (x < 0) return; if (x > screenWidth) return; textureColors[(iy * screenWidth) + ix].A = strokeColorObject.A; textureColors[(iy * screenWidth) + ix].R = strokeColorObject.R; textureColors[(iy * screenWidth) + ix].G = strokeColorObject.G; textureColors[(iy * screenWidth) + ix].B = strokeColorObject.B; } } }