mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
358
Code/BinkMovie/BINKMovie.cpp
Normal file
358
Code/BinkMovie/BINKMovie.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
** 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user