enum Theorafile_VideoState { Stopped, Playing, Paused } function Theorafile_Open(filename) { var _handle = ptr(TheorafileGMS_Open(filename)); show_debug_message("handle: " + string(_handle)); var _yWidth = TheorafileGMS_Width(_handle); var _yHeight = TheorafileGMS_Height(_handle); var _frames_per_second = TheorafileGMS_FPS(_handle); var _uvWidth = TheorafileGMS_UVWidth(_handle); var _uvHeight = TheorafileGMS_UVHeight(_handle); var _bufferSize = TheorafileGMS_RequiredBufferSizeInBytes(_handle); vertex_format_begin(); vertex_format_add_position(); vertex_format_add_texcoord(); var _vformat = vertex_format_end(); var _vbuff = vertex_create_buffer(); vertex_begin(_vbuff, _vformat); vertex_position(_vbuff, -1, 1); vertex_texcoord(_vbuff, 0, 0); vertex_position(_vbuff, 3, 1); vertex_texcoord(_vbuff, 2, 0); vertex_position(_vbuff, -1, -3); vertex_texcoord(_vbuff, 0, 2); vertex_end(_vbuff); return { handle: _handle, bufferSize: _bufferSize, yuvBuffer: buffer_create(_bufferSize, buffer_fixed, 4), yWidth: _yWidth, yHeight: _yHeight, uvWidth: _uvWidth, uvHeight: _uvHeight, framesPerSecond: _frames_per_second, ySurface: surface_create(_yWidth, _yHeight), uSurface: surface_create(_uvWidth, _uvHeight), vSurface: surface_create(_uvWidth, _uvHeight), videoSurface: surface_create(_yWidth, _yHeight), elapsed_time: 0, currentFrame: 0, state: Theorafile_VideoState.Stopped, looped: false, triangle_buffer: _vbuff, triangle_buffer_format: _vformat }; } function Theorafile_Close(video) { buffer_delete(video.yuvBuffer); vertex_format_delete(video.triangle_buffer_format); vertex_delete_buffer(video.triangle_buffer); TheorafileGMS_Close(video.handle); } function Theorafile_Play(video) { if (video.state == Theorafile_VideoState.Stopped) { if (video.handle != 0 && TheorafileGMS_HasVideo(video.handle) == 1) { video.elapsed_time = 0; video.state = Theorafile_VideoState.Playing; TheorafileGMS_ReadVideo(video.handle, buffer_get_address(video.yuvBuffer), 1); } } } function Theorafile_UpdateTextures(video) { if (!surface_exists(video.ySurface)) { video.ySurface = surface_create(video.yWidth, video.yHeight); } if (!surface_exists(video.uSurface)) { video.uSurface = surface_create(video.uvWidth, video.uvHeight); } if (!surface_exists(video.vSurface)) { video.vSurface = surface_create(video.uvWidth, video.uvHeight); } var _y_data_length = (video.yWidth * video.yHeight * 4); var _uv_data_length = (video.uvWidth * video.uvHeight * 4); buffer_set_surface(video.yuvBuffer, video.ySurface, 0); buffer_set_surface(video.yuvBuffer, video.uSurface, _y_data_length); buffer_set_surface(video.yuvBuffer, video.vSurface, _y_data_length + _uv_data_length); } function Theorafile_UpdateSurface(video) { if (video.state == Theorafile_VideoState.Playing) { video.elapsed_time += 1 / room_speed; var _current_frame = video.elapsed_time * video.framesPerSecond; if (floor(_current_frame) > video.currentFrame) { if TheorafileGMS_ReadVideo(video.handle, buffer_get_address(video.yuvBuffer), 1) == 1 { Theorafile_UpdateTextures(video); if !surface_exists(video.videoSurface) { video.videoSurface = surface_create(video.yWidth, video.yHeight); } surface_set_target(video.videoSurface); shader_set(YUVToRGB); ySampler = shader_get_sampler_index(YUVToRGB, "y_tex"); uSampler = shader_get_sampler_index(YUVToRGB, "u_tex"); vSampler = shader_get_sampler_index(YUVToRGB, "v_tex"); texture_set_stage(ySampler, surface_get_texture(video.ySurface)); texture_set_stage(uSampler, surface_get_texture(video.uSurface)); texture_set_stage(vSampler, surface_get_texture(video.vSurface)); vertex_submit(video.triangle_buffer, pr_trianglelist, -1); shader_reset(); surface_reset_target(); } video.currentFrame = floor(_current_frame); } var _ended = TheorafileGMS_EndOfStream(video.handle); if (_ended) { video.elapsed_time = 0; video.most_recent_time = 0; TheorafileGMS_Reset(video.handle); if (video.looped) { video.most_recent_time = get_timer(); } else { video.state = Theorafile_VideoState.Stopped; } } } }