From ea15397725d73782f0fc86eaa6e7bf4b3efa2804 Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 8 Sep 2015 21:55:27 +0300 Subject: [PATCH] Merged linux changes, water effect using a BasicEffect and a simpler pixel shader, multi-colored wires --- .../Content/Items/Electricity/signalitems.xml | 48 ++++++ Subsurface/Content/Items/Weapons/railgun.xml | 2 +- .../Content/Items/Weapons/railgunbase.png | Bin 2001 -> 1987 bytes Subsurface/Content/watershader.mgfx | Bin 0 -> 1874 bytes .../BackgroundSpriteManager.cs | 11 +- Subsurface/Source/EventInput/EventInput.cs | 6 + Subsurface/Source/GUI/TitleScreen.cs | 2 +- Subsurface/Source/Map/Hull.cs | 71 +++++--- Subsurface/Source/Map/WaterRenderer.cs | 161 +++++------------- Subsurface/Source/Networking/GameServer.cs | 1 - Subsurface/Source/PlayerInput.cs | 21 ++- Subsurface/Source/Program.cs | 6 +- Subsurface/Source/Screens/GameScreen.cs | 6 +- Subsurface/Source/Utils/TextureLoader.cs | 75 ++++---- Subsurface/Subsurface.csproj | 3 + Subsurface/Subsurface.csproj.user | 2 +- Subsurface_Solution.sln | 3 - Subsurface_Solution.v12.suo | Bin 647680 -> 668160 bytes 18 files changed, 221 insertions(+), 197 deletions(-) create mode 100644 Subsurface/Content/watershader.mgfx diff --git a/Subsurface/Content/Items/Electricity/signalitems.xml b/Subsurface/Content/Items/Electricity/signalitems.xml index c42fd6b19..8e64051b4 100644 --- a/Subsurface/Content/Items/Electricity/signalitems.xml +++ b/Subsurface/Content/Items/Electricity/signalitems.xml @@ -19,6 +19,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/Subsurface/Content/Items/Weapons/railgunbase.png b/Subsurface/Content/Items/Weapons/railgunbase.png index bf2ef92f7741b6cfbfe72c01182dcdf0fd07eac6..00350556cf0e267ad2c6a970572de25f6133d9df 100644 GIT binary patch literal 1987 zcmb_d`&Uy}7T))A2{#EyAPN{Mx#ekHB7qsIfXWql1PTQ4g$NP~BTTg-Ixq;5TwZmY z+QmydObbPpWd^aPaV&#KX)f5QIx3)|AWKSEq98$tj)6d4b79uZ`~&^r?7i3i_P5Vj z>+J8G(+TlWb{qi*0PLd0;fVkU6C!}K7?*Oa@1Ax?|~ zDD(oL$^aHDjDHD`Cjyv~0tD9qIOo)){UZ{5-6{H9;%GckHS7d|*#e zR{(3Tx8(D=a)0mf*ZW6p#yb>|AKG(IRNH6nmRxS*Qn3ef5E1}iIu8MW0R_MVK;aik zUQ5~Vr#pT*-TK&v1CPyXF1Otd2~rPdUq0cCoeadb0nQG2j|bRSJRHI#ER6bFlV!m? zJUzN-n($lAgLR+C?woIYj}<^blb`FHM>EO72z>)4lf27AkRPq(<^4Inm^(o=m4y~g zo~8gxo7`B7IPfU-k|l*>&WomS5@kr?B!(sU7)vD>CLO#P?M@)5Qd0|Trj)-#&_;bq zVYu|6mixo|B;*%Y0WzdZ_nfp>Ig|QR&mZYx3f>A3Jd|BUIY?i+^NeSzi9FZ3iZp#& z$y09;SEa2b71+TsXPM)zbM$&+j|A;-T!N#Cz35dfH(}Gc{%JOYDLkdq;c~)gknh zVoHP6Z_xx(lXW&w2mkC1ouP$El^9_ZahC2-Y1qyssEiFP>4=>tq%D@@wIV~NbW<~% zp0U^Lwo)2y1jq8J5n(dLY;a0fx76S}uw!PS#iHDhft@$sa8W+%dz7r1`RuCU+h_BQ zD#2s+Z0@0tTj!3Ok6pyf4XW*UMq)BdS*|q6=SMxto@+XixofweEtUzJ(K^wbi#mfG zOVbrbsl3Ak)G67tvr(g4e52|ZIWkO=+{qYldh$lA;xD!Z94*Ev;8e)tCI@fPdG4UI zjHk*gwQ_fKaB88g)xG2hCf(N1uBoN3`O<#{tK3X|U%?h0)$nzaOJkR!64&fJf{840 zr@zE>YA;mNZI_Bx^ha1Jsl}ma;qA3u>|F;`k?^a~dW6&sqB!Ks?v+Dt&ns2N>=(Cv z)jtQ36}qkS`k$VdO!Xpk$YheId%3Zlt{X-TcV(JXLt&TfYopFDlEt6+K~nX8?ZD7rW6YsAD~(`{lmFNtT(MMOTIGcg)RMi z=uNANpA3YR_5Aj&XAKMH>z!*}J-RkyGG=avO-*JMXQ3-}BkTV%G`*hE-Wzj8q`a@T z)IU4WUsR;WA3r+)AA$|ZU;y*(B%0C?R z0T;FuV>IpZ!c}eiR2&ZU2i@qG6Na!oV!+`xK*$ZVuRNFqnEQ3vHLQBhDT) z5vTqpSDoLvI^qn7H}ea0h52%n?w&xRqDg%N;+oHrZY$1rQ%-cyA*H#O7lW+U`cP4h z%9h?$-JSP(@}_)@7|*lBD?p!FzdRMe)%5)dM}-}-$;KrCQ`~%`*%1L=Le6mVmu}H8 zTX9U{fSVU}sn4@s?^1V1D9_oJ%VKfLwtQ<{O&0X^qU&ScZno?#nrqHM(eB^*K)cP2 zU^@pYsv^U4og&Kvq*%hY)Q`G-2jC}Yu?QIPh*hBJmJlj#@MgBhi+;2q|B4u1 zj#XxZCydz(5i#@#Wh@fqnWab-l!vA)=beE~=dEBYZh6q=FW7m=x6nWK;ajbpe!*Ph z)Rtz|&pZ_Z@-V-jRo)0<3cG8Fqy}PZ+Q!K0-5{Ggf}id0dlLQL6!{ef0U zfO$%-%lwv#@{4)&6-NT?+=}oJ2mHUb3LFl*ogDL_jzo~GJKO#AnCL8?_#5T;rAMU< zozN51l?YJ{@A1=cFFi(L?{LyzHPkXtX8&p4->=6dPqHc7_cK2Tn%1qyntZ^ODEo+M zPKa5k1aQYvnh#-L6Vn*g{hS!bKuTNQIO{h-(!)BM)^&@B!hWz~BQ~AFC+bl?qN9Hz14QnR_EB z1*|x-@`hlwtGflkMF9npi%Erb9IRW*!vF~zzy}}{frPy7hSqND?9TqNXU>`LJHPq9 z^L^hrXMSH^ ziwpZ`Hvs9Y0l>2XSRk$PB>*Yj0K7s0*is6Bv+z>vH#-5K9}Eu(+?V=nVldzWcgK6g za8*zK#ze>y?ay1m+Zs4R>Fo8p<(#cr^S4xQB`-F>b_K`rezx}Ve ztYyncr;6${xp;76W9wG#(#`xmMZo|D48Q|8_(d_drZ67dR!#b(6+9nK?DH$91ng~F z?yJL@Il$MJc9cs6!Co{NmpD_Qnkflpnf)Q2tlKPax9)k*G(x|TsDJXPF#3YBG`+z4 za|yV{HM!Dde`G27z^6RHB>rV^ffh#oix6OGH76b2a zhF7xidkW#S_AH-DB{a-mP~@Ciqgw$xus}lAN)`+y_BcZhVH}X{MGd+*t2)E6Z1YUx zZWM?9`8J2ROIK;057IXL0WKQeY-*CURq*o>LKDXcy9cqw0!laq)jLS8m4I`k;ZAST z-$j1jpMc_XYTb}(eqGsU>K87OVfbQ}KElE(oahuP8FtI@M~YbOb)9dqb_ZGt*cQW1 z|C@(iGwmGkS_L+#Q4bDQnML!)cE$(!d>!O%8qXDJeQj}dY`g4a>IPGmH0>~={YSm( z)$wo#wtg8g-MO79z4t+v%V@PHeT_mrm4eMiuqtry+YHu`H>+R@Rr6Hx$S^;2Lm^FK zvWL@r-xnu{E5gedvkf-8+7XO)wQ5tS8cr9xibVEAzk2GsH>ak-Co$&G?a}dlaC+N& z44pqd(Q8i5{@duGl-HY#huvHsn%F}F%1n%?8~=)1JS4|V2{AG2NYe!;NhAkvBCy;n3Mv%UY9l9I@kY$J8~t!? zw;`zsFW154Vs=-5O}!BokS1YPaMQ!pcw>OFvLs#yD$V1A^b;NQJVPl(NDZ2G6hhyv zC0DH)pA@{BP#3P@;2R}z!RI^MPFPLfRPEnu_CM<}X4>#MAy;M)_0|f2YT=ea(zm&k&UF1o6(6)rYGOXyPwso4f4hZ62d|~(DSJz<^t9q6`P$xG?m^IS zq$V5DJiS9E=|fep0QdmU7Uzay1aJuJ9B@J@1kD@&s>CvOfQ*oJFWMI&noEKHDPA?b zR)3VDvF+@T&&#Y2$Kh)bv|z7(uEnMg2*AEYUzE}Sp_I>0OiouD(>cHgCpi2AiwXSL zS@th<@Sfbv?s)sW89=L7j}M}hA1}BDmfHMm_@BM#|3zR8>(?#qza0}YrvszS$EXv^ R5f!kG@Ev42H!wOV6E5;7rC=f!X)D#3XwgEOAdt404#qqaT^x*) zi%VS?z(m4sOpGycbTDxxA-MAo)Ze)ueNDl|n|JO#=lss+{dkM>xw0#Me>(ame2Np1 zh>`TjNmFc`1QlJPY&kP~=&t>eV`I<$T>SjAc69h&z>={T)+?Y;5`Bcb58cex=CuXL zOeDMAG}bAwf-YlbZi*yLsFmZ8P&0I9z~?qmTvDn7O#qq(eLdKl}tZ43)PR69mq}}PLR1j#yLOt&;Gmzx_^yp z9q)(n2aao_WcHW#JUngR?GhChvda^&2#Dwh=q}DE_r?c@ib40-|6y9mmPemd9>-a3 zYkjE{$&9hQnkHv5omMfbh;iy`+Zw_m9S?7kv@U1ta-pvPj)4*3#_r^`uK>p9h=xwB zzg?f}cw8^rOcITLHJJO-4`-A&ZX;G1V2VZnHgGTKdck|vZ+BG3+%c*p<~{)hbpLEI?J-`W7e_tyh0fp~B{bEhc<{yrjSkL`CUA4K!aI%B!%DqS zt*_TwkzP2S(xY}LxfwGU$m~4XJ_9(35qPw!4MrC$+uGhqc(); prefabs = new List(); + XDocument doc = ToolBox.TryLoadXml(configPath); + if (doc == null) return; + foreach (XElement element in doc.Root.Elements()) { prefabs.Add(new BackgroundSpritePrefab(element)); @@ -31,10 +31,13 @@ namespace Subsurface public void SpawnSprites(int count) { - count = Math.Min(count, MaxSprites); activeSprites.Clear(); + if (prefabs.Count == 0) return; + + count = Math.Min(count, MaxSprites); + for (int i = 0; i < count; i++ ) { Vector2 pos = Vector2.Zero; diff --git a/Subsurface/Source/EventInput/EventInput.cs b/Subsurface/Source/EventInput/EventInput.cs index 62bb51bf7..331c8c5d2 100644 --- a/Subsurface/Source/EventInput/EventInput.cs +++ b/Subsurface/Source/EventInput/EventInput.cs @@ -167,6 +167,12 @@ namespace EventInput initialized = true; } + public static void OnCharEntered(char character) + { + if (CharEntered != null) + CharEntered(null, new CharacterEventArgs(character, 0)); + } + static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { IntPtr returnCode = CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam); diff --git a/Subsurface/Source/GUI/TitleScreen.cs b/Subsurface/Source/GUI/TitleScreen.cs index 7379d5fb3..842e51bc1 100644 --- a/Subsurface/Source/GUI/TitleScreen.cs +++ b/Subsurface/Source/GUI/TitleScreen.cs @@ -72,7 +72,7 @@ namespace Subsurface new Vector3(Game1.GraphicsWidth / 2.0f, Game1.GraphicsHeight / 2.0f, 0)); - Hull.renderer.RenderBack(graphics, renderTarget, transform); + Hull.renderer.RenderBack(spriteBatch, renderTarget, transform); spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index b36ad9bd7..441bb0ccb 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -303,7 +303,7 @@ namespace Subsurface public void Render(GraphicsDevice graphicsDevice, Camera cam) { - if (renderer.positionInBuffer > renderer.vertices.Length - 6) return; + if (renderer.PositionInBuffer > renderer.vertices.Length - 6) return; //calculate where the surface should be based on the water volume float top = rect.Y; @@ -313,30 +313,37 @@ namespace Subsurface //interpolate the position of the rendered surface towards the "target surface" surface = surface + (surfaceY - surface) / 10.0f; - Matrix transform = - cam.Transform - * Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1) * 0.5f; + Matrix transform = cam.Transform * Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1) * 0.5f; if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) return; if (!update) { // create the four corners of our triangle. - Vector3 p1 = new Vector3(rect.X, top, 0.0f); - Vector3 p2 = new Vector3(rect.X + rect.Width, top, 0.0f); - Vector3 p3 = new Vector3(p2.X, bottom, 0.0f); - Vector3 p4 = new Vector3(p1.X, bottom, 0.0f); + Vector3[] corners = new Vector3[4]; - renderer.vertices[renderer.positionInBuffer] = new WaterVertex(p1, new Vector2(p1.X, -p1.Y), transform); - renderer.vertices[renderer.positionInBuffer + 1] = new WaterVertex(p2, new Vector2(p2.X, -p2.Y), transform); - renderer.vertices[renderer.positionInBuffer + 2] = new WaterVertex(p3, new Vector2(p3.X, -p3.Y), transform); + corners[0] = new Vector3(rect.X, top, 0.0f); + corners[1] = new Vector3(rect.X + rect.Width, top, 0.0f); - renderer.vertices[renderer.positionInBuffer + 3] = new WaterVertex(p1, new Vector2(p1.X, -p1.Y), transform); - renderer.vertices[renderer.positionInBuffer + 4] = new WaterVertex(p3, new Vector2(p3.X, -p3.Y), transform); - renderer.vertices[renderer.positionInBuffer + 5] = new WaterVertex(p4, new Vector2(p4.X, -p4.Y), transform); + corners[2] = new Vector3(corners[1].X, bottom, 0.0f); + corners[3] = new Vector3(corners[0].X, bottom, 0.0f); - renderer.positionInBuffer += 6; + Vector2[] uvCoords = new Vector2[4]; + for (int i = 0; i < 4; i++ ) + { + uvCoords[i] = Vector2.Transform(new Vector2(corners[i].X, -corners[i].Y), transform); + } + + renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(corners[0], uvCoords[0]); + renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]); + renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]); + + renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(corners[0], uvCoords[0]); + renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]); + renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(corners[3], uvCoords[3]); + + renderer.PositionInBuffer += 6; return; } @@ -353,31 +360,39 @@ namespace Subsurface for (int i = start; i < end; i++) { - if (renderer.positionInBuffer > renderer.vertices.Length - 6) return; + if (renderer.PositionInBuffer > renderer.vertices.Length - 6) return; - Vector3 p1 = new Vector3(x, top, 0.0f); - Vector3 p4 = new Vector3(p1.X, surface + waveY[i], 0.0f); + Vector3[] corners = new Vector3[4]; + + corners[0] = new Vector3(x, top, 0.0f); + corners[3] = new Vector3(corners[0].X, surface + waveY[i], 0.0f); //skip adjacent "water rects" if the surface of the water is roughly at the same position int width = WaveWidth; - while (i("effects"); #if WINDOWS - byte[] bytecode = File.ReadAllBytes("Content/effects.mgfx"); + byte[] bytecode = File.ReadAllBytes("Content/watershader.mgfx"); #endif #if LINUX byte[] bytecode = File.ReadAllBytes("Content/effects_linux.mgfx"); #endif - effect = new Effect(graphicsDevice, bytecode); + waterEffect = new Effect(graphicsDevice, bytecode); - //Texture2D waterBumpMap = Game1.textureLoader.FromFile("Content/waterbump.jpg"); - //effect.Parameters["xBump"].SetValue(waterBumpMap); - //effect.Parameters["xWaveLength"].SetValue(0.5f); - //effect.Parameters["xWaveHeight"].SetValue(0.03f); - effect.Parameters["xProjection"].SetValue(Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1)); - effect.Parameters["xColor"].SetValue(new Vector4(0.75f, 0.8f, 0.9f, 1.0f)); - effect.Parameters["xBlurDistance"].SetValue(0.0005f); + waterTexture = Game1.TextureLoader.FromFile("Content/waterbump.jpg"); + waterEffect.Parameters["xWaveWidth"].SetValue(0.1f); + waterEffect.Parameters["xWaveHeight"].SetValue(0.1f); + waterEffect.Parameters["xBlurDistance"].SetValue(0.0007f); - effect.Parameters["xWaterBumpMap"].SetValue(Game1.TextureLoader.FromFile("Content/waterbump.jpg")); - effect.Parameters["xWaveWidth"].SetValue(0.1f); - effect.Parameters["xWaveHeight"].SetValue(0.1f); + if (basicEffect==null) + { + basicEffect = new BasicEffect(Game1.CurrGraphicsDevice); + basicEffect.VertexColorEnabled = false; - vertexBuffer = new VertexBuffer(graphicsDevice, WaterVertex.VertexDeclaration, DefaultBufferSize, BufferUsage.WriteOnly); + basicEffect.TextureEnabled = true; + } } - public void RenderBack(GraphicsDevice graphicsDevice, RenderTarget2D texture, Matrix transform) - { - WaterVertex[] verts = new WaterVertex[6]; + public void RenderBack (SpriteBatch spriteBatch, RenderTarget2D texture, Matrix transform) + { + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearWrap); - // create the four corners of our triangle. - Vector3 p1 = new Vector3(-graphicsDevice.Viewport.Width / 2.0f, graphicsDevice.Viewport.Height / 2.0f, 0.0f); - Vector3 p2 = new Vector3(-p1.X, p1.Y, 0.0f); - - Vector3 p3 = new Vector3(p2.X, -p1.Y, 0.0f); - Vector3 p4 = new Vector3(p1.X, -p1.Y, 0.0f); - - verts[0] = new WaterVertex(p1, new Vector2(0, 0)); - verts[1] = new WaterVertex(p2, new Vector2(1, 0)); - verts[2] = new WaterVertex(p3, new Vector2(1, 1)); - - verts[3] = new WaterVertex(p1, new Vector2(0, 0)); - verts[4] = new WaterVertex(p3, new Vector2(1, 1)); - verts[5] = new WaterVertex(p4, new Vector2(0, 1)); - - vertexBuffer.SetData(verts); + waterEffect.CurrentTechnique = waterEffect.Techniques["WaterShader"]; + waterEffect.Parameters["xTexture"].SetValue(texture); + waterEffect.Parameters["xWavePos"].SetValue(wavePos); + waterEffect.CurrentTechnique.Passes[0].Apply(); wavePos.X += 0.0001f; wavePos.Y += 0.0001f; - effect.Parameters["xWavePos"].SetValue(wavePos); + spriteBatch.Draw(waterTexture, new Rectangle(0,0,Game1.GraphicsWidth, Game1.GraphicsHeight), Color.White); - effect.CurrentTechnique = effect.Techniques["WaterShader"]; - effect.Parameters["xTexture"].SetValue(texture); - effect.Parameters["xView"].SetValue(Matrix.Identity); - - foreach (EffectPass pass in effect.CurrentTechnique.Passes) - { - pass.Apply(); - -#if WINDOWS - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, verts.Length / 3, WaterVertex.VertexDeclaration); -#endif -#if LINUX - //graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, verts.Length / 3, WaterVertex.VertexDeclaration, ); -#endif - } + spriteBatch.End(); } public void Render(GraphicsDevice graphicsDevice, Camera cam, RenderTarget2D texture, Matrix transform) @@ -128,22 +67,16 @@ namespace Subsurface if (vertices == null) return; if (vertices.Length < 0) return; - vertexBuffer.SetData(vertices); + basicEffect.Texture = texture; - effect.Parameters["xBumpPos"].SetValue(cam.Position / Game1.GraphicsWidth / cam.Zoom); + basicEffect.View = Matrix.Identity; + basicEffect.World = cam.ShaderTransform + * Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1) * 0.5f; + + basicEffect.CurrentTechnique.Passes[0].Apply(); - effect.CurrentTechnique = effect.Techniques["EmptyShader"]; - effect.Parameters["xTexture"].SetValue(texture); - effect.Parameters["xView"].SetValue(transform); - - foreach (EffectPass pass in effect.CurrentTechnique.Passes) - { - pass.Apply(); - -#if WINDOWS - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3, WaterVertex.VertexDeclaration); -#endif - } + graphicsDevice.SamplerStates[0] = SamplerState.LinearWrap; + graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3); } public void Dispose() @@ -154,22 +87,20 @@ namespace Subsurface protected virtual void Dispose(bool disposing) { - if (disposing) + if (!disposing) return; + + if (waterEffect != null) { - if (vertexBuffer != null) - { - vertexBuffer.Dispose(); - vertexBuffer = null; - } - - if (effect != null) - { - effect.Dispose(); - effect = null; - } + waterEffect.Dispose(); + waterEffect = null; } - } + if (basicEffect != null) + { + basicEffect.Dispose(); + basicEffect = null; + } + } } } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index df8d0947b..eb175592c 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -571,7 +571,6 @@ namespace Subsurface.Networking client.characterInfo.Job = new Job(client.assignedJob); } - //todo: fix if (characterInfo != null) { characterInfo.Job = new Job(Game1.NetLobbyScreen.JobPreferences[0]); diff --git a/Subsurface/Source/PlayerInput.cs b/Subsurface/Source/PlayerInput.cs index a6427ac94..913144525 100644 --- a/Subsurface/Source/PlayerInput.cs +++ b/Subsurface/Source/PlayerInput.cs @@ -56,10 +56,6 @@ namespace Subsurface stateQueue = false; return value; } - //set - //{ - // stateQueue = value; - //} } public void Reset() @@ -168,6 +164,23 @@ namespace Subsurface if (timeSinceClick < doubleClickDelay) doubleClicked = true; timeSinceClick = 0.0; } + +#if LINUX + foreach (Keys key in keyboardState.GetPressedKeys()) + { + if (!oldKeyboardState.IsKeyUp(key)) continue; + + char character = (char)key; + + if (keyboardState.IsKeyUp(Keys.LeftShift) && keyboardState.IsKeyUp(Keys.RightShift)) + { + character = char.ToLower(character); + } + + EventInput.EventInput.OnCharEntered(character); + } +#endif + } } } diff --git a/Subsurface/Source/Program.cs b/Subsurface/Source/Program.cs index 0ee45e543..278d37812 100644 --- a/Subsurface/Source/Program.cs +++ b/Subsurface/Source/Program.cs @@ -5,8 +5,10 @@ using System.IO; using System.Reflection; using System.Text; +#if WINDOWS using System.Management; using System.Windows.Forms; +#endif #endregion @@ -70,7 +72,6 @@ namespace Subsurface sb.AppendLine("\n"); sb.AppendLine("System info:"); sb.AppendLine(" Operating system: " + System.Environment.OSVersion + (System.Environment.Is64BitOperatingSystem ? " 64 bit" : " x86")); - sb.AppendLine(" Graphics device handle: " + game.GraphicsDevice.Handle.ToString()); sb.AppendLine("\n"); sb.AppendLine("Exception: "+exception.Message); sb.AppendLine("Target site: " +exception.TargetSite.ToString()); @@ -86,10 +87,11 @@ namespace Subsurface sw.WriteLine(sb.ToString()); - + #if WINDOWS MessageBox.Show( "A crash report (''crashreport.txt'') was saved in the root folder of the game."+ " If you'd like to help fix this bug, please make a bug report on the Undertow Games forum with the report attached.", "Oops! Subsurface just crashed.", MessageBoxButtons.OK, MessageBoxIcon.Error); + #endif sw.Close(); } diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index e51680264..a7f20762d 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -208,7 +208,7 @@ namespace Subsurface spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); - spriteBatch.Draw(renderTarget, new Rectangle(0, 0, Game1.GraphicsWidth, Game1.GraphicsHeight), Color.White); + spriteBatch.Draw(renderTarget, new Rectangle(0, 0, Game1.GraphicsWidth, Game1.GraphicsHeight), new Color(0.75f, 0.8f, 0.9f, 1.0f)); spriteBatch.End(); BlendState blend = new BlendState(); @@ -246,10 +246,10 @@ namespace Subsurface //2. pass the renderTarget to the water shader to do the water effect //---------------------------------------------------------------------------------------- - Hull.renderer.RenderBack(graphics, renderTargetWater, Cam.ShaderTransform); + Hull.renderer.RenderBack(spriteBatch, renderTargetWater, Cam.ShaderTransform); Array.Clear(Hull.renderer.vertices, 0, Hull.renderer.vertices.Length); - Hull.renderer.positionInBuffer = 0; + Hull.renderer.PositionInBuffer = 0; foreach (Hull hull in Hull.hullList) { hull.Render(graphics, cam); diff --git a/Subsurface/Source/Utils/TextureLoader.cs b/Subsurface/Source/Utils/TextureLoader.cs index 0533f07e4..229261e98 100644 --- a/Subsurface/Source/Utils/TextureLoader.cs +++ b/Subsurface/Source/Utils/TextureLoader.cs @@ -51,7 +51,11 @@ namespace Subsurface #endif #if LINUX using (Stream fileStream = File.OpenRead(path)) - return Texture2D.FromStream(_graphicsDevice, fileStream);// .FromStream(fileStream, preMultiplyAlpha); + { + var texture = Texture2D.FromStream(_graphicsDevice, fileStream); + texture = PreMultiplyAlpha(texture); + return texture; + } #endif } @@ -87,43 +91,46 @@ namespace Subsurface texture = Texture2D.FromStream(_graphicsDevice, stream); } - if (preMultiplyAlpha) - { - // Setup a render target to hold our final texture which will have premulitplied alpha values - using (RenderTarget2D renderTarget = new RenderTarget2D(_graphicsDevice, texture.Width, texture.Height)) - { - Viewport viewportBackup = _graphicsDevice.Viewport; - _graphicsDevice.SetRenderTarget(renderTarget); - _graphicsDevice.Clear(Color.Black); - - // Multiply each color by the source alpha, and write in just the color values into the final texture - _spriteBatch.Begin(SpriteSortMode.Immediate, BlendColorBlendState); - _spriteBatch.Draw(texture, texture.Bounds, Color.White); - _spriteBatch.End(); - - // Now copy over the alpha values from the source texture to the final one, without multiplying them - _spriteBatch.Begin(SpriteSortMode.Immediate, BlendAlphaBlendState); - _spriteBatch.Draw(texture, texture.Bounds, Color.White); - _spriteBatch.End(); - - // Release the GPU back to drawing to the screen - _graphicsDevice.SetRenderTarget(null); - _graphicsDevice.Viewport = viewportBackup; - - // Store data from render target because the RenderTarget2D is volatile - Color[] data = new Color[texture.Width * texture.Height]; - renderTarget.GetData(data); - - // Unset texture from graphic device and set modified data back to it - _graphicsDevice.Textures[0] = null; - texture.SetData(data); - } - - } + if (preMultiplyAlpha) texture = PreMultiplyAlpha(texture); return texture; } #endif + + private Texture2D PreMultiplyAlpha(Texture2D texture) + { + // Setup a render target to hold our final texture which will have premulitplied alpha values + using (RenderTarget2D renderTarget = new RenderTarget2D(_graphicsDevice, texture.Width, texture.Height)) + { + Viewport viewportBackup = _graphicsDevice.Viewport; + _graphicsDevice.SetRenderTarget(renderTarget); + _graphicsDevice.Clear(Color.Black); + + // Multiply each color by the source alpha, and write in just the color values into the final texture + _spriteBatch.Begin(SpriteSortMode.Immediate, BlendColorBlendState); + _spriteBatch.Draw(texture, texture.Bounds, Color.White); + _spriteBatch.End(); + + // Now copy over the alpha values from the source texture to the final one, without multiplying them + _spriteBatch.Begin(SpriteSortMode.Immediate, BlendAlphaBlendState); + _spriteBatch.Draw(texture, texture.Bounds, Color.White); + _spriteBatch.End(); + + // Release the GPU back to drawing to the screen + _graphicsDevice.SetRenderTarget(null); + _graphicsDevice.Viewport = viewportBackup; + + // Store data from render target because the RenderTarget2D is volatile + Color[] data = new Color[texture.Width * texture.Height]; + renderTarget.GetData(data); + + // Unset texture from graphic device and set modified data back to it + _graphicsDevice.Textures[0] = null; + texture.SetData(data); + } + + return texture; + } private static readonly BlendState BlendColorBlendState; diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 26e46c3d1..12ee8651d 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -943,6 +943,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Subsurface/Subsurface.csproj.user b/Subsurface/Subsurface.csproj.user index 505c3a0bf..693505ea4 100644 --- a/Subsurface/Subsurface.csproj.user +++ b/Subsurface/Subsurface.csproj.user @@ -9,6 +9,6 @@ en-US false - ProjectFiles + ShowAllFiles \ No newline at end of file diff --git a/Subsurface_Solution.sln b/Subsurface_Solution.sln index 9d5b8a22c..09f07cf09 100644 --- a/Subsurface_Solution.sln +++ b/Subsurface_Solution.sln @@ -307,7 +307,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 67016dc491f02ba36a3ed304f7d72ce6a3c4defc..bd0ea0d9c92509b12f2748abb06e0d5611c2c1df 100644 GIT binary patch delta 12407 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 LEhsY`XsG-bfDr&yHbouiQvSU!!h$-Tc#v-jk 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