Skip to content

Commit 70f35f3

Browse files
committed
Combine individual object textures into sprite sheets and use custom batcher for rendering objects
Massively increases performance
1 parent 9bbacaa commit 70f35f3

File tree

17 files changed

+1152
-501
lines changed

17 files changed

+1152
-501
lines changed

src/TSMapEditor/Content/Content.mgcb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
#begin Shaders/AlphaImageToAlphaMap.fx
1717
/importer:EffectImporter
1818
/processor:EffectProcessor
19-
/processorParam:DebugMode=Debug
19+
/processorParam:DebugMode=Auto
2020
/build:Shaders/AlphaImageToAlphaMap.fx
2121

2222
#begin Shaders/AlphaMapApply.fx
2323
/importer:EffectImporter
2424
/processor:EffectProcessor
25-
/processorParam:DebugMode=Debug
25+
/processorParam:DebugMode=Auto
2626
/build:Shaders/AlphaMapApply.fx
2727

2828
#begin Shaders/ColorDraw.fx
@@ -43,6 +43,12 @@
4343
/processorParam:DebugMode=Auto
4444
/build:Shaders/DepthApply.fx
4545

46+
#begin Shaders/LegacyPalettedColorDraw.fx
47+
/importer:EffectImporter
48+
/processor:EffectProcessor
49+
/processorParam:DebugMode=Auto
50+
/build:Shaders/LegacyPalettedColorDraw.fx
51+
4652
#begin Shaders/PalettedColorDraw.fx
4753
/importer:EffectImporter
4854
/processor:EffectProcessor
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#pragma enable_d3d11_debug_symbols
2+
3+
#if OPENGL
4+
#define SV_POSITION POSITION
5+
#define VS_SHADERMODEL vs_3_0
6+
#define PS_SHADERMODEL ps_3_0
7+
#else
8+
#define VS_SHADERMODEL vs_4_0
9+
#define PS_SHADERMODEL ps_4_0
10+
#endif
11+
12+
// Legacy version of the PalettedColorDraw shader used for drawing objects.
13+
// PalettedColorDraw relies on a custom vertex shader with custom data that
14+
// makes it incompatible with MonoGame's regular SpriteBatch.
15+
16+
// This shader does not include a custom vertex shader, keeping it compatible
17+
// with MonoGame's SpriteBatch. It is used for drawing lines, text, and
18+
// other more complicated elements that we do not have custom batching code for.
19+
20+
float WorldTextureHeight;
21+
bool ComplexDepth;
22+
bool IncreaseDepthUpwards;
23+
bool DecreaseDepthUpwards;
24+
bool IsShadow;
25+
bool UsePalette;
26+
bool UseRemap;
27+
float Opacity;
28+
29+
Texture2D MainTexture;
30+
SamplerState MainSampler
31+
{
32+
Texture = <MainTexture>;
33+
AddressU = clamp;
34+
AddressV = clamp;
35+
MipFilter = Point;
36+
MinFilter = Point;
37+
MagFilter = Point;
38+
};
39+
40+
Texture2D PaletteTexture;
41+
SamplerState PaletteSampler
42+
{
43+
Texture = <PaletteTexture>;
44+
AddressU = clamp;
45+
AddressV = clamp;
46+
MipFilter = Point;
47+
MinFilter = Point;
48+
MagFilter = Point;
49+
};
50+
51+
struct VertexShaderOutput
52+
{
53+
float4 Position : SV_POSITION;
54+
float4 Color : COLOR0;
55+
float2 TextureCoordinates : TEXCOORD0;
56+
};
57+
58+
struct PixelShaderOutput
59+
{
60+
float4 color : SV_Target0;
61+
float depthTarget : SV_Target1;
62+
float depthEmbedded : SV_Depth;
63+
};
64+
65+
66+
PixelShaderOutput MainPS(VertexShaderOutput input)
67+
{
68+
PixelShaderOutput output = (PixelShaderOutput) 0;
69+
70+
// We need to read from the main texture first,
71+
// otherwise the output will be black!
72+
float4 tex = MainTexture.Sample(MainSampler, input.TextureCoordinates);
73+
74+
// Discard transparent areas
75+
clip(tex.a == 0.0f ? -1 : 1);
76+
77+
float totalDepth = input.Position.z;
78+
79+
if (IsShadow)
80+
{
81+
output.color = float4(0, 0, 0, 0.5);
82+
83+
output.depthTarget = totalDepth;
84+
output.depthEmbedded = totalDepth;
85+
}
86+
else
87+
{
88+
if (ComplexDepth || IncreaseDepthUpwards || DecreaseDepthUpwards)
89+
{
90+
// This branch and its sub-branches do not support sprite sheets!
91+
// Only used for drawing objects - terrain uses sprite sheets to increase performance,
92+
// but terrain but does not need complex depth.
93+
uint width;
94+
uint height;
95+
MainTexture.GetDimensions(width, height);
96+
97+
float depthMultiplier = 0.9;
98+
99+
float distanceFromTop = input.TextureCoordinates.y * height;
100+
float distanceFromBottom = height - distanceFromTop;
101+
102+
if (ComplexDepth)
103+
{
104+
float centralX = width * input.Color.a;
105+
float dx = abs((width * input.TextureCoordinates.x) - centralX);
106+
totalDepth = input.Position.z + (((distanceFromBottom - dx) / WorldTextureHeight) * depthMultiplier);
107+
}
108+
else if (IncreaseDepthUpwards)
109+
{
110+
totalDepth = input.Position.z + ((distanceFromBottom / WorldTextureHeight) * depthMultiplier);
111+
}
112+
else if (DecreaseDepthUpwards)
113+
{
114+
totalDepth = input.Position.z - ((distanceFromBottom / WorldTextureHeight) * depthMultiplier);
115+
}
116+
}
117+
118+
output.depthTarget = totalDepth;
119+
output.depthEmbedded = totalDepth;
120+
121+
if (UsePalette)
122+
{
123+
// Get color from palette
124+
float4 paletteColor = PaletteTexture.Sample(PaletteSampler, float2(tex.a, 0.5));
125+
126+
// We need to convert the grayscale into remap
127+
if (UseRemap)
128+
{
129+
float brightness = max(paletteColor.r, max(paletteColor.g, paletteColor.b));
130+
131+
// Brigthen it up a bit
132+
brightness = brightness * 1.25;
133+
134+
output.color = float4(brightness * input.Color.r, brightness * input.Color.g, brightness * input.Color.b, paletteColor.a) * Opacity;
135+
}
136+
else
137+
{
138+
// Multiply the color by 2. This is done because unlike map lighting which can exceed 1.0 and go up to 2.0,
139+
// the color values passed in the pixel shader input are capped at 1.0.
140+
// So the multiplication is done to translate pixel shader input color space into in-game color space.
141+
// We lose a bit of precision from doing this, but we'll have to accept that.
142+
output.color = float4(paletteColor.r * input.Color.r * 2.0,
143+
paletteColor.g * input.Color.g * 2.0,
144+
paletteColor.b * input.Color.b * 2.0,
145+
paletteColor.a) * Opacity;
146+
}
147+
}
148+
else
149+
{
150+
output.color = float4(tex.r * input.Color.r * 2.0,
151+
tex.g * input.Color.g * 2.0,
152+
tex.b * input.Color.b * 2.0, tex.a) * Opacity;
153+
}
154+
}
155+
156+
return output;
157+
}
158+
159+
technique SpriteDrawing
160+
{
161+
pass P0
162+
{
163+
PixelShader = compile PS_SHADERMODEL MainPS();
164+
}
165+
};

