Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions src/audio/miniaudio/ma_audio_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,22 @@ static void maInit(AudioSystem* audio, DataWin* dataWin, FileSystem* fileSystem)
memset(ma->instances, 0, sizeof(ma->instances));
ma->nextInstanceCounter = 0;

repeat(MAX_LISTENERS, i) {
ma_sound_group_init(&ma->engine, 0, NULL, &ma->listenerGroups[i]);
ma_sound_group_set_volume(&ma->listenerGroups[i], 1.0f);
ma->listenerGains[i] = 1.0f;
}

fprintf(stderr, "Audio: miniaudio engine initialized\n");
}

static void maDestroy(AudioSystem* audio) {
MaAudioSystem* ma = (MaAudioSystem*) audio;

repeat(MAX_LISTENERS, i) {
ma_sound_group_uninit(&ma->listenerGroups[i]);
}

// Uninit all active sound instances
repeat(MAX_SOUND_INSTANCES, i) {
if (ma->instances[i].active) {
Expand Down Expand Up @@ -232,7 +242,7 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior

if (isStream) {
// Stream audio: load from file path stored in stream entry
result = ma_sound_init_from_file(&ma->engine, streamPath, MA_SOUND_FLAG_ASYNC, nullptr, nullptr, &slot->maSound);
result = ma_sound_init_from_file(&ma->engine, streamPath, MA_SOUND_FLAG_ASYNC, &ma->listenerGroups[0], nullptr, &slot->maSound);
if (result != MA_SUCCESS) {
fprintf(stderr, "Audio: Failed to load stream file '%s' (error %d)\n", streamPath, result);
return -1;
Expand Down Expand Up @@ -261,7 +271,7 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
}
slot->ownsDecoder = true;

result = ma_sound_init_from_data_source(&ma->engine, &slot->decoder, 0, nullptr, &slot->maSound);
result = ma_sound_init_from_data_source(&ma->engine, &slot->decoder, 0, &ma->listenerGroups[0], &slot->maSound);
if (result != MA_SUCCESS) {
fprintf(stderr, "Audio: Failed to init sound from decoder for '%s' (error %d)\n", sound->name, result);
ma_decoder_uninit(&slot->decoder);
Expand All @@ -275,7 +285,7 @@ static int32_t maPlaySound(AudioSystem* audio, int32_t soundIndex, int32_t prior
return -1;
}

result = ma_sound_init_from_file(&ma->engine, path, MA_SOUND_FLAG_ASYNC, nullptr, nullptr, &slot->maSound);
result = ma_sound_init_from_file(&ma->engine, path, MA_SOUND_FLAG_ASYNC, &ma->listenerGroups[0], nullptr, &slot->maSound);
if (result != MA_SUCCESS) {
fprintf(stderr, "Audio: Failed to load file for '%s' at '%s' (error %d)\n", sound->name, path, result);
free(path);
Expand Down Expand Up @@ -701,6 +711,13 @@ static void maSetMasterGain(AudioSystem* audio, float gain) {
ma_engine_set_volume(&ma->engine, gain);
}

static void maSetMasterGainForListener(AudioSystem* audio, float gain, int32_t id) {
MaAudioSystem* ma = (MaAudioSystem*) audio;
if (id < 0 || id >= MAX_LISTENERS) return;
ma->listenerGains[id] = gain;
ma_sound_group_set_volume(&ma->listenerGroups[id], gain);
}

static void maSetChannelCount(MAYBE_UNUSED AudioSystem* audio, MAYBE_UNUSED int32_t count) {
// miniaudio handles channel management internally, this is a no-op
}
Expand Down Expand Up @@ -842,6 +859,7 @@ MaAudioSystem* MaAudioSystem_create(DataWin* dataWin) {
maAudioSystemVtable.setTrackPosition = maSetTrackPosition;
maAudioSystemVtable.getSoundLength = maGetSoundLength;
maAudioSystemVtable.setMasterGain = maSetMasterGain;
maAudioSystemVtable.setMasterGainForListener = maSetMasterGainForListener;
maAudioSystemVtable.setChannelCount = maSetChannelCount;
maAudioSystemVtable.groupLoad = maGroupLoad;
maAudioSystemVtable.groupIsLoaded = maGroupIsLoaded;
Expand Down
3 changes: 3 additions & 0 deletions src/audio/miniaudio/ma_audio_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define MAX_AUDIO_STREAMS 32
// This is the index space that the native runner uses
#define AUDIO_STREAM_INDEX_BASE 300000
#define MAX_LISTENERS 4

typedef struct {
bool active;
Expand Down Expand Up @@ -41,6 +42,8 @@ typedef struct {
int32_t nextInstanceCounter;
FileSystem* fileSystem;
AudioStreamEntry streams[MAX_AUDIO_STREAMS];
ma_sound_group listenerGroups[MAX_LISTENERS];
float listenerGains[MAX_LISTENERS];
} MaAudioSystem;

MaAudioSystem* MaAudioSystem_create(DataWin* dataWin);
Expand Down
7 changes: 7 additions & 0 deletions src/audio/openal/al_audio_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,12 @@ static float maGetSoundLength(AudioSystem* audio, int32_t soundOrInstance) {
return seconds;
}

static void maSetMasterGainForListener(AudioSystem* audio, float gain, int32_t id) {
(void)audio;
(void)id;
alListenerf(AL_GAIN, gain);
}

static void maSetMasterGain(AudioSystem* audio, float gain) {
(void)audio;
alListenerf(AL_GAIN, gain);
Expand Down Expand Up @@ -917,6 +923,7 @@ AlAudioSystem* AlAudioSystem_create(void) {
AlAudioSystemVtable.setTrackPosition = maSetTrackPosition;
AlAudioSystemVtable.getSoundLength = maGetSoundLength;
AlAudioSystemVtable.setMasterGain = maSetMasterGain;
AlAudioSystemVtable.setMasterGainForListener = maSetMasterGainForListener;
AlAudioSystemVtable.setChannelCount = maSetChannelCount;
AlAudioSystemVtable.groupLoad = maGroupLoad;
AlAudioSystemVtable.groupIsLoaded = maGroupIsLoaded;
Expand Down
7 changes: 7 additions & 0 deletions src/audio/ps2/ps2_audio_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,12 @@ static void ps2SetMasterGain(AudioSystem* audio, float gain) {
ps2->masterGain = gain;
}

static void ps2SetMasterGainForListener(AudioSystem* audio, float gain, int32_t id) {
if (id != 0) return;
Ps2AudioSystem* ps2 = (Ps2AudioSystem*) audio;
ps2->masterGain = gain;
}

static void ps2SetChannelCount(MAYBE_UNUSED AudioSystem* audio, MAYBE_UNUSED int32_t count) {
// No-op: software mixer handles all channels internally
}
Expand Down Expand Up @@ -1340,6 +1346,7 @@ Ps2AudioSystem* Ps2AudioSystem_create(void) {
ps2AudioSystemVtable.setTrackPosition = ps2SetTrackPosition;
ps2AudioSystemVtable.getSoundLength = ps2GetSoundLength;
ps2AudioSystemVtable.setMasterGain = ps2SetMasterGain;
ps2AudioSystemVtable.setMasterGainForListener = ps2SetMasterGainForListener;
ps2AudioSystemVtable.setChannelCount = ps2SetChannelCount;
ps2AudioSystemVtable.groupLoad = ps2GroupLoad;
ps2AudioSystemVtable.groupIsLoaded = ps2GroupIsLoaded;
Expand Down
10 changes: 10 additions & 0 deletions src/audio/web/web_audio_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,15 @@ static void webSetMasterGain(AudioSystem* audio, float gain) {
ma_engine_set_volume(&ma->engine, gain);
}


static void webSetMasterGainForListener(AudioSystem* audio, float gain, int32_t id) {
WebAudioSystem* ma = (WebAudioSystem*) audio;
if (!ma->engineReady) return;
if (id < 0 || id >= MAX_LISTENERS) return;
ma->listenerGains[id] = gain;
ma_sound_group_set_volume(&ma->listenerGroups[id], gain);
}

static void webSetChannelCount(MAYBE_UNUSED AudioSystem* audio, MAYBE_UNUSED int32_t count) {}

static void webGroupLoad(AudioSystem* audio, int32_t groupIndex) {
Expand Down Expand Up @@ -701,6 +710,7 @@ WebAudioSystem* WebAudioSystem_create(DataWin* dataWin, int32_t sampleRate) {
webAudioSystemVtable.setTrackPosition = webSetTrackPosition;
webAudioSystemVtable.getSoundLength = webGetSoundLength;
webAudioSystemVtable.setMasterGain = webSetMasterGain;
webAudioSystemVtable.setMasterGainForListener = webSetMasterGainForListener;
webAudioSystemVtable.setChannelCount = webSetChannelCount;
webAudioSystemVtable.groupLoad = webGroupLoad;
webAudioSystemVtable.groupIsLoaded = webGroupIsLoaded;
Expand Down
3 changes: 3 additions & 0 deletions src/audio/web/web_audio_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define WEB_SOUND_INSTANCE_ID_BASE 100000
#define WEB_MAX_AUDIO_STREAMS 32
#define WEB_AUDIO_STREAM_INDEX_BASE 300000
#define MAX_LISTENERS 4

typedef struct {
bool active;
Expand Down Expand Up @@ -39,6 +40,8 @@ typedef struct {
int32_t nextInstanceCounter;
FileSystem* fileSystem;
WebAudioStreamEntry streams[WEB_MAX_AUDIO_STREAMS];
ma_sound_group listenerGroups[MAX_LISTENERS];
float listenerGains[MAX_LISTENERS];
} WebAudioSystem;

// Creates a no-device miniaudio engine that mixes into a buffer when WebAudioSystem_pullFrames is called.
Expand Down
1 change: 1 addition & 0 deletions src/audio_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef struct {
// Returns 0.0 if unknown (e.g. stream not yet loaded or invalid index).
float (*getSoundLength)(AudioSystem* audio, int32_t soundOrInstance);
void (*setMasterGain)(AudioSystem* audio, float gain);
void (*setMasterGainForListener)(AudioSystem* audio, float gain, int32_t listenerId);
void (*setChannelCount)(AudioSystem* audio, int32_t count);
void (*groupLoad)(AudioSystem* audio, int32_t groupIndex);
bool (*groupIsLoaded)(AudioSystem* audio, int32_t groupIndex);
Expand Down
28 changes: 18 additions & 10 deletions src/collision.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ static inline InstanceBBox Collision_computeBBox(Runner* runner, Instance* inst)
Sprite* spr = Collision_getSprite(runner->dataWin, inst);
if (spr == nullptr) return (InstanceBBox){0, 0, 0, 0, false};

GMLReal marginL = (GMLReal) spr->marginLeft;
GMLReal marginR = (GMLReal) (spr->marginRight + 1);
GMLReal marginT = (GMLReal) spr->marginTop;
GMLReal marginB = (GMLReal) (spr->marginBottom + 1);
GMLReal marginL = (spr->bboxMode == 1) ? 0.0 : (GMLReal) spr->marginLeft;
GMLReal marginR = (spr->bboxMode == 1) ? (GMLReal) spr->width : (GMLReal) (spr->marginRight + 1);
GMLReal marginT = (spr->bboxMode == 1) ? 0.0 : (GMLReal) spr->marginTop;
GMLReal marginB = (spr->bboxMode == 1) ? (GMLReal) spr->height : (GMLReal) (spr->marginBottom + 1);
GMLReal originX = (GMLReal) spr->originX;
GMLReal originY = (GMLReal) spr->originY;

Expand Down Expand Up @@ -115,10 +115,10 @@ static inline InstanceOBB Collision_instanceOBB(Sprite* spr, Instance* inst) {
InstanceOBB obb;
obb.x = inst->x;
obb.y = inst->y;
GMLReal marginL = (GMLReal) spr->marginLeft;
GMLReal marginR = (GMLReal) (spr->marginRight + 1);
GMLReal marginT = (GMLReal) spr->marginTop;
GMLReal marginB = (GMLReal) (spr->marginBottom + 1);
GMLReal marginL = spr->bboxMode == 1 ? 0.0 : (GMLReal) spr->marginLeft;
GMLReal marginR = spr->bboxMode == 1 ? (GMLReal) spr->width : (GMLReal) (spr->marginRight + 1);
GMLReal marginT = spr->bboxMode == 1 ? 0.0 : (GMLReal) spr->marginTop;
GMLReal marginB = spr->bboxMode == 1 ? (GMLReal) spr->height : (GMLReal) (spr->marginBottom + 1);
GMLReal originX = (GMLReal) spr->originX;
GMLReal originY = (GMLReal) spr->originY;
obb.lx0 = inst->imageXscale * (marginL - originX);
Expand Down Expand Up @@ -233,8 +233,9 @@ static inline bool Collision_circleOverlapsInstance(Runner* runner, Instance* in
return dx * dx + dy * dy <= rSq;
}

// Liang-Barsky clip of a parametric line p(t) = p1 + t*(p2-p1), t in [0,1], against an axis-aligned rect [rx1,rx2] x [ry1,ry2]. Returns true if the segment intersects the rect.
static inline bool Collision_segmentVsAARect(GMLReal x1, GMLReal y1, GMLReal x2, GMLReal y2, GMLReal rx1, GMLReal ry1, GMLReal rx2, GMLReal ry2) {
// Liang-Barsky clip of a parametric line p(t) = p1 + t*(p2-p1), t in [0,1], against an axis-aligned rect [rx1,rx2] x [ry1,ry2].
// Returns true if the segment intersects the rect, and writes the clipped parametric range to *outTEnter/*outTExit.
static inline bool Collision_segmentVsAARectClip(GMLReal x1, GMLReal y1, GMLReal x2, GMLReal y2, GMLReal rx1, GMLReal ry1, GMLReal rx2, GMLReal ry2, GMLReal* outTEnter, GMLReal* outTExit) {
GMLReal tEnter = 0.0, tExit = 1.0;
GMLReal dx = x2 - x1, dy = y2 - y1;
GMLReal p[4] = { -dx, dx, -dy, dy };
Expand All @@ -252,9 +253,16 @@ static inline bool Collision_segmentVsAARect(GMLReal x1, GMLReal y1, GMLReal x2,
}
if (tEnter > tExit) return false;
}
*outTEnter = tEnter;
*outTExit = tExit;
return true;
}

static inline bool Collision_segmentVsAARect(GMLReal x1, GMLReal y1, GMLReal x2, GMLReal y2, GMLReal rx1, GMLReal ry1, GMLReal rx2, GMLReal ry2) {
GMLReal tEnter, tExit;
return Collision_segmentVsAARectClip(x1, y1, x2, y2, rx1, ry1, rx2, ry2, &tEnter, &tExit);
}

// Line segment (x1,y1)-(x2,y2) vs instance collision rect.
static inline bool Collision_lineOverlapsInstance(Runner* runner, Instance* inst, GMLReal x1, GMLReal y1, GMLReal x2, GMLReal y2) {
InstanceBBox bbox = Collision_computeBBox(runner, inst);
Expand Down
45 changes: 41 additions & 4 deletions src/gl/gl_renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2424,15 +2424,50 @@ static void glDeleteSprite(Renderer* renderer, int32_t spriteIndex) {
fprintf(stderr, "GL: Deleted sprite %d\n", spriteIndex);
}

static BlendFactors glGpuGetBlendFactors(Renderer* renderer) {
GLRenderer* gl = (GLRenderer*)renderer;
return (BlendFactors){
gl->currentSFactor,
gl->currentDFactor,
gl->currentSFactorAlpha,
gl->currentDFactorAlpha
};
}

static int32_t glGpuGetBlendMode(Renderer* renderer) {
GLRenderer* gl = (GLRenderer*) renderer;
return gl->currentBlendMode;
}

static void glGpuSetBlendMode(Renderer* renderer, int32_t mode) {
flushBatch((GLRenderer*) renderer);
GLRenderer* gl = (GLRenderer*) renderer;
flushBatch(gl);

gl->currentBlendMode = mode;
gl->currentSFactor = GLCommon_blendModeToSFactor(mode);
gl->currentDFactor = GLCommon_blendModeToDFactor(mode);
gl->currentSFactorAlpha = gl->currentSFactor;
gl->currentDFactorAlpha = gl->currentDFactor;

glBlendEquation(GLCommon_blendModeToEquation(mode));
glBlendFunc(GLCommon_blendModeToSFactor(mode), GLCommon_blendModeToDFactor(mode));
glBlendFunc(gl->currentSFactor, gl->currentDFactor);
}

static void glGpuSetBlendModeExt(Renderer* renderer, int32_t sfactor, int32_t dfactor, int32_t sfactor_alpha, int32_t dfactor_alpha) {
flushBatch((GLRenderer*) renderer);
glBlendFuncSeparate(GLCommon_blendFactorToGL(sfactor), GLCommon_blendFactorToGL(dfactor), GLCommon_blendFactorToGL(sfactor_alpha), GLCommon_blendFactorToGL(dfactor_alpha));
GLRenderer* gl = (GLRenderer*) renderer;
flushBatch(gl);
gl->currentBlendMode = bm_complex;
gl->currentSFactor = sfactor;
gl->currentDFactor = dfactor;
gl->currentSFactorAlpha = sfactor_alpha;
gl->currentDFactorAlpha = dfactor_alpha;

glBlendFuncSeparate(
GLCommon_blendFactorToGL(sfactor),
GLCommon_blendFactorToGL(dfactor),
GLCommon_blendFactorToGL(sfactor_alpha),
GLCommon_blendFactorToGL(dfactor_alpha)
);
}

static void glGpuSetBlendEnable(Renderer* renderer, bool enable) {
Expand Down Expand Up @@ -2728,6 +2763,8 @@ Renderer* GLRenderer_create(void) {
glVtable.clearScreen = glClearScreen;
glVtable.createSpriteFromSurface = glCreateSpriteFromSurface;
glVtable.deleteSprite = glDeleteSprite;
glVtable.gpuGetBlendFactors = glGpuGetBlendFactors;
glVtable.gpuGetBlendMode = glGpuGetBlendMode;
glVtable.gpuSetBlendMode = glGpuSetBlendMode;
glVtable.gpuSetBlendModeExt = glGpuSetBlendModeExt;
glVtable.gpuSetBlendEnable = glGpuSetBlendEnable;
Expand Down
7 changes: 7 additions & 0 deletions src/gl/gl_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ typedef struct {
int32_t* surfaceHeight;
uint32_t surfaceCount;

// Blending mode + factors
int32_t currentBlendMode;
int32_t currentSFactor;
int32_t currentDFactor;
int32_t currentSFactorAlpha;
int32_t currentDFactorAlpha;

bool isGL3; // TRUE if running on OpenGL (ES) 3.x+
bool isGLES; // TRUE if running on OpenGL ES (GLES)
} GLRenderer;
Expand Down
45 changes: 41 additions & 4 deletions src/gl_legacy/gl_legacy_renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1379,13 +1379,48 @@ static void glDeleteSprite(Renderer* renderer, int32_t spriteIndex) {
fprintf(stderr, "GL: Deleted sprite %d\n", spriteIndex);
}

static void glGpuSetBlendMode(MAYBE_UNUSED Renderer* renderer, int32_t mode) {
static BlendFactors glGpuGetBlendFactors(Renderer* renderer) {
GLLegacyRenderer* gl = (GLLegacyRenderer*)renderer;
return (BlendFactors){
gl->currentSFactor,
gl->currentDFactor,
gl->currentSFactorAlpha,
gl->currentDFactorAlpha
};
}

static int32_t glGpuGetBlendMode(Renderer* renderer) {
GLLegacyRenderer* gl = (GLLegacyRenderer*) renderer;
return gl->currentBlendMode;
}

static void glGpuSetBlendMode(Renderer* renderer, int32_t mode) {
GLLegacyRenderer* gl = (GLLegacyRenderer*) renderer;

gl->currentBlendMode = mode;
gl->currentSFactor = GLCommon_blendModeToSFactor(mode);
gl->currentDFactor = GLCommon_blendModeToDFactor(mode);
gl->currentSFactorAlpha = gl->currentSFactor;
gl->currentDFactorAlpha = gl->currentDFactor;
glBlendEquation(GLCommon_blendModeToEquation(mode));
glBlendFunc(GLCommon_blendModeToSFactor(mode), GLCommon_blendModeToDFactor(mode));
glBlendFunc(gl->currentSFactor, gl->currentDFactor);
}

static void glGpuSetBlendModeExt(MAYBE_UNUSED Renderer* renderer, int32_t sfactor, int32_t dfactor, int32_t sfactor_alpha, int32_t dfactor_alpha) {
glBlendFuncSeparate(GLCommon_blendFactorToGL(sfactor), GLCommon_blendFactorToGL(dfactor), GLCommon_blendFactorToGL(sfactor_alpha), GLCommon_blendFactorToGL(dfactor_alpha));
static void glGpuSetBlendModeExt(Renderer* renderer, int32_t sfactor, int32_t dfactor, int32_t sfactor_alpha, int32_t dfactor_alpha) {
GLLegacyRenderer* gl = (GLLegacyRenderer*) renderer;

gl->currentBlendMode = bm_complex;
gl->currentSFactor = sfactor;
gl->currentDFactor = dfactor;
gl->currentSFactorAlpha = sfactor_alpha;
gl->currentDFactorAlpha = dfactor_alpha;

glBlendFuncSeparate(
GLCommon_blendFactorToGL(sfactor),
GLCommon_blendFactorToGL(dfactor),
GLCommon_blendFactorToGL(sfactor_alpha),
GLCommon_blendFactorToGL(dfactor_alpha)
);
}

static void glGpuSetBlendEnable(Renderer* renderer, bool enable) {
Expand Down Expand Up @@ -1765,6 +1800,8 @@ Renderer* GLLegacyRenderer_create(void) {
glVtable.clearScreen = glClearScreen;
glVtable.createSpriteFromSurface = glCreateSpriteFromSurface;
glVtable.deleteSprite = glDeleteSprite;
glVtable.gpuGetBlendFactors = glGpuGetBlendFactors;
glVtable.gpuGetBlendMode = glGpuGetBlendMode;
glVtable.gpuSetBlendMode = glGpuSetBlendMode;
glVtable.gpuSetBlendModeExt = glGpuSetBlendModeExt;
glVtable.gpuSetBlendEnable = glGpuSetBlendEnable;
Expand Down
7 changes: 7 additions & 0 deletions src/gl_legacy/gl_legacy_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ typedef struct {
int32_t* surfaceWidth;
int32_t* surfaceHeight;
uint32_t surfaceCount;

// Blending mode + factors
int32_t currentBlendMode;
int32_t currentSFactor;
int32_t currentDFactor;
int32_t currentSFactorAlpha;
int32_t currentDFactorAlpha;
} GLLegacyRenderer;

bool GLLegacyRenderer_ensureTextureLoaded(GLLegacyRenderer* gl, uint32_t pageId);
Expand Down
Loading
Loading