Filesystem update.

This commit is contained in:
Justin Marshall
2026-05-09 07:37:04 -07:00
parent 53dc4276d5
commit 8c4a087aa9
2076 changed files with 11142 additions and 87 deletions
@@ -0,0 +1,105 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "roq.h"
void R_LoadImage( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp, bool makePowerOf2 );
NSBitmapImageRep::NSBitmapImageRep( void ) {
bmap = NULL;
width = 0;
height = 0;
timestamp = 0;
}
NSBitmapImageRep::NSBitmapImageRep( const char *filename ) {
R_LoadImage( filename, &bmap, &width, &height, &timestamp, false );
if (!width || !height) {
common->FatalError( "roqvq: unable to load image %s\n", filename );
}
}
NSBitmapImageRep::NSBitmapImageRep( int wide, int high ) {
bmap = (byte *)Mem_ClearedAlloc( wide * high * 4 );
width = wide;
height = high;
}
void R_StaticFree( void *data );
NSBitmapImageRep::~NSBitmapImageRep() {
R_StaticFree( bmap );
bmap = NULL;
}
int NSBitmapImageRep::samplesPerPixel( void ) {
return 4;
}
int NSBitmapImageRep::pixelsWide( void ) {
return width;
}
int NSBitmapImageRep::pixelsHigh( void ) {
return height;
}
byte * NSBitmapImageRep::bitmapData( void ) {
return bmap;
}
bool NSBitmapImageRep::hasAlpha( void ) {
return false;
}
bool NSBitmapImageRep::isPlanar( void ) {
return false;
}
NSBitmapImageRep &NSBitmapImageRep::operator=( const NSBitmapImageRep &a ) {
// check for assignment to self
if ( this == &a ) {
return *this;
}
if (bmap) {
Mem_Free(bmap);
}
bmap = (byte *)Mem_Alloc( a.width * a.height * 4 );
memcpy( bmap, a.bmap, a.width * a.height * 4 );
width = a.width;
height = a.height;
timestamp = a.timestamp;
return *this;
}
File diff suppressed because it is too large Load Diff
+108
View File
@@ -0,0 +1,108 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#ifndef __codec_h__
#define __codec_h__
#define MAXERRORMAX 200
#define IPSIZE int
const float MOTION_MIN = 1.0f;
const float MIN_SNR = 3.0f;
#define FULLFRAME 0
#define JUSTMOTION 1
#define VQDATA double
#include "gdefs.h"
#include "roq.h"
#include "quaddefs.h"
class codec {
public:
codec();
~codec();
void SparseEncode( void );
void EncodeNothing( void );
void IRGBtab(void);
void InitImages(void);
void QuadX( int startX, int startY, int quadSize);
void InitQStatus();
float Snr(byte *old, byte *bnew, int size);
void FvqData( byte *bitmap, int size, int realx, int realy, quadcel *pquad, bool clamp);
void GetData( unsigned char *iData, int qSize, int startX, int startY, NSBitmapImageRep *bitmap);
int ComputeMotionBlock( byte *old, byte *bnew, int size);
void VqData8( byte *cel, quadcel *pquad);
void VqData4( byte *cel, quadcel *pquad);
void VqData2( byte *cel, quadcel *pquad);
int MotMeanY(void);
int MotMeanX(void);
void SetPreviousImage( const char*filename, NSBitmapImageRep *timage );
int BestCodeword( unsigned char *tempvector, int dimension, VQDATA **codebook );
private:
void VQ( const int numEntries, const int dimension, const unsigned char *vectors, float *snr, VQDATA **codebook, const bool optimize );
void Sort( float *list, int *intIndex, int numElements );
void Segment( int *alist, float *flist, int numElements, float rmse);
void LowestQuad( quadcel*qtemp, int* status, float* snr, int bweigh);
void MakePreviousImage( quadcel *pquad );
float GetCurrentRMSE( quadcel *pquad );
int GetCurrentQuadOutputSize( quadcel *pquad );
int AddQuad( quadcel *pquad, int lownum );
NSBitmapImageRep *image;
NSBitmapImageRep *newImage;
NSBitmapImageRep *previousImage[2]; // the ones in video ram and offscreen ram
int numQuadCels;
int whichFrame;
int slop;
bool detail;
int onQuad;
int initRGBtab;
quadcel *qStatus;
int dxMean;
int dyMean;
int codebooksize;
int index2[256];
int overAmount;
int pixelsWide;
int pixelsHigh;
int codebookmade;
bool used2[256];
bool used4[256];
int dimension2;
int dimension4;
byte luty[256];
byte *luti;
VQDATA **codebook2;
VQDATA **codebook4;
};
#endif // __codec_h__
+68
View File
@@ -0,0 +1,68 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#ifndef __gdefs_h__
#define __gdefs_h__
/*==================*
* TYPE DEFINITIONS *
*==================*/
typedef unsigned char byte;
typedef unsigned short word;
#pragma once
#define dabs(a) (((a)<0) ? -(a) : (a))
#define CLAMP(v,l,h) ((v)<(l) ? (l) : (v)>(h) ? (h) : v)
#define xswap(a,b) { a^=b; b^=a; a^=b; }
#define lum(a) ( 0.2990*(a>>16) + 0.5870*((a>>8)&0xff) + 0.1140*(a&0xff) )
#define gsign(a) ((a) < 0 ? -1 : 1)
#define mnint(a) ((a) < 0 ? (int)(a - 0.5) : (int)(a + 0.5))
#define mmax(a, b) ((a) > (b) ? (a) : (b))
#define mmin(a, b) ((a) < (b) ? (a) : (b))
#define RGBDIST( src0, src1 ) ( ((src0[0]-src1[0])*(src0[0]-src1[0])) + \
((src0[1]-src1[1])*(src0[1]-src1[1])) + \
((src0[2]-src1[2])*(src0[2]-src1[2])) )
#define RGBADIST( src0, src1 ) ( ((src0[0]-src1[0])*(src0[0]-src1[0])) + \
((src0[1]-src1[1])*(src0[1]-src1[1])) + \
((src0[2]-src1[2])*(src0[2]-src1[2])) + \
((src0[3]-src1[3])*(src0[3]-src1[3])) )
#define RMULT 0.2990f // use these for televisions
#define GMULT 0.5870f
#define BMULT 0.1140f
#define RIEMULT -0.16874f
#define RQEMULT 0.50000f
#define GIEMULT -0.33126f
#define GQEMULT -0.41869f
#define BIEMULT 0.50000f
#define BQEMULT -0.08131f
#endif // gdefs
+131
View File
@@ -0,0 +1,131 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#ifndef __quaddefs_h__
#define __quaddefs_h__
#pragma once
#define DEP 0
#define FCC 1
#define CCC 2
#define SLD 3
#define PAT 4
#define MOT 5
#define DEAD 6
#define COLA 0
#define COLB 1
#define COLC 2
#define COLS 3
#define COLPATA 4
#define COLPATB 5
#define COLPATS 6
#define GENERATION 7
#define CCCBITMAP 0
#define FCCDOMAIN 1
#define PATNUMBER 2
#define PATNUMBE2 3
#define PATNUMBE3 4
#define PATNUMBE4 5
#define PATNUMBE5 6
#define MAXSIZE 16
#define MINSIZE 4
#define RoQ_ID 0x1084
#define RoQ_QUAD 0x1000
#define RoQ_PUZZLE_QUAD 0x1003
#define RoQ_QUAD_HANG 0x1013
#define RoQ_QUAD_SMALL 0x1010
#define RoQ_QUAD_INFO 0x1001
#define RoQ_QUAD_VQ 0x1011
#define RoQ_QUAD_JPEG 0x1012
#define RoQ_QUAD_CODEBOOK 0x1002
typedef struct {
byte size; // 32, 16, 8, or 4
word xat; // where is it at on the screen
word yat; //
} shortQuadCel;
typedef struct {
byte size; // 32, 16, 8, or 4
word xat; // where is it at on the screen
word yat; //
float cccsnr; // ccc bitmap snr to actual image
float fccsnr; // fcc bitmap snr to actual image
float motsnr; // delta snr to previous image
float sldsnr; // solid color snr
float patsnr;
float dctsnr;
float rsnr; // what's the current snr
unsigned int cola; // color a for ccc
unsigned int colb; // color b for ccc
unsigned int colc; // color b for ccc
unsigned int sldcol; // sold color
unsigned int colpata;
unsigned int colpatb;
unsigned int colpats;
unsigned int bitmap; // ccc bitmap
word domain; // where to copy from for fcc
word patten[5]; // which pattern
int status;
bool mark;
float snr[DEAD+1]; // snrssss
} quadcel;
typedef struct {
float snr[DEAD+1]; // snrssss
unsigned int cols[8];
unsigned int bitmaps[7]; // ccc bitmap
} dataQuadCel;
typedef struct {
float normal;
unsigned short int index;
} norm;
typedef struct {
unsigned char dtlMap[256];
int r[4];
int g[4];
int b[4];
int a[4];
float ymean;
} dtlCel;
typedef struct {
byte r,g,b,a;
} pPixel;
#endif // quaddef
+826
View File
@@ -0,0 +1,826 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "roq.h"
#include "codec.h"
/*
=========================================================
JPEG writing now uses stb_image_write.h instead of libjpeg.
Put stb_image_write.h somewhere this project can include it.
IMPORTANT:
Only define STB_IMAGE_WRITE_IMPLEMENTATION in ONE cpp file.
If you already define it somewhere else, remove the define below.
=========================================================
*/
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STBI_WRITE_NO_STDIO
#include "stb_image_write.h"
roq* theRoQ; // current roq file
/*
================
roqJpegMemoryBuffer
Small dynamic output buffer used by stbi_write_jpg_to_func().
================
*/
struct roqJpegMemoryBuffer {
byte* data;
int size;
int capacity;
};
/*
================
RoQJpegGrowBuffer
================
*/
static void RoQJpegGrowBuffer(roqJpegMemoryBuffer* buffer, int neededSize) {
byte* newData;
int newCapacity;
if (neededSize <= buffer->capacity) {
return;
}
newCapacity = buffer->capacity;
if (newCapacity <= 0) {
newCapacity = 64 * 1024;
}
while (newCapacity < neededSize) {
newCapacity *= 2;
}
newData = (byte*)Mem_Alloc(newCapacity);
if (buffer->data && buffer->size > 0) {
memcpy(newData, buffer->data, buffer->size);
}
if (buffer->data) {
Mem_Free(buffer->data);
}
buffer->data = newData;
buffer->capacity = newCapacity;
}
/*
================
RoQJpegWriteCallback
stb_image_write calls this with chunks of encoded JPEG data.
================
*/
static void RoQJpegWriteCallback(void* context, void* data, int size) {
roqJpegMemoryBuffer* buffer;
if (!context || !data || size <= 0) {
return;
}
buffer = (roqJpegMemoryBuffer*)context;
RoQJpegGrowBuffer(buffer, buffer->size + size);
memcpy(buffer->data + buffer->size, data, size);
buffer->size += size;
}
roq::roq(void) {
image = 0;
quietMode = false;
encoder = 0;
previousSize = 0;
lastFrame = false;
dataStuff = false;
}
roq::~roq(void) {
if (image) {
delete image;
}
if (encoder) {
delete encoder;
}
return;
}
void roq::EncodeQuietly(bool which) {
quietMode = which;
}
bool roq::IsQuiet(void) {
return quietMode;
}
bool roq::IsLastFrame(void) {
return lastFrame;
}
bool roq::Scaleable(void) {
return paramFile->IsScaleable();
}
bool roq::ParamNoAlpha(void) {
return paramFile->NoAlpha();
}
bool roq::MakingVideo(void) {
return true;
}
bool roq::SearchType(void) {
return paramFile->SearchType();
}
bool roq::HasSound(void) {
return paramFile->HasSound();
}
int roq::PreviousFrameSize(void) {
return previousSize;
}
int roq::FirstFrameSize(void) {
return paramFile->FirstFrameSize();
}
int roq::NormalFrameSize(void) {
return paramFile->NormalFrameSize();
}
const char* roq::CurrentFilename(void) {
return currentFile.c_str();
}
void roq::EncodeStream(const char* paramInputFile) {
int onFrame;
idStr f0, f1, f2;
int morestuff;
onFrame = 1;
encoder = new codec;
paramFile = new roqParam;
paramFile->numInputFiles = 0;
paramFile->InitFromFile(paramInputFile);
if (!paramFile->NumberOfFrames()) {
return;
}
InitRoQFile(paramFile->outputFilename);
numberOfFrames = paramFile->NumberOfFrames();
if (paramFile->NoAlpha() == true) {
common->Printf("encodeStream: eluding alpha\n");
}
f0 = "";
f1 = paramFile->GetNextImageFilename();
if (paramFile->MoreFrames() == true) {
f2 = paramFile->GetNextImageFilename();
}
morestuff = numberOfFrames;
while (morestuff) {
LoadAndDisplayImage(f1);
if (onFrame == 1) {
encoder->SparseEncode();
// WriteLossless();
}
else {
if (!strcmp(f0, f1) && strcmp(f1, f2)) {
WriteHangFrame();
}
else {
encoder->SparseEncode();
}
}
onFrame++;
f0 = f1;
f1 = f2;
if (paramFile->MoreFrames() == true) {
f2 = paramFile->GetNextImageFilename();
}
morestuff--;
session->UpdateScreen();
}
CloseRoQFile();
}
void roq::Write16Word(word* aWord, idFile* stream) {
byte a, b;
a = *aWord & 0xff;
b = *aWord >> 8;
stream->Write(&a, 1);
stream->Write(&b, 1);
}
void roq::Write32Word(unsigned int* aWord, idFile* stream) {
byte a, b, c, d;
a = *aWord & 0xff;
b = (*aWord >> 8) & 0xff;
c = (*aWord >> 16) & 0xff;
d = (*aWord >> 24) & 0xff;
stream->Write(&a, 1);
stream->Write(&b, 1);
stream->Write(&c, 1);
stream->Write(&d, 1);
}
int roq::SizeFile(idFile* ftosize) {
return ftosize->Length();
}
/*
================
roq::WriteLossless
Writes the first/lossless RoQ JPEG frame.
Old code used libjpeg directly.
This version uses stb_image_write.h and writes the JPEG into memory,
then writes that memory into the RoQ_QUAD_JPEG chunk.
The source image is assumed to be RGBA.
JPEG has no alpha, so this writes RGB.
================
*/
void roq::WriteLossless(void) {
word direct;
uint directdw;
int imageWidth;
int imageHeight;
int srcStride;
int dstStride;
int quality;
byte* srcPixels;
byte* rgbPixels;
int x;
int y;
roqJpegMemoryBuffer jpegBuffer;
if (!dataStuff) {
InitRoQPatterns();
dataStuff = true;
}
if (!image || !image->bitmapData()) {
common->Error("WriteLossless: no image loaded\n");
return;
}
imageWidth = image->pixelsWide();
imageHeight = image->pixelsHigh();
if (imageWidth <= 0 || imageHeight <= 0) {
common->Error("WriteLossless: bad image size %d x %d\n", imageWidth, imageHeight);
return;
}
direct = RoQ_QUAD_JPEG;
Write16Word(&direct, RoQFile);
quality = paramFile->JpegQuality();
if (quality < 1) {
quality = 1;
}
if (quality > 100) {
quality = 100;
}
srcStride = imageWidth * 4;
dstStride = imageWidth * 3;
srcPixels = image->bitmapData();
/*
====================
Convert RGBA to RGB and vertically flip.
The old libjpeg path fed rows from bottom to top:
row_pointer[0] = bottom row - next_scanline.
Keep that behavior here so the encoded first frame matches the old orientation.
====================
*/
rgbPixels = (byte*)Mem_Alloc(imageWidth * imageHeight * 3);
for (y = 0; y < imageHeight; y++) {
const byte* srcRow;
byte* dstRow;
srcRow = srcPixels + (imageHeight - 1 - y) * srcStride;
dstRow = rgbPixels + y * dstStride;
for (x = 0; x < imageWidth; x++) {
dstRow[x * 3 + 0] = srcRow[x * 4 + 0];
dstRow[x * 3 + 1] = srcRow[x * 4 + 1];
dstRow[x * 3 + 2] = srcRow[x * 4 + 2];
}
}
jpegBuffer.data = NULL;
jpegBuffer.size = 0;
jpegBuffer.capacity = 0;
if (!stbi_write_jpg_to_func(
RoQJpegWriteCallback,
&jpegBuffer,
imageWidth,
imageHeight,
3,
rgbPixels,
quality)) {
Mem_Free(rgbPixels);
if (jpegBuffer.data) {
Mem_Free(jpegBuffer.data);
}
common->Error("WriteLossless: stbi_write_jpg_to_func failed\n");
return;
}
Mem_Free(rgbPixels);
if (!jpegBuffer.data || jpegBuffer.size <= 0) {
if (jpegBuffer.data) {
Mem_Free(jpegBuffer.data);
}
common->Error("WriteLossless: JPEG encoder produced no data\n");
return;
}
directdw = jpegBuffer.size;
common->Printf("writeLossless: writing %d bytes to RoQ_QUAD_JPEG\n", jpegBuffer.size);
Write32Word(&directdw, RoQFile);
direct = 0; // flags
Write16Word(&direct, RoQFile);
RoQFile->Write(jpegBuffer.data, jpegBuffer.size);
Mem_Free(jpegBuffer.data);
encoder->SetPreviousImage("first frame", image);
}
void roq::InitRoQFile(const char* RoQFilename) {
word i;
static int finit = 0;
if (!finit) {
finit++;
common->Printf("initRoQFile: %s\n", RoQFilename);
RoQFile = fileSystem->OpenFileWrite(RoQFilename);
if (!RoQFile) {
common->Error("Unable to open output file %s.\n", RoQFilename);
}
i = RoQ_ID;
Write16Word(&i, RoQFile);
i = 0xffff;
Write16Word(&i, RoQFile);
Write16Word(&i, RoQFile);
// To retain exact file format write out 30 for new RoQs.
i = 30;
Write16Word(&i, RoQFile);
}
roqOutfile = RoQFilename;
}
void roq::InitRoQPatterns(void) {
uint j;
word direct;
direct = RoQ_QUAD_INFO;
Write16Word(&direct, RoQFile);
j = 8;
Write32Word(&j, RoQFile);
common->Printf("initRoQPatterns: outputting %d bytes to RoQ_INFO\n", j);
direct = image->hasAlpha();
if (ParamNoAlpha() == true) {
direct = 0;
}
Write16Word(&direct, RoQFile);
direct = image->pixelsWide();
Write16Word(&direct, RoQFile);
direct = image->pixelsHigh();
Write16Word(&direct, RoQFile);
direct = 8;
Write16Word(&direct, RoQFile);
direct = 4;
Write16Word(&direct, RoQFile);
}
void roq::CloseRoQFile(void) {
common->Printf("closeRoQFile: closing RoQ file\n");
fileSystem->CloseFile(RoQFile);
}
void roq::WriteHangFrame(void) {
uint j;
word direct;
common->Printf("*******************************************************************\n");
direct = RoQ_QUAD_HANG;
Write16Word(&direct, RoQFile);
j = 0;
Write32Word(&j, RoQFile);
direct = 0;
Write16Word(&direct, RoQFile);
}
void roq::WriteCodeBookToStream(byte* codebook, int csize, word cflags) {
uint j;
word direct;
if (!csize) {
common->Printf("writeCodeBook: false VQ DATA!!!!\n");
return;
}
direct = RoQ_QUAD_CODEBOOK;
Write16Word(&direct, RoQFile);
j = csize;
Write32Word(&j, RoQFile);
common->Printf("writeCodeBook: outputting %d bytes to RoQ_QUAD_CODEBOOK\n", j);
direct = cflags;
Write16Word(&direct, RoQFile);
RoQFile->Write(codebook, j);
}
void roq::WriteCodeBook(byte* codebook) {
memcpy(codes, codebook, 4096);
}
void roq::WriteFrame(quadcel* pquad) {
word action, direct;
int onCCC, onAction, i, code;
uint j;
byte* cccList;
bool* use2, * use4;
int dx, dy, dxMean, dyMean, index2[256], index4[256], dimension;
cccList = (byte*)Mem_Alloc(numQuadCels * 8);
use2 = (bool*)Mem_Alloc(256 * sizeof(bool));
use4 = (bool*)Mem_Alloc(256 * sizeof(bool));
for (i = 0; i < 256; i++) {
use2[i] = false;
use4[i] = false;
}
action = 0;
j = onAction = 0;
onCCC = 2;
dxMean = encoder->MotMeanX();
dyMean = encoder->MotMeanY();
if (image->hasAlpha()) {
dimension = 10;
}
else {
dimension = 6;
}
for (i = 0; i < numQuadCels; i++) {
if (pquad[i].size && pquad[i].size < 16) {
switch (pquad[i].status) {
case SLD:
use4[pquad[i].patten[0]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 0]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 1]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 2]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 3]] = true;
break;
case PAT:
use4[pquad[i].patten[0]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 0]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 1]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 2]] = true;
use2[codes[dimension * 256 + (pquad[i].patten[0] * 4) + 3]] = true;
break;
case CCC:
use2[pquad[i].patten[1]] = true;
use2[pquad[i].patten[2]] = true;
use2[pquad[i].patten[3]] = true;
use2[pquad[i].patten[4]] = true;
break;
}
}
}
if (!dataStuff) {
dataStuff = true;
InitRoQPatterns();
if (image->hasAlpha()) {
i = 3584;
}
else {
i = 2560;
}
WriteCodeBookToStream(codes, i, 0);
for (i = 0; i < 256; i++) {
index2[i] = i;
index4[i] = i;
}
}
else {
j = 0;
for (i = 0; i < 256; i++) {
if (use2[i]) {
index2[i] = j;
for (dx = 0; dx < dimension; dx++) {
cccList[j * dimension + dx] = codes[i * dimension + dx];
}
j++;
}
}
code = j * dimension;
direct = j;
common->Printf("writeFrame: really used %d 2x2 cels\n", j);
j = 0;
for (i = 0; i < 256; i++) {
if (use4[i]) {
index4[i] = j;
for (dx = 0; dx < 4; dx++) {
cccList[j * 4 + code + dx] = index2[codes[i * 4 + (dimension * 256) + dx]];
}
j++;
}
}
code += j * 4;
direct = (direct << 8) + j;
common->Printf("writeFrame: really used %d 4x4 cels\n", j);
if (image->hasAlpha()) {
i = 3584;
}
else {
i = 2560;
}
if (code == i || j == 256) {
WriteCodeBookToStream(codes, i, 0);
}
else {
WriteCodeBookToStream(cccList, code, direct);
}
}
action = 0;
j = onAction = 0;
for (i = 0; i < numQuadCels; i++) {
if (pquad[i].size && pquad[i].size < 16) {
code = -1;
switch (pquad[i].status) {
case DEP:
code = 3;
break;
case SLD:
code = 2;
cccList[onCCC++] = index4[pquad[i].patten[0]];
break;
case MOT:
code = 0;
break;
case FCC:
code = 1;
dx = ((pquad[i].domain >> 8)) - 128 - dxMean + 8;
dy = ((pquad[i].domain & 0xff)) - 128 - dyMean + 8;
if (dx > 15 || dx < 0 || dy > 15 || dy < 0) {
common->Error(
"writeFrame: FCC error %d,%d mean %d,%d at %d,%d,%d rmse %f\n",
dx,
dy,
dxMean,
dyMean,
pquad[i].xat,
pquad[i].yat,
pquad[i].size,
pquad[i].snr[FCC]
);
}
cccList[onCCC++] = (dx << 4) + dy;
break;
case PAT:
code = 2;
cccList[onCCC++] = index4[pquad[i].patten[0]];
break;
case CCC:
code = 3;
cccList[onCCC++] = index2[pquad[i].patten[1]];
cccList[onCCC++] = index2[pquad[i].patten[2]];
cccList[onCCC++] = index2[pquad[i].patten[3]];
cccList[onCCC++] = index2[pquad[i].patten[4]];
break;
case DEAD:
common->Error("dead cels in picture\n");
break;
}
if (code == -1) {
common->Error("writeFrame: an error occurred writing the frame\n");
}
action = (action << 2) | code;
j++;
if (j == 8) {
j = 0;
cccList[onAction + 0] = (action & 0xff);
cccList[onAction + 1] = ((action >> 8) & 0xff);
onAction = onCCC;
onCCC += 2;
}
}
}
if (j) {
action <<= ((8 - j) * 2);
cccList[onAction + 0] = (action & 0xff);
cccList[onAction + 1] = ((action >> 8) & 0xff);
}
direct = RoQ_QUAD_VQ;
Write16Word(&direct, RoQFile);
j = onCCC;
Write32Word(&j, RoQFile);
direct = dyMean;
direct &= 0xff;
direct += (dxMean << 8);
Write16Word(&direct, RoQFile);
common->Printf("writeFrame: outputting %d bytes to RoQ_QUAD_VQ\n", j);
previousSize = j;
RoQFile->Write(cccList, onCCC);
Mem_Free(cccList);
Mem_Free(use2);
Mem_Free(use4);
}
void roq::LoadAndDisplayImage(const char* filename) {
if (image) {
delete image;
}
common->Printf("loadAndDisplayImage: %s\n", filename);
currentFile = filename;
image = new NSBitmapImageRep(filename);
numQuadCels = ((image->pixelsWide() & 0xfff0) * (image->pixelsHigh() & 0xfff0)) / (MINSIZE * MINSIZE);
numQuadCels += numQuadCels / 4 + numQuadCels / 16;
if (!quietMode) {
common->Printf("loadAndDisplayImage: %dx%d\n", image->pixelsWide(), image->pixelsHigh());
}
}
void roq::MarkQuadx(int xat, int yat, int size, float cerror, int choice) {
}
NSBitmapImageRep* roq::CurrentImage(void) {
return image;
}
int roq::NumberOfFrames(void) {
return numberOfFrames;
}
void RoQFileEncode_f(const idCmdArgs& args) {
if (args.Argc() != 2) {
common->Printf("Usage: roq <paramfile>\n");
return;
}
theRoQ = new roq;
int startMsec = Sys_Milliseconds();
theRoQ->EncodeStream(args.Argv(1));
int stopMsec = Sys_Milliseconds();
common->Printf("total encoding time: %i second\n", (stopMsec - startMsec) / 1000);
}
+137
View File
@@ -0,0 +1,137 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following
the terms and conditions of the GNU General Public License which accompanied
the IceTech Source Code. If not, please request a copy in writing from id Software
at the address below.
If you have questions concerning this license or the applicable additional terms,
you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#ifndef __roq_h__
#define __roq_h__
#pragma once
#include "gdefs.h"
#include "roqParam.h"
#include "quaddefs.h"
class codec;
class roqParam;
class NSBitmapImageRep {
public:
NSBitmapImageRep(void);
NSBitmapImageRep(const char* filename);
NSBitmapImageRep(int wide, int high);
~NSBitmapImageRep();
NSBitmapImageRep& operator=(const NSBitmapImageRep& a);
int samplesPerPixel(void);
int pixelsWide(void);
int pixelsHigh(void);
byte* bitmapData(void);
bool hasAlpha(void);
bool isPlanar(void);
private:
byte* bmap;
int width;
int height;
ID_TIME_T timestamp;
};
class roq {
public:
roq();
~roq();
void WriteLossless(void);
void LoadAndDisplayImage(const char* filename);
void CloseRoQFile(bool which);
void InitRoQFile(const char* roqFilename);
void InitRoQPatterns(void);
void EncodeStream(const char* paramInputFile);
void EncodeQuietly(bool which);
bool IsQuiet(void);
bool IsLastFrame(void);
NSBitmapImageRep* CurrentImage(void);
void MarkQuadx(int xat, int yat, int size, float cerror, int choice);
void WritePuzzleFrame(quadcel* pquad);
void WriteFrame(quadcel* pquad);
void WriteCodeBook(byte* codebook);
// Kept for compatibility with existing declarations.
// The implemented private function is WriteCodeBookToStream().
void WwriteCodeBookToStream(byte* codes, int csize, word cflags);
int PreviousFrameSize(void);
bool MakingVideo(void);
bool ParamNoAlpha(void);
bool SearchType(void);
bool HasSound(void);
const char* CurrentFilename(void);
int NormalFrameSize(void);
int FirstFrameSize(void);
bool Scaleable(void);
void WriteHangFrame(void);
int NumberOfFrames(void);
private:
void Write16Word(word* aWord, idFile* stream);
void Write32Word(unsigned int* aWord, idFile* stream);
int SizeFile(idFile* ftosize);
void CloseRoQFile(void);
void WriteCodeBookToStream(byte* codebook, int csize, word cflags);
codec* encoder;
roqParam* paramFile;
idFile* RoQFile;
NSBitmapImageRep* image;
int numQuadCels;
bool quietMode;
bool lastFrame;
idStr roqOutfile;
idStr currentFile;
int numberOfFrames;
int previousSize;
byte codes[4096];
bool dataStuff;
};
extern roq* theRoQ; // current roq
#endif /* !__roq_h__ */
+933
View File
@@ -0,0 +1,933 @@
#import "roq.h"
#import "codec.h"
#ifdef __MACOS__
blah
#endif
@implementation roq
- init
{
cWindow = eWindow = sWindow = 0;
image = 0;
quietMode = NO;
encoder = 0;
previousSize = 0;
lastFrame = NO;
codes = malloc( 4*1024 );
dataStuff=NO;
return self;
}
- (void)dealloc
{
free( codes );
if (image) [image dealloc];
if (encoder) [encoder dealloc];
return;
}
- encodeQuietly:(BOOL)which
{
quietMode = which;
return self;
}
- (BOOL)isQuiet
{
return quietMode;
}
- (BOOL)isLastFrame
{
return lastFrame;
}
- (BOOL)scaleable
{
return [paramFileId isScaleable];
}
- (BOOL)paramNoAlpha
{
return [paramFileId noAlpha];
}
- (BOOL)makingVideo
{
return YES; //[paramFileId timecode];
}
- (BOOL)searchType
{
return [paramFileId searchType];
}
- (BOOL)hasSound
{
return [paramFileId hasSound];
}
- (int)previousFrameSize
{
return previousSize;
}
-(int)firstFrameSize
{
return [paramFileId firstFrameSize];
}
-(int)normalFrameSize
{
return [paramFileId normalFrameSize];
}
- (char *)currentFilename
{
return currentFile;
}
-encodeStream: (id)paramInputFile
{
int onFrame;
char f0[MAXPATHLEN], f1[MAXPATHLEN], f2[MAXPATHLEN];
int morestuff;
onFrame = 1;
encoder = [[codec alloc] init: self];
numberOfFrames = [paramInputFile numberOfFrames];
paramFileId = paramInputFile;
if ([paramInputFile noAlpha]==YES) printf("encodeStream: eluding alpha\n");
f0[0] = 0;
strcpy( f1, [paramInputFile getNextImageFilename]);
if (( [paramInputFile moreFrames] == YES )) strcpy( f2, [paramInputFile getNextImageFilename]);
morestuff = numberOfFrames;
while( morestuff ) {
[self loadAndDisplayImage: f1];
if (onFrame==1 && ([image hadAlpha]==NO || [paramInputFile noAlpha]==YES) && ![self makingVideo] && ![self scaleable]) {
[encoder sparseEncode: self];
// [self writeLossless];
} else {
if (!strcmp( f0, f1 ) && strcmp( f1, f2) ) {
[self writeHangFrame];
} else {
[encoder sparseEncode: self];
}
}
onFrame++;
strcpy( f0, f1 );
strcpy( f1, f2 );
if ([paramInputFile moreFrames] == YES) strcpy( f2, [paramInputFile getNextImageFilename]);
morestuff--;
}
if (numberOfFrames != 1) {
if ([image hadAlpha] && [paramInputFile noAlpha]==NO) {
lastFrame = YES;
[encoder sparseEncode: self];
} else {
[self writeLossless];
}
}
return self;
}
- write16Word:(word *)aWord to:(FILE *)stream
{
byte a, b;
a = *aWord & 0xff;
b = *aWord >> 8;
fputc( a, stream );
fputc( b, stream );
return self;
}
- write32Word:( unsigned int *)aWord to:(FILE *)stream
{
byte a, b, c, d;
a = *aWord & 0xff;
b = (*aWord >> 8) & 0xff;
c = (*aWord >> 16) & 0xff;
d = (*aWord >> 24) & 0xff;
fputc( a, stream );
fputc( b, stream );
fputc( c, stream );
fputc( d, stream );
return self;
}
-(int)sizeFile:(FILE *)ftosize;
{
long int fat, fend;
fat = ftell(ftosize);
fseek( ftosize, 0, SEEK_END );
fend = ftell(ftosize);
fseek( ftosize, fat, SEEK_SET);
return (fend);
}
- convertPlanertoPacked
{
byte *iPlane[5], *newdata, *olddata;
int x,y,index, sample, pixelsWide, pixelsHigh;
TByteBitmapImageRep *newImage;
pixelsWide = [image pixelsWide];
pixelsHigh = [image pixelsHigh];
printf("convertPlanertoPacked: converting\n");
newImage = [[TByteBitmapImageRep alloc] initWithBitmapDataPlanes: NULL
pixelsWide: pixelsWide
pixelsHigh: pixelsHigh
bitsPerSample: 8
samplesPerPixel: 4
hasAlpha: YES
isPlanar: NO
colorSpaceName: NSCalibratedRGBColorSpace
bytesPerRow: 0
bitsPerPixel: 0];
newdata = [newImage bitmapData];
index = 0;
if ([image isPlanar]) {
[image getBitmapDataPlanes: iPlane];
for(y=0;y<pixelsHigh;y++) {
for(x=0;x<pixelsWide;x++) {
newdata[index++] = iPlane[0][y*pixelsWide+x];
newdata[index++] = iPlane[1][y*pixelsWide+x];
newdata[index++] = iPlane[2][y*pixelsWide+x];
if ([image hasAlpha]) {
newdata[index++] = iPlane[3][y*pixelsWide+x];
} else {
newdata[index++] = 255;
}
}
}
} else {
sample = 0;
olddata = [image bitmapData];
for(y=0;y<pixelsHigh;y++) {
for(x=0;x<pixelsWide;x++) {
newdata[index++] = olddata[sample++];
newdata[index++] = olddata[sample++];
newdata[index++] = olddata[sample++];
if ([image hasAlpha]) {
newdata[index++] = olddata[sample++];
} else {
newdata[index++] = 255;
}
}
}
}
[image dealloc];
image = newImage;
return self;
}
- writeLossless
{
word direct;
unsigned int j;
char tempFile[MAXPATHLEN];
FILE *ftemp;
byte *buffer;
int res, mess;
[self convertPlanertoPacked];
if (!dataStuff) {
[self initRoQPatterns];
dataStuff=YES;
}
direct = RoQ_QUAD_JPEG;
[self write16Word: &direct to: RoQFile];
sprintf(tempFile, "%s.jpg",[paramFileId roqTempFilename]);
[image writeJFIF:tempFile quality: [paramFileId jpegQuality]];
ftemp = fopen(tempFile, "rb");
if (!ftemp) { fprintf(stderr, "Could not open temp file\n"); exit(1); }
j = [self sizeFile: ftemp];
printf("writeLossless: writing %d bytes to RoQ_QUAD_JPEG\n", j);
[self write32Word: &j to: RoQFile];
direct = 0; // flags
[self write16Word: &direct to: RoQFile];
buffer = malloc( 16384 );
do {
res = fread( buffer, 1, 16384, ftemp);
mess = fwrite( buffer, 1, res, RoQFile );
if (res != mess) { fprintf(stderr, "Could not write to output stream\n"); exit(1); }
} while ( res == 16384 );
free( buffer );
fclose(ftemp);
[encoder setPreviousImage: tempFile from: image parent: self];
remove( tempFile );
fflush( RoQFile );
return self;
}
- initRoQFile:(const char *)RoQFilename
{
word i;
static int finit = 0;
if (!finit) {
finit++;
printf("initRoQFile: %s\n", RoQFilename);
RoQFile = fopen( RoQFilename, "w" );
// chmod(RoQFilename, S_IREAD|S_IWRITE|S_ISUID|S_ISGID|0070|0007 );
if (!RoQFile) {
fprintf(stderr,"Unable to open output file %s.\n", RoQFilename);
exit(1);
}
i = RoQ_ID;
[self write16Word: &i to: RoQFile];
i = 0xffff;
[self write16Word: &i to: RoQFile];
[self write16Word: &i to: RoQFile];
i = 24; // framerate
[self write16Word: &i to: RoQFile];
fflush( RoQFile );
}
strcpy( roqOutfile, RoQFilename );
return self;
}
- initRoQPatterns
{
int j;
word direct;
direct = RoQ_QUAD_INFO;
[self write16Word: &direct to: RoQFile];
j = 8;
[self write32Word: &j to: RoQFile];
printf("initRoQPatterns: outputting %d bytes to RoQ_INFO\n", j);
direct = [image hadAlpha];
if ([self paramNoAlpha] == YES) direct = 0;
[self write16Word: &direct to: RoQFile];
direct = [image pixelsWide];
[self write16Word: &direct to: RoQFile];
direct = [image pixelsHigh];
[self write16Word: &direct to: RoQFile];
direct = 8;
[self write16Word: &direct to: RoQFile];
direct = 4;
[self write16Word: &direct to: RoQFile];
fflush( RoQFile );
return self;
}
- closeRoQFile
{
fflush( RoQFile );
printf("closeRoQFile: closing RoQ file\n");
fclose( RoQFile );
return self;
}
- writeHangFrame
{
int j;
word direct;
printf("*******************************************************************\n");
direct = RoQ_QUAD_HANG;
[self write16Word: &direct to: RoQFile];
j = 0;
[self write32Word: &j to: RoQFile];
direct = 0;
[self write16Word: &direct to: RoQFile];
return self;
}
- writeCodeBookToStream: (byte *)codebook size: (int)csize flags: (word)cflags
{
int j;
word direct;
if (!csize) {
printf("writeCodeBook: NO VQ DATA!!!!\n");
return self;
}
direct = RoQ_QUAD_CODEBOOK;
[self write16Word: &direct to: RoQFile];
j = csize;
[self write32Word: &j to: RoQFile];
printf("writeCodeBook: outputting %d bytes to RoQ_QUAD_CODEBOOK\n", j);
direct = cflags;
[self write16Word: &direct to: RoQFile];
fwrite( codebook, j, 1, RoQFile);
fflush( RoQFile );
return self;
}
- writeCodeBook: (byte *)codebook
{
memcpy( codes, codebook, 4096 );
return self;
}
- writeFrame:(quadcel *)pquad
{
word action, direct;
int onCCC, onAction, i, j, code;
byte *cccList;
BOOL *use2, *use4;
int dx,dy,dxMean,dyMean,index2[256],index4[256], dimension;
cccList = malloc( numQuadCels * 8); // maximum length
use2 = malloc(256*sizeof(BOOL));
use4 = malloc(256*sizeof(BOOL));
for(i=0;i<256;i++) {
use2[i] = NO;
use4[i] = NO;
}
action = 0;
j = onAction = 0;
onCCC = 2; // onAction going to go at zero
dxMean = [encoder motMeanX];
dyMean = [encoder motMeanY];
if ([image hadAlpha]) dimension = 10; else dimension = 6;
for (i=0; i<numQuadCels; i++) {
if ( pquad[i].size && pquad[i].size < 16 ) {
switch( pquad[i].status ) {
case SLD:
use4[pquad[i].patten[0]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+0]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+1]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+2]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+3]] = YES;
break;
case PAT:
use4[pquad[i].patten[0]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+0]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+1]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+2]] = YES;
use2[codes[dimension*256+(pquad[i].patten[0]*4)+3]] = YES;
break;
case CCC:
use2[pquad[i].patten[1]] = YES;
use2[pquad[i].patten[2]] = YES;
use2[pquad[i].patten[3]] = YES;
use2[pquad[i].patten[4]] = YES;
}
}
}
if (!dataStuff) {
dataStuff=YES;
[self initRoQPatterns];
if ([image hadAlpha]) i = 3584; else i = 2560;
[self writeCodeBookToStream: codes size: i flags: 0];
for(i=0;i<256;i++) {
index2[i] = i;
index4[i] = i;
}
} else {
j = 0;
for(i=0;i<256;i++) {
if (use2[i]) {
index2[i] = j;
for(dx=0;dx<dimension;dx++) cccList[j*dimension+dx] = codes[i*dimension+dx];
j++;
}
}
code = j*dimension;
direct = j;
printf("writeFrame: really used %d 2x2 cels\n", j);
j = 0;
for(i=0;i<256;i++) {
if (use4[i]) {
index4[i] = j;
for(dx=0;dx<4;dx++) cccList[j*4+code+dx] = index2[codes[i*4+(dimension*256)+dx]];
j++;
}
}
code += j*4;
direct = (direct<<8) + j;
printf("writeFrame: really used %d 4x4 cels\n", j);
if ([image hadAlpha]) i = 3584; else i = 2560;
if ( code == i || j == 256) {
[self writeCodeBookToStream: codes size: i flags: 0];
} else {
[self writeCodeBookToStream: cccList size: code flags: direct];
}
}
action = 0;
j = onAction = 0;
for (i=0; i<numQuadCels; i++) {
if ( pquad[i].size && pquad[i].size < 16 ) {
code = -1;
switch( pquad[i].status ) {
case DEP:
code = 3;
break;
case SLD:
code = 2;
cccList[onCCC++] = index4[pquad[i].patten[0]];
break;
case MOT:
code = 0;
break;
case FCC:
code = 1;
dx = ((pquad[i].domain >> 8 )) - 128 - dxMean + 8;
dy = ((pquad[i].domain & 0xff)) - 128 - dyMean + 8;
if (dx>15 || dx<0 || dy>15 || dy<0 ) {
printf("writeFrame: FCC error %d,%d mean %d,%d at %d,%d,%d rmse %f\n", dx,dy, dxMean, dyMean,pquad[i].xat,pquad[i].yat,pquad[i].size, pquad[i].snr[FCC] );
exit(1);
}
cccList[onCCC++] = (dx<<4)+dy;
break;
case PAT:
code = 2;
cccList[onCCC++] = index4[pquad[i].patten[0]];
break;
case CCC:
code = 3;
cccList[onCCC++] = index2[pquad[i].patten[1]];
cccList[onCCC++] = index2[pquad[i].patten[2]];
cccList[onCCC++] = index2[pquad[i].patten[3]];
cccList[onCCC++] = index2[pquad[i].patten[4]];
break;
case DEAD:
fprintf(stderr,"dead cels in picture\n");
break;
}
if (code == -1) {
fprintf(stderr, "writeFrame: an error occurred writing the frame\n");
exit(2);
}
action = (action<<2)|code;
j++;
if (j == 8) {
j = 0;
cccList[onAction+0] = (action & 0xff);
cccList[onAction+1] = ((action >> 8) & 0xff);
onAction = onCCC;
onCCC += 2;
}
}
}
if (j) {
action <<= ((8-j)*2);
cccList[onAction+0] = (action & 0xff);
cccList[onAction+1] = ((action >> 8) & 0xff);
}
direct = RoQ_QUAD_VQ;
[self write16Word: &direct to: RoQFile];
j = onCCC;
[self write32Word: &j to: RoQFile];
direct = dyMean;
direct &= 0xff;
direct += (dxMean<<8); // flags
[self write16Word: &direct to: RoQFile];
printf("writeFrame: outputting %d bytes to RoQ_QUAD_VQ\n", j);
previousSize = j;
fwrite( cccList, onCCC, 1, RoQFile );
fflush( RoQFile );
free( cccList );
free( use2 );
free( use4 );
return self;
}
- writePuzzleFrame:(quadcel *)pquad
{
return self;
}
- (TByteBitmapImageRep *)scaleImage: (TByteBitmapImageRep *)toscale
{
int newx, newy,x,y,s,linesize;
TByteBitmapImageRep *newImage;
unsigned char *i0, *i1;
int newv;
newx = 288;
if ([toscale pixelsHigh] == 160) {
newy = 320;
} else {
newy = [toscale pixelsHigh];
}
newImage = [[TByteBitmapImageRep alloc] initWithBitmapDataPlanes: NULL
pixelsWide: newx
pixelsHigh: newy
bitsPerSample: 8
samplesPerPixel: 4
hasAlpha: YES
isPlanar: NO
colorSpaceName: NSCalibratedRGBColorSpace
bytesPerRow: 0
bitsPerPixel: 0];
i0 = [toscale bitmapData];
i1 = [newImage bitmapData];
linesize = [toscale pixelsWide]*4;
for(y=0; y<newy; y++) {
for(x=0; x<320; x++) {
if (x>=16 && x<304) {
for(s=0;s<4;s++) {
if ([toscale pixelsHigh] == 160) {
newv = i0[(x*2+0)*4+(y>>1)*linesize+s];
newv += i0[(x*2+1)*4+(y>>1)*linesize+s];
newv += i0[(x*2+0)*4+((y>>1)+1)*linesize+s];
newv += i0[(x*2+1)*4+((y>>1)+1)*linesize+s];
newv = newv/4;
} else {
newv = i0[(x*2+0)*4+y*linesize+s];
newv += i0[(x*2+1)*4+y*linesize+s];
newv = newv/2;
}
i1[(x-16)*4+y*(288*4)+s] = newv;
}
}
}
}
return (newImage);
}
//
// load a frame, create a window (if neccesary) and display the frame
//
- loadAndDisplayImage: (const char *) filename
{
NSRect cRect;
char *secondFilename,firstFilename[MAXPATHLEN+1];
id image1;
NSSize newSize;
// unsigned char *imageData;
// static BOOL cleared = NO;
if (image) [image dealloc];
printf("loadAndDisplayImage: %s\n", filename);
strcpy( currentFile, filename );
image = [TByteBitmapImageRep alloc];
if (!(secondFilename= strchr(filename,'\n'))) { //one filename, no compositing
[image initFromFile: filename ];
}
else {
strncpy(firstFilename,filename,secondFilename-filename);
firstFilename[secondFilename-filename]='\0';
secondFilename++;//point past the \n
image1 = [[TByteBitmapImageRep alloc] initFromFile:firstFilename];
[image initFromFile: secondFilename ];//result will be in here
//image is the composite of those two...
[self composite:image1 to:image];
}
//
// wolf stuff
//
newSize.width = 256;
newSize.height = 256;
[image setSize: newSize];
if ([paramFileId output3DO] == YES) {
image1 = [self scaleImage: image];
[image dealloc];
image = image1;
}
numQuadCels = (([image pixelsWide] & 0xfff0)*([image pixelsHigh] & 0xfff0))/(MINSIZE*MINSIZE);
numQuadCels += numQuadCels/4 + numQuadCels/16;
// if ([paramFileId deltaFrames] == YES && cleared == NO && [image isPlanar] == NO) {
// cleared = YES;
// imageData = [image data];
// memset( imageData, 0, [image pixelsWide]*[image pixelsHigh]*[image samplesPerPixel]);
// }
if (!quietMode) printf("loadAndDisplayImage: %dx%d\n", [image pixelsWide], [image pixelsHigh]);
if (!quietMode) {
if (!cWindow) {
cRect.origin.x = 8.0 * 48.0;
cRect.origin.y = ([image pixelsHigh]+80);
cRect.size.width = [image pixelsWide];
cRect.size.height = [image pixelsHigh];
cWindow = [[NSWindow alloc] initWithContentRect:cRect styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered defer:NO];
cRect.origin.x = cRect.origin.y = 0.0;
// [[cWindow contentView] setClipping:NO];
[cWindow setTitle: @"current frame"];
[cWindow makeKeyAndOrderFront: [cWindow contentView]];
[cWindow display];
}
cRect = [[cWindow contentView] bounds];
[[cWindow contentView] lockFocus];
[image drawInRect: cRect];
[[cWindow contentView] unlockFocus];
[cWindow flushWindow];
if (!eWindow) {
cRect.origin.x = 8.0 * 48.0 - ([image pixelsWide]>>1) - 4;
cRect.origin.y = ([image pixelsHigh]+80);
cRect.size.width = [image pixelsWide] >> 1;
cRect.size.height = [image pixelsHigh] >> 1;
eWindow = [[NSWindow alloc] initWithContentRect:cRect styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered defer:NO];
cRect.origin.x = cRect.origin.y = 0.0;
// [[eWindow contentView] setClipping:NO];
[eWindow setTitle: @"cel error"];
[eWindow makeKeyAndOrderFront: [eWindow contentView]];
[eWindow display];
}
if (!sWindow) {
cRect.origin.x = 8.0 * 48.0 - ([image pixelsWide]>>1) - 4;
cRect.origin.y = ([image pixelsHigh]+80) + (([image pixelsHigh]+48)>>1);
cRect.size.width = [image pixelsWide] >> 1;
cRect.size.height = [image pixelsHigh] >> 1;
sWindow = [[NSWindow alloc] initWithContentRect: cRect styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered defer:NO];
cRect.origin.x = cRect.origin.y = 0.0;
// [[eWindow contentView] setClipping:NO];
[sWindow setTitle: @"quadtree map"];
[sWindow makeKeyAndOrderFront: [sWindow contentView]];
[sWindow display];
}
cRect = [[sWindow contentView] bounds];
[[sWindow contentView] lockFocus];
[image drawInRect: cRect];
[[sWindow contentView] unlockFocus];
[sWindow flushWindow];
cRect = [[eWindow contentView] bounds];
[[eWindow contentView] lockFocus];
[image drawInRect: cRect];
[[eWindow contentView] unlockFocus];
[eWindow flushWindow];
if (!errImage) {
errImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL
pixelsWide: 1
pixelsHigh: 1
bitsPerSample: 8
samplesPerPixel: 3
hasAlpha: NO
isPlanar: NO
colorSpaceName: NSCalibratedRGBColorSpace
bytesPerRow: 0
bitsPerPixel: 0];
}
// NSPing();
}
return self;
}
- markQuadx: (int)xat quady: (int)yat quads: (int)size error: (float)cerror type: (int)choice
{
NSRect cRect;
byte *err;
static int ywasat = -1;
if (!quietMode) {
cRect.origin.x = (xat)>>1;
cRect.origin.y = ([image pixelsHigh] - yat - size)>>1;
cRect.size.width = cRect.size.height = (size)>>1;
if (size < 1) {
[[sWindow contentView] lockFocus];
if (size == 8 && choice == 1) {
PSsetgray(NSWhite);
} else if (size == 8 && choice == 3) {
PSsetgray(NSLightGray);
} else if (size == 4) {
PSsetgray(NSDarkGray);
} else if (size == 2) {
PSsetgray(NSBlack);
}
NSFrameRectWithWidth(cRect,0.0);
[[sWindow contentView] unlockFocus];
if (!(ywasat & 31)) {
[sWindow flushWindow];
}
}
err = [errImage bitmapData];
err[0] = err[1] = err[2] = 0;
if ( cerror > 31 ) cerror = 31;
if (choice & 1) err[0] = (int)cerror*8;
if (choice & 2) err[1] = (int)cerror*8;
if (choice & 4) err[2] = (int)cerror*8;
[[eWindow contentView] lockFocus];
[errImage drawInRect: cRect];
[[eWindow contentView] unlockFocus];
if (!(ywasat & 31)) {
[eWindow flushWindow];
}
ywasat++;
}
return self;
}
- (NSBitmapImageRep*)currentImage
{
return image;
}
- (id)errorWindow
{
return eWindow;
}
- (id)scaleWindow
{
return sWindow;
}
- (int)numberOfFrames {
return numberOfFrames;
}
- composite:(NSBitmapImageRep *)source to: (NSBitmapImageRep *)destination
{
unsigned short value;
int x,y,bpp,inc,pixelsWide,pixelsHigh,yoff,pixel;
byte *iPlane[5], *dPlane[5];
bpp = [source samplesPerPixel];
pixelsWide = [source pixelsWide];
pixelsHigh = [source pixelsHigh];
if ([source isPlanar]) {
[source getBitmapDataPlanes: iPlane];
[destination getBitmapDataPlanes: dPlane];
for(y=0;y<pixelsHigh;y++) {
yoff = y*pixelsWide;
for(x=0;x<pixelsWide;x++) {
if ([destination hasAlpha]) {
value = dPlane[3][yoff+x];
} else {
value = 255;
}
if (value == 0) {
dPlane[0][yoff+x] = iPlane[0][yoff+x];
dPlane[1][yoff+x] = iPlane[1][yoff+x];
dPlane[2][yoff+x] = iPlane[2][yoff+x];
dPlane[3][yoff+x] = iPlane[3][yoff+x];
} else if (value != 255) {
pixel = ((iPlane[0][yoff+x]*(255-value))/255) + ((dPlane[0][yoff+x]*value)/255);
dPlane[0][yoff+x] = pixel;
pixel = ((iPlane[1][yoff+x]*(255-value))/255) + ((dPlane[1][yoff+x]*value)/255);
dPlane[1][yoff+x] = pixel;
pixel = ((iPlane[2][yoff+x]*(255-value))/255) + ((dPlane[2][yoff+x]*value)/255);
dPlane[2][yoff+x] = pixel;
if ([destination hasAlpha]) {
if (iPlane[3][yoff+x]>dPlane[3][yoff+x]) dPlane[3][yoff+x] = iPlane[3][yoff+x];
}
}
}
}
} else {
iPlane[0] = [source bitmapData];
dPlane[0] = [destination bitmapData];
for(y=0;y<pixelsHigh;y++) {
yoff = y*pixelsWide*bpp;
for(x=0;x<pixelsWide;x++) {
inc = x*bpp;
if ([destination hasAlpha]) {
value = dPlane[0][yoff+inc+3];
} else {
value = 255;
}
if (value == 0) {
dPlane[0][yoff+inc+0] = iPlane[0][yoff+inc+0];
dPlane[0][yoff+inc+1] = iPlane[0][yoff+inc+1];
dPlane[0][yoff+inc+2] = iPlane[0][yoff+inc+2];
dPlane[0][yoff+inc+3] = iPlane[0][yoff+inc+3];
} else if (value != 255) {
pixel = ((iPlane[0][yoff+inc+0]*(255-value))/255) + ((dPlane[0][yoff+inc+0]*value)/255);
dPlane[0][yoff+inc+0] = pixel;
pixel = ((iPlane[0][yoff+inc+1]*(255-value))/255) + ((dPlane[0][yoff+inc+1]*value)/255);
dPlane[0][yoff+inc+1] = pixel;
pixel = ((iPlane[0][yoff+inc+2]*(255-value))/255) + ((dPlane[0][yoff+inc+2]*value)/255);
dPlane[0][yoff+inc+2] = pixel;
if ([destination hasAlpha]) {
if (iPlane[0][yoff+inc+3]>dPlane[0][yoff+inc+3]) dPlane[0][yoff+inc+3] = iPlane[0][yoff+inc+3];
}
}
}
}
}
return self;
}
@end
@@ -0,0 +1,635 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "roqParam.h"
//
// read a parameter file in (true I bloddy well had to do this again) (and yet again to c++)
//
int parseRange(const char *rangeStr,int field, int skipnum[], int startnum[], int endnum[],int numfiles[],bool padding[],int numpadding[] );
int parseTimecodeRange(const char *rangeStr,int field, int skipnum[], int startnum[], int endnum[],int numfiles[],bool padding[],int numpadding[] );
void roqParam::InitFromFile( const char *fileName )
{
idParser *src;
idToken token;
int i, readarg;
src = new idParser( fileName, LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
if ( !src->IsLoaded() ) {
delete src;
common->Printf("Error: can't open param file %s\n", fileName);
return;
}
common->Printf("initFromFile: %s\n", fileName);
fullSearch = false;
scaleDown = false;
encodeVideo = false;
addPath = false;
screenShots = false;
startPalette = false;
endPalette = false;
fixedPalette = false;
keyColor = false;
justDelta = false;
useTimecodeForRange = false;
onFrame = 0;
numInputFiles = 0;
currentPath[0] = '\0';
make3DO = false;
makeVectors = false;
justDeltaFlag = false;
noAlphaAtAll = false;
twentyFourToThirty = false;
hasSound = false;
isScaleable = false;
firstframesize = 56*1024;
normalframesize = 20000;
jpegDefault = 85;
realnum = 0;
while( 1 ) {
if ( !src->ReadToken( &token ) ) {
break;
}
readarg = 0;
// input dir
if (token.Icmp( "input_dir") == 0) {
src->ReadToken( &token );
addPath = true;
currentPath = token;
// common->Printf(" + input directory is %s\n", currentPath );
readarg++;
continue;
}
// input dir
if (token.Icmp( "scale_down") == 0) {
scaleDown = true;
// common->Printf(" + scaling down input\n" );
readarg++;
continue;
}
// full search
if (token.Icmp( "fullsearch") == 0) {
normalframesize += normalframesize/2;
fullSearch = true;
readarg++;
continue;
}
// scaleable
if (token.Icmp( "scaleable") == 0) {
isScaleable = true;
readarg++;
continue;
}
// input dir
if (token.Icmp( "no_alpha") == 0) {
noAlphaAtAll = true;
// common->Printf(" + scaling down input\n" );
readarg++;
continue;
}
if (token.Icmp( "24_fps_in_30_fps_out") == 0) {
twentyFourToThirty = true;
readarg++;
continue;
}
// video in
if (token.Icmp( "video_in") == 0) {
encodeVideo = true;
// common->Printf(" + Using the video port as input\n");
continue;
}
//timecode range
if (token.Icmp( "timecode") == 0) {
useTimecodeForRange = true;
firstframesize = 12*1024;
normalframesize = 4500;
// common->Printf(" + Using timecode as range\n");
continue;
}
// soundfile for making a .RnR
if (token.Icmp( "sound") == 0) {
src->ReadToken( &token );
soundfile = token;
hasSound = true;
// common->Printf(" + Using timecode as range\n");
continue;
}
// soundfile for making a .RnR
if (token.Icmp( "has_sound") == 0) {
hasSound = true;
continue;
}
// outfile
if (token.Icmp( "filename") == 0) {
src->ReadToken( &token );
outputFilename = token;
i = strlen(outputFilename);
// common->Printf(" + output file is %s\n", outputFilename );
readarg++;
continue;
}
// starting palette
if (token.Icmp( "start_palette") == 0) {
src->ReadToken( &token );
sprintf(startPal, "/LocalLibrary/vdxPalettes/%s", token.c_str());
// common->Error(" + starting palette is %s\n", startPal );
startPalette = true;
readarg++;
continue;
}
// ending palette
if (token.Icmp( "end_palette") == 0) {
src->ReadToken( &token );
sprintf(endPal, "/LocalLibrary/vdxPalettes/%s", token.c_str());
// common->Printf(" + ending palette is %s\n", endPal );
endPalette = true;
readarg++;
continue;
}
// fixed palette
if (token.Icmp( "fixed_palette") == 0) {
src->ReadToken( &token );
sprintf(startPal, "/LocalLibrary/vdxPalettes/%s", token.c_str());
// common->Printf(" + fixed palette is %s\n", startPal );
fixedPalette = true;
readarg++;
continue;
}
// these are screen shots
if (token.Icmp( "screenshot") == 0) {
// common->Printf(" + shooting screen shots\n" );
screenShots = true;
readarg++;
continue;
}
// key_color r g b
if (token.Icmp( "key_color") == 0) {
keyR = src->ParseInt();
keyG = src->ParseInt();
keyB = src->ParseInt();
keyColor = true;
// common->Printf(" + key color is %03d %03d %03d\n", keyR, keyG, keyB );
readarg++;
continue;
}
// only want deltas
if (token.Icmp( "just_delta") == 0) {
// common->Printf(" + outputting deltas in the night\n" );
// justDelta = true;
// justDeltaFlag = true;
readarg++;
continue;
}
// doing 3DO
if (token.Icmp( "3DO") == 0) {
make3DO = true;
readarg++;
continue;
}
// makes codebook vector tables
if (token.Icmp( "codebook") == 0) {
makeVectors = true;
readarg++;
continue;
}
// set first frame size
if (token.Icmp( "firstframesize") == 0) {
firstframesize = src->ParseInt();
readarg++;
continue;
}
// set normal frame size
if (token.Icmp( "normalframesize") == 0) {
normalframesize = src->ParseInt();
readarg++;
continue;
}
// set normal frame size
if (token.Icmp( "stillframequality") == 0) {
jpegDefault = src->ParseInt();
readarg++;
continue;
}
if (token.Icmp( "input") == 0) {
int num_files = 255;
range = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
padding = (bool *)Mem_ClearedAlloc( num_files * sizeof(bool) );
padding2 = (bool *)Mem_ClearedAlloc( num_files * sizeof(bool) );
skipnum = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
skipnum2 = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
startnum = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
startnum2 = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
endnum = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
endnum2 = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
numpadding = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
numpadding2 = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
numfiles = (int *)Mem_ClearedAlloc( num_files * sizeof(int) );
idStr empty;
file.AssureSize( num_files, empty );
file.AssureSize( num_files, empty );
field = 0;
realnum = 0;
do {
src->ReadToken(&token);
if ( token.Icmp( "end_input") != 0 ) {
idStr arg1, arg2, arg3;
file[field] = token;
while (src->ReadTokenOnLine( &token ) && token.Icmp( "[" ) ) {
file[field].Append( token );
}
arg1 = token;
while (src->ReadTokenOnLine( &token ) && token.Icmp( "[" ) ) {
arg1 += token;
}
arg2 = token;
while (src->ReadTokenOnLine( &token ) && token.Icmp( "[" ) ) {
arg2 += token;
}
arg3 = token;
while (src->ReadTokenOnLine( &token ) && token.Icmp( "[" ) ) {
arg3 += token;
}
if ( arg1[0] != '[' ) {
// common->Printf(" + reading %s\n", file[field] );
range[field] = 0;
numfiles[field] = 1;
realnum++;
}
else {
if ( arg1[0] == '[' )
{
range[field] = 1;
if (useTimecodeForRange) {
realnum += parseTimecodeRange( arg1, field, skipnum, startnum, endnum, numfiles, padding, numpadding);
// common->Printf(" + reading %s from %d to %d\n", file[field], startnum[field], endnum[field]);
}
else {
realnum += parseRange( arg1, field, skipnum, startnum, endnum, numfiles, padding, numpadding);
// common->Printf(" + reading %s from %d to %d\n", file[field], startnum[field], endnum[field]);
}
}
else if (( arg1[0] != '[' ) && ( arg2[0] == '[') && ( arg3[0] =='[')) { //a double ranger...
int files1,files2;
file2[field] = arg1;
range[field] = 2;
files1 = parseRange(arg2, field, skipnum, startnum, endnum, numfiles, padding, numpadding);
// common->Printf(" + reading %s from %d to %d\n", file[field], startnum[field], endnum[field]);
files2 = parseRange(arg3, field, skipnum2, startnum2, endnum2, numfiles, padding2, numpadding2);
// common->Printf(" + reading %s from %d to %d\n", file2[field], startnum2[field], endnum2[field]);
if (files1 != files2) {
common->Error( "You had %d files for %s and %d for %s!", files1, arg1.c_str(), files2, arg2.c_str() );
}
else {
realnum += files1;//not both, they are parallel
}
}
else {
common->Error("Error: invalid range on open (%s %s %s)\n", arg1.c_str(), arg2.c_str(), arg3.c_str() );
}
}
field++;
}
} while (token.Icmp( "end_input"));
}
}
if (TwentyFourToThirty()) realnum = realnum+(realnum>>2);
numInputFiles = realnum;
common->Printf(" + reading a total of %d frames in %s\n", numInputFiles, currentPath.c_str() );
delete src;
}
void roqParam::GetNthInputFileName( idStr &fileName, int n ) {
int i, myfield, index,hrs,mins,secs,frs;
char tempfile[33], left[256], right[256], *strp;
if ( n > realnum ) n = realnum;
// overcome starting at zero by ++ing and then --ing.
if (TwentyFourToThirty()) { n++; n = (n/5) * 4 + (n % 5); n--; }
i = 0;
myfield = 0;
while (i <= n) {
i += numfiles[myfield++];
}
myfield--;
i -= numfiles[myfield];
if ( range[myfield] == 1 ) {
strcpy( left, file[myfield] );
strp = strstr( left, "*" );
*strp++ = 0;
sprintf(right, "%s", strp);
if ( startnum[myfield] <= endnum[myfield] ) {
index = startnum[myfield] + ((n-i)*skipnum[myfield]);
} else {
index = startnum[myfield] - ((n-i)*skipnum[myfield]);
}
if ( padding[myfield] == true ) {
if (useTimecodeForRange) {
hrs = index/(30*60*60) ;
mins = (index/(30*60)) %60;
secs = (index/(30)) % 60;
frs = index % 30;
sprintf(fileName,"%s%.02d%.02d/%.02d%.02d%.02d%.02d%s",left,hrs,mins,hrs,mins,secs,frs,right);
}
else {
sprintf(tempfile, "%032d", index );
sprintf(fileName, "%s%s%s", left, &tempfile[ 32-numpadding[myfield] ], right );
}
} else {
if (useTimecodeForRange) {
hrs = index/(30*60*60) ;
mins = (index/(30*60)) %60;
secs = (index/(30)) % 60;
frs = index % 30;
sprintf(fileName,"%s%.02d%.02d/%.02d%.02d%.02d%.02d%s",left,hrs,mins,hrs,mins,secs,frs,right);
}
else {
sprintf(fileName, "%s%d%s", left, index, right );
}
}
} else if ( range[myfield] == 2 ) {
strcpy( left, file[myfield] );
strp = strstr( left, "*" );
*strp++ = 0;
sprintf(right, "%s", strp);
if ( startnum[myfield] <= endnum[myfield] ) {
index = startnum[myfield] + ((n-i)*skipnum[myfield]);
} else {
index = startnum[myfield] - ((n-i)*skipnum[myfield]);
}
if ( padding[myfield] == true ) {
sprintf(tempfile, "%032d", index );
sprintf(fileName, "%s%s%s", left, &tempfile[ 32-numpadding[myfield] ], right );
} else {
sprintf(fileName, "%s%d%s", left, index, right );
}
strcpy( left, file2[myfield] );
strp = strstr( left, "*" );
*strp++ = 0;
sprintf(right, "%s", strp);
if ( startnum2[myfield] <= endnum2[myfield] ) {
index = startnum2[myfield] + ((n-i)*skipnum2[myfield]);
} else {
index = startnum2[myfield] - ((n-i)*skipnum2[myfield]);
}
if ( padding2[myfield] == true ) {
sprintf(tempfile, "%032d", index );
fileName += va( "\n%s%s%s", left, &tempfile[ 32-numpadding2[myfield] ], right );
} else {
fileName += va( "\n%s%d%s", left, index, right );
}
} else {
fileName = file[myfield];
}
}
const char* roqParam::GetNextImageFilename( void ) {
idStr tempBuffer;
int i;
int len;
GetNthInputFileName( tempBuffer, onFrame++);
if ( justDeltaFlag == true ) {
onFrame--;
justDeltaFlag = false;
}
if ( addPath == true ) {
currentFile = currentPath + "/" + tempBuffer;
} else {
currentFile = tempBuffer;
}
len = currentFile.Length();
for(i=0;i<len;i++) {
if (currentFile[i] == '^') {
currentFile[i] = ' ';
}
}
return currentFile.c_str();
}
const char* roqParam::RoqFilename( void ) {
return outputFilename.c_str();
}
const char* roqParam::SoundFilename( void ) {
return soundfile.c_str();
}
const char* roqParam::RoqTempFilename( void ) {
int i, j, len;
j = 0;
len = outputFilename.Length();
for(i=0; i<len; i++ )
if ( outputFilename[i] == '/' ) j = i;
sprintf(tempFilename, "/%s.temp", &outputFilename[j+1] );
return tempFilename.c_str();
}
bool roqParam::Timecode( void ) {
return useTimecodeForRange;
}
bool roqParam::OutputVectors( void ) {
return makeVectors;
}
bool roqParam::HasSound( void ) {
return hasSound;
}
bool roqParam::DeltaFrames( void ) {
return justDelta;
}
bool roqParam::NoAlpha( void ) {
return noAlphaAtAll;
}
bool roqParam::SearchType( void ) {
return fullSearch;
}
bool roqParam::MoreFrames( void ) {
if (onFrame < numInputFiles) {
return true;
} else {
return false;
}
}
bool roqParam::TwentyFourToThirty( void ) {
return twentyFourToThirty;
}
int roqParam::NumberOfFrames( void ) {
return numInputFiles;
}
int roqParam::FirstFrameSize( void ) {
return firstframesize;
}
int roqParam::NormalFrameSize( void ) {
return normalframesize;
}
bool roqParam::IsScaleable( void ) {
return isScaleable;
}
int roqParam::JpegQuality( void ) {
return jpegDefault;
}
int parseRange(const char *rangeStr,int field, int skipnum[], int startnum[], int endnum[],int numfiles[],bool padding[],int numpadding[] ) {
char start[64], end[64], skip[64];
char *stptr, *enptr, *skptr;
int i,realnum;
i = 1;
realnum = 0;
stptr = start;
enptr = end;
skptr = skip;
do {
*stptr++ = rangeStr[i++];
} while ( rangeStr[i] >= '0' && rangeStr[i] <= '9' );
*stptr = '\0';
if ( rangeStr[i++] != '-' ) {
common->Error("Error: invalid range on middle \n");
}
do {
*enptr++ = rangeStr[i++];
} while ( rangeStr[i] >= '0' && rangeStr[i] <= '9' );
*enptr = '\0';
if ( rangeStr[i] != ']' ) {
if ( rangeStr[i++] != '+' ) {
common->Error("Error: invalid range on close\n");
}
do {
*skptr++ = rangeStr[i++];
} while ( rangeStr[i] >= '0' && rangeStr[i] <= '9' );
*skptr = '\0';
skipnum[field] = atoi( skip );
} else {
skipnum[field] = 1;
}
startnum[field] = atoi( start );
endnum[field] = atoi( end );
numfiles[field] = (abs( startnum[field] - endnum[field] ) / skipnum[field]) + 1;
realnum += numfiles[field];
if ( start[0] == '0' && start[1] != '\0' ) {
padding[field] = true;
numpadding[field] = strlen( start );
} else {
padding[field] = false;
}
return realnum;
}
int parseTimecodeRange(const char *rangeStr,int field, int skipnum[], int startnum[], int endnum[],int numfiles[],bool padding[],int numpadding[] )
{
char start[64], end[64], skip[64];
char *stptr, *enptr, *skptr;
int i,realnum,hrs,mins,secs,frs;
i = 1;//skip the '['
realnum = 0;
stptr = start;
enptr = end;
skptr = skip;
do {
*stptr++ = rangeStr[i++];
} while ( rangeStr[i] >= '0' && rangeStr[i] <= '9' );
*stptr = '\0';
if ( rangeStr[i++] != '-' ) {
common->Error("Error: invalid range on middle \n");
}
do {
*enptr++ = rangeStr[i++];
} while ( rangeStr[i] >= '0' && rangeStr[i] <= '9' );
*enptr = '\0';
if ( rangeStr[i] != ']' ) {
if ( rangeStr[i++] != '+' ) {
common->Error("Error: invalid range on close\n");
}
do {
*skptr++ = rangeStr[i++];
} while ( rangeStr[i] >= '0' && rangeStr[i] <= '9' );
*skptr = '\0';
skipnum[field] = atoi( skip );
} else {
skipnum[field] = 1;
}
sscanf(start,"%2d%2d%2d%2d",&hrs,&mins,&secs,&frs);
startnum[field] = hrs*30*60*60 + mins *60*30 + secs*30 +frs;
sscanf(end,"%2d%2d%2d%2d",&hrs,&mins,&secs,&frs);
endnum[field] = hrs*30*60*60 + mins *60*30 + secs*30 +frs;
numfiles[field] = (abs( startnum[field] - endnum[field] ) / skipnum[field]) + 1;
realnum += numfiles[field];
if ( start[0] == '0' && start[1] != '\0' ) {
padding[field] = true;
numpadding[field] = strlen( start );
} else {
padding[field] = false;
}
return realnum;
}
+105
View File
@@ -0,0 +1,105 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code 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.
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
===========================================================================
*/
#ifndef __roqParam_h__
#define __roqParam_h__
#include "gdefs.h"
#pragma once
class roqParam
{
public:
const char* RoqFilename( void );
const char* RoqTempFilename( void );
const char* GetNextImageFilename( void );
const char* SoundFilename( void );
void InitFromFile( const char *fileName );
void GetNthInputFileName( idStr &fileName, int n);
bool MoreFrames( void );
bool OutputVectors( void );
bool Timecode( void );
bool DeltaFrames( void );
bool NoAlpha( void );
bool SearchType( void );
bool TwentyFourToThirty( void );
bool HasSound( void );
int NumberOfFrames( void );
int NormalFrameSize( void );
int FirstFrameSize( void );
int JpegQuality( void );
bool IsScaleable( void );
idStr outputFilename;
int numInputFiles;
private:
int *range;
bool *padding, *padding2;
idStrList file;
idStrList file2;
idStr soundfile;
idStr currentPath;
idStr tempFilename;
idStr startPal;
idStr endPal;
idStr currentFile;
int *skipnum, *skipnum2;
int *startnum, *startnum2;
int *endnum, *endnum2;
int *numpadding, *numpadding2;
int *numfiles;
byte keyR, keyG, keyB;
int field;
int realnum;
int onFrame;
int firstframesize;
int normalframesize;
int jpegDefault;
bool scaleDown;
bool twentyFourToThirty;
bool encodeVideo;
bool useTimecodeForRange;
bool addPath;
bool screenShots;
bool startPalette;
bool endPalette;
bool fixedPalette;
bool keyColor;
bool justDelta;
bool make3DO;
bool makeVectors;
bool justDeltaFlag;
bool noAlphaAtAll;
bool fullSearch;
bool hasSound;
bool isScaleable;
};
#endif // roqParam
File diff suppressed because it is too large Load Diff