1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-01 10:05:55 +00:00
CLK/Outputs/CRT/Internals/TextureTarget.cpp

148 lines
4.3 KiB
C++

//
// TextureTarget.cpp
// Clock Signal
//
// Created by Thomas Harte on 07/02/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "TextureTarget.hpp"
#include <math.h>
#include <stdlib.h>
using namespace OpenGL;
TextureTarget::TextureTarget(GLsizei width, GLsizei height, GLenum texture_unit) :
_width(width),
_height(height),
_pixel_shader(nullptr),
_drawing_vertex_array(0),
_drawing_array_buffer(0),
_set_aspect_ratio(0.0f),
_texture_unit(texture_unit)
{
glGenFramebuffers(1, &_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
_expanded_width = 1 << (GLsizei)ceil(log2(width));
_expanded_height = 1 << (GLsizei)ceil(log2(height));
glGenTextures(1, &_texture);
glActiveTexture(texture_unit);
glBindTexture(GL_TEXTURE_2D, _texture);
uint8_t *blank_buffer = (uint8_t *)calloc((size_t)(_expanded_width * _expanded_height), 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)_expanded_width, (GLsizei)_expanded_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank_buffer);
free(blank_buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw ErrorFramebufferIncomplete;
}
TextureTarget::~TextureTarget()
{
glDeleteFramebuffers(1, &_framebuffer);
glDeleteTextures(1, &_texture);
if(_drawing_vertex_array) glDeleteVertexArrays(1, &_drawing_vertex_array);
if(_drawing_array_buffer) glDeleteBuffers(1, &_drawing_array_buffer);
}
void TextureTarget::bind_framebuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
glViewport(0, 0, _width, _height);
}
void TextureTarget::bind_texture()
{
glBindTexture(GL_TEXTURE_2D, _texture);
}
void TextureTarget::draw(float aspect_ratio)
{
if(!_pixel_shader)
{
const char *vertex_shader =
"#version 150\n"
"in vec2 texCoord;"
"in vec2 position;"
"out vec2 texCoordVarying;"
"void main(void)"
"{"
"texCoordVarying = texCoord;"
"gl_Position = vec4(position, 0.0, 1.0);"
"}";
const char *fragment_shader =
"#version 150\n"
"in vec2 texCoordVarying;"
"uniform sampler2D texID;"
"out vec4 fragColour;"
"void main(void)"
"{"
"fragColour = texture(texID, texCoordVarying);"
"}";
_pixel_shader.reset(new Shader(vertex_shader, fragment_shader, nullptr));
_pixel_shader->bind();
glGenVertexArrays(1, &_drawing_vertex_array);
glGenBuffers(1, &_drawing_array_buffer);
glBindVertexArray(_drawing_vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, _drawing_array_buffer);
GLint positionAttribute = _pixel_shader->get_attrib_location("position");
GLint texCoordAttribute = _pixel_shader->get_attrib_location("texCoord");
glEnableVertexAttribArray((GLuint)positionAttribute);
glEnableVertexAttribArray((GLuint)texCoordAttribute);
const GLsizei vertexStride = 4 * sizeof(GLfloat);
glVertexAttribPointer((GLuint)positionAttribute, 2, GL_FLOAT, GL_FALSE, vertexStride, (void *)0);
glVertexAttribPointer((GLuint)texCoordAttribute, 2, GL_FLOAT, GL_FALSE, vertexStride, (void *)(2 * sizeof(GLfloat)));
GLint texIDUniform = _pixel_shader->get_uniform_location("texID");
glUniform1i(texIDUniform, (GLint)(_texture_unit - GL_TEXTURE0));
}
if(_set_aspect_ratio != aspect_ratio)
{
_set_aspect_ratio = aspect_ratio;
float buffer[4*4];
// establish texture coordinates
buffer[2] = 0.0f;
buffer[3] = 0.0f;
buffer[6] = 0.0f;
buffer[7] = (float)_height / (float)_expanded_height;
buffer[10] = (float)_width / (float)_expanded_width;
buffer[11] = 0;
buffer[14] = buffer[10];
buffer[15] = buffer[7];
// determine positions; rule is to keep the same height and centre
float internal_aspect_ratio = (float)_width / (float)_height;
float aspect_ratio_ratio = internal_aspect_ratio / aspect_ratio;
buffer[0] = -aspect_ratio_ratio; buffer[1] = -1.0f;
buffer[4] = -aspect_ratio_ratio; buffer[5] = 1.0f;
buffer[8] = aspect_ratio_ratio; buffer[9] = -1.0f;
buffer[12] = aspect_ratio_ratio; buffer[13] = 1.0f;
// upload buffer
glBindBuffer(GL_ARRAY_BUFFER, _drawing_array_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
}
_pixel_shader->bind();
glBindVertexArray(_drawing_vertex_array);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}