Итак, интересная вещь в этой проблеме: я пытался использовать RenderDoc, но RenderDoc зависал при попытке загрузить захваченный кадр, это происходило каждый раз, когда я пытался, поэтому казалось бы, что инструменты отладки графикине поможет мне в этой ситуации ...
Я использую C # и хороший набор привязок OpenGL и GLFW под названием CSGL (https://github.com/ThatOneCheetah/CSGL)
Вот мой код рендеринга (моя игра используетпроцедурные сплошные цветные прямоугольники в качестве графической основы, класс ниже предназначен для пакетирования всех моих вызовов отрисовки.)
using System;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using static CSGL.OpenGL;
namespace BoxBlight
{
class BoxRenderer
{
public const int MAX_RECTANGLES = 500;
static Rectangle[] rectangles = new Rectangle[MAX_RECTANGLES];
static int index = 0;
static uint VAO = 250;
static uint VBO = 250;
static uint CBO = 250;
static bool err = false;
const string vertShader = @"
#version 150
in vec3 in_Position;
in vec4 in_Color;
out vec4 ex_Color;
void main(void) {
gl_Position = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
ex_Color = in_Color;
}
";
const string fragShader = @"
#version 150
precision highp float;
in vec4 ex_Color;
out vec4 gl_FragColor;
void main(void) {
gl_FragColor = ex_Color;
}
";
static uint shaderProg = 250;
static uint vs = 0;
static uint fs = 0;
public static void draw(Rectangle rectangle, int offsetX, int offsetY)
{
Rectangle r2 = new Rectangle(rectangle);
r2.x += offsetX;
r2.y += offsetY;
rectangles[index++] = r2;
}
public static void init()
{
if (VAO == 250)
{
glGenVertexArrays(1, ref VAO);
}
if (VBO == 250)
{
glGenBuffers(1, ref VBO);
}
if (CBO == 250)
{
glGenBuffers(1, ref CBO);
}
if (shaderProg == 250)
{
shaderProg = glCreateProgram();
uint vertShd = glCreateShader(GL_VERTEX_SHADER);
IntPtr str = Marshal.AllocHGlobal(vertShader.Length);
Marshal.Copy(Encoding.ASCII.GetBytes(vertShader), 0, str, vertShader.Length);
int length = vertShader.Length;
glShaderSource(vertShd, 1, ref str, ref length);
glCompileShader(vertShd);
Marshal.FreeHGlobal(str);
int isCompiled = 0;
glGetShaderiv(vertShd, GL_COMPILE_STATUS, ref isCompiled);
if (isCompiled == 0)
{
int loglen = 0;
glGetShaderiv(vertShd, GL_INFO_LOG_LENGTH, ref loglen);
IntPtr log = Marshal.AllocHGlobal(loglen);
glGetShaderInfoLog(vertShd, loglen, ref loglen, log);
char[] chrs = new char[loglen];
string logs = "";
Marshal.Copy(log, chrs, 0, loglen);
logs.Concat(chrs.AsEnumerable());
Marshal.FreeHGlobal(log);
Console.Error.WriteLine(logs);
err = true;
return;
}
uint fragShd = glCreateShader(GL_FRAGMENT_SHADER);
str = Marshal.AllocHGlobal(fragShader.Length);
Marshal.Copy(Encoding.ASCII.GetBytes(fragShader), 0, str, fragShader.Length);
length = fragShader.Length;
glShaderSource(fragShd, 1, ref str, ref length);
glCompileShader(fragShd);
Marshal.FreeHGlobal(str);
isCompiled = 0;
glGetShaderiv(fragShd, GL_COMPILE_STATUS, ref isCompiled);
if (isCompiled == 0)
{
int loglen = 0;
glGetShaderiv(fragShd, GL_INFO_LOG_LENGTH, ref loglen);
IntPtr log = Marshal.AllocHGlobal(loglen);
glGetShaderInfoLog(fragShd, loglen, ref loglen, log);
char[] chrs = new char[loglen];
string logs = "";
Marshal.Copy(log, chrs, 0, loglen);
logs.Concat(chrs.AsEnumerable());
Marshal.FreeHGlobal(log);
Console.Error.WriteLine(logs);
err = true;
return;
}
glAttachShader(shaderProg, vertShd);
glAttachShader(shaderProg, fragShd);
glLinkProgram(shaderProg);
int isLinked = 0;
glGetProgramiv(shaderProg, GL_LINK_STATUS, ref isLinked);
if (isLinked == 0)
{
int loglen = 0;
glGetProgramiv(shaderProg, GL_INFO_LOG_LENGTH, ref loglen);
IntPtr log = Marshal.AllocHGlobal(loglen);
glGetProgramInfoLog(shaderProg, loglen, ref loglen, log);
char[] chrs = new char[loglen];
string logs = "";
Marshal.Copy(log, chrs, 0, loglen);
logs.Concat(chrs.AsEnumerable());
Marshal.FreeHGlobal(log);
Console.Error.WriteLine(logs);
err = true;
return;
}
vs = vertShd;
fs = fragShd;
}
}
public static void flush(int xoffset, int yoffset, Rectangle camera)
{
if (err)
{
index = 0;
return;
}
double[] verts = new double[index * 18];
double[] colrs = new double[index * 24];
int indecies = 0;
for(int i = 0; i < index; i++)
{
Rectangle rect = rectangles[i];
rect.x += xoffset;
rect.y += yoffset;
if(camera.Intersects(rect))
{
double x1, y1, x2, y2;
x1 = (double)rect.x / camera.w * 2 - 1;
x2 = ((double)rect.x + rect.w) / camera.w * 2 - 1;
y1 = (1 - (double)rect.y / camera.h) * 2 - 1;
y2 = (1 - ((double)rect.y + rect.h) / camera.h) * 2 - 1;
verts[i * 18 + 0 ] = x1;
verts[i * 18 + 1 ] = y1;
verts[i * 18 + 2 ] = 1;
verts[i * 18 + 3 ] = x2;
verts[i * 18 + 4 ] = y1;
verts[i * 18 + 5 ] = 1;
verts[i * 18 + 6 ] = x1;
verts[i * 18 + 7 ] = y2;
verts[i * 18 + 8 ] = 1;
verts[i * 18 + 9 ] = x2;
verts[i * 18 + 10] = y1;
verts[i * 18 + 11] = 1;
verts[i * 18 + 12] = x1;
verts[i * 18 + 13] = y2;
verts[i * 18 + 14] = 1;
verts[i * 18 + 15] = x1;
verts[i * 18 + 16] = y2;
verts[i * 18 + 17] = 1;
for (int j = 0; j < 6; j++)
{
colrs[i * 24 + j * 4 + 0] = (double)rect.c.R / 255;
colrs[i * 24 + j * 4 + 1] = (double)rect.c.G / 255;
colrs[i * 24 + j * 4 + 2] = (double)rect.c.B / 255;
colrs[i * 24 + j * 4 + 3] = (double)rect.c.A / 255;
}
indecies += 6;
}
}
glBindVertexArray(VAO);
IntPtr data0 = Marshal.AllocHGlobal(verts.Length * sizeof(double));
Marshal.Copy(verts, 0, data0, verts.Length);
glBindBuffer(GL_VERTEX_ARRAY, VBO);
glBufferData(GL_VERTEX_ARRAY, verts.Length * sizeof(double), data0, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(VBO);
glVertexAttribPointer(VBO, 3, GL_DOUBLE, GL_FALSE, 0, IntPtr.Zero);
IntPtr data1 = Marshal.AllocHGlobal(colrs.Length * sizeof(double));
Marshal.Copy(colrs, 0, data1, colrs.Length);
glBindBuffer(GL_VERTEX_ARRAY, CBO);
glBufferData(GL_VERTEX_ARRAY, colrs.Length * sizeof(double), data1, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(CBO);
glVertexAttribPointer(CBO, 4, GL_DOUBLE, GL_FALSE, 0, IntPtr.Zero);
glUseProgram(shaderProg);
glBindAttribLocation(shaderProg, VBO, "in_Position");
glBindAttribLocation(shaderProg, CBO, "in_Color");
glDrawArrays(GL_TRIANGLES, 0, indecies);
glFlush();
Marshal.FreeHGlobal(data0);
Marshal.FreeHGlobal(data1);
glUseProgram(0);
glDisableVertexAttribArray(VBO);
glDisableVertexAttribArray(CBO);
index = 0;
rectangles = new Rectangle[MAX_RECTANGLES];
}
public static void clean()
{
glDetachShader(shaderProg, vs);
glDetachShader(shaderProg, fs);
glDeleteProgram(shaderProg);
glDeleteShader(vs);
glDeleteShader(fs);
glDeleteBuffers(1, ref VBO);
glDeleteBuffers(1, ref CBO);
glDeleteVertexArrays(1, ref VAO);
rectangles = new Rectangle[0];
index = 0;
err = true;
}
}
}
Вот мой основной игровой класс:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static CSGL.CSGL;
using static CSGL.OpenGL;
using static CSGL.Glfw3;
using System.Drawing;
namespace BoxBlight
{
class Program
{
public static IntPtr window = IntPtr.Zero;
public static bool running = true;
public const long FPS = 60;
public static long CurrentTimeMS { get => DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; }
static void Main(string[] args)
{
csglLoadGlfw();
if(glfwInit() != GLFW_TRUE)
{
Console.Error.WriteLine("Failed to initialize GLFW!");
}
glfwDefaultWindowHints();
window = glfwCreateWindow(1024, 768, "Box Blight (v1.0.0)", IntPtr.Zero, IntPtr.Zero);
if(window == IntPtr.Zero)
{
Console.Error.WriteLine("Failed to create window!");
}
glfwMakeContextCurrent(window);
csglLoadGL();
glInitNames();
long lastTime = CurrentTimeMS;
glViewport(0, 0, 1024, 768);
BoxRenderer.init();
while(running)
{
glOrtho(0, 1024, 768, 0, 0.1, 3);
BoxRenderer.draw(new Rectangle(0, 0, 1024, 768, Color.HotPink), 0, 0);
BoxRenderer.draw(new Rectangle(16, 16, 16, 16, Color.White), 0, 0);
BoxRenderer.flush(0, 0, new Rectangle(0, 0, 1024, 768, Color.Black));
glfwSwapBuffers(window);
glfwPollEvents();
while (lastTime + FPS / 1000 > CurrentTimeMS) ;
}
BoxRenderer.clean();
glfwTerminate();
}
}
}