From 6ab425deda7d3fa67697f578fa57c317c14de405 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 5 Feb 2016 21:35:39 -0500 Subject: [PATCH] There is now a semi-reasonable amount of screen output again. --- Machines/Electron/Electron.cpp | 8 +- .../Mac/Clock Signal/Views/CSCathodeRayView.m | 104 ------ Outputs/CRT/CRT.hpp | 3 + Outputs/CRT/CRTOpenGL.cpp | 308 +++++++++++------- 4 files changed, 195 insertions(+), 228 deletions(-) diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 825fe437f..ba8a62f35 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -30,10 +30,10 @@ Machine::Machine() : _crt(Outputs::CRT(crt_cycles_per_line, Outputs::CRT::DisplayType::PAL50, 1, 1)) { _crt.set_rgb_sampling_function( - "vec4 sample(vec2 coordinate)\n" - "{\n" - "float texValue = texture(texID, coordinate).r;\n" - "return vec4( 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)), 1.0);\n" + "vec3 rgb_sample(vec2 coordinate)" + "{" + "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)));" "}"); memset(_keyStates, 0, sizeof(_keyStates)); diff --git a/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m b/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m index 1dc801978..c0b721534 100644 --- a/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m +++ b/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m @@ -186,110 +186,6 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt // self.frameBounds = CGRectMake(0.0, 0.0, 1.0, 1.0); } -/* - -#pragma mark - Frame output - -#if defined(DEBUG) -- (void)logErrorForObject:(GLuint)object -{ - GLint isCompiled = 0; - glGetShaderiv(object, GL_COMPILE_STATUS, &isCompiled); - if(isCompiled == GL_FALSE) - { - GLint logLength; - glGetShaderiv(object, GL_INFO_LOG_LENGTH, &logLength); - if (logLength > 0) { - GLchar *log = (GLchar *)malloc((size_t)logLength); - glGetShaderInfoLog(object, logLength, &logLength, log); - NSLog(@"Compile log:\n%s", log); - free(log); - } - } -} -#endif - -- (GLuint)compileShader:(const char *)source type:(GLenum)type -{ - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, NULL); - glCompileShader(shader); - -#ifdef DEBUG - [self logErrorForObject:shader]; -#endif - - return shader; -} - -- (void)setSignalDecoder:(nonnull NSString *)signalDecoder type:(CSCathodeRayViewSignalType)type -{ - _signalType = type; - _signalDecoder = [signalDecoder copy]; - OSAtomicIncrement32(&_signalDecoderGeneration); -} - -- (void)prepareShader -{ - if(_shaderProgram) - { - glDeleteProgram(_shaderProgram); - glDeleteShader(_vertexShader); - glDeleteShader(_fragmentShader); - } - - if(!_signalDecoder) - return; - - NSString *const vertexShader = [self vertexShaderForType:_signalType]; - NSString *const fragmentShader = [self fragmentShaderForType:_signalType]; - - _shaderProgram = glCreateProgram(); - _vertexShader = [self compileShader:[vertexShader UTF8String] type:GL_VERTEX_SHADER]; - _fragmentShader = [self compileShader:_signalDecoder ? - [[NSString stringWithFormat:fragmentShader, _signalDecoder] UTF8String] : - [fragmentShader UTF8String] - type:GL_FRAGMENT_SHADER]; - - glAttachShader(_shaderProgram, _vertexShader); - glAttachShader(_shaderProgram, _fragmentShader); - glLinkProgram(_shaderProgram); - -#ifdef DEBUG -// [self logErrorForObject:_shaderProgram]; -#endif - - - glUseProgram(_shaderProgram); - - _positionAttribute = glGetAttribLocation(_shaderProgram, "position"); - _textureCoordinatesAttribute = glGetAttribLocation(_shaderProgram, "srcCoordinates"); - _lateralAttribute = glGetAttribLocation(_shaderProgram, "lateral"); - _alphaUniform = glGetUniformLocation(_shaderProgram, "alpha"); - _textureSizeUniform = glGetUniformLocation(_shaderProgram, "textureSize"); - _windowSizeUniform = glGetUniformLocation(_shaderProgram, "windowSize"); - _boundsSizeUniform = glGetUniformLocation(_shaderProgram, "boundsSize"); - _boundsOriginUniform = glGetUniformLocation(_shaderProgram, "boundsOrigin"); - - GLint texIDUniform = glGetUniformLocation(_shaderProgram, "texID"); - GLint shadowMaskTexIDUniform = glGetUniformLocation(_shaderProgram, "shadowMaskTexID"); - - [self pushSizeUniforms]; - - glUniform1i(texIDUniform, 0); - glUniform1i(shadowMaskTexIDUniform, 1); - - glEnableVertexAttribArray((GLuint)_positionAttribute); - glEnableVertexAttribArray((GLuint)_textureCoordinatesAttribute); - glEnableVertexAttribArray((GLuint)_lateralAttribute); - - const GLsizei vertexStride = kCRTSizeOfVertex; - glVertexAttribPointer((GLuint)_positionAttribute, 2, GL_UNSIGNED_SHORT, GL_TRUE, vertexStride, (void *)kCRTVertexOffsetOfPosition); - glVertexAttribPointer((GLuint)_textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTexCoord); - glVertexAttribPointer((GLuint)_lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfLateral); - -}*/ - - (void)drawRect:(NSRect)dirtyRect { [self drawViewOnlyIfDirty:NO]; diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 3d21807d4..c5233aee6 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -294,9 +294,12 @@ class CRT { void construct_openGL(); void destruct_openGL(); + void prepare_shader(); + void push_size_uniforms(unsigned int output_width, unsigned int output_height); char *get_vertex_shader(); char *get_fragment_shader(); + char *get_compound_shader(const char *base, const char *insert); }; } diff --git a/Outputs/CRT/CRTOpenGL.cpp b/Outputs/CRT/CRTOpenGL.cpp index 83ed3a0b9..cdfb0e8f6 100644 --- a/Outputs/CRT/CRTOpenGL.cpp +++ b/Outputs/CRT/CRTOpenGL.cpp @@ -31,6 +31,32 @@ struct CRT::OpenGLState { GLuint textureName, shadowMaskTextureName; CRTSize textureSize; + + GLuint compile_shader(const char *source, GLenum type) + { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + +#if defined(DEBUG) + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if(isCompiled == GL_FALSE) + { + GLint logLength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar *)malloc((size_t)logLength); + glGetShaderInfoLog(shader, logLength, &logLength, log); + printf("Compile log:\n%s\n", log); + free(log); + } + } +#endif + + return shader; + } + }; static GLenum formatForDepth(unsigned int depth) @@ -86,8 +112,12 @@ void CRT::draw_frame(int output_width, int output_height, bool only_if_dirty) glBindVertexArray(_openGL_state->vertexArray); glGenBuffers(1, &_openGL_state->arrayBuffer); glBindBuffer(GL_ARRAY_BUFFER, _openGL_state->arrayBuffer); + + prepare_shader(); } + push_size_uniforms(output_width, output_height); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(_current_frame->number_of_vertices * _current_frame->size_per_vertex), _current_frame->vertices, GL_DYNAMIC_DRAW); glBindTexture(GL_TEXTURE_2D, _openGL_state->textureName); @@ -112,6 +142,28 @@ void CRT::set_openGL_context_will_change(bool should_delete_resources) { } +void CRT::push_size_uniforms(unsigned int output_width, unsigned int output_height) +{ + if(_openGL_state->windowSizeUniform >= 0) + { + glUniform2f(_openGL_state->windowSizeUniform, output_width, output_height); + } + +// GLfloat outputAspectRatioMultiplier = 1.0;//(viewSize.x / viewSize.y) / (4.0 / 3.0); + +// _aspectRatioCorrectedBounds = _frameBounds; + +// CGFloat bonusWidth = (outputAspectRatioMultiplier - 1.0f) * _frameBounds.size.width; +// _aspectRatioCorrectedBounds.origin.x -= bonusWidth * 0.5f * _aspectRatioCorrectedBounds.size.width; +// _aspectRatioCorrectedBounds.size.width *= outputAspectRatioMultiplier; + + if(_openGL_state->boundsOriginUniform >= 0) + glUniform2f(_openGL_state->boundsOriginUniform, 0.0, 0.0); //(GLfloat)_aspectRatioCorrectedBounds.origin.x, (GLfloat)_aspectRatioCorrectedBounds.origin.y); + + if(_openGL_state->boundsSizeUniform >= 0) + glUniform2f(_openGL_state->boundsSizeUniform, 1.0, 1.0);//(GLfloat)_aspectRatioCorrectedBounds.size.width, (GLfloat)_aspectRatioCorrectedBounds.size.height); +} + void CRT::set_composite_sampling_function(const char *shader) { _composite_shader = strdup(shader); @@ -128,140 +180,156 @@ char *CRT::get_vertex_shader() // top left to OpenGL's [-1,1]x[-1,1] with the origin in the lower left, and to convert input data coordinates // from integral to floating point; there's also some setup for NTSC, PAL or whatever. - const char *const ntscVertexShaderGlobals = - "out vec2 srcCoordinatesVarying[4];\n" - "out float phase;\n"; +// const char *const ntscVertexShaderGlobals = +// "out vec2 srcCoordinatesVarying[4];\n" +// "out float phase;\n"; +// +// const char *const ntscVertexShaderBody = +// "phase = srcCoordinates.x * 6.283185308;\n" +// "\n" +// "srcCoordinatesVarying[0] = vec2(srcCoordinates.x / textureSize.x, (srcCoordinates.y + 0.5) / textureSize.y);\n" +// "srcCoordinatesVarying[3] = srcCoordinatesVarying[0] + vec2(0.375 / textureSize.x, 0.0);\n" +// "srcCoordinatesVarying[2] = srcCoordinatesVarying[0] + vec2(0.125 / textureSize.x, 0.0);\n" +// "srcCoordinatesVarying[1] = srcCoordinatesVarying[0] - vec2(0.125 / textureSize.x, 0.0);\n" +// "srcCoordinatesVarying[0] = srcCoordinatesVarying[0] - vec2(0.325 / textureSize.x, 0.0);\n"; - const char *const ntscVertexShaderBody = - "phase = srcCoordinates.x * 6.283185308;\n" - "\n" - "srcCoordinatesVarying[0] = vec2(srcCoordinates.x / textureSize.x, (srcCoordinates.y + 0.5) / textureSize.y);\n" - "srcCoordinatesVarying[3] = srcCoordinatesVarying[0] + vec2(0.375 / textureSize.x, 0.0);\n" - "srcCoordinatesVarying[2] = srcCoordinatesVarying[0] + vec2(0.125 / textureSize.x, 0.0);\n" - "srcCoordinatesVarying[1] = srcCoordinatesVarying[0] - vec2(0.125 / textureSize.x, 0.0);\n" - "srcCoordinatesVarying[0] = srcCoordinatesVarying[0] - vec2(0.325 / textureSize.x, 0.0);\n"; - -// const char *const rgbVertexShaderGlobals = -// "out vec2 srcCoordinatesVarying[5];\n"; - -// const char *const rgbVertexShaderBody = -// "srcCoordinatesVarying[2] = vec2(srcCoordinates.x / textureSize.x, (srcCoordinates.y + 0.5) / textureSize.y);\n" -// "srcCoordinatesVarying[0] = srcCoordinatesVarying[1] - vec2(1.0 / textureSize.x, 0.0);\n" -// "srcCoordinatesVarying[1] = srcCoordinatesVarying[1] - vec2(0.5 / textureSize.x, 0.0);\n" -// "srcCoordinatesVarying[3] = srcCoordinatesVarying[1] + vec2(0.5 / textureSize.x, 0.0);\n" -// "srcCoordinatesVarying[4] = srcCoordinatesVarying[1] + vec2(1.0 / textureSize.x, 0.0);\n"; - - const char *const vertexShader = + return strdup( "#version 150\n" - "\n" - "in vec2 position;\n" - "in vec2 srcCoordinates;\n" - "in float lateral;\n" - "\n" - "uniform vec2 boundsOrigin;\n" - "uniform vec2 boundsSize;\n" - "\n" - "out float lateralVarying;\n" - "out vec2 shadowMaskCoordinates;\n" - "\n" - "uniform vec2 textureSize;\n" - "\n" - "const float shadowMaskMultiple = 600;\n" - "\n" - "%@\n" - "void main (void)\n" - "{\n" - "lateralVarying = lateral + 1.0707963267949;\n" - "\n" - "shadowMaskCoordinates = position * vec2(shadowMaskMultiple, shadowMaskMultiple * 0.85057471264368);\n" - "\n" - "%@\n" - "\n" + + "in vec2 position;" + "in vec2 srcCoordinates;" + "in float lateral;" + + "uniform vec2 boundsOrigin;" + "uniform vec2 boundsSize;" + + "out float lateralVarying;" + "out vec2 shadowMaskCoordinates;" + + "uniform vec2 textureSize;" + + "const float shadowMaskMultiple = 600;" + + "out vec2 srcCoordinatesVarying;" + + "void main(void)" + "{" + "lateralVarying = lateral + 1.0707963267949;" + + "shadowMaskCoordinates = position * vec2(shadowMaskMultiple, shadowMaskMultiple * 0.85057471264368);" + + "srcCoordinatesVarying = vec2(srcCoordinates.x / textureSize.x, (srcCoordinates.y + 0.5) / textureSize.y);\n" + "vec2 mappedPosition = (position - boundsOrigin) / boundsSize;" - "gl_Position = vec4(mappedPosition.x * 2.0 - 1.0, 1.0 - mappedPosition.y * 2.0, 0.0, 1.0);\n" - "}\n"; - - return nullptr; -// + mappedPosition.x / 131.0 - -// switch(_signalType) -// { -// case CSCathodeRayViewSignalTypeNTSC: return [NSString stringWithFormat:vertexShader, ntscVertexShaderGlobals, ntscVertexShaderBody]; -// case CSCathodeRayViewSignalTypeRGB: return [NSString stringWithFormat:vertexShader, rgbVertexShaderGlobals, rgbVertexShaderBody]; -// } + "gl_Position = vec4(mappedPosition.x * 2.0 - 1.0, 1.0 - mappedPosition.y * 2.0, 0.0, 1.0);" + "}"); } char *CRT::get_fragment_shader() { // assumes y = [0, 1], i and q = [-0.5, 0.5]; therefore i components are multiplied by 1.1914 versus standard matrices, q by 1.0452 - const char *const yiqToRGB = "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 1.1389784, -0.3240608, -1.3176884, 0.6490692, -0.6762444, 1.7799756);"; +// const char *const yiqToRGB = "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 1.1389784, -0.3240608, -1.3176884, 0.6490692, -0.6762444, 1.7799756);"; // assumes y = [0,1], u and v = [-0.5, 0.5]; therefore u components are multiplied by 1.14678899082569, v by 0.8130081300813 - const char *const yuvToRGB = "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 0.0, -0.75213899082569, 2.33040137614679, 0.92669105691057, -0.4720325203252, 0.0);"; +// const char *const yuvToRGB = "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 0.0, -0.75213899082569, 2.33040137614679, 0.92669105691057, -0.4720325203252, 0.0);"; - const char *const fragmentShader = - "#version 150\n" - "\n" - "in float lateralVarying;\n" - "in vec2 shadowMaskCoordinates;\n" - "out vec4 fragColour;\n" - "\n" - "uniform sampler2D texID;\n" - "uniform sampler2D shadowMaskTexID;\n" - "uniform float alpha;\n" - "\n" - "in vec2 srcCoordinatesVarying[4];\n" - "in float phase;\n" - "%@\n" - "%@\n" - "\n" - "void main(void)\n" - "{\n" - "%@\n" - "}\n"; +// const char *const ntscFragmentShaderGlobals = +// "in vec2 srcCoordinatesVarying[4];\n" +// "in float phase;\n" +// "\n" +// "// for conversion from i and q are in the range [-0.5, 0.5] (so i needs to be multiplied by 1.1914 and q by 1.0452)\n" +// "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 1.1389784, -0.3240608, -1.3176884, 0.6490692, -0.6762444, 1.7799756);\n"; - const char *const ntscFragmentShaderGlobals = - "in vec2 srcCoordinatesVarying[4];\n" - "in float phase;\n" - "\n" - "// for conversion from i and q are in the range [-0.5, 0.5] (so i needs to be multiplied by 1.1914 and q by 1.0452)\n" - "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 1.1389784, -0.3240608, -1.3176884, 0.6490692, -0.6762444, 1.7799756);\n"; - - const char *const ntscFragmentShaderBody = - "vec4 angles = vec4(phase) + vec4(-2.35619449019234, -0.78539816339745, 0.78539816339745, 2.35619449019234);\n" - "vec4 samples = vec4(" - " sample(srcCoordinatesVarying[0], angles.x)," - " sample(srcCoordinatesVarying[1], angles.y)," - " sample(srcCoordinatesVarying[2], angles.z)," - " sample(srcCoordinatesVarying[3], angles.w)" - ");\n" - "\n" - "float y = dot(vec4(0.25), samples);\n" - "samples -= vec4(y);\n" - "\n" - "float i = dot(cos(angles), samples);\n" - "float q = dot(sin(angles), samples);\n" - "\n" - "fragColour = 5.0 * texture(shadowMaskTexID, shadowMaskCoordinates) * vec4(yiqToRGB * vec3(y, i, q), 1.0);//sin(lateralVarying));\n"; - -// const char *const rgbFragmentShaderGlobals = -// "in vec2 srcCoordinatesVarying[5];\n"; // texture(shadowMaskTexID, shadowMaskCoordinates) * - -// const char *const rgbFragmentShaderBody = -// "fragColour = sample(srcCoordinatesVarying[2]);"; -// @"fragColour = (sample(srcCoordinatesVarying[0]) * -0.1) + \ -// (sample(srcCoordinatesVarying[1]) * 0.3) + \ -// (sample(srcCoordinatesVarying[2]) * 0.6) + \ -// (sample(srcCoordinatesVarying[3]) * 0.3) + \ -// (sample(srcCoordinatesVarying[4]) * -0.1);"; +// const char *const ntscFragmentShaderBody = +// "vec4 angles = vec4(phase) + vec4(-2.35619449019234, -0.78539816339745, 0.78539816339745, 2.35619449019234);\n" +// "vec4 samples = vec4(" +// " sample(srcCoordinatesVarying[0], angles.x)," +// " sample(srcCoordinatesVarying[1], angles.y)," +// " sample(srcCoordinatesVarying[2], angles.z)," +// " sample(srcCoordinatesVarying[3], angles.w)" +// ");\n" +// "\n" +// "float y = dot(vec4(0.25), samples);\n" +// "samples -= vec4(y);\n" +// "\n" +// "float i = dot(cos(angles), samples);\n" +// "float q = dot(sin(angles), samples);\n" +// "\n" +// "fragColour = 5.0 * texture(shadowMaskTexID, shadowMaskCoordinates) * vec4(yiqToRGB * vec3(y, i, q), 1.0);//sin(lateralVarying));\n"; // dot(vec3(1.0/6.0, 2.0/3.0, 1.0/6.0), vec3(sample(srcCoordinatesVarying[0]), sample(srcCoordinatesVarying[0]), sample(srcCoordinatesVarying[0])));//sin(lateralVarying));\n"; - return nullptr; + return get_compound_shader( + "#version 150\n" -// switch(_signalType) -// { -// case CSCathodeRayViewSignalTypeNTSC: return [NSString stringWithFormat:fragmentShader, ntscFragmentShaderGlobals, ntscFragmentShaderBody]; -// case CSCathodeRayViewSignalTypeRGB: return [NSString stringWithFormat:fragmentShader, rgbFragmentShaderGlobals, rgbFragmentShaderBody]; -// } + "in float lateralVarying;" + "in vec2 shadowMaskCoordinates;" + "out vec4 fragColour;" + + "uniform sampler2D texID;" + "uniform sampler2D shadowMaskTexID;" + "uniform float alpha;" + + "in vec2 srcCoordinatesVarying;" + "in float phase;\n" + "%s\n" + + "void main(void)" + "{" + "fragColour = vec4(rgb_sample(srcCoordinatesVarying).rgb, 1.0);" + "}" + , _rgb_shader); +} + +char *CRT::get_compound_shader(const char *base, const char *insert) +{ + size_t totalLength = strlen(base) + strlen(insert) + 1; + char *text = new char[totalLength]; + snprintf(text, totalLength, base, insert); + return text; +} + +void CRT::prepare_shader() +{ + char *vertex_shader = get_vertex_shader(); + char *fragment_shader = get_fragment_shader(); + + _openGL_state->shaderProgram = glCreateProgram(); + _openGL_state->vertexShader = _openGL_state->compile_shader(vertex_shader, GL_VERTEX_SHADER); + _openGL_state->fragmentShader = _openGL_state->compile_shader(fragment_shader, GL_FRAGMENT_SHADER); + + delete vertex_shader; + delete fragment_shader; + + glAttachShader(_openGL_state->shaderProgram, _openGL_state->vertexShader); + glAttachShader(_openGL_state->shaderProgram, _openGL_state->fragmentShader); + glLinkProgram(_openGL_state->shaderProgram); + + glUseProgram(_openGL_state->shaderProgram); + + _openGL_state->positionAttribute = glGetAttribLocation(_openGL_state->shaderProgram, "position"); + _openGL_state->textureCoordinatesAttribute = glGetAttribLocation(_openGL_state->shaderProgram, "srcCoordinates"); + _openGL_state->lateralAttribute = glGetAttribLocation(_openGL_state->shaderProgram, "lateral"); + _openGL_state->alphaUniform = glGetUniformLocation(_openGL_state->shaderProgram, "alpha"); + _openGL_state->textureSizeUniform = glGetUniformLocation(_openGL_state->shaderProgram, "textureSize"); + _openGL_state->windowSizeUniform = glGetUniformLocation(_openGL_state->shaderProgram, "windowSize"); + _openGL_state->boundsSizeUniform = glGetUniformLocation(_openGL_state->shaderProgram, "boundsSize"); + _openGL_state->boundsOriginUniform = glGetUniformLocation(_openGL_state->shaderProgram, "boundsOrigin"); + + GLint texIDUniform = glGetUniformLocation(_openGL_state->shaderProgram, "texID"); + GLint shadowMaskTexIDUniform = glGetUniformLocation(_openGL_state->shaderProgram, "shadowMaskTexID"); + +// [self pushSizeUniforms]; + + glUniform1i(texIDUniform, 0); + glUniform1i(shadowMaskTexIDUniform, 1); + + glEnableVertexAttribArray((GLuint)_openGL_state->positionAttribute); + glEnableVertexAttribArray((GLuint)_openGL_state->textureCoordinatesAttribute); + glEnableVertexAttribArray((GLuint)_openGL_state->lateralAttribute); + + const GLsizei vertexStride = kCRTSizeOfVertex; + glVertexAttribPointer((GLuint)_openGL_state->positionAttribute, 2, GL_UNSIGNED_SHORT, GL_TRUE, vertexStride, (void *)kCRTVertexOffsetOfPosition); + glVertexAttribPointer((GLuint)_openGL_state->textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfTexCoord); + glVertexAttribPointer((GLuint)_openGL_state->lateralAttribute, 1, GL_UNSIGNED_BYTE, GL_FALSE, vertexStride, (void *)kCRTVertexOffsetOfLateral); }