Commit 865206e0 authored by pcy's avatar pcy
Browse files

initial

parents
bin/
lib/*
default: all
CSC ?= mcs # use csc here if you're on windows
MONO ?= mono # leave this empty on windows
CSFLAGS := -checked- -unsafe+
CSFLAGS += -lib:lib/ -r:FNA.dll
SOURCES := $(wildcard src/*.cs)
TARGET := bin/fnaglsl.exe
LIBS := lib/FNA.dll lib/FNA.dll.config lib/libmojoshader.so
$(TARGET): bin/ $(SOURCES) $(LIBS)
$(CSC) $(CSFLAGS) -target:exe -out:"$@" $(SOURCES)
all: $(TARGET)
$(LIBS): lib/
@>&2 echo "You need to put FNA.dll{,.config} and libmojoshader.so in the" \
"'lib/' directory."; false
debug: CSFLAGS += -debug+
debug: all
release: CSFLAGS += -optimize+
release: all
t: debug
TERM=xterm MONO_PATH="$$PWD/lib/:$$MONO_PATH" \
LD_LIBRARY_PATH="$$PWD/lib:$$LD_LIBRARY_PATH" \
FNA_KEYBOARD_USE_SCANCODES=1 FNA_OPENGL_DISABLE_LATESWAPTEAR=1 \
FNA_OPENGL_FORCE_CORE_PROFILE=1 \
$(MONO) --debug=mdb-optimizations "$(TARGET)"
clean:
@$(RM) -v bin/*
%/:
@mkdir -vp "$@"
.PHONY: default all debug release t clean
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
/* TODO:
* * apply
* * HOW????
* * OnApply: protecteed internal :(
* * INTERNAL_applyEffect: internal...
* + calls mojoshader! --> hijack?!!
* -> glEffect{Begin,End}: state mgmt | unbind shader!
* -> glEffect{Begin,End}Pass: bind shader! | state mgmt
* * GD draw calls: ok
* * EXCEPT mojoshader: glProgramReady, glProgramViewportInfo
* -> set up uniforms!
* * uniforms
* * samplers, textures
*/
namespace PoroCYon.FNAGLSL {
public class GLSLEffect : Effect {
uint[] glshdrs;
uint glprgm;
public unsafe GLSLEffect(GraphicsDevice gd,
IDictionary<GLSLPurpose, string> shaders)
: base(/*UGLY hack*/new BasicEffect(gd)) {
GL.Init(gd);
// TODO: gd.GLDevice.DeleteEffect(base.glEffect),
// set base.glEffect.{GL,}EffectData to IntPtr.Zero
var shdrs = new uint[shaders.Count];
bool ok = false;
uint prgm = 0;
try {
prgm = GL.CreateProgram();
if (prgm == 0) GL.Throw();
int i = 0;
foreach (var kvp in shaders) {
uint sh = GL.CreateShader(kvp.Key);
if (sh == 0) GL.Throw();
byte[] utf8src = Encoding.UTF8.GetBytes(kvp.Value);
fixed (byte* sbuf = utf8src) {
sbyte** uurgh = stackalloc sbyte*[1];
*uurgh = (sbyte*)sbuf;
int* uurgh2 = stackalloc int[1];
*uurgh2 = utf8src.Length;
GL.ShaderSource(sh, 1, uurgh, uurgh2);
}
GL.Throw();
GL.CompileShader(sh);
if (GL.GetError() != 0 || GL.GetShaderiv(sh, GL.COMPILE_STATUS) == 0) {
int len = GL.GetShaderiv(sh, GL.INFO_LOG_LENGTH);
var msg = new sbyte[len];
fixed (sbyte* buf = msg) {
GL.GetShaderInfoLog(sh, len, null, buf);
throw new GLSLCompileException(new String(buf, 0, len-1));
}
}
GL.AttachShader(prgm, sh);
GL.Throw();
shdrs[i++] = sh;
}
GL.LinkProgram(prgm);
if (GL.GetError() != 0 || GL.GetProgramiv(prgm, GL.LINK_STATUS) == 0) {
int len = GL.GetProgramiv(prgm, GL.INFO_LOG_LENGTH);
var msg = new sbyte[len];
fixed (sbyte* buf = msg) {
GL.GetProgramInfoLog(prgm, len, null, buf);
throw new GLSLLinkException(new String(buf, 0, len-1));
}
}
ok = true;
}
finally {
if (!ok) {
DelShdrPrgm();
} else {
glshdrs = shdrs;
glprgm = prgm ;
}
}
}
void DelShdrPrgm() {
for (int i = 0; i < glshdrs.Length; ++i)
if (shdrs[i] != 0)
GL.DeleteShader(shdrs[i]);
if (prgm != 0)
GL.DeleteProgram(prgm);
}
protected override void Dispose(bool disposing) {
if (!IsDisposed) {
DelShdrPrgm();
}
base.Dispose(disposing);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace PoroCYon.FNAGLSL {
public class GLException : Exception {
public readonly GLError Error;
public GLException(GLError err)
: base(TranslateMsg(err)) {
Error = err;
}
public static string TranslateMsg(GLError err) {
switch (err) {
case GLError.NoError: return "No error";
case GLError.InvalidEnum: return "Invalid enum";
case GLError.InvalidValue: return "Invalid value";
case GLError.InvalidOperation: return "Invalid operation";
case GLError.StackOverflow: return "Stack overflow";
case GLError.StackUnderflow: return "Stack underflow";
case GLError.OutOfMemory: return "Out of memory";
default: return String.Format("??? ({0})", (uint)err);
}
}
}
public class GLSLCompileException : Exception {
public GLSLCompileException(string msg) : base(msg) { }
}
public class GLSLLinkException : Exception {
public GLSLLinkException(string msg) : base(msg) { }
}
public enum GLError : uint/*GLenum*/ {
NoError = 0,
InvalidEnum = 0x0500,
InvalidValue = 0x0501,
InvalidOperation = 0x0502,
StackOverflow = 0x0503,
StackUnderflow = 0x0504,
OutOfMemory = 0x0505
}
public enum GLSLPurpose {
VertexShader = 0x8B31,
GeomShader = 0x8DD9,
TessCtrlShader = 0x8E88,
TessEvalShader = 0x8E87,
FragmentShader = 0x8B30,
//ComputeShader = 0x91B9
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SDL2;
using static SDL2.SDL;
namespace PoroCYon.FNAGLSL {
public static unsafe partial class GL {
public static void Throw() {
GLError err = GetError();
if (err != GLError.NoError) throw new GLException(GetError());
}
internal static void CheckFNA() {
if (typeof(Vector2).Assembly != typeof(Texture2D).Assembly) {
throw new NotSupportedException(
"Running XNA or MonoGame, not FNA! Can't use FNA-GLSL.");
}
}
static T GetProcAddress<T>(string name)
where T : class {
if (!typeof(T).IsSubclassOf(typeof(Delegate))) {
throw new ArgumentException("Type '" + typeof(T) + "' is not a delegate type!");
}
IntPtr fn = SDL_GL_GetProcAddress("gl"+name);
if (fn == IntPtr.Zero) {
throw new NotSupportedException("gl"+name);
}
return (T)(object)Marshal.GetDelegateForFunctionPointer(fn, typeof(T));
}
static bool inited = false;
public static void Init(GraphicsDevice gd) {
CheckFNA();
if (inited) return;
var gldev = gd.GetType().GetField("GLDevice",
BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance
).GetValue(gd);
if (gldev.GetType().Name.EndsWith("MetalDevice"))
throw new NotSupportedException("Metal isn't supported, need OpenGL!");
InitProcs();
inited = true;
}
public static void Deinit() {
DeinitProcs();
inited = false;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using GLenum = System.UInt32;
using GLboolean = System.Byte ;
using GLbitfield = System.UInt32;
using GLvoid = System.Void ;
using GLbyte = System.SByte ;
using GLshort = System.Int16 ;
using GLint = System.Int32 ;
using GLubyte = System.Byte ;
using GLushort = System.UInt16;
using GLuint = System.UInt32;
using GLsizei = System.Int32 ;
using GLfloat = System.Single;
using GLclampf = System.Single;
using GLdouble = System.Double;
using GLclampd = System.Double;
using GLchar = System.SByte ;
namespace PoroCYon.FNAGLSL {
public static unsafe partial class GL {
public const GLenum
COMPILE_STATUS = 0x8B81,
INFO_LOG_LENGTH = 0x8B84,
LINK_STATUS = 0x8B82;
static void InitProcs() {
_GetError = GetProcAddress<Func<GLenum>>("GetError");
_CreateProgram = GetProcAddress<Func<GLuint>>("CreateProgram");
_CreateShader = GetProcAddress<Func<GLenum, GLuint>>("CreateShader");
_ShaderSource = GetProcAddress<Action<GLuint, GLsizei, IntPtr, IntPtr>>("ShaderSource");
_CompileShader = GetProcAddress<Action<GLuint>>("CompileShader");
_GetShaderiv = GetProcAddress<Action<GLuint, GLenum, IntPtr>>("GetShaderiv");
_GetShaderInfoLog = GetProcAddress<Action<GLuint, GLsizei, IntPtr, IntPtr>>("GetShaderInfoLog");
_AttachShader = GetProcAddress<Action<GLuint, GLuint>>("AttachShader");
_LinkProgram = GetProcAddress<Action<GLuint>>("LinkProgram");
_GetProgramiv = GetProcAddress<Action<GLuint, GLenum, IntPtr>>("GetProgramiv");
_GetProgramInfoLog = GetProcAddress<Action<GLuint, GLsizei, IntPtr, IntPtr>>("GetProgramInfoLog");
_DeleteShader = GetProcAddress<Action<GLuint>>("DeleteShader");
_DeleteProgram = GetProcAddress<Action<GLuint>>("DeleteProgram");
}
static void DeinitProcs() {
_GetError = null;
_CreateProgram = null;
_CreateShader = null;
_ShaderSource = null;
_CompileShader = null;
_GetShaderiv = null;
_GetShaderInfoLog = null;
_AttachShader = null;
_LinkProgram = null;
_GetProgramiv = null;
_GetProgramInfoLog = null;
_DeleteShader = null;
_DeleteProgram = null;
}
static Func<GLenum> _GetError;
public static GLError GetError() => (GLError)_GetError();
static Func<GLuint> _CreateProgram;
public static GLuint CreateProgram() => _CreateProgram();
static Func<GLenum, GLuint> _CreateShader;
public static GLuint CreateShader(GLSLPurpose shtyp)
=> _CreateShader((GLenum)shtyp);
static Action<GLuint, GLsizei, IntPtr, IntPtr> _ShaderSource;
public static void ShaderSource(GLuint sh, GLsizei count,
GLchar** str, GLint* len) {
_ShaderSource(sh, count, (IntPtr)str, (IntPtr)len);
}
static Action<GLuint> _CompileShader;
public static void CompileShader(GLuint sh) { _CompileShader(sh); }
static Action<GLuint, GLenum, IntPtr> _GetShaderiv;
public static GLint GetShaderiv(GLuint sh, GLenum pname) {
GLint* parm = stackalloc GLint[1];
*parm = 0;
_GetShaderiv(sh, pname, (IntPtr)parm);
return *parm;
}
static Action<GLuint, GLsizei, IntPtr, IntPtr> _GetShaderInfoLog;
public static void GetShaderInfoLog(GLuint sh, GLsizei maxl,
GLsizei* len, GLchar* infolog) {
_GetShaderInfoLog(sh, maxl, (IntPtr)len, (IntPtr)infolog);
}
static Action<GLuint, GLuint> _AttachShader;
public static void AttachShader(GLuint prgm, GLuint sh) {
_AttachShader(prgm, sh);
}
static Action<GLuint> _LinkProgram;
public static void LinkProgram(GLuint prgm) { _LinkProgram(prgm); }
static Action<GLuint, GLenum, IntPtr> _GetProgramiv;
// FIXME: won't work with GL_COMPUTE_WORK_GROUP_SIZE
public static GLint GetProgramiv(GLuint prgm, GLenum pname) {
GLint* parm = stackalloc GLint[3];
parm[2] = parm[1] = parm[0] = 0;
_GetProgramiv(prgm, pname, (IntPtr)parm);
return parm[0];
}
static Action<GLuint, GLsizei, IntPtr, IntPtr> _GetProgramInfoLog;
public static void GetProgramInfoLog(GLuint prgm, GLsizei maxl,
GLsizei* len, GLchar* infolog) {
_GetProgramInfoLog(prgm, maxl, (IntPtr)len, (IntPtr)infolog);
}
static Action<GLuint> _DeleteShader;
public static void DeleteShader(GLuint sh) { _DeleteShader(sh); }
static Action<GLuint> _DeleteProgram;
public static void DeleteProgram(GLuint prgm) { _DeleteProgram(prgm); }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
//using VertexType = Microsoft.Xna.Framework.Graphics.VertexPositionColorTexture;
[Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)]
struct VertexType {
Vector3 pos;
Vector2 uv ;
Color col;
public VertexType(Vector3 p, Color c, Vector2 uv) {
pos = p; this.uv = uv; col = c;
}
public unsafe static VertexDeclaration Format = new VertexDeclaration(
// what is the 4th argument even supposed to be?!!
new VertexElement(0 ,
VertexElementFormat.Vector3, VertexElementUsage.Position , 0)
, new VertexElement(0+sizeof(Vector3) ,
VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
, new VertexElement(0+sizeof(Vector3)+sizeof(Vector2),
VertexElementFormat.Color , VertexElementUsage.Color , 0)
);
}
class TestGame : Game {
GraphicsDeviceManager gdm;
SpriteBatch sb;
KeyboardState ks;
BasicEffect hlsl;
readonly VertexType[] vertices = 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))
};
public TestGame() : base() {
gdm = new GraphicsDeviceManager(this);
}
protected override void Initialize() {
IsMouseVisible = true;
Window.AllowUserResizing = true;
Window.Title = "FNA GLSL hax";
base.Initialize();
}
protected override void LoadContent() {
sb = new SpriteBatch(GraphicsDevice);
hlsl = new BasicEffect(GraphicsDevice);
hlsl.LightingEnabled = false;
hlsl.PreferPerPixelLighting = false;
hlsl.FogEnabled = false;
hlsl.TextureEnabled = false;
hlsl.VertexColorEnabled = true;
hlsl.World = hlsl.View = hlsl.Projection = Matrix.Identity;
base.LoadContent();
}
protected override void UnloadContent() {
base.UnloadContent();
}
protected override void Update(GameTime gt) {
ks = Keyboard.GetState();
base.Update(gt);
if (ks.IsKeyDown(Keys.Escape)) {
Exit();
return;
}
}
protected override void Draw(GameTime gt) {
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gt);
/*for (int i = 0; i < hlsl.Techniques.Count; ++i)
Console.WriteLine(String.Format("t{0}: {1}", i, hlsl.Techniques[i].Name));*/
var tech = hlsl.CurrentTechnique = hlsl.Techniques[0];
for (int i = 0; i < tech.Passes.Count; ++i) {
//Console.WriteLine(String.Format("p{0}: {1}", i, tech.Passes[i].Name));
tech.Passes[i].Apply();
GraphicsDevice.DrawUserPrimitives<VertexType>(
PrimitiveType.TriangleStrip, vertices, 0, 2, VertexType.Format);
}
}
}
static class Program {
[STAThread]
static void Main(string[] args) {
using (var g = new TestGame())
g.Run();
}
}
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