Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SmackerLib API #303

Merged
merged 14 commits into from
Apr 19, 2023
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ option(DETHRACE_FIX_BUGS "Fix Dethrace bugs" ON)

add_subdirectory(src/harness)
add_subdirectory(src/S3)
add_subdirectory(src/smackw32)
add_subdirectory(src/BRSRC13)
add_subdirectory(src/DETHRACE)

Expand Down
19 changes: 12 additions & 7 deletions docs/CODE_LAYOUT.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,32 @@
### DETHRACE
Game logic. According to the symbol dump, these files were originally stored in `C:\DETHRACE\src`.

- `DETHRACE/common` - all common logic
- `DETHRACE/pc-dos` - all platform-specific functions (DOS, in this case)
- `DETHRACE/common` - common game logic
- `DETHRACE/pc-dos` - DOS-specific functions
- `DETHRACE/win95sys.c` - Windows-specific functions
- `DETHRACE/pd` - platform-dependent generic headers.

_All code here is kept as similar to how we think the original code might have been. Any changes required are implemented as hooks into `harness`._
_All code here is kept as similar to how we think the original code might have looked. Any changes required are implemented as hooks into `harness`._

### BRSRC13

Graphics rendering library. [BRender](https://en.wikipedia.org/wiki/Argonaut_Games#BRender), originally stored in `C:\BRSRC13`.

- Stainless Software used their own build of BRender with unknown modifications.

_All code here is kept as similar to how we think the original code might have been. Any changes required are implemented as hooks into `harness`._
_All code here is kept as similar to how we think the original code might have looked. Any changes required are implemented as hooks into `harness`._

### S3

Audio library. No other information.
Audio library. Possibly short for "Stainless Sound System"?! Supports at least two audio backends - [SOS](http://web.archive.org/web/19990221132448/http://www.humanmachine.com/sos.html) (DOS) and DirectSound.

_All code here is kept as similar to how we think the original code might have been. Any changes required are implemented as hooks into `harness`._
_All code here is kept as similar to how we think the original code might have looked, with the addition of a small amount of code integrating [miniaudio](https://miniaud.io)

### smackw32

Implements the [RAD Smacker lib](https://wiki.multimedia.cx/index.php/RAD_Game_Tools_Smacker_API) interface. The implementation is backed by [libsmacker](https://libsmacker.sourceforge.net/).

### harness

- Provides functions that the original game logic calls to implement modern cross-platform support.
- SDL2 for windowing + input + networking, OpenGL for rendering, OpenAL for audio
- SDL2, OpenGL, miniaudio
12 changes: 6 additions & 6 deletions lib/libsmacker/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo" FORCE)
endif()

project(smacker C)
project(libsmacker C)

add_library(smacker STATIC)
add_library(libsmacker STATIC)

target_include_directories(smacker PUBLIC
target_include_directories(libsmacker PUBLIC
.
)

if(NOT MSVC)
target_compile_options(smacker PRIVATE -Wall)
target_compile_options(libsmacker PRIVATE -Wall)
else()
target_compile_definitions(smacker PRIVATE -D_CRT_SECURE_NO_WARNINGS)
target_compile_definitions(libsmacker PRIVATE -D_CRT_SECURE_NO_WARNINGS)
endif()

target_sources(smacker PRIVATE
target_sources(libsmacker PRIVATE
smacker.c
smk_bitstream.c
smk_hufftree.c
Expand Down
2 changes: 1 addition & 1 deletion src/DETHRACE/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ target_include_directories(dethrace_obj
pd
)

target_link_libraries(dethrace_obj PUBLIC SDL2::SDL2 smacker harness brender s3)
target_link_libraries(dethrace_obj PUBLIC SDL2::SDL2 smackw32 harness brender s3)


if (CMAKE_C_COMPILER_ID MATCHES "MSVC")
Expand Down
75 changes: 28 additions & 47 deletions src/DETHRACE/common/cutscene.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "input.h"
#include "loading.h"
#include "pd/sys.h"
#include "smacker.h"
#include "smackw32/smackw32.h"
#include "sound.h"
#include "utility.h"
#include <stdlib.h>
Expand Down Expand Up @@ -60,94 +60,75 @@ void PlaySmackerFile(char* pSmack_name) {
tPath_name the_path;
br_colour* br_colours_ptr;
tU8* smack_colours_ptr;
// Smack* smk;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I was able to reverse the logic for carmageddon 2: https://github.com/madebr/rec2/blob/master/src/carma2/common/cutscene.c

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome. So much similarity. I'm sad they got rid of the fuck_off variable :P

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind, I forgot you have to make up your own names. Well, probably what you have as keyPressed is really still fuck_off in the OG code! :)

Smack* smk;
int i;
int j;
int len;
int fuck_off;

LOG_TRACE("(\"%s\")", pSmack_name);

smk s;
br_uint_8* dest_pix = (br_uint_8*)gBack_screen->pixels;
unsigned long w, h, f;
unsigned char r, g, b;
double usf;
tU32 last_frame_time;

if (!gSound_override && !gCut_scene_override) {
StopMusic();
FadePaletteDown();
ClearEntireScreen();
SmackSoundUseDirectSound(NULL);
br_colours_ptr = gCurrent_palette->pixels;
PathCat(the_path, gApplication_path, "CUTSCENE");
PathCat(the_path, the_path, pSmack_name);

dr_dprintf("Trying to open smack file '%s'", the_path);
s = smk_open_file(the_path, SMK_MODE_MEMORY);
if (s == NULL) {
smk = SmackOpen(the_path, SMACKTRACKS, SMACKAUTOEXTRA);
if (smk == NULL) {
dr_dprintf("Unable to open smack file - attempt to load smack from CD...");
if (GetCDPathFromPathsTxtFile(the_path)) {
strcat(the_path, gDir_separator);
strcat(the_path, "DATA");
PathCat(the_path, the_path, "CUTSCENE");
PathCat(the_path, the_path, pSmack_name);
if (PDCheckDriveExists(the_path)) {
s = smk_open_file(the_path, SMK_MODE_MEMORY);
smk = SmackOpen(the_path, SMACKTRACKS, SMACKAUTOEXTRA);
}
} else {
dr_dprintf("Can't get CD directory name");
}
}
if (s != NULL) {
if (smk != NULL) {
dr_dprintf("Smack file opened OK");
smk_info_all(s, NULL, &f, &usf);
smk_info_video(s, &w, &h, NULL);
double fps = 1000000.0 / usf;
int delay_ms = (1 / fps) * 1000;

smk_enable_video(s, 1);

smk_first(s);
do {
const unsigned char* pal = smk_get_palette(s);
for (i = 0; i < 256; i++) {
r = pal[(i * 3)];
g = pal[(i * 3) + 1];
b = pal[(i * 3) + 2];
br_colours_ptr[i] = b | (g << 8) | (r << 16);
}
DRSetPalette(gCurrent_palette);
EnsurePaletteUp();
for (i = 1; i <= smk->Frames; i++) {
SmackToBuffer(smk, 0, 0, gBack_screen->row_bytes, gBack_screen->height, gBack_screen->pixels, 0);

const unsigned char* frame = smk_get_video(s);
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
dest_pix[(i * gBack_screen->row_bytes) + j] = frame[i * w + j];
if (smk->NewPalette) {
smack_colours_ptr = smk->Palette;
for (j = 0; j < 256; j++) {
br_colours_ptr[j] = (smack_colours_ptr[j * 3] << 16) | smack_colours_ptr[j * 3 + 2] | (smack_colours_ptr[j * 3 + 1] << 8);
}

// TOOD: remove the commented-out line below when smk->NewPalette is set correctly per-frame
// memset(gBack_screen->pixels, 0, gBack_screen->row_bytes * gBack_screen->height);
DRSetPalette(gCurrent_palette);
PDScreenBufferSwap(0);
EnsurePaletteUp();
}

SmackDoFrame(smk);
if (i != smk->Frames) {
SmackNextFrame(smk);
}
PDScreenBufferSwap(0);
last_frame_time = PDGetTotalTime();

do {
fuck_off = AnyKeyDown() || EitherMouseButtonDown();
// added by dethrace to avoid 100% cpu
gHarness_platform.Sleep(1);
} while (!fuck_off && PDGetTotalTime() - last_frame_time < delay_ms);
} while (!fuck_off && SmackWait(smk));
if (fuck_off) {
break;
}
} while (smk_next(s) == SMK_MORE);

smk_close(s);

}
FadePaletteDown();
ClearEntireScreen();
StartMusic();
SmackClose(smk);
} else {
dr_dprintf("Smack file '%s' failed to open", pSmack_name);
StartMusic();
}
StartMusic();
}
}

Expand Down
56 changes: 0 additions & 56 deletions src/DETHRACE/dr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2942,62 +2942,6 @@ typedef struct _tag_sos_timer_system {
W32 wMIDIActiveSongHandle;
} _SOS_TIMER_SYSTEM;

typedef struct SmackTag {
unsigned long Version;
unsigned long Width;
unsigned long Height;
unsigned long Frames;
unsigned long MSPerFrame;
unsigned long SmackerType;
unsigned long LargestInTrack[7];
unsigned long tablesize;
unsigned long codesize;
unsigned long absize;
unsigned long detailsize;
unsigned long typesize;
unsigned long TrackType[7];
unsigned long extra;
unsigned long NewPalette;
unsigned char Palette[772];
unsigned long PalType;
unsigned long FrameNum;
unsigned long FrameSize;
unsigned long SndSize;
unsigned long LastRectx;
unsigned long LastRecty;
unsigned long LastRectw;
unsigned long LastRecth;
unsigned long OpenFlags;
unsigned long LeftOfs;
unsigned long TopOfs;
unsigned long ReadError;
unsigned long addr32;
} Smack;

typedef struct SmackSumTag {
unsigned long TotalTime;
unsigned long MS100PerFrame;
unsigned long TotalOpenTime;
unsigned long TotalFrames;
unsigned long SkippedFrames;
unsigned long SoundSkips;
unsigned long TotalBlitTime;
unsigned long TotalReadTime;
unsigned long TotalDecompTime;
unsigned long TotalBackReadTime;
unsigned long TotalReadSpeed;
unsigned long SlowestFrameTime;
unsigned long Slowest2FrameTime;
unsigned long SlowestFrameNum;
unsigned long Slowest2FrameNum;
unsigned long AverageFrameSize;
unsigned long Highest1SecRate;
unsigned long Highest1SecFrame;
unsigned long HighestMemAmount;
unsigned long TotalExtraMemory;
unsigned long HighestExtraUsed;
} SmackSum;

#ifndef _WIN32
typedef struct _heapinfo {
void* _pentry;
Expand Down
3 changes: 1 addition & 2 deletions src/harness/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ if(DETHRACE_FIX_BUGS)
target_compile_definitions(harness PRIVATE DETHRACE_FIX_BUGS)
endif()

target_link_libraries(harness PRIVATE brender compile_with_werror)
target_link_libraries(harness PRIVATE brender s3 compile_with_werror)

if(WIN32)
target_link_libraries(harness PRIVATE dbghelp)
Expand Down Expand Up @@ -89,7 +89,6 @@ if (IO_PLATFORM STREQUAL "SDL_OpenGL")
resources/3d_frag.glsl.h
)
target_include_directories(harness PRIVATE "${dethrace_SOURCE_DIR}/src/DETHRACE/common")
target_include_directories(harness PRIVATE "${dethrace_SOURCE_DIR}/src/S3/include")
target_link_libraries(harness PRIVATE SDL2::SDL2 glad)
endif()

Expand Down
24 changes: 24 additions & 0 deletions src/smackw32/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
add_library(smackw32 STATIC)

target_include_directories(smackw32
PUBLIC
include
PRIVATE
${CMAKE_SOURCE_DIR}
)

target_link_libraries(smackw32 PRIVATE harness brender libsmacker compile_with_werror)

if(NOT MSVC)

else()
target_compile_definitions(smackw32 PRIVATE -D_CRT_SECURE_NO_WARNINGS)
target_compile_options(smackw32 PRIVATE
/wd4101
/wd4996
)
endif()

target_sources(smackw32 PRIVATE
smackw32.c
)
10 changes: 10 additions & 0 deletions src/smackw32/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# smackw32

Implementation of a minimal form of the Smacker API used by dethrace.

See:
- https://wiki.multimedia.cx/index.php/RAD_Game_Tools_Smacker_API
- https://github.com/OpenSourcedGames/Aliens-vs-Predator/blob/master/source/AvP_vc/3dc/win95/SMACK.H


Backed by http://libsmacker.sourceforge.net
55 changes: 55 additions & 0 deletions src/smackw32/include/smackw32/smackw32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include <stddef.h>
#include <stdint.h>

#define SMACKTRACK1 0x02000 // Play audio track 1
#define SMACKTRACK2 0x04000 // Play audio track 2
#define SMACKTRACK3 0x08000 // Play audio track 3
#define SMACKTRACK4 0x10000 // Play audio track 4
#define SMACKTRACK5 0x20000 // Play audio track 5
#define SMACKTRACK6 0x40000 // Play audio track 6
#define SMACKTRACK7 0x80000 // Play audio track 7
#define SMACKTRACKS (SMACKTRACK1 | SMACKTRACK2 | SMACKTRACK3 | SMACKTRACK4 | SMACKTRACK5 | SMACKTRACK6 | SMACKTRACK7)
#define SMACKAUTOEXTRA 0xffffffff

typedef struct SmackTag {
unsigned long Version;
unsigned long Width;
unsigned long Height;
unsigned long Frames;
unsigned long MSPerFrame;
unsigned long SmackerType;
unsigned long LargestInTrack[7];
unsigned long tablesize;
unsigned long codesize;
unsigned long absize;
unsigned long detailsize;
unsigned long typesize;
unsigned long TrackType[7];
unsigned long extra;
unsigned long NewPalette;
unsigned char Palette[772];
unsigned long PalType;
unsigned long FrameNum;
unsigned long FrameSize;
unsigned long SndSize;
unsigned long LastRectx;
unsigned long LastRecty;
unsigned long LastRectw;
unsigned long LastRecth;
unsigned long OpenFlags;
unsigned long LeftOfs;
unsigned long TopOfs;
unsigned long ReadError;
unsigned long addr32;

// added by dethrace
void* smk_handle;
} Smack;

Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf);
int SmackSoundUseDirectSound(void* dd); // NULL mean create instance (apparently)
void SmackToBuffer(Smack* smack, uint32_t left, uint32_t top, uint32_t pitch, uint32_t destheight, void* buf, uint32_t flags);
uint32_t SmackDoFrame(Smack* smack);
void SmackNextFrame(Smack* smack);
uint32_t SmackWait(Smack* smack);
void SmackClose(Smack* smack);
Loading