Commit bff4ae50 authored by pcy's avatar pcy
Browse files

add tML example code

parent 144b84e6
glsltest.FNA.*
glsltest.XNA.*
MMHOOK*dll
*.nop
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ModLoader;
using Terraria.ModLoader.Core;
using PoroCYon.FNAGLSL;
using VertexType = Microsoft.Xna.Framework.Graphics.VertexPositionColorTexture;
namespace glsltest {
public partial class GLSLBackground : ModSurfaceBgStyle {
internal static BasicEffect hlsl;
internal static GLSLEffect glsl;
internal static TimeSpan totalElapsed = TimeSpan.Zero;
// called from our Mod instance
internal static void Load(GraphicsDevice gd) {
totalElapsed = TimeSpan.Zero;
hlsl = new BasicEffect(gd);
hlsl.LightingEnabled = false;
hlsl.PreferPerPixelLighting = false;
hlsl.FogEnabled = false;
hlsl.TextureEnabled = false;
hlsl.VertexColorEnabled = true;
hlsl.World = hlsl.View = hlsl.Projection = Matrix.Identity;
glsl = new GLSLEffect(gd, new Dictionary<GLSLPurpose, string>() {
{ GLSLPurpose.VertexShader , vsh },
{ GLSLPurpose.FragmentShader, fsh_bonzo }
});
}
internal static void Unload() {
totalElapsed = TimeSpan.Zero;
if (hlsl != null) {
hlsl.Dispose();
hlsl = null;
}
if (glsl != null) {
glsl.Dispose();
glsl = null;
}
}
public override bool ChooseBgStyle() => true;
public override void ModifyFarFades(float[] fades, float transitionSpeed) {
for (int i = 0; i < fades.Length; ++i) {
if (i == Slot) fades[i] = 1;
else fades[i] = 0;
}
}
public override bool PreDrawCloseBackground(SpriteBatch sb) {
var gd = Main.instance.GraphicsDevice;
// you can mix these with HLSL shaders!
/*var tech = hlsl.CurrentTechnique = hlsl.Techniques[0];
for (int i = 0; i < tech.Passes.Count; ++i) {
tech.Passes[i].Apply();
gd.DrawUserPrimitives(PrimitiveType.TriangleStrip, vertices_l, 0, 2);
}*/
var vp = gd.Viewport;
glsl.Parameters["fGlobalTime" ].SetValue((float)totalElapsed.TotalSeconds);
glsl.Parameters["v2Resolution"].SetValue(new Vector2(vp.Width, vp.Height));
using (var bound = glsl.Bind()) {
gd.DrawUserPrimitives(PrimitiveType.TriangleStrip, vertices_fs/*r*/, 0, 2);
}
return false;
}
readonly static VertexType[] vertices_fs = new[] {
new VertexType(new Vector3(-1, -1, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3(-1, 1, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 1, -1, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 1, 1, 0), Color.Yellow, new Vector2(1, 1))
};
readonly static VertexType[] vertices_r = new[] {
new VertexType(new Vector3( 0, -1, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3( 0, 1, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 1, -1, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 1, 1, 0), Color.Yellow, new Vector2(1, 1))
};
readonly static VertexType[] vertices_l = new[] {
new VertexType(new Vector3(-1, -1, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3(-1, 1, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 0, -1, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 0, 1, 0), Color.Yellow, new Vector2(1, 1))
};
readonly static VertexType[] vertices_tr = new[] {
new VertexType(new Vector3( 0, 0, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3( 0, 1, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 1, 0, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 1, 1, 0), Color.Yellow, new Vector2(1, 1))
};
readonly static VertexType[] vertices_br = new[] {
new VertexType(new Vector3( 0, -1, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3( 0, 0, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 1, -1, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 1, 0, 0), Color.Yellow, new Vector2(1, 1))
};
readonly static VertexType[] vertices_tl = new[] {
new VertexType(new Vector3(-1, 0, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3(-1, 1, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 0, 0, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 0, 1, 0), Color.Yellow, new Vector2(1, 1))
};
readonly static VertexType[] vertices_bl = new[] {
new VertexType(new Vector3(-1, -1, 0), Color.Red , new Vector2(0, 0))
, new VertexType(new Vector3(-1, 0, 0), Color.Blue , new Vector2(0, 1))
, new VertexType(new Vector3( 0, -1, 0), Color.Green , new Vector2(1, 0))
, new VertexType(new Vector3( 0, 0, 0), Color.Yellow, new Vector2(1, 1))
};
}
}
namespace glsltest {
public partial class GLSLBackground {
// simple passthru vertex shader
readonly static string vsh =
"#version 330 core\n"+
"\n"+
"in vec3 in_pos;\n"+
"in vec4 in_col;\n"+
"in vec2 in_texcoord;\n"+
"\n"+
"out vec2 out_texcoord;\n"+
"\n"+
"void main() {\n"+
" gl_Position = vec4(in_pos.x, in_pos.y, in_pos.z, 1.0);\n"+
" out_texcoord = in_texcoord;\n"+
"}\n";
// default Bonzomatic fragment shader (see https://github.com/Gargaj/Bonzomatic )
readonly static string fsh_bonzo =
"#version 330 core\n"+
"\n"+
"uniform float fGlobalTime;\n"+
"uniform vec2 v2Resolution;\n"+
"\n"+
"layout(location = 0) out vec4 C;\n"+
"\n"+
"vec4 plas(float time, vec2 v) {\n"+
" float c = 0.5 + sin(v.x * 10.0) + cos(sin(time + v.y) * 20.0);\n"+
" return vec4(sin(c * 0.2 + cos(time)), c * 0.15, cos(c * 0.1 + time / .4) * .25, 1.0);\n"+
"}\n"+
"\n"+
"void main() {\n"+
" float pi = 4.0*atan(1.0);\n"+
" vec2 uv = vec2(gl_FragCoord.x/v2Resolution.x, gl_FragCoord.y/v2Resolution.y);\n"+
" uv -= 0.5;\n"+
" uv /= vec2(v2Resolution.y/v2Resolution.x, 1.);\n"+
"\n"+
" vec2 m;\n"+
" m.x = atan(uv.x / uv.y) / pi;\n"+
" m.y = 1 / length(uv) * .2;\n"+
" float d = m.y;\n"+
" m.x += sin(fGlobalTime) * 0.1;\n"+
" m.y += fGlobalTime * 0.25;\n"+
"\n"+
" vec4 t = plas(fGlobalTime, m * pi) / d;\n"+
" C = clamp(t, 0.0, 1.0);\n"+
"}\n";
// a raymarched scene! (no I'm not going to explain how it works)
// greets to iq, mercury, shane, and noby alkama blackle #lsc halcy
// yx evvvvil nusan and countless others
readonly static string fsh_raymarch = @"
#version 410 core
uniform float fGlobalTime; // in seconds
uniform vec2 v2Resolution; // viewport resolution (in pixels)
layout(location = 0) out vec4 out_color;
// global raymarcher structure (probably?) based on something Shane wrote, iirc
#define PI 4.0*atan(1.0)
const float EPS = 0.005;
const int MAX_ITER = 128;
// stolen from hg_sdf
float pMod1(inout float p,float s){
float hs=s*0.5;
float c=floor((p+hs)/s);
p=mod(p+hs,s)-hs;
return c;
}
float pModPolar(inout vec2 p, float repetitions) {
float angle = 2*PI/repetitions;
float a = atan(p.y, p.x) + angle/2.;
float r = length(p);
float c = floor(a/angle);
a = mod(a,angle) - angle/2.;
p = vec2(cos(a), sin(a))*r;
if (abs(c) >= (repetitions/2)) c = abs(c);
return c;
}
float bigegg(vec3 p) {
p.xz /= 1.4;
return length(p)-1.3;
}
float smallspheres(vec3 p) {
pModPolar(p.xz,16.);
p.x-=1;
float c = abs(pMod1(p.y,0.5));
if (c==0) {
p.x-=2;
}else p.x-=1/(c*0.7);
return length(p)-0.15*(1+sin(fGlobalTime)*0.5);
}
float scene(in vec3 p) {
p.xz=vec2(p.x*cos(fGlobalTime*0.2)+p.z*sin(fGlobalTime*0.2),
p.z*cos(fGlobalTime*0.2)-p.x*sin(fGlobalTime*0.2));
return min(smallspheres(p),bigegg(p));
}
vec3 getNormal(in vec3 p) {
return normalize(vec3(
scene(vec3(p.x+EPS,p.y,p.z))-scene(vec3(p.x-EPS,p.y,p.z)),
scene(vec3(p.x,p.y+EPS,p.z))-scene(vec3(p.x,p.y-EPS,p.z)),
scene(vec3(p.x,p.y,p.z+EPS))-scene(vec3(p.x,p.y,p.z-EPS))
));
}
float march_basic(vec3 o, vec3 d, float t_min, float t_max, out vec3 pos, int mxit) {
float t = t_min;
for (int i = 0; i < mxit; ++i) {
pos = o + d * t;
float rad = scene(pos);
t+=rad;
if (rad < EPS || t > t_max) {
return t;
}
}
return t_max*2;
}
float march_hg(vec3 o, vec3 d, float t_min, float t_max, out vec3 pos) {
float O = 1.2;
float t = t_min;
float cerr = 1e9;
float ct = t_min;
float prad = 0.;
float sl = 0.;
float sg = scene(o) < 0. ? -1. : 1.;
float pxrad=0.5/length(v2Resolution);
for (int i = 0; i < MAX_ITER; ++i) {
pos =o+d*t;
float sr = sg * scene(pos);
float rr = abs(sr);
bool sfail = O > 1. && (rr+prad) < sl;
if (sfail) {
sl -= O*sl;
O=1;
}else {
sl=sr*O;
}
prad = rr;
float err = rr/t;
if (!sfail && err < cerr) {
ct = t;
cerr = err;
}
if (!sfail && err < pxrad || t > t_max) {
break;
}
t+=sl;
}
if (t>t_max||cerr>pxrad)return t_max*2.;
return ct;
}
vec3 envcol(vec3 n) {
float x = normalize(n).y;
x = (x+1)*0.5;
return mix(vec3(0.1,0.1,0.25),vec3(0.4,0.6,0.9), smoothstep(0.,1.,smoothstep(0.,1.,smoothstep(0.,1.,x))));
}
vec3 shadeAt(vec3 p, vec3 n, vec3 camPos, vec3 obj){
vec3 ret = vec3(0);
for (int i=0;i<3;++i){
vec3 lp;// = vec3(2,1,-2);//vec3(2*sin(fGlobalTime*0.5), 0.0, 2*cos(fGlobalTime*0.5));
if (i==0)lp=vec3(2,1,-2);
else if (i==1)lp=vec3(-2,1,-2);
else lp=vec3(2,-1,-2);
vec3 ld = lp-p;
vec3 lcolor = vec3(1.);
float len = length(ld);
ld /= len;
float lightAtten = min(1.0 / (0.25*len*len), 1.0);
vec3 ref = reflect(-ld, n);
float ambient = .8;
float specularPower = 64.0;
float diffuse = max( 0.0, dot(n, ld) );
float specular = max( 0.0, dot(ref, normalize(camPos-p)));
specular = pow(specular, specularPower);
ret+= (obj*(diffuse*0.5+ambient)+specular*0.5)*lcolor*lightAtten/3.;
}
return ret;
}
void main(void) {
vec2 aspect = vec2(v2Resolution.x/v2Resolution.y, 1.0);
vec2 screenCoords = (2.0*gl_FragCoord.xy/v2Resolution.xy - 1.0)*aspect;
vec3 lookAt = vec3(0.,0.,0.);
vec3 camPos = vec3(0., -0.25, -5.);
vec3 forward = normalize(lookAt-camPos);
vec3 right = vec3(forward.z, 0., -forward.x);
vec3 up = normalize(cross(forward,right));
float FOV = 0.5;
vec3 ro = camPos;
vec2 rdo = screenCoords;
float cth=0.25;
rdo=vec2(rdo.x*cos(cth)+rdo.y*sin(cth),rdo.y*cos(cth)-rdo.x*sin(cth))*FOV;
vec3 rd = normalize(forward + rdo.x*right + rdo.y*up);
vec3 bgcolor = envcol(rd);
const float clipNear = 0.0;
const float clipFar = 10.0;
vec3 sp = vec3(0.);
float dist = march_hg(ro, rd, clipNear, clipFar, sp);
if (dist >= clipFar) {
out_color = vec4(bgcolor, 1.0);
return;
}
vec3 norm = getNormal(sp);
vec3 sceneColor = vec3(0.0);
vec3 objColor = envcol(norm);
vec3 newn=norm,newp=sp+norm*0.1;
for (int iii=0;iii < 2; ++iii) {
float d = march_basic(newp, newn, 0., 10., newp, 10);
if (d < 10.){
newn= getNormal(newp);
objColor = shadeAt(newp, newn, camPos, objColor);
newp+=newn*0.1;
}}
sceneColor = shadeAt(sp, norm, camPos, objColor);
out_color = vec4(clamp(sceneColor, 0.0, 1.0), 1.0);
}
";
}
}
TERRPATH ?= $$HOME/games/tModLoader/tModLoader
#TMLEXE ?= $(TERRPATH)/tModLoader.exe
TMLBUILDSERV ?= mono $(TERRPATH)/tModLoaderServer.exe
MCS ?= mcs
TMLLOCDIR ?= $$HOME/.local/share/Terraria/ModLoader
REFDIRS := $(TERRPATH)/ModCompile/ $(TERRPATH)/ $(TMLLOCDIR)/references
GENERICREFS := \
tModLoader.exe Steamworks.NET.dll ReLogic.dll Ionic.Zip.Reduced.dll \
Mono.Cecil.dll Mono.Cecil.Mdb.dll Mono.Cecil.Pdb.dll \
MonoMod.RuntimeDetour.dll MonoMod.Utils.dll TerrariaHooks.dll
#XNAREF_Windows := Microsoft.Xna.Framework.dll \
Microsoft.Xna.Framework.Graphics.dll Microsoft.Xna.Framework.Game.dll
XNAREF_XNA := FNA.dll # fuck it
XNAREF_FNA := FNA.dll
MCSFLAGS := -checked- -debug -target:library -unsafe+ \
$(patsubst %,-lib:"%",$(REFDIRS)) \
$(patsubst %,-r:"%",$(GENERICREFS))
SOURCES := $(wildcard *.cs */*.cs)
glsltest.%.dll: $(SOURCES)
$(MCS) -out:"glsltest.dll" $(MCSFLAGS) $(patsubst %,-r:"%",$(XNAREF_$*)) $^
mv glsltest.dll "$@"
mv glsltest.dll.mdb "glsltest.$*".pdb
all: glsltest.FNA.dll glsltest.XNA.dll
$(TMLBUILDSERV) -build "$(PWD)" -eac glsltest.FNA.dll \
-define 'DEBUG;TRACE' -unsafe 1
clean:
@-$(RM) -v *.dll *.pdb
{
"profiles": {
"Terraria": {
"commandName": "Executable",
"executablePath": "$(tMLPath)",
"workingDirectory": "$(TerrariaSteamPath)"
},
"TerrariaServer": {
"commandName": "Executable",
"executablePath": "$(tMLServerPath)",
"workingDirectory": "$(TerrariaSteamPath)"
}
}
}
\ No newline at end of file
# fnaglsl
## glsltest
Getting those shaders to work in Terraria (tModLoader) now.
## caveats
* ***DON'T*** use this *UNLESS YOU KNOW WHAT YOU'RE DOING*
* ***DON'T*** ASK ME FOR HELP FOR WRITING SHADERS. YOU'RE ON YOUR OWN.
* It will most likely crash. I only tested this on my computer. Idk if this
actually works *at all* on Windows or OS X.
displayName = glsltest
author = PoroCYon
version = 0.1
includePDB = false
includeSource = true
buildIgnore = *.csproj, *.user, obj\*, bin\*, .vs\*
side = Client
noCompile = true
GLSL Shaders in tModLoader!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ModLoader;
using Terraria.ModLoader.Core;
using Terraria.ModLoader.Engine;
namespace glsltest {
public class glsltest : Mod {
public glsltest() { }
// creating GLSL shaders needs to happen on the main graphics thread,
// but mod loading happens on a background thread...
// GLCallLocker.InvokeAsync can be used to call things on the main
// thread, but it's internal, so we have to do this instead
static MethodInfo glcl_InvokeAsync_mi = null;
static Task<T> GLCallLocker_InvokeAsync<T>(Func<T> f) {
if (glcl_InvokeAsync_mi == null) {
glcl_InvokeAsync_mi = typeof(GLCallLocker).GetMethods(
BindingFlags.InvokeMethod|BindingFlags.Static|BindingFlags.NonPublic)
.First(mi => mi.Name == "InvokeAsync");
}
return (Task<T>)glcl_InvokeAsync_mi.MakeGenericMethod(new[]{typeof(T)}).Invoke(null, new[]{f});
}
public override void Load() {
GLCallLocker_InvokeAsync(() => {
GLSLBackground.Load(Main.instance.GraphicsDevice);
return 0;
}).Wait();
}
public override void Unload() {
GLCallLocker_InvokeAsync(() => {
GLSLBackground.Unload();
return 0;
}).Wait();
}
// need some way to keep track of time
public override void UpdateUI(GameTime gt) {
GLSLBackground.totalElapsed += gt.ElapsedGameTime;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\references\tModLoader.targets" />
<PropertyGroup>
<AssemblyName>glsltest</AssemblyName>
<TargetFramework>net45</TargetFramework>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<Target Name="BuildMod" AfterTargets="Build">
<Exec Command="&quot;$(tMLBuildServerPath)&quot; -build $(ProjectDir) -eac $(TargetPath) -define &quot;$(DefineConstants)&quot; -unsafe $(AllowUnsafeBlocks)" />
</Target>
<ItemGroup>
<PackageReference Include="tModLoader.CodeAssist" Version="0.1.*" />
</ItemGroup>
</Project>
../src
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment