Update to v093 release.

byuu says:

Changelog:
- added Cocoa target: higan can now be compiled for OS X Lion
  [Cydrak, byuu]
- SNES/accuracy profile hires color blending improvements - fixes
  Marvelous text [AWJ]
- fixed a slight bug in SNES/SA-1 VBR support caused by a typo
- added support for multi-pass shaders that can load external textures
  (requires OpenGL 3.2+)
- added game library path (used by ananke->Import Game) to
  Settings->Advanced
- system profiles, shaders and cheats database can be stored in "all
  users" shared folders now (eg /usr/share on Linux)
- all configuration files are in BML format now, instead of XML (much
  easier to read and edit this way)
- main window supports drag-and-drop of game folders (but not game files
  / ZIP archives)
- audio buffer clears when entering a modal loop on Windows (prevents
  audio repetition with DirectSound driver)
- a substantial amount of code clean-up (probably the biggest
  refactoring to date)

One highly desired target for this release was to default to the optimal
drivers instead of the safest drivers, but because AMD drivers don't
seem to like my OpenGL 3.2 driver, I've decided to postpone that. AMD
has too big a market share. Hopefully with v093 officially released, we
can get some public input on what AMD doesn't like.
This commit is contained in:
Tim Allen
2013-08-18 13:21:14 +10:00
parent c74865e171
commit 4e2eb23835
1928 changed files with 4834 additions and 84223 deletions

103
ruby/video/opengl/bind.hpp Normal file
View File

@@ -0,0 +1,103 @@
#if !defined(PLATFORM_OSX)
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
PFNGLCREATESHADERPROC glCreateShader = nullptr;
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLDETACHSHADERPROC glDetachShader = nullptr;
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr;
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
PFNGLBUFFERDATAPROC glBufferData = nullptr;
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation = nullptr;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr;
PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
PFNGLGETUNIFORMIVPROC glGetUniformiv = nullptr;
PFNGLUNIFORM1IPROC glUniform1i = nullptr;
PFNGLUNIFORM1FPROC glUniform1f = nullptr;
PFNGLUNIFORM2FPROC glUniform2f = nullptr;
PFNGLUNIFORM2FVPROC glUniform2fv = nullptr;
PFNGLUNIFORM4FPROC glUniform4f = nullptr;
PFNGLUNIFORM4FVPROC glUniform4fv = nullptr;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = nullptr;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr;
PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
static bool OpenGLBind() {
#define bind(prototype, function) \
function = (prototype)glGetProcAddress(#function); \
if(function == nullptr) return false
bind(PFNGLCREATEPROGRAMPROC, glCreateProgram);
bind(PFNGLDELETEPROGRAMPROC, glDeleteProgram);
bind(PFNGLUSEPROGRAMPROC, glUseProgram);
bind(PFNGLCREATESHADERPROC, glCreateShader);
bind(PFNGLDELETESHADERPROC, glDeleteShader);
bind(PFNGLSHADERSOURCEPROC, glShaderSource);
bind(PFNGLCOMPILESHADERPROC, glCompileShader);
bind(PFNGLGETSHADERIVPROC, glGetShaderiv);
bind(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog);
bind(PFNGLATTACHSHADERPROC, glAttachShader);
bind(PFNGLDETACHSHADERPROC, glDetachShader);
bind(PFNGLLINKPROGRAMPROC, glLinkProgram);
bind(PFNGLVALIDATEPROGRAMPROC, glValidateProgram);
bind(PFNGLGETPROGRAMIVPROC, glGetProgramiv);
bind(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog);
bind(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays);
bind(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays);
bind(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray);
bind(PFNGLGENBUFFERSPROC, glGenBuffers);
bind(PFNGLDELETEBUFFERSPROC, glDeleteBuffers);
bind(PFNGLBINDBUFFERPROC, glBindBuffer);
bind(PFNGLBUFFERDATAPROC, glBufferData);
bind(PFNGLGETATTRIBLOCATIONPROC, glGetAttribLocation);
bind(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer);
bind(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray);
bind(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray);
bind(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation);
bind(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation);
bind(PFNGLGETUNIFORMIVPROC, glGetUniformiv);
bind(PFNGLUNIFORM1IPROC, glUniform1i);
bind(PFNGLUNIFORM1FPROC, glUniform1f);
bind(PFNGLUNIFORM2FPROC, glUniform2f);
bind(PFNGLUNIFORM2FVPROC, glUniform2fv);
bind(PFNGLUNIFORM4FPROC, glUniform4f);
bind(PFNGLUNIFORM4FVPROC, glUniform4fv);
bind(PFNGLUNIFORMMATRIX4FVPROC, glUniformMatrix4fv);
bind(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers);
bind(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers);
bind(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer);
bind(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D);
bind(PFNGLACTIVETEXTUREPROC, glActiveTexture);
#undef bind
return true;
}
#else
static bool OpenGLBind() {
return true;
}
#endif

147
ruby/video/opengl/main.hpp Normal file
View File

@@ -0,0 +1,147 @@
void OpenGL::shader(const char* pathname) {
for(auto& program : programs) program.release();
programs.reset();
format = GL_RGBA8;
filter = GL_LINEAR;
wrap = GL_CLAMP_TO_BORDER;
absoluteWidth = 0, absoluteHeight = 0;
relativeWidth = 0, relativeHeight = 0;
if(pathname) {
auto document = Markup::Document(file::read({pathname, "manifest.bml"}));
for(auto& node : document.find("program")) {
unsigned n = programs.size();
programs(n).bind(this, node, pathname);
}
bind(this, document["output"], pathname);
}
}
bool OpenGL::lock(uint32_t*& data, unsigned& pitch) {
pitch = width * sizeof(uint32_t);
return data = buffer;
}
void OpenGL::clear() {
for(auto& p : programs) {
glUseProgram(p.program);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
glUseProgram(0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
void OpenGL::refresh() {
clear();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, inputFormat, buffer);
struct History {
GLuint texture;
unsigned width, height;
GLuint filter, wrap;
};
vector<History> history;
unsigned sourceWidth = width, sourceHeight = height;
history.prepend({texture, sourceWidth, sourceHeight, filter, wrap});
for(auto& p : programs) {
unsigned targetWidth = p.absoluteWidth ? p.absoluteWidth : outputWidth;
unsigned targetHeight = p.absoluteHeight ? p.absoluteHeight : outputHeight;
if(p.relativeWidth) targetWidth = sourceWidth * p.relativeWidth;
if(p.relativeHeight) targetHeight = sourceHeight * p.relativeHeight;
p.size(targetWidth, targetHeight);
glUseProgram(p.program);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer);
glrUniform1i("phase", p.phase);
glrUniform1i("sourceLength", history.size());
glrUniform1i("pixmapLength", p.pixmaps.size());
glrUniform4f("targetSize", targetWidth, targetHeight, 1.0 / targetWidth, 1.0 / targetHeight);
glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight);
//glrUniform4f("targetActualSize", glrSize(targetWidth), glrSize(targetHeight), 1.0 / glrSize(targetWidth), 1.0 / glrSize(targetHeight));
//glrUniform4f("outputActualSize", glrSize(outputWidth), glrSize(outputHeight), 1.0 / glrSize(outputWidth), 1.0 / glrSize(outputHeight));
unsigned aid = 0;
for(auto& pixmap : history) {
glrUniform1i({"source[", aid, "]"}, aid);
glrUniform4f({"sourceSize[", aid, "]"}, pixmap.width, pixmap.height, 1.0 / pixmap.width, 1.0 / pixmap.height);
//glrUniform4f({"sourceActualSize[", aid, "]"}, glrSize(pixmap.width), glrSize(pixmap.height), 1.0 / glrSize(pixmap.width), 1.0 / glrSize(pixmap.height));
glActiveTexture(GL_TEXTURE0 + (aid++));
glBindTexture(GL_TEXTURE_2D, pixmap.texture);
glrParameters(pixmap.filter, pixmap.wrap);
}
unsigned bid = 0;
for(auto& pixmap : p.pixmaps) {
glrUniform1i({"pixmap[", bid, "]"}, aid + bid);
glrUniform4f({"pixmapSize[", bid, "]"}, pixmap.width, pixmap.height, 1.0 / pixmap.width, 1.0 / pixmap.height);
//glrUniform4f({"pixmapActualSize[", bid, "]"}, glrSize(pixmap.width), glrSize(pixmap.height), 1.0 / glrSize(pixmap.width), 1.0 / glrSize(pixmap.height));
glActiveTexture(GL_TEXTURE0 + aid + (bid++));
glBindTexture(GL_TEXTURE_2D, pixmap.texture);
glrParameters(pixmap.filter, pixmap.wrap);
}
glActiveTexture(GL_TEXTURE0);
glrParameters(p.filter, p.wrap);
p.render(sourceWidth, sourceHeight, targetWidth, targetHeight);
glBindTexture(GL_TEXTURE_2D, p.texture);
p.phase = (p.phase + 1) % p.modulo;
sourceWidth = p.width, sourceHeight = p.height;
history.prepend({p.texture, sourceWidth, sourceHeight, p.filter, p.wrap});
}
unsigned targetWidth = absoluteWidth ? absoluteWidth : outputWidth;
unsigned targetHeight = absoluteHeight ? absoluteHeight : outputHeight;
if(relativeWidth) targetWidth = sourceWidth * relativeWidth;
if(relativeHeight) targetHeight = sourceHeight * relativeHeight;
glUseProgram(program);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glrUniform1i("source[0]", 0);
glrUniform4f("targetSize", targetWidth, targetHeight, 1.0 / targetWidth, 1.0 / targetHeight);
glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight);
glrParameters(filter, wrap);
render(sourceWidth, sourceHeight, outputWidth, outputHeight);
}
bool OpenGL::init() {
if(!OpenGLBind()) return false;
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_POLYGON_SMOOTH);
glDisable(GL_STENCIL_TEST);
glEnable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
program = glCreateProgram();
vertex = glrCreateShader(program, GL_VERTEX_SHADER, OpenGLOutputVertexShader);
//geometry = glrCreateShader(program, GL_GEOMETRY_SHADER, OpenGLGeometryShader);
fragment = glrCreateShader(program, GL_FRAGMENT_SHADER, OpenGLFragmentShader);
OpenGLSurface::allocate();
glrLinkProgram(program);
shader(nullptr);
return true;
}
void OpenGL::term() {
OpenGLSurface::release();
if(buffer) { delete[] buffer; buffer = nullptr; }
}

View File

@@ -0,0 +1,82 @@
#if defined(PLATFORM_X)
#include <GL/gl.h>
#include <GL/glx.h>
#define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(PLATFORM_OSX)
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#elif defined(PLATFORM_WIN)
#include <GL/gl.h>
#include <GL/glext.h>
#define glGetProcAddress(name) wglGetProcAddress(name)
#else
#error "ruby::OpenGL: unsupported platform"
#endif
namespace ruby {
#include "bind.hpp"
#include "shaders.hpp"
#include "utility.hpp"
struct OpenGL;
struct OpenGLTexture {
GLuint texture = 0;
unsigned width = 0;
unsigned height = 0;
GLuint format = GL_RGBA8;
GLuint filter = GL_LINEAR;
GLuint wrap = GL_CLAMP_TO_BORDER;
};
struct OpenGLSurface : OpenGLTexture {
GLuint program = 0;
GLuint framebuffer = 0;
GLuint vao = 0;
GLuint vbo[3] = {0, 0, 0};
GLuint vertex = 0;
GLuint geometry = 0;
GLuint fragment = 0;
uint32_t* buffer = nullptr;
void allocate();
void size(unsigned width, unsigned height);
void release();
void render(unsigned sourceWidth, unsigned sourceHeight, unsigned targetWidth, unsigned targetHeight);
};
struct OpenGLProgram : OpenGLSurface {
//configuration
unsigned phase = 0; //frame counter
unsigned modulo = 0; //frame counter modulus
unsigned absoluteWidth = 0;
unsigned absoluteHeight = 0;
double relativeWidth = 0;
double relativeHeight = 0;
vector<OpenGLTexture> pixmaps;
void bind(OpenGL* instance, const Markup::Node& node, const string& pathname);
void release();
};
struct OpenGL : OpenGLProgram {
vector<OpenGLProgram> programs;
GLuint inputFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
unsigned outputWidth = 0;
unsigned outputHeight = 0;
void shader(const char* pathname);
bool lock(uint32_t*& data, unsigned& pitch);
void clear();
void refresh();
bool init();
void term();
};
#include "surface.hpp"
#include "program.hpp"
#include "main.hpp"
}

View File

@@ -0,0 +1,87 @@
void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const string& pathname) {
filter = glrFilter(node["filter"].text());
wrap = glrWrap(node["wrap"].text());
modulo = glrModulo(node["modulo"].integer());
string w = node["width"].text(), h = node["height"].text();
if(w.endswith("%")) relativeWidth = real(w.rtrim<1>("%")) / 100.0;
else absoluteWidth = decimal(w);
if(h.endswith("%")) relativeHeight = real(h.rtrim<1>("%")) / 100.0;
else absoluteHeight = decimal(h);
if(node.name != "program") return;
format = glrFormat(node["format"].text());
program = glCreateProgram();
glGenFramebuffers(1, &framebuffer);
if(file::exists({pathname, node["vertex"].text()})) {
string source = file::read({pathname, node["vertex"].text()});
vertex = glrCreateShader(program, GL_VERTEX_SHADER, source);
} else {
vertex = glrCreateShader(program, GL_VERTEX_SHADER, OpenGLVertexShader);
}
if(file::exists({pathname, node["geometry"].text()})) {
string source = file::read({pathname, node["geometry"].text()});
geometry = glrCreateShader(program, GL_GEOMETRY_SHADER, source);
} else {
//geometry shaders, when attached, must pass all vertex output through to the fragment shaders
//geometry = glrCreateShader(program, GL_GEOMETRY_SHADER, OpenGLGeometryShader);
}
if(file::exists({pathname, node["fragment"].text()})) {
string source = file::read({pathname, node["fragment"].text()});
fragment = glrCreateShader(program, GL_FRAGMENT_SHADER, source);
} else {
fragment = glrCreateShader(program, GL_FRAGMENT_SHADER, OpenGLFragmentShader);
}
for(auto& leaf : node.find("pixmap")) {
nall::image image({pathname, leaf.text()});
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
if(image.empty()) continue;
GLuint texture;
glGenTextures(1, &texture);
unsigned n = pixmaps.size();
pixmaps(n).texture = texture;
pixmaps(n).width = image.width;
pixmaps(n).height = image.height;
pixmaps(n).format = format;
pixmaps(n).filter = filter;
pixmaps(n).wrap = wrap;
if(leaf["format"].exists()) pixmaps(n).format = glrFormat(leaf["format"].text());
if(leaf["filter"].exists()) pixmaps(n).filter = glrFilter(leaf["filter"].text());
if(leaf["wrap"].exists()) pixmaps(n).wrap = glrWrap(leaf["wrap"].text());
unsigned w = glrSize(image.width), h = glrSize(image.height);
uint32_t* buffer = new uint32_t[w * h]();
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, pixmaps(n).format, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width, image.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.data);
delete[] buffer;
}
OpenGLSurface::allocate();
glrLinkProgram(program);
}
void OpenGLProgram::release() {
OpenGLSurface::release();
for(auto& pixmap : pixmaps) glDeleteTextures(1, &pixmap.texture);
pixmaps.reset();
width = 0;
height = 0;
format = GL_RGBA8;
filter = GL_LINEAR;
wrap = GL_CLAMP_TO_BORDER;
phase = 0;
modulo = 0;
absoluteWidth = 0;
absoluteHeight = 0;
relativeWidth = 0;
relativeHeight = 0;
}

View File