src/TSMapEditor/Content/Shaders/PalettedColorDraw.fx

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@
99
#define PS_SHADERMODEL ps_4_0
1010
#endif
1111

12-
// The "main shader" of the editor.
12+
// Flexible shader for rendering objects.
1313
// Can render objects in either paletted or RGBA mode,
1414
// takes depth into account, and can also draw shadows.
1515

16+
// Relies on custom data in the vertex shader,
17+
// meaning it is not compatible with SpriteBatch
18+
// and needs a custom batcher instead.
19+
1620
float WorldTextureHeight;
1721
bool ComplexDepth;
1822
bool IncreaseDepthUpwards;
@@ -44,11 +48,22 @@ SamplerState PaletteSampler
4448
MagFilter = Point;
4549
};
4650

51+
struct VertexShaderInput
52+
{
53+
float3 Position : POSITION;
54+
float4 Color : COLOR0;
55+
float2 TextureCoordinates : TEXCOORD0;
56+
float4 CustomData : TEXCOORD1;
57+
};
58+
59+
matrix WorldViewProj : register(c0);
60+
4761
struct VertexShaderOutput
4862
{
4963
float4 Position : SV_POSITION;
5064
float4 Color : COLOR0;
5165
float2 TextureCoordinates : TEXCOORD0;
66+
float4 CustomData : TEXCOORD1;
5267
};
5368

