diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 4023ceabd..5f791a349 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -40,7 +40,7 @@ Machine::Machine() : "float texValue = texture(texID, coordinate).r;" "return vec3(step(4.0/256.0, mod(texValue, 8.0/256.0)), step(2.0/256.0, mod(texValue, 4.0/256.0)), step(1.0/256.0, mod(texValue, 2.0/256.0)));" "}"); - _crt->set_output_device(Outputs::CRT::Television); + _crt->set_output_device(Outputs::CRT::Monitor); // _crt->set_visible_area(Outputs::Rect(0.23108f, 0.0f, 0.8125f, 0.98f)); //1875 memset(_key_states, 0, sizeof(_key_states)); diff --git a/Outputs/CRT/CRTOpenGL.cpp b/Outputs/CRT/CRTOpenGL.cpp index c99846ea8..2e12a788b 100644 --- a/Outputs/CRT/CRTOpenGL.cpp +++ b/Outputs/CRT/CRTOpenGL.cpp @@ -71,15 +71,20 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool { _openGL_state = new OpenGLState; - glGenTextures(1, &_openGL_state->textureName); - glBindTexture(GL_TEXTURE_2D, _openGL_state->textureName); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // generate and bind textures for every one of the requested buffers + for(unsigned int buffer = 0; buffer < _buffer_builder->number_of_buffers; buffer++) + { + glGenTextures(1, &_openGL_state->textureName); + glActiveTexture(GL_TEXTURE3 + buffer); + glBindTexture(GL_TEXTURE_2D, _openGL_state->textureName); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - GLenum format = formatForDepth(_buffer_builder->buffers[0].bytes_per_pixel); - glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight, 0, format, GL_UNSIGNED_BYTE, _buffer_builder->buffers[0].data); + GLenum format = formatForDepth(_buffer_builder->buffers[buffer].bytes_per_pixel); + glTexImage2D(GL_TEXTURE_2D, 0, (GLint)format, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight, 0, format, GL_UNSIGNED_BYTE, _buffer_builder->buffers[buffer].data); + } glGenVertexArrays(1, &_openGL_state->vertexArray); glGenBuffers(1, &_openGL_state->arrayBuffer); @@ -91,13 +96,24 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool glBindVertexArray(_openGL_state->vertexArray); prepare_vertex_array(); + // This should return either an actual framebuffer number, if this is a target with a framebuffer intended for output, + // or 0 if no framebuffer is bound, in which case 0 is also what we want to supply to bind the implied framebuffer. So + // it works either way. glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&_openGL_state->defaultFramebuffer); -// _openGL_state->compositeTexture = std::unique_ptr(new OpenGL::TextureTarget(2048, kCRTFrameIntermediateBufferHeight)); -// _openGL_state->filteredYTexture = std::unique_ptr(new OpenGL::TextureTarget(2048, kCRTFrameIntermediateBufferHeight)); -// _openGL_state->filteredTexture = std::unique_ptr(new OpenGL::TextureTarget(2048, kCRTFrameIntermediateBufferHeight)); + // Create intermediate textures and bind to slots 0, 1 and 2 + glActiveTexture(GL_TEXTURE0); + _openGL_state->compositeTexture = std::unique_ptr(new OpenGL::TextureTarget(CRTIntermediateBufferWidth, CRTIntermediateBufferHeight)); + glActiveTexture(GL_TEXTURE1); + _openGL_state->filteredYTexture = std::unique_ptr(new OpenGL::TextureTarget(CRTIntermediateBufferWidth, CRTIntermediateBufferHeight)); + glActiveTexture(GL_TEXTURE2); + _openGL_state->filteredTexture = std::unique_ptr(new OpenGL::TextureTarget(CRTIntermediateBufferWidth, CRTIntermediateBufferHeight)); } +// glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&_openGL_state->defaultFramebuffer); +// +// printf("%d", glIsFramebuffer(_openGL_state->defaultFramebuffer)); + // lock down any further work on the current frame _output_mutex->lock(); @@ -107,27 +123,35 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool // clear the buffer glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, _openGL_state->defaultFramebuffer); +// glBindTexture(GL_TEXTURE_2D, _openGL_state->textureName); +// glGetIntegerv(GL_VIEWPORT, results); + // upload more source pixel data if any; we'll always resubmit the last line submitted last // time as it may have had extra data appended to it - GLenum format = formatForDepth(_buffer_builder->buffers[0].bytes_per_pixel); - if(_buffer_builder->_next_write_y_position < _buffer_builder->last_uploaded_line) + for(unsigned int buffer = 0; buffer < _buffer_builder->number_of_buffers; buffer++) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, (GLint)_buffer_builder->last_uploaded_line, - CRTInputBufferBuilderWidth, (GLint)(CRTInputBufferBuilderHeight - _buffer_builder->last_uploaded_line), - format, GL_UNSIGNED_BYTE, - &_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * CRTInputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]); - _buffer_builder->last_uploaded_line = 0; - } + glActiveTexture(GL_TEXTURE3 + buffer); + GLenum format = formatForDepth(_buffer_builder->buffers[0].bytes_per_pixel); + if(_buffer_builder->_next_write_y_position < _buffer_builder->last_uploaded_line) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, (GLint)_buffer_builder->last_uploaded_line, + CRTInputBufferBuilderWidth, (GLint)(CRTInputBufferBuilderHeight - _buffer_builder->last_uploaded_line), + format, GL_UNSIGNED_BYTE, + &_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * CRTInputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]); + _buffer_builder->last_uploaded_line = 0; + } - if(_buffer_builder->_next_write_y_position > _buffer_builder->last_uploaded_line) - { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, (GLint)_buffer_builder->last_uploaded_line, - CRTInputBufferBuilderWidth, (GLint)(1 + _buffer_builder->_next_write_y_position - _buffer_builder->last_uploaded_line), - format, GL_UNSIGNED_BYTE, - &_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * CRTInputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]); - _buffer_builder->last_uploaded_line = _buffer_builder->_next_write_y_position; + if(_buffer_builder->_next_write_y_position > _buffer_builder->last_uploaded_line) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, (GLint)_buffer_builder->last_uploaded_line, + CRTInputBufferBuilderWidth, (GLint)(1 + _buffer_builder->_next_write_y_position - _buffer_builder->last_uploaded_line), + format, GL_UNSIGNED_BYTE, + &_buffer_builder->buffers[0].data[_buffer_builder->last_uploaded_line * CRTInputBufferBuilderWidth * _buffer_builder->buffers[0].bytes_per_pixel]); + _buffer_builder->last_uploaded_line = _buffer_builder->_next_write_y_position; + } } // ensure array buffer is up to date @@ -149,6 +173,8 @@ void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool } } + glBindFramebuffer(GL_FRAMEBUFFER, _openGL_state->defaultFramebuffer); + // draw all sitting frames unsigned int run = (unsigned int)_run_write_pointer; // printf("%d: %zu v %zu\n", run, _run_builders[run]->uploaded_vertices, _run_builders[run]->number_of_vertices); @@ -368,7 +394,7 @@ void CRT::prepare_shader() GLint scanNormalUniform = _openGL_state->shaderProgram->get_uniform_location("scanNormal"); GLint positionConversionUniform = _openGL_state->shaderProgram->get_uniform_location("positionConversion"); - glUniform1i(texIDUniform, 0); + glUniform1i(texIDUniform, 3); glUniform1i(shadowMaskTexIDUniform, 1); glUniform2f(textureSizeUniform, CRTInputBufferBuilderWidth, CRTInputBufferBuilderHeight); glUniform1f(ticksPerFrameUniform, (GLfloat)(_cycles_per_line * _height_of_display)); diff --git a/Outputs/CRT/TextureTarget.cpp b/Outputs/CRT/TextureTarget.cpp index 8b61dcf7a..60c030f47 100644 --- a/Outputs/CRT/TextureTarget.cpp +++ b/Outputs/CRT/TextureTarget.cpp @@ -10,7 +10,7 @@ using namespace OpenGL; -TextureTarget::TextureTarget(unsigned int width, unsigned int height) +TextureTarget::TextureTarget(GLsizei width, GLsizei height) : _width(width), _height(height) { glGenFramebuffers(1, &_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); @@ -24,9 +24,8 @@ TextureTarget::TextureTarget(unsigned int width, unsigned int height) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); - // TODO: raise an exception if check framebuffer status fails. -// if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) -// return nil; + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + throw ErrorFramebufferIncomplete; } TextureTarget::~TextureTarget() @@ -38,6 +37,7 @@ TextureTarget::~TextureTarget() void TextureTarget::bind_framebuffer() { glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); + glViewport(0, 0, _width, _height); } void TextureTarget::bind_texture() diff --git a/Outputs/CRT/TextureTarget.hpp b/Outputs/CRT/TextureTarget.hpp index b4b77f42d..f4ec3f665 100644 --- a/Outputs/CRT/TextureTarget.hpp +++ b/Outputs/CRT/TextureTarget.hpp @@ -15,14 +15,19 @@ namespace OpenGL { class TextureTarget { public: - TextureTarget(unsigned int width, unsigned int height); + TextureTarget(GLsizei width, GLsizei height); ~TextureTarget(); void bind_framebuffer(); void bind_texture(); + enum { + ErrorFramebufferIncomplete + }; + private: GLuint _framebuffer, _texture; + GLsizei _width, _height; }; }