StrawberryBF/src/PlatformLayer/SDL2/SDL2PlatformLayer.bf
2021-02-21 12:48:53 -08:00

265 lines
6.9 KiB
Brainfuck

using SDL2;
using System;
using System.Diagnostics;
using ImGui;
namespace Strawberry.SDL2
{
public class SDL2PlatformLayer : PlatformLayer
{
public int TransformMatrixLocation { get; private set; }
public int TextureMatrixLocation { get; private set; }
public Texture.Filters TextureFilter = .Nearest;
public bool TextureClamping = false;
public Color ClearColor = .Black;
private SDL.Window* window;
private SDL.Surface* screen;
private SDL.Rect screenRect;
private SDL.Renderer* renderer;
private Shader shader;
private SDL.SDL_GameController*[] gamepads;
private bool* keyboard;
private SDL.SDL_GLContext glContext;
private uint glProgram;
public this(String title, int screenWidth, int screenHeight, int windowScale)
: base(title, screenWidth, screenHeight, windowScale)
{
SDL.Version version;
SDL.GetVersion(out version);
Calc.Log("SDL Version {0}.{1}.{2}", version.major, version.minor, version.patch);
{
SDL.InitFlag init = .Video | .Events | .Audio | .Timer;
if (Input.GamepadLimit > 0)
init |= .GameController;
if (SDL.Init(init) != 0)
Runtime.FatalError("Failed to initialize SDL");
}
SDL.EventState(.JoyAxisMotion, .Disable);
SDL.EventState(.JoyBallMotion, .Disable);
SDL.EventState(.JoyHatMotion, .Disable);
SDL.EventState(.JoyButtonDown, .Disable);
SDL.EventState(.JoyButtonUp, .Disable);
SDL.EventState(.JoyDeviceAdded, .Disable);
SDL.EventState(.JoyDeviceRemoved, .Disable);
//Graphics
{
screenRect = SDL.Rect(0, 0, (int32)(ScreenWidth * WindowScale), (int32)(ScreenHeight * WindowScale));
window = SDL.CreateWindow(Title, .Centered, .Centered, screenRect.w, screenRect.h, .Shown | .OpenGL);
renderer = SDL.CreateRenderer(window, -1, .Accelerated);
screen = SDL.GetWindowSurface(window);
SDLImage.Init(.PNG | .JPG);
SDLTTF.Init();
glContext = SDL.GL_CreateContext(window);
SDL.GL_SetSwapInterval(1);
GL.Init(=> SdlGetProcAddress);
//We need to activate this somehwere to make use of the alpha layer
GL.glEnable(GL.GL_BLEND);
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
shader = new Shader(String[2] (
// vertex shader
"""
#version 330
uniform mat4 u_matrix;
layout(location=0) in vec2 a_position;
layout(location=1) in vec2 a_tex;
layout(location=2) in vec4 a_color;
layout(location=3) in vec3 a_type;
out vec2 v_tex;
out vec4 v_col;
out vec3 v_type;
void main(void)
{
gl_Position = u_matrix * vec4(a_position.xy, 0, 1);
v_tex = a_tex;
v_col = a_color;
v_type = a_type;
}
""",
// fragment shader
"""
#version 330
uniform sampler2D u_texture;
in vec2 v_tex;
in vec4 v_col;
in vec3 v_type;
out vec4 o_color;
void main(void)
{
vec4 color = texture(u_texture, v_tex);
o_color =
v_type.x * color * v_col +
v_type.y * color.a * v_col +
v_type.z * v_col;
}
"""));
glProgram = GL.glCreateProgram();
GL.glAttachShader(glProgram, shader.vertexHandle);
GL.glAttachShader(glProgram, shader.fragmentHandle);
GL.glLinkProgram(glProgram);
TransformMatrixLocation = GL.glGetUniformLocation(glProgram, "u_matrix");
TextureMatrixLocation = GL.glGetUniformLocation(glProgram, "u_texture");
int32 logLen = 0;
char8[1024] log;
GL.glGetProgramInfoLog(glProgram, 1024, &logLen, &log);
if (logLen > 0)
Calc.Log(&log, logLen);
}
//Audio
{
SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096);
}
//Input
{
keyboard = SDL.GetKeyboardState(null);
gamepads = new SDL.SDL_GameController*[Input.GamepadLimit];
for (let i < gamepads.Count)
gamepads[i] = SDL.GameControllerOpen((int32)i);
}
//ImGui
{
ImGui.CHECKVERSION();
ImGui.CreateContext();
ImGui.StyleColorsDark();
ImGuiImplSDL2.InitForOpenGL(window, &glContext);
ImGuiImplOpenGL3.Init();
}
}
public ~this()
{
delete gamepads;
delete shader;
ImGui.ImGuiImplOpenGL3.Shutdown();
ImGui.ImGuiImplSDL2.Shutdown();
ImGui.ImGui.DestroyContext();
GL.glDeleteProgram(glProgram);
SDL.GL_DeleteContext(glContext);
SDL.DestroyWindow(window);
SDL.Quit();
}
static void* SdlGetProcAddress(StringView string)
{
return SDL.SDL_GL_GetProcAddress(string.ToScopeCStr!());
}
public override bool Closed()
{
SDL.Event event;
return (SDL.PollEvent(out event) != 0 && event.type == .Quit);
}
public override uint32 Ticks => SDL.GetTicks();
public override void RenderBegin()
{
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0);
GL.glClearColor(ClearColor.Rf, ClearColor.Gf, ClearColor.Bf, ClearColor.Af);
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
}
public override void GameRenderBegin()
{
GL.glUseProgram(glProgram);
}
public override void GameRenderEnd()
{
GL.glUseProgram(0);
GL.glFlush();
}
public override void ImGuiRenderBegin()
{
ImGuiImplOpenGL3.NewFrame();
ImGuiImplSDL2.NewFrame(window);
ImGui.NewFrame();
}
public override void ImGuiRenderEnd()
{
ImGui.Render();
ImGuiImplOpenGL3.RenderDrawData(ImGui.ImGui.GetDrawData());
}
public override void RenderEnd()
{
SDL.GL_SwapWindow(window);
}
public override Batcher CreateBatcher()
{
return new SDL2Batcher(this);
}
public override Texture LoadTexture(String path)
{
let surface = SDLImage.Load(path);
Debug.Assert(surface != null, "Could not load from path.");
Debug.Assert(surface.format.bytesPerPixel == 4, "Surface format incorrect.");
var tex = new Texture(surface.w, surface.h, (uint8*)surface.pixels, TextureFilter, TextureClamping);
SDL.FreeSurface(surface);
return tex;
}
public override void UpdateInput()
{
SDL.PumpEvents();
SDL.GameControllerUpdate();
}
public override bool PollKey(Keys key)
{
Debug.Assert(keyboard != null, "Polling keyboard before initialized");
return keyboard[(uint32)key];
}
public override bool CapsLock => SDL.GetModState() & .Caps > 0;
public override bool NumLock => SDL.GetModState() & .Num > 0;
public override bool PollGamepadButton(int gamepadID, Buttons button)
{
Debug.Assert(gamepads != null, "Polling gamepad before initialized");
Debug.Assert(gamepadID >= 0 && gamepadID < gamepads.Count, "Gamepad index out of range (increase Game.gamepadLimit?)");
return SDL.GameControllerGetButton(gamepads[gamepadID], (SDL.SDL_GameControllerButton)button) == 1;
}
public override float PollGamepadAxis(int gamepadID, Axes axis)
{
Debug.Assert(gamepads != null, "Polling gamepad before initialized");
Debug.Assert(gamepadID >= 0 && gamepadID < gamepads.Count, "Gamepad index out of range (increase Game.gamepadLimit?)");
let val = SDL.GameControllerGetAxis(gamepads[gamepadID], (SDL.SDL_GameControllerAxis)axis);
if (val == 0)
return 0;
else if (val > 0)
return val / 32767f;
else
return val / 32768f;
}
}
}