5469
struct PixelShaderOutput
@@ -59,6 +74,17 @@ struct PixelShaderOutput
5974
};
6075

6176

77+
VertexShaderOutput MainVS(VertexShaderInput input)
78+
{
79+
VertexShaderOutput output;
80+
output.Position = mul(float4(input.Position, 1.0), WorldViewProj);
81+
output.Color = input.Color;
82+
output.TextureCoordinates = input.TextureCoordinates;
83+
output.CustomData = input.CustomData;
84+
return output;
85+
}
86+
87+
6288
PixelShaderOutput MainPS(VertexShaderOutput input)
6389
{
6490
PixelShaderOutput output = (PixelShaderOutput) 0;
@@ -70,37 +96,36 @@ PixelShaderOutput MainPS(VertexShaderOutput input)
7096
// Discard transparent areas
7197
clip(tex.a == 0.0f ? -1 : 1);
7298

73-
float totalDepth;
99+
float totalDepth = input.Position.z;
74100

75101
if (IsShadow)
76102
{
77103
output.color = float4(0, 0, 0, 0.5);
78104

79-
totalDepth = input.Position.z;
80-
81105
output.depthTarget = totalDepth;
82106
output.depthEmbedded = totalDepth;
83107
}
84108
else
85109
{
86110
if (ComplexDepth || IncreaseDepthUpwards || DecreaseDepthUpwards)
87111
{
88-
// This branch and its sub-branches do not support sprite sheets!
89-
// Only used for drawing objects - terrain uses sprite sheets to increase performance,
90-
// but terrain but does not need complex depth.
91-
uint width;
92-
uint height;
93-
MainTexture.GetDimensions(width, height);
112+
float imageHeight = input.CustomData.y;
113+
114+
uint spriteSheetWidth;
115+
uint spriteSheetHeight;
116+
MainTexture.GetDimensions(spriteSheetWidth, spriteSheetHeight);
94117

95-
float depthMultiplier = 0.75;
118+
float depthMultiplier = 0.9;
96119

97-
float distanceFromTop = input.TextureCoordinates.y * height;
98-
float distanceFromBottom = height - distanceFromTop;
120+
float distanceFromTop = (input.TextureCoordinates.y - input.CustomData.w) * spriteSheetHeight;
121+
float distanceFromBottom = imageHeight - distanceFromTop;
99122

100123
if (ComplexDepth)
101124
{
102-
float centralX = width * input.Color.a;
103-
float dx = abs((width * input.TextureCoordinates.x) - centralX);
125+
float imageWidth = input.CustomData.x;
126+
127+
float centralX = imageWidth * input.Color.a;
128+
float dx = abs((spriteSheetWidth * (input.TextureCoordinates.x - input.CustomData.z)) - centralX);
104129
totalDepth = input.Position.z + (((distanceFromBottom - dx) / WorldTextureHeight) * depthMultiplier);
105130
}
106131
else if (IncreaseDepthUpwards)
@@ -112,10 +137,6 @@ PixelShaderOutput MainPS(VertexShaderOutput input)
112137
totalDepth = input.Position.z - ((distanceFromBottom / WorldTextureHeight) * depthMultiplier);
113138
}
114139
}
115-
else
116-
{
117-
totalDepth = input.Position.z;
118-
}
119140

120141
output.depthTarget = totalDepth;
121142
output.depthEmbedded = totalDepth;
@@ -162,6 +183,7 @@ technique SpriteDrawing
162183
{
163184
pass P0
164185
{
186+
VertexShader = compile VS_SHADERMODEL MainVS();
165187
PixelShader = compile PS_SHADERMODEL MainPS();
166188
}
167189
};

src/TSMapEditor/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@
3434
// You can specify all the values or you can default the Build and Revision Numbers
3535
// by using the '*' as shown below:
3636
// [assembly: AssemblyVersion("1.0.*")]
37-
[assembly: AssemblyVersion("1.5.*")]
37+
[assembly: AssemblyVersion("1.6.*")]

0 commit comments

Comments
 (0)