mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-10 07:12:07 +00:00
Add support of smacker files
https://sourceforge.net/projects/libsmacker/files/libsmacker-1.2/ libsmacker is released under the Lesser GNU Public License, v2.1.
This commit is contained in:
parent
85ebca9979
commit
c898573885
6 changed files with 2106 additions and 13 deletions
1
Makefile
1
Makefile
|
@ -853,6 +853,7 @@ CLIENT_OBJS_ := \
|
|||
src/client/curl/download.o \
|
||||
src/client/curl/qcurl.o \
|
||||
src/client/input/sdl.o \
|
||||
src/client/cinema/smacker.o \
|
||||
src/client/menu/menu.o \
|
||||
src/client/menu/qmenu.o \
|
||||
src/client/menu/videomenu.o \
|
||||
|
|
1797
src/client/cinema/smacker.c
Normal file
1797
src/client/cinema/smacker.c
Normal file
File diff suppressed because it is too large
Load diff
103
src/client/cinema/smacker.h
Normal file
103
src/client/cinema/smacker.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
libsmacker - A C library for decoding .smk Smacker Video files
|
||||
Copyright (C) 2012-2020 Greg Kennedy
|
||||
|
||||
libsmacker is a cross-platform C library which can be used for
|
||||
decoding Smacker Video files produced by RAD Game Tools.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SMACKER_H
|
||||
#define SMACKER_H
|
||||
|
||||
/* includes - needed for FILE* here */
|
||||
#include <stdio.h>
|
||||
|
||||
/** forward-declaration for an struct */
|
||||
typedef struct smk_t * smk;
|
||||
|
||||
/** a few defines as return codes from smk_next() */
|
||||
#define SMK_DONE 0x00
|
||||
#define SMK_MORE 0x01
|
||||
#define SMK_LAST 0x02
|
||||
#define SMK_ERROR -1
|
||||
|
||||
/** file-processing mode, pass to smk_open_file */
|
||||
#define SMK_MODE_DISK 0x00
|
||||
#define SMK_MODE_MEMORY 0x01
|
||||
|
||||
/** Y-scale meanings */
|
||||
#define SMK_FLAG_Y_NONE 0x00
|
||||
#define SMK_FLAG_Y_INTERLACE 0x01
|
||||
#define SMK_FLAG_Y_DOUBLE 0x02
|
||||
|
||||
/** track mask and enable bits */
|
||||
#define SMK_AUDIO_TRACK_0 0x01
|
||||
#define SMK_AUDIO_TRACK_1 0x02
|
||||
#define SMK_AUDIO_TRACK_2 0x04
|
||||
#define SMK_AUDIO_TRACK_3 0x08
|
||||
#define SMK_AUDIO_TRACK_4 0x10
|
||||
#define SMK_AUDIO_TRACK_5 0x20
|
||||
#define SMK_AUDIO_TRACK_6 0x40
|
||||
#define SMK_VIDEO_TRACK 0x80
|
||||
|
||||
/* PUBLIC FUNCTIONS */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* OPEN OPERATIONS */
|
||||
/** open an smk (from a file) */
|
||||
smk smk_open_file(const char * filename, unsigned char mode);
|
||||
/** open an smk (from a file pointer) */
|
||||
smk smk_open_filepointer(FILE * file, unsigned char mode);
|
||||
/** read an smk (from a memory buffer) */
|
||||
smk smk_open_memory(const unsigned char * buffer, unsigned long size);
|
||||
|
||||
/* CLOSE OPERATIONS */
|
||||
/** close out an smk file and clean up memory */
|
||||
void smk_close(smk object);
|
||||
|
||||
/* GET FILE INFO OPERATIONS */
|
||||
char smk_info_all(const smk object, unsigned long * frame, unsigned long * frame_count, double * usf);
|
||||
char smk_info_video(const smk object, unsigned long * w, unsigned long * h, unsigned char * y_scale_mode);
|
||||
char smk_info_audio(const smk object, unsigned char * track_mask, unsigned char channels[7], unsigned char bitdepth[7], unsigned long audio_rate[7]);
|
||||
|
||||
/* ENABLE/DISABLE Switches */
|
||||
char smk_enable_all(smk object, unsigned char mask);
|
||||
char smk_enable_video(smk object, unsigned char enable);
|
||||
char smk_enable_audio(smk object, unsigned char track, unsigned char enable);
|
||||
|
||||
/** Retrieve palette */
|
||||
const unsigned char * smk_get_palette(const smk object);
|
||||
/** Retrieve video frame, as a buffer of size w*h */
|
||||
const unsigned char * smk_get_video(const smk object);
|
||||
/** Retrieve decoded audio chunk, track N */
|
||||
const unsigned char * smk_get_audio(const smk object, unsigned char track);
|
||||
/** Get size of currently pointed decoded audio chunk, track N */
|
||||
unsigned long smk_get_audio_size(const smk object, unsigned char track);
|
||||
|
||||
/** rewind to first frame and unpack */
|
||||
char smk_first(smk object);
|
||||
/** advance to next frame and unpack */
|
||||
char smk_next(smk object);
|
||||
/** seek to first keyframe before/at N in an smk */
|
||||
char smk_seek_keyframe(smk object, unsigned long frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
56
src/client/cinema/smk_malloc.h
Normal file
56
src/client/cinema/smk_malloc.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
libsmacker - A C library for decoding .smk Smacker Video files
|
||||
Copyright (C) 2012-2017 Greg Kennedy
|
||||
|
||||
See smacker.h for more information.
|
||||
|
||||
smk_malloc.h
|
||||
"Safe" implementations of malloc and free.
|
||||
Verbose implementation of assert.
|
||||
*/
|
||||
|
||||
#ifndef SMK_MALLOC_H
|
||||
#define SMK_MALLOC_H
|
||||
|
||||
/* assert */
|
||||
#include <assert.h>
|
||||
/* calloc */
|
||||
#include <stdlib.h>
|
||||
/* fprintf */
|
||||
#include <stdio.h>
|
||||
|
||||
/* Error messages from calloc */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
Safe free: attempts to prevent double-free by setting pointer to NULL.
|
||||
Optionally warns on attempts to free a NULL pointer.
|
||||
*/
|
||||
#define smk_free(p) \
|
||||
{ \
|
||||
assert (p); \
|
||||
free(p); \
|
||||
p = NULL; \
|
||||
}
|
||||
|
||||
/**
|
||||
Safe malloc: exits if calloc() returns NULL.
|
||||
Also initializes blocks to 0.
|
||||
Optionally warns on attempts to malloc over an existing pointer.
|
||||
Ideally, one should not exit() in a library. However, if you cannot
|
||||
calloc(), you probably have bigger problems.
|
||||
*/
|
||||
#define smk_malloc(p, x) \
|
||||
{ \
|
||||
assert (p == NULL); \
|
||||
p = calloc(1, x); \
|
||||
if (!p) \
|
||||
{ \
|
||||
fprintf(stderr, "libsmacker::smk_malloc(" #p ", %lu) - ERROR: calloc() returned NULL (file: %s, line: %lu)\n\tReason: [%d] %s\n", \
|
||||
(unsigned long) (x), __FILE__, (unsigned long)__LINE__, errno, strerror(errno)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "header/client.h"
|
||||
#include "input/header/input.h"
|
||||
#include "cinema/smacker.h"
|
||||
|
||||
// don't need HDR stuff
|
||||
#define STBI_NO_LINEAR
|
||||
|
@ -55,6 +56,12 @@ typedef struct
|
|||
int count;
|
||||
} cblock_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
video_cin,
|
||||
video_smk,
|
||||
} cinema_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean restart_sound;
|
||||
|
@ -64,10 +71,13 @@ typedef struct
|
|||
|
||||
int width;
|
||||
int height;
|
||||
float fps;
|
||||
int color_bits;
|
||||
cinema_t video_type;
|
||||
byte *pic;
|
||||
byte *pic_pending;
|
||||
|
||||
/* cin video */
|
||||
/* order 1 huffman stuff */
|
||||
int *hnodes1;
|
||||
|
||||
|
@ -76,11 +86,17 @@ typedef struct
|
|||
|
||||
int h_used[512];
|
||||
int h_count[512];
|
||||
|
||||
/* shared video buffer */
|
||||
void *raw_video;
|
||||
|
||||
/* smacker video */
|
||||
smk smk_video;
|
||||
} cinematics_t;
|
||||
|
||||
cinematics_t cin;
|
||||
|
||||
void
|
||||
static void
|
||||
SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height)
|
||||
{
|
||||
byte *raw;
|
||||
|
@ -184,6 +200,18 @@ SCR_StopCinematic(void)
|
|||
{
|
||||
cl.cinematictime = 0; /* done */
|
||||
|
||||
if (cin.smk_video)
|
||||
{
|
||||
smk_close(cin.smk_video);
|
||||
cin.smk_video = NULL;
|
||||
}
|
||||
|
||||
if (cin.raw_video)
|
||||
{
|
||||
FS_FreeFile(cin.raw_video);
|
||||
cin.raw_video = NULL;
|
||||
}
|
||||
|
||||
if (cin.pic)
|
||||
{
|
||||
Z_Free(cin.pic);
|
||||
|
@ -230,7 +258,7 @@ SCR_FinishCinematic(void)
|
|||
SZ_Print(&cls.netchan.message, va("nextserver %i\n", cl.servercount));
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
SmallestNode1(int numhnodes)
|
||||
{
|
||||
int i;
|
||||
|
@ -270,7 +298,7 @@ SmallestNode1(int numhnodes)
|
|||
/*
|
||||
* Reads the 64k counts table and initializes the node trees
|
||||
*/
|
||||
void
|
||||
static void
|
||||
Huff1TableInit(void)
|
||||
{
|
||||
int prev;
|
||||
|
@ -327,7 +355,7 @@ Huff1TableInit(void)
|
|||
}
|
||||
}
|
||||
|
||||
cblock_t
|
||||
static cblock_t
|
||||
Huff1Decompress(cblock_t in)
|
||||
{
|
||||
byte *input;
|
||||
|
@ -385,7 +413,40 @@ Huff1Decompress(cblock_t in)
|
|||
return out;
|
||||
}
|
||||
|
||||
byte *
|
||||
static byte *
|
||||
SCR_ReadNextSMKFrame(void)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
byte *buffer = Z_Malloc(cin.height * cin.width);
|
||||
|
||||
/* audio */
|
||||
count = smk_get_audio_size(cin.smk_video, 0);
|
||||
if (count && cin.s_channels)
|
||||
{
|
||||
count /= (cin.s_width * cin.s_channels);
|
||||
S_RawSamples(count, cin.s_rate, cin.s_width, cin.s_channels,
|
||||
smk_get_audio(cin.smk_video, 0), Cvar_VariableValue("s_volume"));
|
||||
}
|
||||
|
||||
/* update palette */
|
||||
memcpy(cl.cinematicpalette, smk_get_palette(cin.smk_video), sizeof(cl.cinematicpalette));
|
||||
cl.cinematicpalette_active = 0;
|
||||
|
||||
/* get pic */
|
||||
memcpy(buffer, smk_get_video(cin.smk_video), cin.height * cin.width);
|
||||
cl.cinematicframe++;
|
||||
|
||||
if (smk_next(cin.smk_video) != SMK_MORE)
|
||||
{
|
||||
Z_Free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static byte *
|
||||
SCR_ReadNextFrame(void)
|
||||
{
|
||||
int r;
|
||||
|
@ -442,8 +503,8 @@ SCR_ReadNextFrame(void)
|
|||
FS_Read(compressed, size, cl.cinematic_file);
|
||||
|
||||
/* read sound */
|
||||
start = cl.cinematicframe * cin.s_rate / 14;
|
||||
end = (cl.cinematicframe + 1) * cin.s_rate / 14;
|
||||
start = cl.cinematicframe * cin.s_rate / cin.fps;
|
||||
end = (cl.cinematicframe + 1) * cin.s_rate / cin.fps;
|
||||
count = end - start;
|
||||
|
||||
FS_Read(samples, count * cin.s_width * cin.s_channels,
|
||||
|
@ -491,11 +552,11 @@ SCR_RunCinematic(void)
|
|||
if (cls.key_dest != key_game)
|
||||
{
|
||||
/* pause if menu or console is up */
|
||||
cl.cinematictime = cls.realtime - cl.cinematicframe * 1000 / 14;
|
||||
cl.cinematictime = cls.realtime - cl.cinematicframe * 1000 / cin.fps;
|
||||
return;
|
||||
}
|
||||
|
||||
frame = (cls.realtime - cl.cinematictime) * 14.0 / 1000;
|
||||
frame = (cls.realtime - cl.cinematictime) * cin.fps / 1000;
|
||||
|
||||
if (frame <= cl.cinematicframe)
|
||||
{
|
||||
|
@ -505,7 +566,7 @@ SCR_RunCinematic(void)
|
|||
if (frame > cl.cinematicframe + 1)
|
||||
{
|
||||
Com_Printf("Dropped frame: %i > %i\n", frame, cl.cinematicframe + 1);
|
||||
cl.cinematictime = cls.realtime - cl.cinematicframe * 1000 / 14;
|
||||
cl.cinematictime = cls.realtime - cl.cinematicframe * 1000 / cin.fps;
|
||||
}
|
||||
|
||||
if (cin.pic)
|
||||
|
@ -515,7 +576,15 @@ SCR_RunCinematic(void)
|
|||
|
||||
cin.pic = cin.pic_pending;
|
||||
cin.pic_pending = NULL;
|
||||
cin.pic_pending = SCR_ReadNextFrame();
|
||||
switch (cin.video_type)
|
||||
{
|
||||
case video_cin:
|
||||
cin.pic_pending = SCR_ReadNextFrame();
|
||||
break;
|
||||
case video_smk:
|
||||
cin.pic_pending = SCR_ReadNextSMKFrame();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cin.pic_pending)
|
||||
{
|
||||
|
@ -647,7 +716,7 @@ SCR_DrawCinematic(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
byte *
|
||||
static byte *
|
||||
SCR_LoadHiColor(const char* namewe, const char *ext, int *width, int *height)
|
||||
{
|
||||
char filename[256];
|
||||
|
@ -754,6 +823,69 @@ SCR_PlayCinematic(char *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
if (dot && !strcmp(dot, ".smk"))
|
||||
{
|
||||
unsigned char trackmask, channels[7], depth[7];
|
||||
unsigned long width, height;
|
||||
unsigned long rate[7];
|
||||
double usf; /* microseconds per frame */
|
||||
size_t len;
|
||||
|
||||
Com_sprintf(name, sizeof(name), "video/%s", arg);
|
||||
len = FS_LoadFile(name, &cin.raw_video);
|
||||
|
||||
if (!cin.raw_video || len <=0)
|
||||
{
|
||||
cl.cinematictime = 0; /* done */
|
||||
return;
|
||||
}
|
||||
|
||||
cin.smk_video = smk_open_memory(cin.raw_video, len);
|
||||
if (!cin.smk_video)
|
||||
{
|
||||
FS_FreeFile(cin.raw_video);
|
||||
cin.raw_video = NULL;
|
||||
cl.cinematictime = 0; /* done */
|
||||
return;
|
||||
}
|
||||
|
||||
SCR_EndLoadingPlaque();
|
||||
|
||||
cin.color_bits = 8;
|
||||
cls.state = ca_active;
|
||||
|
||||
smk_info_audio(cin.smk_video, &trackmask, channels, depth, rate);
|
||||
if (trackmask != SMK_AUDIO_TRACK_0)
|
||||
{
|
||||
Com_Printf("%s has different track mask %d.\n", name, trackmask);
|
||||
cin.s_channels = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cin.s_rate = rate[0];
|
||||
cin.s_width = depth[0] / 8;
|
||||
cin.s_channels = channels[0];
|
||||
smk_enable_audio(cin.smk_video, 0, true);
|
||||
}
|
||||
|
||||
smk_info_all(cin.smk_video, NULL, NULL, &usf);
|
||||
smk_info_video(cin.smk_video, &width, &height, NULL);
|
||||
smk_enable_video(cin.smk_video, true);
|
||||
cin.width = width;
|
||||
cin.height = height;
|
||||
cin.fps = 1000000.0f / usf;
|
||||
|
||||
/* process first frame */
|
||||
smk_first(cin.smk_video);
|
||||
|
||||
cl.cinematicframe = 0;
|
||||
cin.pic = SCR_ReadNextSMKFrame();
|
||||
cl.cinematictime = Sys_Milliseconds();
|
||||
|
||||
cin.video_type = video_smk;
|
||||
return;
|
||||
}
|
||||
|
||||
Com_sprintf(name, sizeof(name), "video/%s", arg);
|
||||
FS_FOpenFile(name, &cl.cinematic_file, false);
|
||||
|
||||
|
@ -773,6 +905,7 @@ SCR_PlayCinematic(char *arg)
|
|||
FS_Read(&height, 4, cl.cinematic_file);
|
||||
cin.width = LittleLong(width);
|
||||
cin.height = LittleLong(height);
|
||||
cin.fps = 14.0f;
|
||||
|
||||
FS_Read(&cin.s_rate, 4, cl.cinematic_file);
|
||||
cin.s_rate = LittleLong(cin.s_rate);
|
||||
|
@ -786,5 +919,7 @@ SCR_PlayCinematic(char *arg)
|
|||
cl.cinematicframe = 0;
|
||||
cin.pic = SCR_ReadNextFrame();
|
||||
cl.cinematictime = Sys_Milliseconds();
|
||||
|
||||
cin.video_type = video_cin;
|
||||
}
|
||||
|
||||
|
|
|
@ -544,7 +544,8 @@ SV_Map(qboolean attractloop, char *levelstring, qboolean loadgame, qboolean isau
|
|||
--l;
|
||||
}
|
||||
|
||||
if ((l > 4) && !strcmp(level + l - 4, ".cin"))
|
||||
if ((l > 4) && (!strcmp(level + l - 4, ".cin") ||
|
||||
!strcmp(level + l - 4, ".smk")))
|
||||
{
|
||||
#ifndef DEDICATED_ONLY
|
||||
SCR_BeginLoadingPlaque(); /* for local system */
|
||||
|
|
Loading…
Reference in a new issue