mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-12 16:14:25 +02:00
#9 add simple sound mixing for a PCM, MS ADPCM (from TR3 cdaudio.wad), MP3 (via minimp3 lib) & OGG (via stb_vorbis lib)
This commit is contained in:
@@ -166,8 +166,9 @@ struct Controller {
|
||||
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
||||
uint32 c = level->soundOffsets[b.offset + rand() % ((b.flags & 0xFF) >> 2)];
|
||||
void *p = &level->soundData[c];
|
||||
#ifdef WIN32
|
||||
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
||||
#ifdef WIN32
|
||||
Sound::play(new Stream(p, 1024 * 1024), b.volume / 255.0f, 0.0f, Sound::Flags::PAN);
|
||||
// PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "utils.h"
|
||||
#include "input.h"
|
||||
#include "sound.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#if defined(_MSC_VER) // Visual Studio
|
||||
@@ -119,10 +120,11 @@ namespace Core {
|
||||
GetProcOGL(glBindBuffer);
|
||||
GetProcOGL(glBufferData);
|
||||
#endif
|
||||
Sound::init();
|
||||
}
|
||||
|
||||
void free() {
|
||||
//
|
||||
Sound::free();
|
||||
}
|
||||
|
||||
void clear(const vec4 &color) {
|
||||
|
@@ -525,7 +525,7 @@ namespace Debug {
|
||||
|
||||
void info(const TR::Level &level, const TR::Entity &entity) {
|
||||
char buf[255];
|
||||
sprintf(buf, "DIP = %d, TRI = %d", Core::stats.dips, Core::stats.tris);
|
||||
sprintf(buf, "DIP = %d, TRI = %d, SND = %d", Core::stats.dips, Core::stats.tris, Sound::channelsCount);
|
||||
Debug::Draw::text(vec2(16, 16), vec4(1.0f), buf);
|
||||
sprintf(buf, "pos = (%d, %d, %d), room = %d", entity.x, entity.y, entity.z, entity.room);
|
||||
Debug::Draw::text(vec2(16, 32), vec4(1.0f), buf);
|
||||
|
@@ -14,6 +14,10 @@ namespace Game {
|
||||
Core::init();
|
||||
Stream stream("LEVEL2_DEMO.PHD");
|
||||
level = new Level(stream);
|
||||
|
||||
//Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0);
|
||||
Sound::play(new Stream("05.ogg"), 1, 1, 0);
|
||||
//Sound::play(new Stream("03.mp3"), 1, 1, 0);
|
||||
}
|
||||
|
||||
void free() {
|
||||
|
90
src/libs/minimp3/libc.h
Normal file
90
src/libs/minimp3/libc.h
Normal file
@@ -0,0 +1,90 @@
|
||||
// a libc replacement (more or less) for the Microsoft Visual C compiler
|
||||
// this file is public domain -- do with it whatever you want!
|
||||
#ifndef __LIBC_H_INCLUDED__
|
||||
#define __LIBC_H_INCLUDED__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define INLINE __forceinline
|
||||
#define FASTCALL __fastcall
|
||||
#ifdef NOLIBC
|
||||
#ifdef MAIN_PROGRAM
|
||||
int _fltused=0;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define INLINE inline
|
||||
#define FASTCALL __attribute__((fastcall))
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !NEED_MINILIBC
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#ifndef __int8_t_defined
|
||||
#define __int8_t_defined
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef signed __int64 int64_t;
|
||||
#else
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef signed long long int64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979
|
||||
#endif
|
||||
|
||||
#define libc_malloc malloc
|
||||
#define libc_calloc calloc
|
||||
#define libc_realloc realloc
|
||||
#define libc_free free
|
||||
|
||||
#define libc_memset memset
|
||||
#define libc_memcpy memcpy
|
||||
#define libc_memmove memmove
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_DEBUG)
|
||||
static INLINE double libc_frexp(double x, int *e) {
|
||||
double res = -9999.999;
|
||||
unsigned __int64 i = *(unsigned __int64*)(&x);
|
||||
if (!(i & 0x7F00000000000000UL)) {
|
||||
*e = 0;
|
||||
return x;
|
||||
}
|
||||
*e = ((i << 1) >> 53) - 1022;
|
||||
i &= 0x800FFFFFFFFFFFFFUL;
|
||||
i |= 0x3FF0000000000000UL;
|
||||
return *(double*)(&i) * 0.5;
|
||||
}
|
||||
#else
|
||||
#define libc_frexp frexp
|
||||
#endif
|
||||
|
||||
#define libc_exp exp
|
||||
#define libc_pow pow
|
||||
|
||||
#endif//__LIBC_H_INCLUDED__
|
2666
src/libs/minimp3/minimp3.cpp
Normal file
2666
src/libs/minimp3/minimp3.cpp
Normal file
File diff suppressed because it is too large
Load Diff
18
src/libs/minimp3/minimp3.h
Normal file
18
src/libs/minimp3/minimp3.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef __MINIMP3_H_INCLUDED__
|
||||
#define __MINIMP3_H_INCLUDED__
|
||||
|
||||
typedef struct _mp3_info {
|
||||
int sample_rate;
|
||||
int channels;
|
||||
int audio_bytes; // generated amount of audio per frame
|
||||
} mp3_info_t;
|
||||
|
||||
typedef void* mp3_decoder_t;
|
||||
|
||||
mp3_decoder_t mp3_create(void);
|
||||
extern int mp3_decode(mp3_decoder_t dec, void *buf, int bytes, signed short *out, mp3_info_t *info);
|
||||
void mp3_done(mp3_decoder_t dec);
|
||||
int mp3_decode_init();
|
||||
void mp3_decode_free();
|
||||
|
||||
#endif//__MINIMP3_H_INCLUDED__
|
5422
src/libs/stb_vorbis/stb_vorbis.c
Normal file
5422
src/libs/stb_vorbis/stb_vorbis.c
Normal file
File diff suppressed because it is too large
Load Diff
356
src/sound.h
Normal file
356
src/sound.h
Normal file
@@ -0,0 +1,356 @@
|
||||
#ifndef H_SOUND
|
||||
#define H_SOUND
|
||||
|
||||
#include "utils.h"
|
||||
#include "libs/minimp3/minimp3.h"
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include "libs/stb_vorbis/stb_vorbis.c"
|
||||
|
||||
#define SND_CHANNELS_MAX 32
|
||||
#define BUFFER_SIZE_MP3 8192
|
||||
|
||||
namespace Sound {
|
||||
|
||||
struct Frame {
|
||||
short L, R;
|
||||
};
|
||||
|
||||
struct Decoder {
|
||||
Stream *stream;
|
||||
int channels, offset;
|
||||
|
||||
Decoder(Stream *stream, int channels) : stream(stream), channels(channels), offset(stream->pos) {}
|
||||
virtual ~Decoder() { delete stream; }
|
||||
virtual int decode(Frame *frames, int count) { return 0; }
|
||||
};
|
||||
|
||||
struct PCM : Decoder {
|
||||
int freq, size, bits;
|
||||
|
||||
PCM(Stream *stream, int channels, int freq, int size, int bits) : Decoder(stream, channels), freq(freq), size(size), bits(bits) {}
|
||||
|
||||
virtual int decode(Frame *frames, int count) {
|
||||
if (stream->pos - offset >= size) return 0;
|
||||
if (bits == 16) {
|
||||
int16 value;
|
||||
if (channels == 2) {
|
||||
frames[0].L = stream->read(value);
|
||||
frames[0].R = stream->read(value);
|
||||
} else
|
||||
frames[0].L = frames[0].R = stream->read(value);
|
||||
} else if (bits == 8) {
|
||||
uint8 value;
|
||||
if (channels == 2) {
|
||||
frames[0].L = stream->read(value) * 257 - 32768;
|
||||
frames[0].R = stream->read(value) * 257 - 32768;
|
||||
} else
|
||||
frames[0].L = frames[0].R = stream->read(value) * 257 - 32768;
|
||||
} else {
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int k = 44100 / freq;
|
||||
for (int i = 1; i < k; i++) frames[i] = frames[0];
|
||||
return k;
|
||||
}
|
||||
};
|
||||
|
||||
struct ADPCM : Decoder { // https://wiki.multimedia.cx/?title=Microsoft_ADPCM
|
||||
int size, block;
|
||||
|
||||
ADPCM(Stream *stream, int channels, int size, int block) : Decoder(stream, channels), size(size), block(block) {}
|
||||
|
||||
struct Channel {
|
||||
int16 c1, c2;
|
||||
int16 delta;
|
||||
int16 sample1;
|
||||
int16 sample2;
|
||||
|
||||
int predicate(uint8 nibble) {
|
||||
static const int table[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 };
|
||||
|
||||
int8 ns = nibble;
|
||||
if (ns & 8) ns -= 16;
|
||||
|
||||
int sample = (sample1 * c1 + sample2 * c2) / 256 + ns * delta;
|
||||
sample = clamp(sample, -32768, 32767);
|
||||
sample2 = sample1;
|
||||
sample1 = sample;
|
||||
delta = max(table[nibble] * delta / 256, 16);
|
||||
return sample;
|
||||
}
|
||||
} channel[2];
|
||||
|
||||
virtual int decode(Frame *frames, int count) {
|
||||
static const int coeff1[] = { 256, 512, 0, 192, 240, 460, 392 };
|
||||
static const int coeff2[] = { 0, -256, 0, 64, 0, -208, -232 };
|
||||
|
||||
int seek = stream->pos - offset;
|
||||
if (seek >= size) return 0;
|
||||
|
||||
if (seek % block == 0) {
|
||||
for (int i = 0; i < channels; i++) {
|
||||
char index;
|
||||
stream->read(index);
|
||||
channel[i].c1 = coeff1[index];
|
||||
channel[i].c2 = coeff2[index];
|
||||
}
|
||||
for (int i = 0; i < channels; i++) stream->read(channel[i].delta);
|
||||
for (int i = 0; i < channels; i++) stream->read(channel[i].sample1);
|
||||
for (int i = 0; i < channels; i++) stream->read(channel[i].sample2);
|
||||
|
||||
if (channels == 1) {
|
||||
frames[0].L = frames[0].R = channel[0].sample2;
|
||||
frames[1].L = frames[1].R = channel[0].sample1;
|
||||
} else {
|
||||
frames[0].L = channel[0].sample2;
|
||||
frames[0].R = channel[1].sample2;
|
||||
frames[1].L = channel[0].sample1;
|
||||
frames[1].R = channel[1].sample1;
|
||||
}
|
||||
return 2;
|
||||
} else {
|
||||
uint8 value;
|
||||
stream->read(value);
|
||||
uint8 n1 = value >> 4, n2 = value & 0xF;
|
||||
|
||||
if (channels == 1) {
|
||||
frames[0].L = frames[0].R = channel[0].predicate(n1);
|
||||
frames[1].L = frames[1].R = channel[0].predicate(n2);
|
||||
return 2;
|
||||
} else {
|
||||
frames[0].L = channel[0].predicate(n1);
|
||||
frames[0].R = channel[1].predicate(n2);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MP3 : Decoder {
|
||||
mp3_decoder_t mp3;
|
||||
char *buffer;
|
||||
int size, pos;
|
||||
|
||||
MP3(Stream *stream, int channels) : Decoder(stream, channels), size(stream->size), pos(0) {
|
||||
mp3 = mp3_create();
|
||||
buffer = new char[size]; // TODO: file streaming
|
||||
stream->raw(buffer, size);
|
||||
}
|
||||
|
||||
virtual ~MP3() {
|
||||
delete[] buffer;
|
||||
mp3_done(mp3);
|
||||
}
|
||||
|
||||
virtual int decode(Frame *frames, int count) {
|
||||
mp3_info_t info;
|
||||
int i = 0;
|
||||
char *ptr = (char*)frames;
|
||||
while (ptr < (char*)&frames[count]) {
|
||||
int res = mp3_decode(mp3, buffer + pos, size - pos, (short*)ptr, &info);
|
||||
if (res) {
|
||||
pos += res;
|
||||
ptr += info.audio_bytes;
|
||||
i += info.audio_bytes;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
struct OGG : Decoder {
|
||||
stb_vorbis *ogg;
|
||||
stb_vorbis_alloc alloc;
|
||||
|
||||
char *buffer;
|
||||
int size, pos;
|
||||
|
||||
OGG(Stream *stream, int channels) : Decoder(stream, channels), size(stream->size), pos(0) {
|
||||
buffer = new char[size]; // TODO: file streaming
|
||||
stream->raw(buffer, size);
|
||||
int error;
|
||||
alloc.alloc_buffer_length_in_bytes = 256 * 1024;
|
||||
alloc.alloc_buffer = new char[alloc.alloc_buffer_length_in_bytes];
|
||||
ogg = stb_vorbis_open_memory((unsigned char*)buffer, size, &error, &alloc);
|
||||
stb_vorbis_info info = stb_vorbis_get_info(ogg);
|
||||
channels = info.channels;
|
||||
}
|
||||
|
||||
virtual ~OGG() {
|
||||
stb_vorbis_close(ogg);
|
||||
delete[] alloc.alloc_buffer;
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
virtual int decode(Frame *frames, int count) {
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
int res = stb_vorbis_get_samples_short_interleaved(ogg, channels, (short*)frames + i, (count - i) * 2);
|
||||
if (!res) break;
|
||||
i += res;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
struct Listener {
|
||||
mat4 matrix;
|
||||
vec3 velocity;
|
||||
} listener;
|
||||
|
||||
enum Flags {
|
||||
LOOP = 1,
|
||||
PAN = 2,
|
||||
REVERB_NEAR = 4,
|
||||
REVERB_MIDDLE = 8,
|
||||
REVERB_FAR = 16,
|
||||
};
|
||||
|
||||
struct Sample {
|
||||
Decoder *decoder;
|
||||
float volume;
|
||||
float pitch;
|
||||
int flags;
|
||||
bool isPlaying;
|
||||
|
||||
Sample(Stream *stream, float volume, float pitch, int flags) : decoder(NULL), volume(volume), pitch(pitch), flags(flags), isPlaying(true) {
|
||||
uint32 fourcc;
|
||||
stream->read(fourcc);
|
||||
if (fourcc == FOURCC("RIFF")) { // wav
|
||||
|
||||
struct {
|
||||
uint16 format;
|
||||
uint16 channels;
|
||||
uint32 samplesPerSec;
|
||||
uint32 bytesPerSec;
|
||||
uint16 block;
|
||||
uint16 sampleBits;
|
||||
} waveFmt;
|
||||
|
||||
stream->seek(8);
|
||||
while (stream->pos < stream->size) {
|
||||
uint32 type, size;
|
||||
stream->read(type);
|
||||
stream->read(size);
|
||||
if (type == FOURCC("fmt ")) {
|
||||
stream->read(waveFmt);
|
||||
stream->seek(size - sizeof(waveFmt));
|
||||
} else if (type == FOURCC("data")) {
|
||||
if (waveFmt.format == 1) decoder = new PCM(stream, waveFmt.channels, waveFmt.samplesPerSec, size, waveFmt.sampleBits);
|
||||
if (waveFmt.format == 2) decoder = new ADPCM(stream, waveFmt.channels, size, waveFmt.block);
|
||||
break;
|
||||
} else
|
||||
stream->seek(size);
|
||||
}
|
||||
} else if (fourcc == FOURCC("OggS")) { // ogg
|
||||
stream->seek(-4);
|
||||
decoder = new OGG(stream, 2);
|
||||
} else if (fourcc == FOURCC("ID3\3")) { // mp3
|
||||
decoder = new MP3(stream, 2);
|
||||
}
|
||||
|
||||
ASSERT(decoder != NULL);
|
||||
}
|
||||
|
||||
~Sample() {
|
||||
delete decoder;
|
||||
}
|
||||
|
||||
bool render(Frame *frames, int count) {
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
int res = decoder->decode(&frames[i], count - i);
|
||||
if (res == 0) {
|
||||
if (i == 0) isPlaying = false;
|
||||
break;
|
||||
}
|
||||
i += res;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} *channels[SND_CHANNELS_MAX];
|
||||
int channelsCount;
|
||||
|
||||
void init() {
|
||||
channelsCount = 0;
|
||||
mp3_decode_init();
|
||||
}
|
||||
|
||||
void free() {
|
||||
for (int i = 0; i < channelsCount; i++)
|
||||
delete channels[i];
|
||||
mp3_decode_free();
|
||||
}
|
||||
|
||||
void fill(Frame *frames, int count) {
|
||||
struct FrameHI {
|
||||
int L, R;
|
||||
};
|
||||
|
||||
FrameHI *result = new FrameHI[count];
|
||||
memset(result, 0, sizeof(FrameHI) * count);
|
||||
|
||||
Frame *buffer = new Frame[count];
|
||||
|
||||
for (int i = 0; i < channelsCount; i++) {
|
||||
|
||||
memset(buffer, 0, sizeof(Frame) * count);
|
||||
channels[i]->render(buffer, count);
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
result[j].L += buffer[j].L;
|
||||
result[j].R += buffer[j].R;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
frames[i].L = clamp(result[i].L, -32768, 32767);
|
||||
frames[i].R = clamp(result[i].R, -32768, 32767);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
delete[] result;
|
||||
|
||||
for (int i = 0; i < channelsCount; i++)
|
||||
if (!channels[i]->isPlaying) {
|
||||
delete channels[i];
|
||||
channels[i] = channels[--channelsCount];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
Stream *openWAD(const char *name) {
|
||||
Stream *stream = new Stream("cdaudio.wad");
|
||||
if (stream->size) {
|
||||
struct Item {
|
||||
char name[260];
|
||||
int size;
|
||||
int offset;
|
||||
} entity;
|
||||
|
||||
for (int i = 0; i < 130; i++) {
|
||||
stream->read(entity);
|
||||
if (strcmp(name, entity.name) == 0) {
|
||||
stream->setPos(entity.offset);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void play(Stream *stream, float volume, float pitch, int flags) {
|
||||
if (!stream) return;
|
||||
if (channelsCount < SND_CHANNELS_MAX)
|
||||
channels[channelsCount++] = new Sample(stream, volume, pitch, flags);
|
||||
else
|
||||
LOG("! no free channels\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
29
src/utils.h
29
src/utils.h
@@ -36,6 +36,8 @@ typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#define FOURCC(str) (*((uint32*)str))
|
||||
|
||||
struct ubyte4 {
|
||||
uint8 x, y, z, w;
|
||||
};
|
||||
@@ -473,9 +475,12 @@ struct mat4 {
|
||||
|
||||
struct Stream {
|
||||
FILE *f;
|
||||
int size, pos;
|
||||
const char *data;
|
||||
int size, pos;
|
||||
|
||||
Stream(const char *name) : pos(0) {
|
||||
Stream(const void *data, int size) : f(NULL), data((char*)data), size(size), pos(0) {}
|
||||
|
||||
Stream(const char *name) : data(NULL), size(-1), pos(0) {
|
||||
f = fopen(name, "rb");
|
||||
if (!f) LOG("error loading file\n");
|
||||
fseek(f, 0, SEEK_END);
|
||||
@@ -484,32 +489,36 @@ struct Stream {
|
||||
}
|
||||
|
||||
~Stream() {
|
||||
fclose(f);
|
||||
if (f) fclose(f);
|
||||
}
|
||||
|
||||
void setPos(int pos) {
|
||||
this->pos = pos;
|
||||
fseek(f, pos, SEEK_SET);
|
||||
if (f) fseek(f, pos, SEEK_SET);
|
||||
}
|
||||
|
||||
void seek(int offset) {
|
||||
fseek(f, offset, SEEK_CUR);
|
||||
if (!offset) return;
|
||||
if (f) fseek(f, offset, SEEK_CUR);
|
||||
pos += offset;
|
||||
}
|
||||
|
||||
int raw(void *data, int size) {
|
||||
pos += size;
|
||||
return fread(data, 1, size, f);
|
||||
void raw(void *data, int count) {
|
||||
if (f)
|
||||
fread(data, 1, count, f);
|
||||
else
|
||||
memcpy(data, this->data + pos, count);
|
||||
pos += count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& read(T &x) {
|
||||
inline T& read(T &x) {
|
||||
raw(&x, sizeof(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* read(T *&a, int count) {
|
||||
inline T* read(T *&a, int count) {
|
||||
if (count) {
|
||||
a = new T[count];
|
||||
raw(a, count * sizeof(T));
|
||||
|
@@ -1,3 +1,3 @@
|
||||
set SRC=main.cpp
|
||||
call em++ %SRC% -O2 --llvm-opts 2 --closure 1 -std=c++11 -o OpenLara.js --preload-file ./LEVEL2_DEMO.PHD -I..\
|
||||
set SRC=main.cpp ../libs/minimp3/minimp3.cpp ../libs/stb_vorbis/stb_vorbis.c
|
||||
call em++ %SRC% -O2 -s ASSERTIONS=1 -Wno-deprecated-register --llvm-opts 2 --closure 2 -std=c++11 -o OpenLara.js --preload-file ./LEVEL2_DEMO.PHD -I..\
|
||||
gzip.exe -9 -f OpenLara.data OpenLara.js OpenLara.js.mem
|
@@ -56,8 +56,10 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>NOMINMAX;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>STB_VORBIS_NO_STDIO;NOMINMAX;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FloatingPointModel>Strict</FloatingPointModel>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -73,26 +75,30 @@
|
||||
<Optimization>Full</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NOMINMAX;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>STB_VORBIS_NO_STDIO;NOMINMAX;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FloatingPointModel>Strict</FloatingPointModel>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalOptions>/d2noftol3 %(AdditionalOptions)</AdditionalOptions>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;winmm.lib;wcrt.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>wcrt.lib;opengl32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\libs\minimp3\minimp3.cpp" />
|
||||
<ClCompile Include="..\libs\stb_vorbis\stb_vorbis.c" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -105,8 +111,11 @@
|
||||
<ClInclude Include="..\input.h" />
|
||||
<ClInclude Include="..\lara.h" />
|
||||
<ClInclude Include="..\level.h" />
|
||||
<ClInclude Include="..\libs\minimp3\libc.h" />
|
||||
<ClInclude Include="..\libs\minimp3\minimp3.h" />
|
||||
<ClInclude Include="..\mesh.h" />
|
||||
<ClInclude Include="..\shader.h" />
|
||||
<ClInclude Include="..\sound.h" />
|
||||
<ClInclude Include="..\texture.h" />
|
||||
<ClInclude Include="..\format.h" />
|
||||
<ClInclude Include="..\trigger.h" />
|
||||
|
@@ -1,7 +1,13 @@
|
||||
#ifdef _DEBUG
|
||||
#include "crtdbg.h"
|
||||
#endif
|
||||
/* // VS2015 ?
|
||||
#include <stdint.h>
|
||||
|
||||
void __cdecl operator delete(void *ptr, unsigned int size) {
|
||||
//
|
||||
}
|
||||
*/
|
||||
#include "game.h"
|
||||
|
||||
DWORD getTime() {
|
||||
@@ -16,6 +22,7 @@ DWORD getTime() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// common input functions
|
||||
InputKey keyToInputKey(int code) {
|
||||
int codes[] = {
|
||||
VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_SPACE, VK_RETURN, VK_ESCAPE, VK_SHIFT, VK_CONTROL, VK_MENU,
|
||||
@@ -35,7 +42,8 @@ InputKey mouseToInputKey(int msg) {
|
||||
(msg >= WM_RBUTTONDOWN && msg <= WM_RBUTTONDBLCLK) ? ikMouseR : ikMouseM;
|
||||
}
|
||||
|
||||
#define JOY_DEAD_ZONE_STICK 0.3f
|
||||
// joystick
|
||||
#define JOY_DEAD_ZONE_STICK 0.3f
|
||||
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
||||
|
||||
bool joyReady;
|
||||
@@ -99,11 +107,75 @@ void joyUpdate() {
|
||||
joyFree();
|
||||
}
|
||||
|
||||
// sound
|
||||
#define SND_SIZE 4608*2
|
||||
|
||||
bool sndReady;
|
||||
char *sndData;
|
||||
CRITICAL_SECTION sndCS;
|
||||
HWAVEOUT waveOut;
|
||||
WAVEFORMATEX waveFmt = { WAVE_FORMAT_PCM, 2, 44100, 44100 * 4, 4, 16, sizeof(waveFmt) };
|
||||
WAVEHDR waveBuf[2];
|
||||
|
||||
void soundFree() {
|
||||
if (!sndReady) return;
|
||||
sndReady = false;
|
||||
EnterCriticalSection(&sndCS);
|
||||
waveOutUnprepareHeader(waveOut, &waveBuf[0], sizeof(WAVEHDR));
|
||||
waveOutUnprepareHeader(waveOut, &waveBuf[1], sizeof(WAVEHDR));
|
||||
waveOutReset(waveOut);
|
||||
waveOutClose(waveOut);
|
||||
delete[] sndData;
|
||||
LeaveCriticalSection(&sndCS);
|
||||
DeleteCriticalSection(&sndCS);
|
||||
}
|
||||
|
||||
void CALLBACK sndFill(HWAVEOUT waveOut, UINT uMsg, DWORD_PTR dwInstance, LPWAVEHDR waveBuf, DWORD dwParam2) {
|
||||
if (!sndReady) return;
|
||||
if (uMsg == MM_WOM_CLOSE) {
|
||||
soundFree();
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&sndCS);
|
||||
waveOutUnprepareHeader(waveOut, waveBuf, sizeof(WAVEHDR));
|
||||
Sound::fill((Sound::Frame*)waveBuf->lpData, SND_SIZE / 4);
|
||||
waveOutPrepareHeader(waveOut, waveBuf, sizeof(WAVEHDR));
|
||||
waveOutWrite(waveOut, waveBuf, sizeof(WAVEHDR));
|
||||
LeaveCriticalSection(&sndCS);
|
||||
}
|
||||
|
||||
void soundInit(HWND hwnd) {
|
||||
InitializeCriticalSection(&sndCS);
|
||||
if (waveOutOpen(&waveOut, WAVE_MAPPER, &waveFmt, (INT_PTR)sndFill, 0, CALLBACK_FUNCTION) == MMSYSERR_NOERROR) {
|
||||
sndReady = true;
|
||||
sndData = new char[SND_SIZE * 2];
|
||||
memset(&waveBuf, 0, sizeof(waveBuf));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
waveBuf[i].dwBufferLength = SND_SIZE;
|
||||
waveBuf[i].lpData = sndData + SND_SIZE * i;
|
||||
sndFill(waveOut, 0, 0, &waveBuf[i], 0);
|
||||
}
|
||||
} else {
|
||||
sndReady = false;
|
||||
sndData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (msg) {
|
||||
// window
|
||||
case WM_ACTIVATE :
|
||||
Input::reset();
|
||||
break;
|
||||
case WM_SIZE:
|
||||
Core::width = LOWORD(lParam);
|
||||
Core::height = HIWORD(lParam);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
// keyboard
|
||||
case WM_KEYDOWN :
|
||||
case WM_KEYUP :
|
||||
@@ -134,19 +206,13 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
case WM_MOUSEMOVE :
|
||||
Input::setPos(ikMouseL, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam)));
|
||||
break;
|
||||
// gamepad
|
||||
// joystick
|
||||
case WM_DEVICECHANGE :
|
||||
joyInit();
|
||||
return 1;
|
||||
// touch
|
||||
// ...
|
||||
case WM_SIZE :
|
||||
Core::width = LOWORD(lParam);
|
||||
Core::height = HIWORD(lParam);
|
||||
break;
|
||||
case WM_DESTROY :
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
// TODO
|
||||
// sound
|
||||
default :
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
@@ -187,11 +253,12 @@ int main() {
|
||||
|
||||
HWND hWnd = CreateWindow("static", "OpenLara", WS_OVERLAPPEDWINDOW, 0, 0, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0);
|
||||
|
||||
joyInit();
|
||||
|
||||
HDC hDC = GetDC(hWnd);
|
||||
HDC hDC = GetDC(hWnd);
|
||||
HGLRC hRC = initGL(hDC);
|
||||
Game::init();
|
||||
|
||||
joyInit();
|
||||
soundInit(hWnd);
|
||||
Game::init();
|
||||
|
||||
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
@@ -211,11 +278,13 @@ int main() {
|
||||
continue;
|
||||
|
||||
float delta = (time - lastTime) * 0.001f;
|
||||
EnterCriticalSection(&sndCS);
|
||||
while (delta > EPS) {
|
||||
Core::deltaTime = min(delta, 1.0f / 30.0f);
|
||||
Game::update();
|
||||
delta -= Core::deltaTime;
|
||||
}
|
||||
LeaveCriticalSection(&sndCS);
|
||||
lastTime = time;
|
||||
|
||||
Core::stats.dips = 0;
|
||||
@@ -232,7 +301,9 @@ int main() {
|
||||
}
|
||||
} while (msg.message != WM_QUIT);
|
||||
|
||||
soundFree();
|
||||
Game::free();
|
||||
|
||||
freeGL(hRC);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
|
||||
|
Reference in New Issue
Block a user