| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "binkmovie.h"
- #include "dx8wrapper.h"
- #include "formconv.h"
- #include "render2d.h"
- #include "Bink.h"
- #include "rect.h"
- #include "subtitlemanager.h"
- #include "dx8caps.h"
- class BINKMovieClass
- {
- private:
- StringClass Filename;
- HBINK Bink;
- bool FrameChanged;
- unsigned TextureCount;
- unsigned long TicksPerFrame;
- struct TextureInfoStruct {
- TextureClass* Texture;
- int TextureWidth;
- int TextureHeight;
- int TextureLocX;
- int TextureLocY;
- RectClass UV;
- RectClass Rect;
- };
- TextureInfoStruct* TextureInfos;
- unsigned char* TempBuffer;
- Render2DClass Renderer;
- SubTitleManagerClass* SubTitleManager;
- public:
- BINKMovieClass(const char* filename,const char* subtitlename,FontCharsClass* font);
- ~BINKMovieClass();
- void Update();
- void Render();
- bool Is_Complete();
- };
- static BINKMovieClass* CurrentMovie;
- void BINKMovie::Play(const char* filename,const char* subtitlename, FontCharsClass* font)
- {
- if (CurrentMovie) {
- delete CurrentMovie;
- CurrentMovie = NULL;
- }
- CurrentMovie = new BINKMovieClass(filename,subtitlename,font);
- }
- void BINKMovie::Stop()
- {
- if (CurrentMovie) {
- delete CurrentMovie;
- CurrentMovie = NULL;
- }
- }
- void BINKMovie::Update()
- {
- if (CurrentMovie) {
- CurrentMovie->Update();
- }
- }
- void BINKMovie::Render()
- {
- if (CurrentMovie) {
- CurrentMovie->Render();
- }
- }
- void BINKMovie::Init()
- {
- BinkSoundUseDirectSound(0);
- }
- void BINKMovie::Shutdown()
- {
- Stop();
- }
- bool BINKMovie::Is_Complete()
- {
- if (CurrentMovie) {
- return CurrentMovie->Is_Complete();
- }
- return true;
- }
- // ----------------------------------------------------------------------------
- BINKMovieClass::BINKMovieClass(const char* filename, const char* subtitlename, FontCharsClass* font)
- :
- Filename(filename),
- Bink(0),
- FrameChanged(true),
- TicksPerFrame(0),
- SubTitleManager(NULL)
- {
- Bink = BinkOpen(Filename, 0);
- if (Bink == NULL) {
- return;
- }
- TempBuffer = new unsigned char[Bink->Width * Bink->Height*2];
- const D3DCAPS8& dx8caps = DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps();
- unsigned poweroftwowidth = 1;
- while (poweroftwowidth < Bink->Width) {
- poweroftwowidth <<= 1;
- }
- unsigned poweroftwoheight = 1;
-
- while (poweroftwoheight < Bink->Height) {
- poweroftwoheight <<= 1;
- }
- if (poweroftwowidth > dx8caps.MaxTextureWidth) {
- poweroftwowidth = dx8caps.MaxTextureWidth;
- }
-
- if (poweroftwoheight > dx8caps.MaxTextureHeight) {
- poweroftwoheight = dx8caps.MaxTextureHeight;
- }
- TextureCount = 0;
- unsigned max_width = poweroftwowidth;
- unsigned max_height = poweroftwoheight;
- unsigned x, y;
- for (y = 0; y < Bink->Height; y += max_height-2) { // Two pixels are lost due to duplicated edges to prevent bilinear artifacts
- for (x = 0; x < Bink->Width; x += max_width-2) {
- ++TextureCount;
- }
- }
- TextureInfos = new TextureInfoStruct[TextureCount];
- unsigned cnt = 0;
-
- for (y = 0; y < Bink->Height; y += max_height-1) {
- for (x = 0; x < Bink->Width; x += max_width-1) {
- TextureInfos[cnt].Texture = new TextureClass(
- max_width, max_height, D3DFormat_To_WW3DFormat(D3DFMT_R5G6B5),
- TextureClass::MIP_LEVELS_1, TextureClass::POOL_MANAGED, false);
- TextureInfos[cnt].TextureLocX = x;
- TextureInfos[cnt].TextureLocY = y;
- TextureInfos[cnt].TextureWidth = max_width;
- TextureInfos[cnt].UV.Right = float(max_width) / float(max_width);
- if ((TextureInfos[cnt].TextureWidth + x) > Bink->Width) {
- TextureInfos[cnt].TextureWidth = Bink->Width - x;
- TextureInfos[cnt].UV.Right = float(TextureInfos[cnt].TextureWidth - 1) / float(max_width);
- }
- TextureInfos[cnt].TextureHeight = max_height;
- TextureInfos[cnt].UV.Bottom = float(max_height) / float(max_height);
- if ((TextureInfos[cnt].TextureHeight + y) > Bink->Height) {
- TextureInfos[cnt].TextureHeight = Bink->Height - y;
- TextureInfos[cnt].UV.Bottom = float(TextureInfos[cnt].TextureHeight + 1) / float(max_height);
- }
- TextureInfos[cnt].UV.Left = 1.0f / float(max_width);
- TextureInfos[cnt].UV.Top = 1.0f / float(max_height);
- TextureInfos[cnt].Rect.Left = float(TextureInfos[cnt].TextureLocX) / float(Bink->Width);
- TextureInfos[cnt].Rect.Top = float(TextureInfos[cnt].TextureLocY) / float(Bink->Height);
- TextureInfos[cnt].Rect.Right = float(TextureInfos[cnt].TextureLocX + TextureInfos[cnt].TextureWidth) / float(Bink->Width);
- TextureInfos[cnt].Rect.Bottom = float(TextureInfos[cnt].TextureLocY + TextureInfos[cnt].TextureHeight) / float(Bink->Height);
- ++cnt;
- }
- }
- Renderer.Reset();
- // Calculate the time per frame of video
- unsigned int rate = (Bink->FrameRate / Bink->FrameRateDiv);
- TicksPerFrame = (60 / rate);
- if (subtitlename && font) {
- SubTitleManager = SubTitleManagerClass::Create(filename, subtitlename, font);
- }
- }
- BINKMovieClass::~BINKMovieClass()
- {
- if (Bink == NULL) {
- return;
- }
- if (Bink) {
- BinkClose(Bink);
- }
- delete[] TempBuffer;
- if (TextureInfos) {
- for (unsigned t = 0; t < TextureCount; ++t) {
- REF_PTR_RELEASE(TextureInfos[t].Texture);
- }
- delete[] TextureInfos;
- }
- if (SubTitleManager) {
- delete SubTitleManager;
- }
- }
- void BINKMovieClass::Update()
- {
- if (!Bink) {
- return;
- }
- FrameChanged |= !BinkWait(Bink);
- }
- static unsigned char* Get_Tex_Address(unsigned char* buffer, int x, int y, int w, int h)
- {
- if (x < 0) {
- x = 0;
- } else if (x >= w) {
- x = w - 1;
- }
- if (y < 0) {
- y = 0;
- } else if (y >= h) {
- y = h - 1;
- }
- return buffer + x * 2 + y * 2 * w;
- }
- void BINKMovieClass::Render()
- {
- if (!Bink) {
- return;
- }
- // decompress a frame
- if (FrameChanged) {
- BinkDoFrame(Bink);
- FrameChanged = false;
- BinkCopyToBuffer(Bink, TempBuffer, Bink->Width * 2, Bink->Height, 0, 0, BINKSURFACE565|BINKCOPYNOSCALING);
- for (unsigned t = 0; t < TextureCount; ++t) {
- IDirect3DTexture8* d3d_texture = TextureInfos[t].Texture->Peek_DX8_Texture();
- if (d3d_texture) {
- unsigned char* cur_tex_ptr = Get_Tex_Address(TempBuffer, TextureInfos[t].TextureLocX,
- TextureInfos[t].TextureLocY, Bink->Width, Bink->Height);
- unsigned w = TextureInfos[t].TextureWidth;
- unsigned h = TextureInfos[t].TextureHeight;
- if (w > Bink->Width-TextureInfos[t].TextureLocX) {
- w = Bink->Width-TextureInfos[t].TextureLocX;
- }
- if (h > Bink->Height-TextureInfos[t].TextureLocY) {
- h = Bink->Height-TextureInfos[t].TextureLocY;
- }
- D3DSURFACE_DESC d3d_surf_desc;
- D3DLOCKED_RECT locked_rect;
- DX8_ErrorCode(d3d_texture->GetLevelDesc(0, &d3d_surf_desc));
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = w;
- rect.bottom = h;
- DX8_ErrorCode(d3d_texture->LockRect(0,&locked_rect,&rect,0));
- for (unsigned y = 0; y < h; ++y) {
- unsigned char* dest = (unsigned char*)locked_rect.pBits + y * locked_rect.Pitch;
- memcpy(dest, cur_tex_ptr, w * 2);
- cur_tex_ptr += Bink->Width * 2;
- }
- DX8_ErrorCode(d3d_texture->UnlockRect(0));
- }
- }
- if (Bink->FrameNum < Bink->Frames) // goto the next if not on the last
- BinkNextFrame(Bink);
- }
- for (unsigned t = 0; t < TextureCount; ++t) {
- Renderer.Reset();
- Renderer.Set_Texture(TextureInfos[t].Texture);
- Renderer.Set_Coordinate_Range(RectClass(0.0f, 0.0f, 1.0f, 1.0f));//Bink->Width,Bink->Height));
- RectClass rect(TextureInfos[t].TextureLocX, TextureInfos[t].TextureLocY, TextureInfos[t].TextureWidth, TextureInfos[t].TextureHeight);
- Renderer.Add_Quad(TextureInfos[t].Rect, TextureInfos[t].UV, 0xffffffff);
- Renderer.Render();
- }
- if (SubTitleManager) {
- unsigned long movieTime = (Bink->FrameNum * TicksPerFrame);
- SubTitleManager->Process(movieTime);
- SubTitleManager->Render();
- }
- }
- bool BINKMovieClass::Is_Complete()
- {
- if (!Bink) return true;
- return (Bink->FrameNum>=Bink->Frames);
- }
|