/* ** 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 . */ // FramGrab.cpp: implementation of the FrameGrabClass class. // ////////////////////////////////////////////////////////////////////// #include "framgrab.h" #include #include //#include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// FrameGrabClass::FrameGrabClass(const char *filename, MODE mode, int width, int height, int bitcount, float framerate) { HRESULT hr; Mode = mode; Filename = filename; FrameRate = framerate; Counter = 0; Stream = 0; AVIFile = 0; if(Mode != AVI) return; AVIFileInit(); // opens AVIFile library // find the first free file with this prefix int counter = 0; int result; char file[256]; do { sprintf(file, "%s%d.AVI", filename, counter++); result = _access(file, 0); } while(result != -1); // Create new AVI file using AVIFileOpen. hr = AVIFileOpen(&AVIFile, file, OF_WRITE | OF_CREATE, NULL); if (hr != 0) { char buf[256]; sprintf(buf, "Unable to open %s\n", Filename); OutputDebugString(buf); CleanupAVI(); return; } // Create a stream using AVIFileCreateStream. AVIStreamInfo.fccType = streamtypeVIDEO; AVIStreamInfo.fccHandler = mmioFOURCC('M','S','V','C'); AVIStreamInfo.dwFlags = 0; AVIStreamInfo.dwCaps = 0; AVIStreamInfo.wPriority = 0; AVIStreamInfo.wLanguage = 0; AVIStreamInfo.dwScale = 1; AVIStreamInfo.dwRate = (int)FrameRate; AVIStreamInfo.dwStart = 0; AVIStreamInfo.dwLength = 0; AVIStreamInfo.dwInitialFrames = 0; AVIStreamInfo.dwSuggestedBufferSize = 0; AVIStreamInfo.dwQuality = 0; AVIStreamInfo.dwSampleSize = 0; SetRect(&AVIStreamInfo.rcFrame, 0, 0, width, height); AVIStreamInfo.dwEditCount = 0; AVIStreamInfo.dwFormatChangeCount = 0; sprintf(AVIStreamInfo.szName,"G"); hr = AVIFileCreateStream(AVIFile, &Stream, &AVIStreamInfo); if (hr != 0) { CleanupAVI(); return; } // Set format of new stream BitmapInfoHeader.biWidth = width; BitmapInfoHeader.biHeight = height; BitmapInfoHeader.biBitCount = (unsigned short)bitcount; BitmapInfoHeader.biSizeImage = ((((UINT)BitmapInfoHeader.biBitCount * BitmapInfoHeader.biWidth + 31) & ~31) / 8) * BitmapInfoHeader.biHeight; BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // size of structure BitmapInfoHeader.biPlanes = 1; // must be set to 1 BitmapInfoHeader.biCompression = BI_RGB; // uncompressed BitmapInfoHeader.biXPelsPerMeter = 1; // not used BitmapInfoHeader.biYPelsPerMeter = 1; // not used BitmapInfoHeader.biClrUsed = 0; // all colors are used BitmapInfoHeader.biClrImportant = 0; // all colors are important hr = AVIStreamSetFormat(Stream, 0, &BitmapInfoHeader, sizeof(BitmapInfoHeader)); if (hr != 0) { CleanupAVI(); return; } Bitmap = (long *) GlobalAllocPtr(GMEM_MOVEABLE, BitmapInfoHeader.biSizeImage); } FrameGrabClass::~FrameGrabClass() { if(Mode == AVI) { CleanupAVI(); } } void FrameGrabClass::CleanupAVI() { if(Bitmap != 0) { GlobalFreePtr(Bitmap); Bitmap = 0; } if(Stream != 0) { AVIStreamRelease(Stream); Stream = 0; } if(AVIFile != 0) { AVIFileRelease(AVIFile); AVIFile = 0; } AVIFileExit(); Mode = RAW; } void FrameGrabClass::GrabAVI(void *BitmapPointer) { // CompressDIB(&bi, lpOld, &biNew, lpNew); // Save the compressed data using AVIStreamWrite. HRESULT hr = AVIStreamWrite(Stream, Counter++, 1, BitmapPointer, BitmapInfoHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); if(hr != 0) { char buf[256]; sprintf(buf, "avi write error %x/%d\n", hr, hr); OutputDebugString(buf); } } void FrameGrabClass::GrabRawFrame(void * /*BitmapPointer*/) { } void FrameGrabClass::ConvertGrab(void *BitmapPointer) { ConvertFrame(BitmapPointer); Grab( Bitmap ); } void FrameGrabClass::Grab(void *BitmapPointer) { if(Mode == AVI) GrabAVI(BitmapPointer); else GrabRawFrame(BitmapPointer); } void FrameGrabClass::ConvertFrame(void *BitmapPointer) { int width = BitmapInfoHeader.biWidth; int height = BitmapInfoHeader.biHeight; long *image = (long *) BitmapPointer; // copy the data, doing a vertical flip & byte re-ordering of the pixel longwords int y = height; while(y--) { int x = width; int yoffset = y * width; int yoffset2 = (height - y) * width; while(x--) { long *source = &image[yoffset + x]; long *dest = &Bitmap[yoffset2 + x]; *dest = *source; unsigned char *c = (unsigned char *) dest; c[3] = c[0]; c[0] = c[2]; c[2] = c[3]; c[3] = 0; } } }