1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-27 18:55:48 +00:00

Started making the format of data included in a CRTFrame less a matter of variously hard-coded magic constants. Which will allow me to separate the idea of an internal lateral position from the direct texture coordinate, avoiding precision sampling errors at the top and bottom.

This commit is contained in:
Thomas Harte 2015-08-02 14:25:21 -04:00
parent be421587ad
commit 3ab6585789
3 changed files with 46 additions and 24 deletions

View File

@ -11,6 +11,7 @@
#import <OpenGL/gl3.h>
#import <OpenGL/gl3ext.h>
@implementation CSCathodeRayView {
CVDisplayLinkRef displayLink;
@ -19,6 +20,7 @@
GLuint _arrayBuffer, _vertexArray;
GLint _positionAttribute;
GLint _textureCoordinatesAttribute;
GLint _lateralAttribute;
GLuint _textureName;
CRTSize _textureSize;
@ -128,7 +130,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
if(crtFrame)
{
[self.openGLContext makeCurrentContext];
glBufferData(GL_ARRAY_BUFFER, _crtFrame->number_of_runs * sizeof(GLushort) * 24, _crtFrame->runs, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, _crtFrame->number_of_runs * sizeof(GLushort) * kCRTSizeOfVertex * 6, _crtFrame->runs, GL_DYNAMIC_DRAW);
glBindTexture(GL_TEXTURE_2D, _textureName);
@ -156,10 +158,12 @@ const char *vertexShader =
"in vec2 srcCoordinates;\n"
"\n"
"out vec2 srcCoordinatesVarying;\n"
"out float offsetVarying;\n"
"\n"
"void main (void)\n"
"{\n"
"srcCoordinatesVarying = vec2(srcCoordinates.x / 512.0, srcCoordinates.y / 512.0);\n"
"offsetVarying = mod(srcCoordinatesVarying.y * 512, 1.0) * 2.09435310266667 + 0.52359877566668;"
"gl_Position = vec4(position.x * 2.0 - 1.0, 1.0 - position.y * 2.0 + position.x / 131.0, 0.0, 1.0);\n"
"}\n";
@ -168,12 +172,13 @@ const char *fragmentShader =
"#version 150\n"
"\n"
"in vec2 srcCoordinatesVarying;\n"
"in float offsetVarying;"
"out vec4 fragColour;\n"
"uniform sampler2D texID;\n"
"\n"
"void main(void)\n"
"{\n"
"fragColour = texture(texID, srcCoordinatesVarying) * vec4(1.0, 1.0, 1.0, sin(mod(srcCoordinatesVarying.y * 512, 1.0) * 2.09435310266667 + 0.52359877566668));\n" // vec4(1.0, 1.0, 1.0, 0.5)
"fragColour = texture(texID, srcCoordinatesVarying) * vec4(1.0, 1.0, 1.0, sin(offsetVarying));\n" // vec4(1.0, 1.0, 1.0, 0.5)
"}\n";
#if defined(DEBUG)
@ -226,12 +231,16 @@ const char *fragmentShader =
_positionAttribute = glGetAttribLocation(_shaderProgram, "position");
_textureCoordinatesAttribute = glGetAttribLocation(_shaderProgram, "srcCoordinates");
_lateralAttribute = glGetAttribLocation(_shaderProgram, "lateral");
glEnableVertexAttribArray(_positionAttribute);
glEnableVertexAttribArray(_textureCoordinatesAttribute);
glEnableVertexAttribArray(_lateralAttribute);
glVertexAttribPointer(_positionAttribute, 2, GL_UNSIGNED_SHORT, GL_TRUE, 4 * sizeof(GLushort), (void *)0);
glVertexAttribPointer(_textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, 4 * sizeof(GLushort), (void *)(2 * sizeof(GLushort)));
const GLsizei vertexStride = kCRTSizeOfVertex * sizeof(GLushort);
glVertexAttribPointer(_positionAttribute, 2, GL_UNSIGNED_SHORT, GL_TRUE, vertexStride, (void *)(kCRTVertexOffsetOfPosition * sizeof(GLushort)));
glVertexAttribPointer(_textureCoordinatesAttribute, 2, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)(kCRTVertexOffsetOfTexCoord * sizeof(GLushort)));
glVertexAttribPointer(_lateralAttribute, 1, GL_UNSIGNED_SHORT, GL_FALSE, vertexStride, (void *)(kCRTVertexOffsetOfLateral * sizeof(GLushort)));
glGenTextures(1, &_textureName);
glBindTexture(GL_TEXTURE_2D, _textureName);

View File

@ -20,8 +20,8 @@ static const uint32_t kCRTFixedPointOffset = 0x08000000;
void CRT::set_new_timing(int cycles_per_line, int height_of_display)
{
const int syncCapacityLineChargeThreshold = 3;
const int millisecondsHorizontalRetraceTime = 7; // source: Dictionary of Video and Television Technology, p. 234
const int syncCapacityLineChargeThreshold = 4;
const int millisecondsHorizontalRetraceTime = 10; // source: Dictionary of Video and Television Technology, p. 234
const int scanlinesVerticalRetraceTime = 7; // source: ibid
_time_multiplier = (1000 + cycles_per_line - 1) / cycles_per_line;
@ -207,17 +207,23 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
// uint32_t *width = _widths[lengthMask];
uint32_t *width = _widths[0];
#define position_x(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 0]
#define position_y(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfPosition + 1]
#define tex_x(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTexCoord + 0]
#define tex_y(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfTexCoord + 1]
#define lateral(v) next_run[kCRTSizeOfVertex*v + kCRTVertexOffsetOfLateral]
if(next_run)
{
// set the type, initial raster position and type of this run
next_run[0] = next_run[20] = (kCRTFixedPointOffset + _rasterPosition.x + width[0]) >> 16;
next_run[1] = next_run[21] = (kCRTFixedPointOffset + _rasterPosition.y + width[1]) >> 16;
next_run[4] = (kCRTFixedPointOffset + _rasterPosition.x - width[0]) >> 16;
next_run[5] = (kCRTFixedPointOffset + _rasterPosition.y - width[1]) >> 16;
position_x(0) = position_x(4) = (kCRTFixedPointOffset + _rasterPosition.x + width[0]) >> 16;
position_y(0) = position_y(4) = (kCRTFixedPointOffset + _rasterPosition.y + width[1]) >> 16;
position_x(1) = (kCRTFixedPointOffset + _rasterPosition.x - width[0]) >> 16;
position_y(1) = (kCRTFixedPointOffset + _rasterPosition.y - width[1]) >> 16;
next_run[2] = next_run[6] = next_run[22] = tex_x;
next_run[3] = next_run[23] = tex_y;
next_run[7] = tex_y + 1;
tex_x(0) = tex_x(1) = tex_x(4) = tex_x;
tex_y(0) = tex_y(4) = tex_y;
tex_y(1) = tex_y + 1;
}
// advance the raster position as dictated by current sync status
@ -234,19 +240,18 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool
if(next_run)
{
// store the final raster position
next_run[8] = next_run[12] = (kCRTFixedPointOffset + _rasterPosition.x - width[0]) >> 16;
next_run[9] = next_run[13] = (kCRTFixedPointOffset + _rasterPosition.y - width[1]) >> 16;
next_run[16] = (kCRTFixedPointOffset + _rasterPosition.x + width[0]) >> 16;
next_run[17] = (kCRTFixedPointOffset + _rasterPosition.y + width[1]) >> 16;
position_x(2) = position_x(3) = (kCRTFixedPointOffset + _rasterPosition.x - width[0]) >> 16;
position_y(2) = position_y(3) = (kCRTFixedPointOffset + _rasterPosition.y - width[1]) >> 16;
position_x(5) = (kCRTFixedPointOffset + _rasterPosition.x + width[0]) >> 16;
position_y(5) = (kCRTFixedPointOffset + _rasterPosition.y + width[1]) >> 16;
// if this is a data run then advance the buffer pointer
if(type == Type::Data) tex_x += next_run_length / _time_multiplier;
// if this is a data or level run then store the end point
next_run[10] = next_run[14] = next_run[18] = tex_x;
next_run[11] = next_run[15] = tex_y + 1;
next_run[19] = tex_y;
tex_x(2) = tex_x(3) = tex_x(5) = tex_x;
tex_y(2) = tex_y(3) = tex_y+1;
tex_y(5) = tex_y;
}
// decrement the number of cycles left to run for and increment the
@ -419,13 +424,16 @@ void CRTFrameBuilder::complete()
uint16_t *CRTFrameBuilder::get_next_run()
{
const size_t vertices_per_run = 6;
const size_t size_of_run = kCRTSizeOfVertex * vertices_per_run;
// get a run from the allocated list, allocating more if we're about to overrun
if(frame.number_of_runs * 24 >= _all_runs.size())
if(frame.number_of_runs * size_of_run >= _all_runs.size())
{
_all_runs.resize(_all_runs.size() + 2400);
_all_runs.resize(_all_runs.size() + size_of_run * 200);
}
uint16_t *next_run = &_all_runs[frame.number_of_runs * 24];
uint16_t *next_run = &_all_runs[frame.number_of_runs * size_of_run];
frame.number_of_runs++;
return next_run;

View File

@ -36,4 +36,9 @@ typedef struct {
}
#endif
static const int kCRTSizeOfVertex = 5;
static const int kCRTVertexOffsetOfPosition = 0;
static const int kCRTVertexOffsetOfTexCoord = 2;
static const int kCRTVertexOffsetOfLateral = 4;
#endif /* CRTFrame_h */