diff --git a/gamemaker/TheorafileGMS/TheorafileGMS.yyp b/gamemaker/TheorafileGMS/TheorafileGMS.yyp index 1579ae7..1ef60a8 100644 --- a/gamemaker/TheorafileGMS/TheorafileGMS.yyp +++ b/gamemaker/TheorafileGMS/TheorafileGMS.yyp @@ -3,6 +3,7 @@ {"id":{"name":"TheorafileGMS","path":"extensions/TheorafileGMS/TheorafileGMS.yy",},"order":0,}, {"id":{"name":"TheorafileGMS_Scripts","path":"scripts/TheorafileGMS_Scripts/TheorafileGMS_Scripts.yy",},"order":0,}, {"id":{"name":"YUVToRGB","path":"shaders/YUVToRGB/YUVToRGB.yy",},"order":0,}, + {"id":{"name":"Renderer","path":"objects/Renderer/Renderer.yy",},"order":0,}, {"id":{"name":"Room1","path":"rooms/Room1/Room1.yy",},"order":0,}, ], "Options": [ @@ -44,7 +45,9 @@ "TextureGroups": [ {"isScaled":true,"autocrop":true,"border":2,"mipsToGenerate":0,"groupParent":null,"targets":-1,"resourceVersion":"1.3","name":"Default","resourceType":"GMTextureGroup",}, ], - "IncludedFiles": [], + "IncludedFiles": [ + {"CopyToMask":-1,"filePath":"datafiles","resourceVersion":"1.0","name":"celery_man.ogg","resourceType":"GMIncludedFile",}, + ], "MetaData": { "IDEVersion": "2.3.6.595", }, diff --git a/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.dll b/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.dll index 304725a..43179a2 100644 Binary files a/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.dll and b/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.dll differ diff --git a/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.yy b/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.yy index 6f899da..42c7cb1 100644 --- a/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.yy +++ b/gamemaker/TheorafileGMS/extensions/TheorafileGMS/TheorafileGMS.yy @@ -69,6 +69,7 @@ {"name":"TheorafileGMS_EndOfStream","path":"extensions/TheorafileGMS/TheorafileGMS.yy",}, {"name":"TheorafileGMS_ReadVideo","path":"extensions/TheorafileGMS/TheorafileGMS.yy",}, ],"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMExtensionFile",}, + {"filename":"libtheorafile.dll","origname":"","init":"","final":"","kind":1,"uncompress":false,"functions":[],"constants":[],"ProxyFiles":[],"copyToTargets":-1,"order":[],"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMExtensionFile",}, ], "classname": "", "tvosclassname": null, @@ -89,7 +90,7 @@ "androidactivityinject": "", "gradleinject": "", "androidcodeinjection": "", - "hasConvertedCodeInjection": false, + "hasConvertedCodeInjection": true, "ioscodeinjection": "", "tvoscodeinjection": "", "iosSystemFrameworkEntries": [], diff --git a/gamemaker/TheorafileGMS/extensions/TheorafileGMS/libtheorafile.dll b/gamemaker/TheorafileGMS/extensions/TheorafileGMS/libtheorafile.dll new file mode 100644 index 0000000..016b8a8 Binary files /dev/null and b/gamemaker/TheorafileGMS/extensions/TheorafileGMS/libtheorafile.dll differ diff --git a/gamemaker/TheorafileGMS/objects/Renderer/CleanUp_0.gml b/gamemaker/TheorafileGMS/objects/Renderer/CleanUp_0.gml new file mode 100644 index 0000000..ce920f6 --- /dev/null +++ b/gamemaker/TheorafileGMS/objects/Renderer/CleanUp_0.gml @@ -0,0 +1 @@ +Theorafile_Close(video); \ No newline at end of file diff --git a/gamemaker/TheorafileGMS/objects/Renderer/Create_0.gml b/gamemaker/TheorafileGMS/objects/Renderer/Create_0.gml new file mode 100644 index 0000000..3fb44aa --- /dev/null +++ b/gamemaker/TheorafileGMS/objects/Renderer/Create_0.gml @@ -0,0 +1,3 @@ +video = Theorafile_Open("celery_man.ogg"); + +Theorafile_Play(video); diff --git a/gamemaker/TheorafileGMS/objects/Renderer/Draw_0.gml b/gamemaker/TheorafileGMS/objects/Renderer/Draw_0.gml new file mode 100644 index 0000000..1487f70 --- /dev/null +++ b/gamemaker/TheorafileGMS/objects/Renderer/Draw_0.gml @@ -0,0 +1,3 @@ +Theorafile_UpdateSurface(video); + +draw_surface_stretched(video.videoSurface, 0, 0, surface_get_width(application_surface), surface_get_height(application_surface)); \ No newline at end of file diff --git a/gamemaker/TheorafileGMS/objects/Renderer/Renderer.yy b/gamemaker/TheorafileGMS/objects/Renderer/Renderer.yy new file mode 100644 index 0000000..af36d4d --- /dev/null +++ b/gamemaker/TheorafileGMS/objects/Renderer/Renderer.yy @@ -0,0 +1,35 @@ +{ + "spriteId": null, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 1, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":8,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":12,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "Objects", + "path": "folders/Objects.yy", + }, + "resourceVersion": "1.0", + "name": "Renderer", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/gamemaker/TheorafileGMS/options/windows/options_windows.yy b/gamemaker/TheorafileGMS/options/windows/options_windows.yy index 44cc31c..c3699e9 100644 --- a/gamemaker/TheorafileGMS/options/windows/options_windows.yy +++ b/gamemaker/TheorafileGMS/options/windows/options_windows.yy @@ -28,7 +28,7 @@ "option_windows_enable_steam": false, "option_windows_disable_sandbox": false, "option_windows_steam_use_alternative_launcher": false, - "option_windows_use_x64": false, + "option_windows_use_x64": true, "resourceVersion": "1.1", "name": "Windows", "tags": [], diff --git a/gamemaker/TheorafileGMS/rooms/Room1/Room1.yy b/gamemaker/TheorafileGMS/rooms/Room1/Room1.yy index f69dcfa..9f8825d 100644 --- a/gamemaker/TheorafileGMS/rooms/Room1/Room1.yy +++ b/gamemaker/TheorafileGMS/rooms/Room1/Room1.yy @@ -13,19 +13,23 @@ {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, ], "layers": [ - {"instances":[],"visible":true,"depth":0,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Instances","tags":[],"resourceType":"GMRInstanceLayer",}, + {"instances":[ + {"properties":[],"isDnd":false,"objectId":{"name":"Renderer","path":"objects/Renderer/Renderer.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":0.0,"y":0.0,"resourceVersion":"1.0","name":"inst_4739AA0A","tags":[],"resourceType":"GMRInstance",}, + ],"visible":true,"depth":0,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Instances","tags":[],"resourceType":"GMRInstanceLayer",}, {"spriteId":null,"colour":4278190080,"x":0,"y":0,"htiled":false,"vtiled":false,"hspeed":0.0,"vspeed":0.0,"stretch":false,"animationFPS":15.0,"animationSpeedType":0,"userdefinedAnimFPS":false,"visible":true,"depth":100,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Background","tags":[],"resourceType":"GMRBackgroundLayer",}, ], "inheritLayers": false, "creationCodeFile": "", "inheritCode": false, - "instanceCreationOrder": [], + "instanceCreationOrder": [ + {"name":"inst_4739AA0A","path":"rooms/Room1/Room1.yy",}, + ], "inheritCreationOrder": false, "sequenceId": null, "roomSettings": { "inheritRoomSettings": false, - "Width": 1366, - "Height": 768, + "Width": 960, + "Height": 540, "persistent": false, }, "viewSettings": { diff --git a/gamemaker/TheorafileGMS/scripts/TheorafileGMS_Scripts/TheorafileGMS_Scripts.gml b/gamemaker/TheorafileGMS/scripts/TheorafileGMS_Scripts/TheorafileGMS_Scripts.gml index 2977657..247dd36 100644 --- a/gamemaker/TheorafileGMS/scripts/TheorafileGMS_Scripts/TheorafileGMS_Scripts.gml +++ b/gamemaker/TheorafileGMS/scripts/TheorafileGMS_Scripts/TheorafileGMS_Scripts.gml @@ -1,34 +1,161 @@ +enum Theorafile_VideoState +{ + Stopped, + Playing, + Paused +} + function Theorafile_Open(filename) { - var address = TheorafileGMS_Open(filename); - if (address == 0) - { - show_debug_message("Could not open theora video at filename: " + filename); - return; - } + var _handle = ptr(TheorafileGMS_Open(filename)); + show_debug_message("handle: " + string(_handle)); - var _yWidth = TheorafileGMS_Width(filename); - var _yHeight = TheorafileGMS_Height(filename); - var _frames_per_second = TheorafileGMS_FPS(filename); - var _uvWidth = TheorafileGMS_UVWidth(filename); - var _uvHeight = TheorafileGMS_UVHeight(filename); + 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: ptr(address), + handle: _handle, + bufferSize: _bufferSize, + yuvBuffer: buffer_create(_bufferSize, buffer_fixed, 4), yWidth: _yWidth, yHeight: _yHeight, uvWidth: _uvWidth, - uvHeight: _uvHeight + 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(pointer) +function Theorafile_Close(video) { - TheorafileGMS_Close(pointer) + buffer_delete(video.yuvBuffer); + vertex_format_delete(video.triangle_buffer_format); + vertex_delete_buffer(video.triangle_buffer); + TheorafileGMS_Close(video.handle); } -function Theorafile_Play(pointer) +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; + } + } + } } diff --git a/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.fsh b/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.fsh index 68412ff..8fa31f9 100644 --- a/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.fsh +++ b/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.fsh @@ -22,8 +22,8 @@ void main() vec4 color; color.x = dot(yuv, Rcoeff); - color.y = dot(yuv, GCoeff); - color.z = dot(yuv, BCoeff); + color.y = dot(yuv, Gcoeff); + color.z = dot(yuv, Bcoeff); color.w = 1.0; gl_FragColor = color; diff --git a/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.vsh b/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.vsh index 033b69e..26dd4c6 100644 --- a/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.vsh +++ b/gamemaker/TheorafileGMS/shaders/YUVToRGB/YUVToRGB.vsh @@ -1,4 +1,4 @@ -attribute vec3 in_Position; // (x,y,z) +attribute vec2 in_Position; // (x,y,z) attribute vec2 in_TextureCoord; // (u,v) varying vec2 v_vTexcoord; @@ -6,5 +6,5 @@ varying vec2 v_vTexcoord; void main() { v_vTexcoord = in_TextureCoord; - gl_Position = vec4(in_Position, 1.0); + gl_Position = vec4(in_Position, 0.0, 1.0); } diff --git a/src/TheorafileGMS.c b/src/TheorafileGMS.c index 583e2a0..0d5c339 100644 --- a/src/TheorafileGMS.c +++ b/src/TheorafileGMS.c @@ -59,7 +59,10 @@ char* TheorafileGMS_Open(char* filename) return NULL; } - return (char*)file; + static char retaddr[64]; + SDL_memset(retaddr, 0, sizeof(retaddr)); + SDL_snprintf(retaddr, sizeof(retaddr) - 1, "%p%p", (void*)((uintptr_t)file >> 32), file); /* cursed hack for exporting 64-bit pointer */ + return retaddr; } void TheorafileGMS_Close(char* filePointer) @@ -231,7 +234,6 @@ double TheorafileGMS_ReadVideo(char* filePointer, char* buffer, double numFrames /* Game Maker doesnt have R8 textures so we have to do this padding bullshit */ char* yuvBuffer = SDL_malloc(requiredBufferSize * 4); - SDL_memset(yuvBuffer, 0, requiredBufferSize * 4); int updated = tf_readvideo(file, yuvBuffer, (int)numFrames); diff --git a/visualc/TheorafileGMS.vcxproj b/visualc/TheorafileGMS.vcxproj index a344b40..adbf1f5 100644 --- a/visualc/TheorafileGMS.vcxproj +++ b/visualc/TheorafileGMS.vcxproj @@ -72,7 +72,7 @@ DebugFull NotSet - SetupAPI.lib;Version.lib;Winmm.lib;Imm32.lib;libucrt.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + libucrt.lib;SetupAPI.lib;Version.lib;Winmm.lib;Imm32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) false @@ -85,6 +85,7 @@ false true MultiThreaded + ../lib/SDL/include;../lib/Theorafile;../lib/Theorafile/lib;$(OutDir) true