@@ -0,0 +1,93 @@
static string OpenGLOutputVertexShader = R"(
#version 150
uniform vec4 targetSize;
uniform vec4 outputSize;
in vec2 texCoord;
out Vertex {
vec4 position;
vec2 texCoord;
} vertexOut;
void main() {
//center image within output window
if(gl_VertexID == 0 || gl_VertexID == 2) {
gl_Position.x = -(targetSize.x / outputSize.x);
} else {
gl_Position.x = +(targetSize.x / outputSize.x);
}
//center and flip vertically (buffer[0, 0] = top-left; OpenGL[0, 0] = bottom-left)
if(gl_VertexID == 0 || gl_VertexID == 1) {
gl_Position.y = +(targetSize.y / outputSize.y);
} else {
gl_Position.y = -(targetSize.y / outputSize.y);
}
//align image to even pixel boundary to prevent aliasing
vec2 align = fract((outputSize.xy + targetSize.xy) / 2.0) * 2.0;
gl_Position.xy -= align / outputSize.xy;
gl_Position.zw = vec2(0.0, 1.0);
vertexOut.texCoord = texCoord;
}
)";
static string OpenGLVertexShader = R"(
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec4 position;
vec2 texCoord;
} vertexOut;
void main() {
gl_Position = position;
vertexOut.texCoord = texCoord;
}
)";
static string OpenGLGeometryShader = R"(
#version 150
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in Vertex {
vec2 texCoord;
} vertexIn[];
out Vertex {
vec2 texCoord;
};
void main() {
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = gl_in[i].gl_Position;
texCoord = vertexIn[i].texCoord;
EmitVertex();
}
EndPrimitive();
}
)";
static string OpenGLFragmentShader = R"(
#version 150
uniform sampler2D source[];
in Vertex {
vec2 texCoord;
};
out vec4 fragColor;
void main() {
fragColor = texture(source[0], texCoord);
}
)";

View File

@@ -0,0 +1,114 @@
void OpenGLSurface::allocate() {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(3, &vbo[0]);
}
void OpenGLSurface::size(unsigned w, unsigned h) {
if(width == w && height == h) return;
width = w, height = h;
w = glrSize(w), h = glrSize(h);
if(texture) { glDeleteTextures(1, &texture); texture = 0; }
if(buffer) { delete[] buffer; buffer = nullptr; }
buffer = new uint32_t[w * h]();
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
if(framebuffer) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
delete[] buffer;
buffer = nullptr;
}
}
void OpenGLSurface::release() {
if(vbo[0]) { glDeleteBuffers(3, &vbo[0]); for(auto &o : vbo) o = 0; }
if(vao) { glDeleteVertexArrays(1, &vao); vao = 0; }
if(vertex) { glDetachShader(program, vertex); glDeleteShader(vertex); vertex = 0; }
if(geometry) { glDetachShader(program, geometry); glDeleteShader(geometry); geometry = 0; }
if(fragment) { glDetachShader(program, fragment); glDeleteShader(fragment); fragment = 0; }
if(texture) { glDeleteTextures(1, &texture); texture = 0; }
if(framebuffer) { glDeleteFramebuffers(1, &framebuffer); framebuffer = 0; }
if(program) { glDeleteProgram(program); program = 0; }
width = 0, height = 0;
}
void OpenGLSurface::render(unsigned sourceWidth, unsigned sourceHeight, unsigned targetWidth, unsigned targetHeight) {
glViewport(0, 0, targetWidth, targetHeight);
float w = (float)sourceWidth / (float)glrSize(sourceWidth);
float h = (float)sourceHeight / (float)glrSize(sourceHeight);
float u = (float)targetWidth, v = (float)targetHeight;
GLint location;
GLfloat modelView[] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
GLfloat projection[] = {
2.0f/u, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f/v, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
};
GLfloat modelViewProjection[4 * 4];
Matrix::Multiply(modelViewProjection, modelView, 4, 4, projection, 4, 4);
GLfloat vertices[] = {
0, 0, 0, 1,
u, 0, 0, 1,
0, v, 0, 1,
u, v, 0, 1,
};
GLfloat positions[4 * 4];
for(unsigned n = 0; n < 16; n += 4) {
Matrix::Multiply(&positions[n], &vertices[n], 1, 4, modelViewProjection, 4, 4);
}
GLfloat texCoords[] = {
0, 0,
w, 0,
0, h,
w, h,
};
glrUniformMatrix4fv("modelView", modelView);
glrUniformMatrix4fv("projection", projection);
glrUniformMatrix4fv("modelViewProjection", modelViewProjection);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
GLuint locationVertex = glGetAttribLocation(program, "vertex");
glEnableVertexAttribArray(locationVertex);
glVertexAttribPointer(locationVertex, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(GLfloat), positions, GL_STATIC_DRAW);
GLuint locationPosition = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(locationPosition);
glVertexAttribPointer(locationPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), texCoords, GL_STATIC_DRAW);
GLuint locationTexCoord = glGetAttribLocation(program, "texCoord");
glEnableVertexAttribArray(locationTexCoord);
glVertexAttribPointer(locationTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindFragDataLocation(program, 0, "fragColor");
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(locationVertex);
glDisableVertexAttribArray(locationPosition);
glDisableVertexAttribArray(locationTexCoord);
}

View File

@@ -0,0 +1,104 @@
static unsigned glrSize(unsigned size) {
return size;
//return bit::round(size); //return nearest power of two
}
static GLuint glrFormat(const string& format) {
if(format == "rgba8" ) return GL_RGBA8;
if(format == "rgb10a2") return GL_RGB10_A2;
if(format == "rgba12" ) return GL_RGBA12;
if(format == "rgba16" ) return GL_RGBA16;
if(format == "rgba16f") return GL_RGBA16F;
if(format == "rgba32f") return GL_RGBA32F;
return GL_RGBA8;
}
static GLuint glrFilter(const string& filter) {
if(filter == "nearest") return GL_NEAREST;
if(filter == "linear" ) return GL_LINEAR;
return GL_LINEAR;
}
static GLuint glrWrap(const string& wrap) {
if(wrap == "border") return GL_CLAMP_TO_BORDER;
if(wrap == "edge" ) return GL_CLAMP_TO_EDGE;
if(wrap == "repeat") return GL_REPEAT;
return GL_CLAMP_TO_BORDER;
}
static unsigned glrModulo(unsigned modulo) {
if(modulo) return modulo;
return 300; //divisible by 2, 3, 4, 5, 6, 10, 12, 15, 20, 25, 30, 50, 60, 100, 150
}
static GLuint glrProgram() {
GLuint program = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&program);
return program;
}
static void glrUniform1i(const string& name, GLint value) {
GLint location = glGetUniformLocation(glrProgram(), name);
glUniform1i(location, value);
}
static void glrUniform4f(const string& name, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3) {
GLint location = glGetUniformLocation(glrProgram(), name);
glUniform4f(location, value0, value1, value2, value3);
}
static void glrUniformMatrix4fv(const string& name, GLfloat *values) {
GLint location = glGetUniformLocation(glrProgram(), name);
glUniformMatrix4fv(location, 1, GL_FALSE, values);
}
static void glrParameters(GLuint filter, GLuint wrap) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
}
static GLuint glrCreateShader(GLuint program, GLuint type, const char* source) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
GLint result = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if(result == GL_FALSE) {
GLint length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
char text[length + 1];
glGetShaderInfoLog(shader, length, &length, text);
text[length] = 0;
print("[ruby::OpenGL: shader compiler error]\n", (const char*)text, "\n\n");
return 0;
}
glAttachShader(program, shader);
return shader;
}
static void glrLinkProgram(GLuint program) {
glLinkProgram(program);
GLint result = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &result);
if(result == GL_FALSE) {
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
char text[length + 1];
glGetProgramInfoLog(program, length, &length, text);
text[length] = 0;
print("[ruby::OpenGL: shader linker error]\n", (const char*)text, "\n\n");
}
glValidateProgram(program);
result = GL_FALSE;
glGetProgramiv(program, GL_VALIDATE_STATUS, &result);
if(result == GL_FALSE) {
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
char text[length + 1];
glGetProgramInfoLog(program, length, &length, text);
text[length] = 0;
print("[ruby::OpenGL: shader validation error]\n", (const char*)text, "\n\n");
}
}