More progress on audio and rendering
This commit is contained in:
BIN
assets/audio/testaid.mid
Normal file
BIN
assets/audio/testaid.mid
Normal file
Binary file not shown.
20
items/item.c
20
items/item.c
@@ -16,17 +16,18 @@ uint16_t itemRegistryIndex = 0;
|
|||||||
|
|
||||||
double speed = 1.0f / TILE_SIZE; // fraction of tile per tick
|
double speed = 1.0f / TILE_SIZE; // fraction of tile per tick
|
||||||
|
|
||||||
void updateItems() {
|
|
||||||
const int dirDx[8] = {-1, -1, -1, 0, 1, 1, 1, 0};
|
const int dirDx[8] = {-1, -1, -1, 0, 1, 1, 1, 0};
|
||||||
const int dirDy[8] = {1, 0, -1, -1, -1, 0, 1, 1};
|
const int dirDy[8] = {1, 0, -1, -1, -1, 0, 1, 1};
|
||||||
|
|
||||||
const float epsilon = 0.999f; // if we can't move, back it off just below 1
|
const float epsilon = 0.999f; // if we can't move, back it off just below 1
|
||||||
|
void updateItems() {
|
||||||
|
|
||||||
for (int y = 0; y < MAP_HEIGHT; y++) {
|
for (int i = 0; i < neededUpdates.activeCount; i++) {
|
||||||
for (int x = 0; x < MAP_WIDTH; x++) {
|
int x = neededUpdates.tiles[i].x;
|
||||||
|
int y = neededUpdates.tiles[i].y;
|
||||||
Tile *t = &tileMap[y][x];
|
Tile *t = &tileMap[y][x];
|
||||||
TileTypeReg tt = TileRegistry[t->type];
|
|
||||||
if (t->type == TYPE_AIR) continue;
|
if (t->type == TYPE_AIR) continue;
|
||||||
|
TileTypeReg tt = TileRegistry[t->type];
|
||||||
int dir = t->direction;
|
int dir = t->direction;
|
||||||
|
|
||||||
bool horz = (dir == ORIENT_LEFT || dir == ORIENT_RIGHT);
|
bool horz = (dir == ORIENT_LEFT || dir == ORIENT_RIGHT);
|
||||||
@@ -115,7 +116,6 @@ void updateItems() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void registerItem(char name[20], SDL_Renderer *renderer) {
|
void registerItem(char name[20], SDL_Renderer *renderer) {
|
||||||
@@ -129,8 +129,10 @@ void registerItem(char name[20], SDL_Renderer *renderer) {
|
|||||||
ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT],
|
ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT],
|
||||||
TILE_SIZE / 2, TILE_SIZE / 2);
|
TILE_SIZE / 2, TILE_SIZE / 2);
|
||||||
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
||||||
ItemRegistry[itemRegistryIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT], renderer);
|
ItemRegistry[itemRegistryIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(
|
||||||
ItemRegistry[itemRegistryIndex].atlasRectsOnBelt[ORIENT_LEFT] = allocate_16x16(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], renderer);
|
ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT], renderer);
|
||||||
|
ItemRegistry[itemRegistryIndex].atlasRectsOnBelt[ORIENT_LEFT] = allocate_16x16(
|
||||||
|
ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], renderer);
|
||||||
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
|
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
|
||||||
ItemRegistry[itemRegistryIndex].isTile = false;
|
ItemRegistry[itemRegistryIndex].isTile = false;
|
||||||
ItemRegistry[itemRegistryIndex].miscVal = 60;
|
ItemRegistry[itemRegistryIndex].miscVal = 60;
|
||||||
@@ -294,7 +296,9 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play
|
|||||||
adjustRect(&rectA, playerRect);
|
adjustRect(&rectA, playerRect);
|
||||||
SDL_RenderFillRect(renderer, &rectA);
|
SDL_RenderFillRect(renderer, &rectA);
|
||||||
}
|
}
|
||||||
SDL_RenderCopy(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &rect);
|
//SDL_RenderCopyx(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &rect);
|
||||||
|
SDL_RenderCopy(renderer, atlasTexture, &ItemRegistry[item.type].atlasRectsOnBelt[ORIENT_LEFT], &rect);
|
||||||
|
|
||||||
if (debugMode) {
|
if (debugMode) {
|
||||||
renderText(renderer, fonts[3], tempStr, rectA.x, rectA.y);
|
renderText(renderer, fonts[3], tempStr, rectA.x, rectA.y);
|
||||||
}
|
}
|
||||||
|
82
main.c
82
main.c
@@ -14,7 +14,8 @@ typedef struct GameState {
|
|||||||
Player player;
|
Player player;
|
||||||
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
BackgroundTile backgroundTileMap[MAP_HEIGHT][MAP_WIDTH];
|
BackgroundTile backgroundTileMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
SynthVoice voices[NUM_SYNTH_VOICES];
|
AudioData audioData;
|
||||||
|
TileArray neededUpdates;
|
||||||
} GameState;
|
} GameState;
|
||||||
GameState gameState;
|
GameState gameState;
|
||||||
|
|
||||||
@@ -34,7 +35,10 @@ int loadGameState(char *filename, Player *plr) {
|
|||||||
memcpy(plr, &gameState.player, sizeof(gameState.player));
|
memcpy(plr, &gameState.player, sizeof(gameState.player));
|
||||||
memcpy(tileMap, gameState.tileMap, sizeof(tileMap));
|
memcpy(tileMap, gameState.tileMap, sizeof(tileMap));
|
||||||
memcpy(backgroundMap, gameState.backgroundTileMap, sizeof(backgroundMap));
|
memcpy(backgroundMap, gameState.backgroundTileMap, sizeof(backgroundMap));
|
||||||
memcpy(audioData.synthVoices, gameState.voices, sizeof(gameState.voices));
|
SDL_Rect *tmp = audioData.playerRect;
|
||||||
|
memcpy(&audioData, &gameState.audioData, sizeof(gameState.audioData));
|
||||||
|
audioData.playerRect = tmp;
|
||||||
|
memcpy(&neededUpdates, &gameState.neededUpdates, sizeof(gameState.neededUpdates));
|
||||||
plr->cursor.targetTile = NULL;
|
plr->cursor.targetTile = NULL;
|
||||||
plr->cursor.prevTargetTile = NULL;
|
plr->cursor.prevTargetTile = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -46,7 +50,8 @@ void saveGameState(char *filename, Player *plr) {
|
|||||||
memcpy(&gameState.player, plr, sizeof(gameState.player));
|
memcpy(&gameState.player, plr, sizeof(gameState.player));
|
||||||
memcpy(gameState.tileMap, tileMap, sizeof(gameState.tileMap));
|
memcpy(gameState.tileMap, tileMap, sizeof(gameState.tileMap));
|
||||||
memcpy(gameState.backgroundTileMap, backgroundMap, sizeof(gameState.backgroundTileMap));
|
memcpy(gameState.backgroundTileMap, backgroundMap, sizeof(gameState.backgroundTileMap));
|
||||||
memcpy(gameState.voices, audioData.synthVoices, sizeof(gameState.voices));
|
memcpy(&gameState.audioData, &audioData, sizeof(gameState.audioData));
|
||||||
|
memcpy(&gameState.neededUpdates, &neededUpdates, sizeof(neededUpdates));
|
||||||
|
|
||||||
FILE *gameSave = fopen(filename, "wb");
|
FILE *gameSave = fopen(filename, "wb");
|
||||||
if (!gameSave) {
|
if (!gameSave) {
|
||||||
@@ -98,9 +103,11 @@ int init() {
|
|||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
memset(tileMap, 0, sizeof(tileMap));
|
memset(tileMap, 0, sizeof(tileMap));
|
||||||
|
memset(&neededUpdates, 0, sizeof(neededUpdates));
|
||||||
|
|
||||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
||||||
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
|
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
|
||||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1");
|
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1");
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
|
||||||
@@ -161,13 +168,16 @@ int init() {
|
|||||||
spec.callback = audio_callback;
|
spec.callback = audio_callback;
|
||||||
spec.userdata = &audioData;
|
spec.userdata = &audioData;
|
||||||
|
|
||||||
// SDL_AudioDeviceID dev = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0);
|
SDL_AudioDeviceID dev = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0);
|
||||||
// if (dev == 0) {
|
if (dev == 0) {
|
||||||
// printf("Failed to open audio: %s\n", SDL_GetError());
|
printf("Failed to open audio: %s\n", SDL_GetError());
|
||||||
// SDL_Quit();
|
SDL_Quit();
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SDL_PauseAudioDevice(dev, 1);
|
load_midi_file("assets/audio/testaid.mid");
|
||||||
|
|
||||||
|
SDL_PauseAudioDevice(dev, 0);
|
||||||
|
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(mainRenderer);
|
SDL_RenderClear(mainRenderer);
|
||||||
@@ -203,19 +213,23 @@ int render() {
|
|||||||
SDL_Rect rect2;
|
SDL_Rect rect2;
|
||||||
rect2.x = 0;
|
rect2.x = 0;
|
||||||
rect2.y = 0;
|
rect2.y = 0;
|
||||||
rect2.w = 0;
|
rect2.w = ATLAS_SIZE;
|
||||||
rect2.h = 0;
|
rect2.h = ATLAS_SIZE;
|
||||||
|
|
||||||
renderAllTiles(mainRenderer, player.rect);
|
renderAllTiles(mainRenderer, player.rect);
|
||||||
renderPlayer(&player);
|
renderPlayer(&player);
|
||||||
|
|
||||||
// SDL_RenderCopy(mainRenderer, backgroundTexture, &screenRect, &screenRect);
|
|
||||||
// SDL_RenderCopy(mainRenderer, tilesTexture, &screenRect, &screenRect);
|
if (!renderAtlas) {
|
||||||
// SDL_RenderCopy(mainRenderer, itemsTexture, &screenRect, &screenRect);
|
SDL_RenderCopy(mainRenderer, backgroundTexture, &screenRect, &screenRect);
|
||||||
// SDL_RenderCopy(mainRenderer, entityTexture, &screenRect, &screenRect);
|
SDL_RenderCopy(mainRenderer, tilesTexture, &screenRect, &screenRect);
|
||||||
// SDL_RenderCopy(mainRenderer, hudTexture, &screenRect, &screenRect);
|
SDL_RenderCopy(mainRenderer, itemsTexture, &screenRect, &screenRect);
|
||||||
SDL_QueryTexture(atlasTexture, NULL, NULL, &rect2.w, &rect2.h);
|
SDL_RenderCopy(mainRenderer, entityTexture, &screenRect, &screenRect);
|
||||||
|
SDL_RenderCopy(mainRenderer, hudTexture, &screenRect, &screenRect);
|
||||||
|
|
||||||
|
} else {
|
||||||
SDL_RenderCopy(mainRenderer, atlasTexture, &rect2, &rect2);
|
SDL_RenderCopy(mainRenderer, atlasTexture, &rect2, &rect2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_RenderPresent(mainRenderer);
|
SDL_RenderPresent(mainRenderer);
|
||||||
@@ -246,11 +260,12 @@ int processEvent(SDL_Event e) {
|
|||||||
speed = speed == 0 ? 0.004f : 0;
|
speed = speed == 0 ? 0.004f : 0;
|
||||||
break;
|
break;
|
||||||
case SDLK_r:
|
case SDLK_r:
|
||||||
if (player.cursor.canReach && player.cursor.targetTile->type != TYPE_AIR) {
|
if (player.inventory.activeSlotIndex == 0 && player.cursor.canReach &&
|
||||||
|
player.cursor.targetTile->type != TYPE_AIR) {
|
||||||
player.cursor.direction = player.cursor.targetTile->direction;
|
player.cursor.direction = player.cursor.targetTile->direction;
|
||||||
}
|
}
|
||||||
player.cursor.direction = (player.cursor.direction + 2) % ORIENT_DIRECTION_COUNT;
|
player.cursor.direction = (player.cursor.direction + 2) % ORIENT_DIRECTION_COUNT;
|
||||||
if (player.cursor.canReach) {
|
if (player.inventory.activeSlotIndex == 0 && player.cursor.canReach) {
|
||||||
player.cursor.targetTile->direction = player.cursor.direction;
|
player.cursor.targetTile->direction = player.cursor.direction;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -260,6 +275,9 @@ int processEvent(SDL_Event e) {
|
|||||||
case SDLK_F3:
|
case SDLK_F3:
|
||||||
debugMode = !debugMode;
|
debugMode = !debugMode;
|
||||||
break;
|
break;
|
||||||
|
case SDLK_F10:
|
||||||
|
renderAtlas = !renderAtlas;
|
||||||
|
break;
|
||||||
case SDLK_F4:
|
case SDLK_F4:
|
||||||
Tile *tile = &tileMap[playerTileY][playerTileX];
|
Tile *tile = &tileMap[playerTileY][playerTileX];
|
||||||
break;
|
break;
|
||||||
@@ -306,6 +324,12 @@ void processMousePosition() {
|
|||||||
if (player.inventory.slotCounts[player.inventory.activeSlotIndex] > 0) {
|
if (player.inventory.slotCounts[player.inventory.activeSlotIndex] > 0) {
|
||||||
player.inventory.slotCounts[player.inventory.activeSlotIndex]--;
|
player.inventory.slotCounts[player.inventory.activeSlotIndex]--;
|
||||||
player.cursor.targetTile->type = player.inventory.activeSlotIndex;
|
player.cursor.targetTile->type = player.inventory.activeSlotIndex;
|
||||||
|
player.cursor.targetTile->rect.x = player.cursor.tileX;
|
||||||
|
player.cursor.targetTile->rect.y = player.cursor.tileY;
|
||||||
|
if (TileRegistry[player.inventory.activeSlotIndex].needsTicks) {
|
||||||
|
player.cursor.targetTile->neededUpdateIndex = add_tile(&neededUpdates,
|
||||||
|
player.cursor.targetTile->rect);
|
||||||
|
}
|
||||||
player.cursor.targetTile->direction = player.cursor.direction;
|
player.cursor.targetTile->direction = player.cursor.direction;
|
||||||
}
|
}
|
||||||
} else if (player.cursor.targetTile->type == player.inventory.activeSlotIndex) {
|
} else if (player.cursor.targetTile->type == player.inventory.activeSlotIndex) {
|
||||||
@@ -329,6 +353,12 @@ void processMousePosition() {
|
|||||||
player.cursor.targetTile->items[lane].type = 0;
|
player.cursor.targetTile->items[lane].type = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int neededIndex = player.cursor.targetTile->neededUpdateIndex;
|
||||||
|
if (TileRegistry[player.cursor.targetTile->type].needsTicks &&
|
||||||
|
neededUpdates.tiles[neededIndex].x == player.cursor.targetTile->rect.x &&
|
||||||
|
neededUpdates.tiles[neededIndex].y == player.cursor.targetTile->rect.y) {
|
||||||
|
remove_tile(&neededUpdates, neededIndex);
|
||||||
|
}
|
||||||
player.cursor.targetTile->type = TYPE_AIR;
|
player.cursor.targetTile->type = TYPE_AIR;
|
||||||
player.cursor.breakingProgress = 0;
|
player.cursor.breakingProgress = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -461,8 +491,10 @@ void processKeyboardHeld() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (keyboardState[SDL_SCANCODE_Q]) {
|
if (keyboardState[SDL_SCANCODE_Q]) {
|
||||||
if (player.cursor.targetTile->type > 0) {
|
if (player.cursor.targetTile->type > 0 && player.inventory.activeSlotIndex == 0) {
|
||||||
setActivePlayerSlot(&player, player.cursor.targetTile->type);
|
setActivePlayerSlot(&player, player.cursor.targetTile->type);
|
||||||
|
} else {
|
||||||
|
setActivePlayerSlot(&player, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyboardState[SDL_SCANCODE_Y]) {
|
if (keyboardState[SDL_SCANCODE_Y]) {
|
||||||
@@ -519,6 +551,14 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
genInitMap();
|
genInitMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// audioData.synthVoices[0].frequency = 1000;
|
||||||
|
// audioData.synthVoices[0].phase = 0;
|
||||||
|
// audioData.synthVoices[0].sourceRect.w = TILE_SIZE;
|
||||||
|
// audioData.synthVoices[0].sourceRect.h = TILE_SIZE;
|
||||||
|
// audioData.synthVoices[0].sourceRect.x = 100 * TILE_SIZE;
|
||||||
|
// audioData.synthVoices[0].sourceRect.y = 100 * TILE_SIZE;
|
||||||
|
// audioData.synthVoices[0].volume = 255;
|
||||||
|
// audioData.synthVoices[0].waveform = WAVE_SINE;
|
||||||
|
|
||||||
//Hack to get window to stay up
|
//Hack to get window to stay up
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "../tiles/tile.h"
|
#include "../tiles/tile.h"
|
||||||
#include "../util/font.h"
|
#include "../util/font.h"
|
||||||
|
#include "../util/atlas.h"
|
||||||
|
|
||||||
#define HEALTH_MARGIN 4
|
#define HEALTH_MARGIN 4
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ SDL_Texture *hudTexture;
|
|||||||
|
|
||||||
SDL_Texture *PlayerTexture;
|
SDL_Texture *PlayerTexture;
|
||||||
SDL_Rect PlayerRect;
|
SDL_Rect PlayerRect;
|
||||||
|
SDL_Rect playerTextureRect;
|
||||||
|
|
||||||
SDL_Rect targetItemBGRect;
|
SDL_Rect targetItemBGRect;
|
||||||
|
|
||||||
@@ -28,9 +30,6 @@ SDL_Color breakingBarColor = {128, 128, 0, 255};
|
|||||||
|
|
||||||
void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) {
|
void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) {
|
||||||
activeSlotIndex = activeSlotIndex % itemRegistryIndex;
|
activeSlotIndex = activeSlotIndex % itemRegistryIndex;
|
||||||
if (activeSlotIndex <= 0) {
|
|
||||||
activeSlotIndex = 1;
|
|
||||||
}
|
|
||||||
plr->inventory.activeSlotIndex = activeSlotIndex;
|
plr->inventory.activeSlotIndex = activeSlotIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ void moveActivePlayerSlot(Player *plr, bool up, bool seek) {
|
|||||||
|
|
||||||
// Stop if we found a slot with count > 0
|
// Stop if we found a slot with count > 0
|
||||||
if (!strlen(ItemRegistry[newSlot].name)) continue;
|
if (!strlen(ItemRegistry[newSlot].name)) continue;
|
||||||
if (newSlot == 0) continue;
|
if (newSlot == 0) break;
|
||||||
if (seek) {
|
if (seek) {
|
||||||
if (plr->inventory.slotCounts[newSlot] > 0) break;
|
if (plr->inventory.slotCounts[newSlot] > 0) break;
|
||||||
} else {
|
} else {
|
||||||
@@ -104,6 +103,7 @@ void initPlayer(Player *plr) {
|
|||||||
SDL_QueryTexture(PlayerTexture, NULL, NULL, &PlayerRect.w, &PlayerRect.h);
|
SDL_QueryTexture(PlayerTexture, NULL, NULL, &PlayerRect.w, &PlayerRect.h);
|
||||||
PlayerRect.x = (DISPLAY_WIDTH / 2) - (PlayerRect.w / 2);
|
PlayerRect.x = (DISPLAY_WIDTH / 2) - (PlayerRect.w / 2);
|
||||||
PlayerRect.y = (DISPLAY_HEIGHT / 2) - (PlayerRect.h / 2);
|
PlayerRect.y = (DISPLAY_HEIGHT / 2) - (PlayerRect.h / 2);
|
||||||
|
playerTextureRect = allocate_32x32(PlayerTexture, mainRenderer);
|
||||||
plr->health = 64;
|
plr->health = 64;
|
||||||
plr->healthIdle = 0;
|
plr->healthIdle = 0;
|
||||||
|
|
||||||
@@ -112,12 +112,12 @@ void initPlayer(Player *plr) {
|
|||||||
plr->rect.w = TILE_SIZE;
|
plr->rect.w = TILE_SIZE;
|
||||||
plr->rect.h = TILE_SIZE;
|
plr->rect.h = TILE_SIZE;
|
||||||
|
|
||||||
for (ItemType ui = 0; ui < tileTypeIndex; ui++) {
|
for (ItemType ui = 1; ui < tileTypeIndex; ui++) {
|
||||||
plr->inventory.slotCounts[ui] = 64;
|
plr->inventory.slotCounts[ui] = 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ItemType ui = ITEMREGISTRY_SIZE / 2; ui < itemRegistryIndex; ui++) {
|
for (ItemType ui = ITEMREGISTRY_SIZE / 2; ui < itemRegistryIndex; ui++) {
|
||||||
plr->inventory.slotCounts[ui] = 64;
|
plr->inventory.slotCounts[ui] = 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
hudTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
hudTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
||||||
@@ -135,12 +135,12 @@ void initPlayer(Player *plr) {
|
|||||||
plr->cursor.targetTileRect.h = TILE_SIZE;
|
plr->cursor.targetTileRect.h = TILE_SIZE;
|
||||||
|
|
||||||
targetItemBGRect.w = DISPLAY_WIDTH;
|
targetItemBGRect.w = DISPLAY_WIDTH;
|
||||||
targetItemBGRect.h = TILE_SIZE;
|
targetItemBGRect.h = TILE_SIZE + fonts[2].size * 2;
|
||||||
targetItemBGRect.x = 0;
|
targetItemBGRect.x = 0;
|
||||||
targetItemBGRect.y = DISPLAY_HEIGHT - 32;
|
targetItemBGRect.y = DISPLAY_HEIGHT - TILE_SIZE - fonts[2].size * 2;
|
||||||
|
|
||||||
targetItemRect.w = TILE_SIZE / 2;
|
targetItemRect.w = TILE_SIZE;
|
||||||
targetItemRect.h = TILE_SIZE / 2;
|
targetItemRect.h = TILE_SIZE;
|
||||||
|
|
||||||
plr->cursor.heldItemRect.w = TILE_SIZE;
|
plr->cursor.heldItemRect.w = TILE_SIZE;
|
||||||
plr->cursor.heldItemRect.h = TILE_SIZE;
|
plr->cursor.heldItemRect.h = TILE_SIZE;
|
||||||
@@ -164,7 +164,8 @@ void renderPlayer(Player *plr) {
|
|||||||
|
|
||||||
SDL_SetRenderTarget(mainRenderer, entityTexture);
|
SDL_SetRenderTarget(mainRenderer, entityTexture);
|
||||||
SDL_RenderClear(mainRenderer);
|
SDL_RenderClear(mainRenderer);
|
||||||
SDL_RenderCopy(mainRenderer, PlayerTexture, NULL, &PlayerRect);
|
SDL_RenderCopy(mainRenderer, atlasTexture, &playerTextureRect, &PlayerRect);
|
||||||
|
//SDL_RenderCopy(mainRenderer, PlayerTexture, NULL, &PlayerRect);
|
||||||
SDL_SetRenderTarget(mainRenderer, hudTexture);
|
SDL_SetRenderTarget(mainRenderer, hudTexture);
|
||||||
SDL_RenderClear(mainRenderer);
|
SDL_RenderClear(mainRenderer);
|
||||||
|
|
||||||
@@ -172,29 +173,31 @@ void renderPlayer(Player *plr) {
|
|||||||
DrawThickRect(mainRenderer, plr->cursor.targetTileRect, 4);
|
DrawThickRect(mainRenderer, plr->cursor.targetTileRect, 4);
|
||||||
|
|
||||||
ItemType itemIndex = plr->inventory.activeSlotIndex;
|
ItemType itemIndex = plr->inventory.activeSlotIndex;
|
||||||
SDL_Texture *itemTex;
|
//SDL_Texture *itemTex;
|
||||||
char itemStringCount[6];
|
char itemStringCount[6];
|
||||||
if (itemIndex < itemRegistryIndex) {
|
if (itemIndex < itemRegistryIndex && itemIndex > 0) {
|
||||||
plr->cursor.heldItemRect.x = plr->cursor.windowX;
|
plr->cursor.heldItemRect.x = plr->cursor.windowX;
|
||||||
plr->cursor.heldItemRect.y = plr->cursor.windowY;
|
plr->cursor.heldItemRect.y = plr->cursor.windowY;
|
||||||
itemTex = ItemRegistry[itemIndex].textureOnBelt[plr->cursor.direction];
|
//itemTex = ItemRegistry[itemIndex].textureOnBelt[plr->cursor.direction];
|
||||||
if (itemTex == NULL) {
|
SDL_Rect itemAtlasRect = ItemRegistry[itemIndex].atlasRects[plr->cursor.direction];
|
||||||
itemTex = ItemRegistry[itemIndex].textureOnBelt[ORIENT_LEFT];
|
if (itemAtlasRect.w == 0 || itemAtlasRect.h == 0) {
|
||||||
|
itemAtlasRect = ItemRegistry[itemIndex].atlasRects[ORIENT_LEFT];
|
||||||
}
|
}
|
||||||
if (itemTex != NULL) {
|
if (itemAtlasRect.w != 0 && itemAtlasRect.h != 0) {
|
||||||
|
|
||||||
if (plr->inventory.slotCounts[itemIndex] <= 0) {
|
// if (plr->inventory.slotCounts[itemIndex] <= 0) {
|
||||||
// Set a red tint (255, 0, 0)
|
// // Set a red tint (255, 0, 0)
|
||||||
SDL_SetTextureColorMod(itemTex, 128, 128, 255);
|
// SDL_SetTextureColorMod(itemTex, 128, 128, 255);
|
||||||
|
//
|
||||||
SDL_SetTextureAlphaMod(itemTex, 192);
|
// SDL_SetTextureAlphaMod(itemTex, 192);
|
||||||
} else {
|
// } else {
|
||||||
SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
// SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
||||||
|
//
|
||||||
SDL_SetTextureAlphaMod(itemTex, 255);
|
// SDL_SetTextureAlphaMod(itemTex, 255);
|
||||||
}
|
// }
|
||||||
SDL_RenderCopy(mainRenderer, itemTex, NULL,
|
// SDL_RenderCopy(mainRenderer, itemTex, NULL,
|
||||||
&plr->cursor.heldItemRect);
|
// &plr->cursor.heldItemRect);
|
||||||
|
SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRect, &plr->cursor.heldItemRect);
|
||||||
renderText(mainRenderer, fonts[2], ItemRegistry[itemIndex].name, plr->cursor.heldItemRect.x,
|
renderText(mainRenderer, fonts[2], ItemRegistry[itemIndex].name, plr->cursor.heldItemRect.x,
|
||||||
plr->cursor.heldItemRect.y - (fonts[2].size * 3 / 2));
|
plr->cursor.heldItemRect.y - (fonts[2].size * 3 / 2));
|
||||||
}
|
}
|
||||||
@@ -215,21 +218,22 @@ void renderPlayer(Player *plr) {
|
|||||||
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
||||||
SDL_RenderFillRect(mainRenderer, &targetItemBGRect);
|
SDL_RenderFillRect(mainRenderer, &targetItemBGRect);
|
||||||
|
|
||||||
targetItemRect.y = DISPLAY_HEIGHT - 30 + TILE_SIZE / 4 + 3;
|
targetItemRect.y = DISPLAY_HEIGHT - TILE_SIZE;
|
||||||
targetItemRect.x = TILE_SIZE / 4;
|
targetItemRect.x = TILE_SIZE / 4;
|
||||||
|
|
||||||
for (ItemType i = 1; i < ITEMREGISTRY_SIZE; i++) {
|
SDL_SetTextureBlendMode(atlasTexture, SDL_BLENDMODE_ADD);
|
||||||
itemTex = ItemRegistry[i].textureOnBelt[plr->cursor.direction];
|
for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) {
|
||||||
if (itemTex == NULL) {
|
SDL_Rect itemAtlasRectd = ItemRegistry[i].atlasRects[plr->cursor.direction];
|
||||||
itemTex = ItemRegistry[i].textureOnBelt[ORIENT_LEFT];
|
if (itemAtlasRectd.w == 0 || itemAtlasRectd.h == 0) {
|
||||||
|
itemAtlasRectd = ItemRegistry[i].atlasRects[ORIENT_LEFT];
|
||||||
}
|
}
|
||||||
if (itemTex != NULL) {
|
if (itemAtlasRectd.w != 0 && itemAtlasRectd.h != 0) {
|
||||||
if (plr->inventory.slotCounts[i] <= 0) {
|
// if (plr->inventory.slotCounts[i] <= 0) {
|
||||||
// Set a red tint (255, 0, 0)
|
// // Set a red tint (255, 0, 0)
|
||||||
SDL_SetTextureColorMod(itemTex, 128, 128, 255);
|
// SDL_SetTextureColorMod(itemTex, 128, 128, 255);
|
||||||
}
|
// }
|
||||||
SDL_RenderCopy(mainRenderer, itemTex, NULL, &targetItemRect);
|
SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRectd, &targetItemRect);
|
||||||
SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
//SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
||||||
|
|
||||||
if (plr->inventory.activeSlotIndex == i) {
|
if (plr->inventory.activeSlotIndex == i) {
|
||||||
SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16,
|
SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16,
|
||||||
@@ -240,9 +244,10 @@ void renderPlayer(Player *plr) {
|
|||||||
renderText(mainRenderer, fonts[2], itemStringCount, targetItemRect.x - 3,
|
renderText(mainRenderer, fonts[2], itemStringCount, targetItemRect.x - 3,
|
||||||
targetItemRect.y - (fonts[2].size * 3 / 2));
|
targetItemRect.y - (fonts[2].size * 3 / 2));
|
||||||
//targetItemRect.x += (TILE_SIZE / 2) + (TILE_SIZE / 4);
|
//targetItemRect.x += (TILE_SIZE / 2) + (TILE_SIZE / 4);
|
||||||
targetItemRect.x += TILE_SIZE;
|
targetItemRect.x += TILE_SIZE / 2 * 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SDL_SetTextureBlendMode(atlasTexture, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
SDL_SetRenderTarget(mainRenderer, originalTarget);
|
SDL_SetRenderTarget(mainRenderer, originalTarget);
|
||||||
}
|
}
|
10
tiles/belt.c
10
tiles/belt.c
@@ -8,6 +8,7 @@
|
|||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
|
#include "../util/atlas.h"
|
||||||
|
|
||||||
|
|
||||||
void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect playerRect, SDL_Renderer *renderer) {
|
void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect playerRect, SDL_Renderer *renderer) {
|
||||||
@@ -36,8 +37,10 @@ void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect player
|
|||||||
adjustRect(&dst1, playerRect);
|
adjustRect(&dst1, playerRect);
|
||||||
adjustRect(&dst2, playerRect);
|
adjustRect(&dst2, playerRect);
|
||||||
|
|
||||||
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1);
|
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1); //TODO CONVERT TO ATLAS
|
||||||
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2);
|
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2); //TODO CONVERT TO ATLAS
|
||||||
|
// SDL_RenderCopyx(renderer, atlasTexture, &TileRegistry[tileType].atlasRects[dir], NULL);
|
||||||
|
// SDL_RenderCopyx(renderer, atlasTexture, &TileRegistry[tileType].atlasRects[dir], NULL);
|
||||||
} else {
|
} else {
|
||||||
int offset = scrollFrame % TILE_SIZE;
|
int offset = scrollFrame % TILE_SIZE;
|
||||||
|
|
||||||
@@ -56,6 +59,9 @@ void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect player
|
|||||||
|
|
||||||
|
|
||||||
// Rotate to make the belt vertical
|
// Rotate to make the belt vertical
|
||||||
|
// SDL_RenderCopyx(renderer, atlasTexture, &ItemRegistry[item.type].atlasRectsOnBelt[ORIENT_LEFT], NULL);
|
||||||
|
// SDL_RenderCopyx(renderer, atlasTexture, &ItemRegistry[item.type].atlasRectsOnBelt[ORIENT_LEFT], NULL);
|
||||||
|
|
||||||
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1);
|
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1);
|
||||||
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2);
|
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2);
|
||||||
}
|
}
|
||||||
|
@@ -27,16 +27,19 @@ void updateFurnace(Tile *tile) {
|
|||||||
if (tile->miscVal == 0) {
|
if (tile->miscVal == 0) {
|
||||||
tile->audioCh = getAvailableChannel();
|
tile->audioCh = getAvailableChannel();
|
||||||
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
audioData.synthVoices[tile->audioCh].volume = 1;
|
audioData.synthVoices[tile->audioCh].volume = 255;
|
||||||
audioData.synthVoices[tile->audioCh].phase = 0;
|
audioData.synthVoices[tile->audioCh].phase = 0;
|
||||||
audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->x;
|
audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->rect.x;
|
||||||
audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->y;
|
audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->rect.y;
|
||||||
audioData.synthVoices[tile->audioCh].waveform = WAVE_TRIANGLE;
|
audioData.synthVoices[tile->audioCh].waveform = WAVE_SINE;
|
||||||
audioData.synthVoices[tile->audioCh].frequency = 99;
|
audioData.synthVoices[tile->audioCh].frequency = 200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
audioData.synthVoices[tile->audioCh].frequency++;
|
printf("frq: %d\n", ++audioData.synthVoices[tile->audioCh].frequency);
|
||||||
|
}
|
||||||
|
if (audioData.synthVoices[tile->audioCh].volume < 255) {
|
||||||
|
audioData.synthVoices[tile->audioCh].volume++;
|
||||||
}
|
}
|
||||||
if (outItem->type == 0 && ++tile->miscVal >= targetOutItem.miscVal) {
|
if (outItem->type == 0 && ++tile->miscVal >= targetOutItem.miscVal) {
|
||||||
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
|
76
tiles/tile.c
76
tiles/tile.c
@@ -2,15 +2,31 @@
|
|||||||
// Created by bruno on 4/24/25.
|
// Created by bruno on 4/24/25.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "furnace.h"
|
#include "furnace.h"
|
||||||
#include "../util/atlas.h"
|
#include "../util/atlas.h"
|
||||||
|
#include "../util/font.h"
|
||||||
|
|
||||||
int scrollFrame = 0;
|
int scrollFrame = 0;
|
||||||
unsigned long beltFrames = 0;
|
unsigned long beltFrames = 0;
|
||||||
|
|
||||||
|
TileArray neededUpdates;
|
||||||
|
|
||||||
|
int add_tile(TileArray *arr, MiniRect t) {
|
||||||
|
if (arr->activeCount >= MAX_TILES) return 0;
|
||||||
|
arr->tiles[arr->activeCount] = t;
|
||||||
|
arr->activeCount++;
|
||||||
|
return arr->activeCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_tile(TileArray *arr, int index) {
|
||||||
|
if (index < 0 || index >= arr->activeCount) return;
|
||||||
|
arr->activeCount--;
|
||||||
|
arr->tiles[index] = arr->tiles[arr->activeCount]; // swap with last active
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_Texture *backgroundTexture;
|
SDL_Texture *backgroundTexture;
|
||||||
SDL_Texture *tilesTexture;
|
SDL_Texture *tilesTexture;
|
||||||
SDL_Texture *itemsTexture;
|
SDL_Texture *itemsTexture;
|
||||||
@@ -30,8 +46,8 @@ void generateTestMap() {
|
|||||||
for (int y = 0; y < DISPLAY_MAP_HEIGHT; y++) {
|
for (int y = 0; y < DISPLAY_MAP_HEIGHT; y++) {
|
||||||
for (int x = 0; x < DISPLAY_MAP_WIDTH; x++) {
|
for (int x = 0; x < DISPLAY_MAP_WIDTH; x++) {
|
||||||
Tile tile = {0};
|
Tile tile = {0};
|
||||||
tile.x = x;
|
tile.rect.x = x;
|
||||||
tile.y = y;
|
tile.rect.y = y;
|
||||||
tileMap[y][x] = tile;
|
tileMap[y][x] = tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,21 +82,19 @@ void registerTile(char name[20], SDL_Renderer *renderer) {
|
|||||||
TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT] = createFlippedTexture(renderer, texture, SDL_FLIP_HORIZONTAL);
|
TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT] = createFlippedTexture(renderer, texture, SDL_FLIP_HORIZONTAL);
|
||||||
TileRegistry[tileTypeIndex].textures[ORIENT_UP] = createRotatedTexture(renderer, texture, 90);
|
TileRegistry[tileTypeIndex].textures[ORIENT_UP] = createRotatedTexture(renderer, texture, 90);
|
||||||
TileRegistry[tileTypeIndex].textures[ORIENT_DOWN] = createRotatedTexture(renderer, texture, 270);
|
TileRegistry[tileTypeIndex].textures[ORIENT_DOWN] = createRotatedTexture(renderer, texture, 270);
|
||||||
if (tileTypeIndex == 0) {
|
|
||||||
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_LEFT], 64);
|
|
||||||
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_RIGHT], 64);
|
|
||||||
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_UP], 64);
|
|
||||||
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_DOWN], 64);
|
|
||||||
}
|
|
||||||
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_UP], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_UP], SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
TileRegistry[tileTypeIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], renderer);
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(
|
||||||
TileRegistry[tileTypeIndex].atlasRects[ORIENT_RIGHT] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], renderer);
|
TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], renderer);
|
||||||
TileRegistry[tileTypeIndex].atlasRects[ORIENT_UP] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_UP], renderer);
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_RIGHT] = allocate_32x32(
|
||||||
TileRegistry[tileTypeIndex].atlasRects[ORIENT_DOWN] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], renderer);
|
TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], renderer);
|
||||||
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_UP] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_UP],
|
||||||
|
renderer);
|
||||||
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_DOWN] = allocate_32x32(
|
||||||
|
TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], renderer);
|
||||||
|
|
||||||
TileRegistry[tileTypeIndex].type = tileTypeIndex;
|
TileRegistry[tileTypeIndex].type = tileTypeIndex;
|
||||||
TileRegistry[tileTypeIndex].breakTime = 15;
|
TileRegistry[tileTypeIndex].breakTime = 15;
|
||||||
@@ -96,7 +110,8 @@ void registerBackgroundTile(char name[20], SDL_Renderer *renderer) {
|
|||||||
SDL_Texture *texture = IMG_LoadTexture(renderer, texturePath);
|
SDL_Texture *texture = IMG_LoadTexture(renderer, texturePath);
|
||||||
BackgroundTileRegistry[backgroundTileTypeIndex].texture = texture;
|
BackgroundTileRegistry[backgroundTileTypeIndex].texture = texture;
|
||||||
SDL_SetTextureBlendMode(BackgroundTileRegistry[backgroundTileTypeIndex].texture, SDL_BLENDMODE_NONE);
|
SDL_SetTextureBlendMode(BackgroundTileRegistry[backgroundTileTypeIndex].texture, SDL_BLENDMODE_NONE);
|
||||||
BackgroundTileRegistry[backgroundTileTypeIndex].atlasRect = allocate_32x32(BackgroundTileRegistry[backgroundTileTypeIndex].texture, renderer);
|
BackgroundTileRegistry[backgroundTileTypeIndex].atlasRect = allocate_32x32(
|
||||||
|
BackgroundTileRegistry[backgroundTileTypeIndex].texture, renderer);
|
||||||
|
|
||||||
BackgroundTileRegistry[backgroundTileTypeIndex].type = backgroundTileTypeIndex;
|
BackgroundTileRegistry[backgroundTileTypeIndex].type = backgroundTileTypeIndex;
|
||||||
|
|
||||||
@@ -128,6 +143,8 @@ void setupTiles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1;
|
TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1;
|
||||||
|
TileRegistry[TYPE_FURNACE].needsTicks = true;
|
||||||
|
TileRegistry[TYPE_BELT].needsTicks = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getBreakTime(int type) {
|
uint16_t getBreakTime(int type) {
|
||||||
@@ -186,8 +203,10 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|||||||
|
|
||||||
BackgroundTile bt = backgroundMap[y][x];
|
BackgroundTile bt = backgroundMap[y][x];
|
||||||
SDL_Texture *tex = BackgroundTileRegistry[bt.type].texture;
|
SDL_Texture *tex = BackgroundTileRegistry[bt.type].texture;
|
||||||
if (tex != NULL) {
|
SDL_Rect atlRect = BackgroundTileRegistry[bt.type].atlasRect;
|
||||||
SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
if (atlRect.w != 0 && atlRect.h != 0) {
|
||||||
|
SDL_RenderCopy(renderer, atlasTexture, &atlRect, &dstRect);
|
||||||
|
//SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,14 +228,21 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|||||||
|
|
||||||
Tile t = tileMap[y][x];
|
Tile t = tileMap[y][x];
|
||||||
switch (t.type) {
|
switch (t.type) {
|
||||||
|
case TYPE_AIR:
|
||||||
|
break;
|
||||||
case TYPE_BELT:
|
case TYPE_BELT:
|
||||||
renderBelt(x, y, tileSize, tileSize, t.direction, playerRect, renderer);
|
renderBelt(x, y, tileSize, tileSize, t.direction, playerRect, renderer);
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
|
SDL_Rect atlRect = TileRegistry[t.type].atlasRects[t.direction];
|
||||||
SDL_Texture *tex = TileRegistry[t.type].textures[t.direction];
|
SDL_Texture *tex = TileRegistry[t.type].textures[t.direction];
|
||||||
if (tex == NULL) tex = TileRegistry[t.type].textures[ORIENT_LEFT];
|
if (atlRect.w == 0 || atlRect.h == 0) {
|
||||||
if (tex != NULL) {
|
tex = TileRegistry[t.type].textures[ORIENT_LEFT];
|
||||||
SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
atlRect = TileRegistry[t.type].atlasRects[ORIENT_LEFT];
|
||||||
|
}
|
||||||
|
if (atlRect.w != 0 && atlRect.h != 0) {
|
||||||
|
//SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
||||||
|
SDL_RenderCopy(renderer, atlasTexture, &atlRect, &dstRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,6 +257,18 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|||||||
if (x < 0 || x >= MAP_WIDTH) continue;
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
||||||
|
|
||||||
Tile t = tileMap[y][x];
|
Tile t = tileMap[y][x];
|
||||||
|
if (debugMode) {
|
||||||
|
char locChar[20];
|
||||||
|
sprintf(locChar, "X:%d\nY:%d", x, y);
|
||||||
|
SDL_Rect dstRect = {
|
||||||
|
.x = x * TILE_SIZE,
|
||||||
|
.y = y * TILE_SIZE,
|
||||||
|
.w = TILE_SIZE,
|
||||||
|
.h = TILE_SIZE
|
||||||
|
};
|
||||||
|
adjustRect(&dstRect, playerRect);
|
||||||
|
renderText(renderer, fonts[3], locChar, dstRect.x, dstRect.y);
|
||||||
|
}
|
||||||
if (t.type == TYPE_BELT || itemViewing) {
|
if (t.type == TYPE_BELT || itemViewing) {
|
||||||
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
||||||
if (t.items[lane].type != 0) {
|
if (t.items[lane].type != 0) {
|
||||||
|
29
tiles/tile.h
29
tiles/tile.h
@@ -7,10 +7,9 @@
|
|||||||
|
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
//#include "../items/item.h"
|
|
||||||
|
|
||||||
#define MAP_WIDTH 100
|
#define MAP_WIDTH 1000
|
||||||
#define MAP_HEIGHT 100
|
#define MAP_HEIGHT 1000
|
||||||
|
|
||||||
#define DISPLAY_MAP_WIDTH 60
|
#define DISPLAY_MAP_WIDTH 60
|
||||||
#define DISPLAY_MAP_HEIGHT 31
|
#define DISPLAY_MAP_HEIGHT 31
|
||||||
@@ -20,6 +19,25 @@
|
|||||||
#define DISPLAY_WIDTH DISPLAY_MAP_WIDTH * TILE_SIZE
|
#define DISPLAY_WIDTH DISPLAY_MAP_WIDTH * TILE_SIZE
|
||||||
#define DISPLAY_HEIGHT DISPLAY_MAP_HEIGHT * TILE_SIZE
|
#define DISPLAY_HEIGHT DISPLAY_MAP_HEIGHT * TILE_SIZE
|
||||||
|
|
||||||
|
typedef struct MiniRect {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} MiniRect;
|
||||||
|
|
||||||
|
#define MAX_TILES MAP_WIDTH * MAP_HEIGHT
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MiniRect tiles[MAX_TILES];
|
||||||
|
int activeCount;
|
||||||
|
} TileArray;
|
||||||
|
|
||||||
|
extern TileArray neededUpdates;
|
||||||
|
|
||||||
|
void remove_tile(TileArray *arr, int index);
|
||||||
|
|
||||||
|
int add_tile(TileArray *arr, MiniRect t);
|
||||||
|
|
||||||
extern SDL_Texture *tilesTexture;
|
extern SDL_Texture *tilesTexture;
|
||||||
extern SDL_Texture *itemsTexture;
|
extern SDL_Texture *itemsTexture;
|
||||||
extern SDL_Texture *backgroundTexture;
|
extern SDL_Texture *backgroundTexture;
|
||||||
@@ -77,6 +95,7 @@ typedef struct TileTypeReg {
|
|||||||
bool itemMoves;
|
bool itemMoves;
|
||||||
bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE];
|
bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE];
|
||||||
bool outputLane[ItemSlotCount];
|
bool outputLane[ItemSlotCount];
|
||||||
|
bool needsTicks;
|
||||||
} TileTypeReg;
|
} TileTypeReg;
|
||||||
|
|
||||||
typedef struct BackgroundTileType {
|
typedef struct BackgroundTileType {
|
||||||
@@ -106,8 +125,8 @@ typedef struct Tile {
|
|||||||
int miscVal;
|
int miscVal;
|
||||||
ItemOnBelt items[ItemSlotCount];
|
ItemOnBelt items[ItemSlotCount];
|
||||||
uint16_t audioCh;
|
uint16_t audioCh;
|
||||||
int x;
|
MiniRect rect;
|
||||||
int y;
|
int neededUpdateIndex;
|
||||||
} Tile;
|
} Tile;
|
||||||
|
|
||||||
|
|
||||||
|
108
util/atlas.c
108
util/atlas.c
@@ -7,50 +7,97 @@
|
|||||||
|
|
||||||
SDL_Texture *atlasTexture;
|
SDL_Texture *atlasTexture;
|
||||||
|
|
||||||
int atlasX = 0, atlasY = 0;
|
int tileIndex16 = 0, quadrantIndex16 = 0;
|
||||||
|
int tileIndex32 = 0;
|
||||||
|
|
||||||
int tileIndex = 0; // Which 32x32 tile we're on
|
#define MAX_RECTS 256
|
||||||
int quadrantIndex = 0; // Which 16x16 slot inside that tile
|
int allocatedRectCount = 0;
|
||||||
|
SDL_Rect allocatedRects[MAX_RECTS];
|
||||||
|
|
||||||
|
|
||||||
|
bool isIntersecting(SDL_Rect a) {
|
||||||
|
for (int i = 0; i < allocatedRectCount; i++) {
|
||||||
|
SDL_Rect b = allocatedRects[i];
|
||||||
|
if (SDL_HasIntersection(&a, &b)) {
|
||||||
|
printf("Rect intersection %d - X:%d, Y: %d, W: %d, H: %d with X:%d, Y: %d, W: %d, H: %d\n",
|
||||||
|
allocatedRectCount, a.x, a.y, a.w, a.h, b.x, b.y, b.w, b.h);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeRect(SDL_Rect rect) {
|
||||||
|
if (isIntersecting(rect)) {
|
||||||
|
printf("PROBLEM\n");
|
||||||
|
}
|
||||||
|
if (allocatedRectCount < MAX_RECTS) {
|
||||||
|
allocatedRects[allocatedRectCount++] = rect;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: atlas rect limit reached!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Rect allocate_16x16(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
SDL_Rect allocate_16x16(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
||||||
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
||||||
SDL_SetRenderTarget(renderer, atlasTexture);
|
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||||
int tileX = tileIndex % ATLAS_TILES_PER_ROW;
|
|
||||||
int tileY = tileIndex / ATLAS_TILES_PER_ROW;
|
|
||||||
|
|
||||||
int dx = (quadrantIndex % 2) * QUADRANT_SIZE;
|
|
||||||
int dy = (quadrantIndex / 2) * QUADRANT_SIZE;
|
|
||||||
|
|
||||||
SDL_Rect destRect = {
|
SDL_Rect sourceRect = {
|
||||||
tileX * TILE_SIZE + dx,
|
0,
|
||||||
tileY * TILE_SIZE + dy,
|
0,
|
||||||
QUADRANT_SIZE,
|
QUADRANT_SIZE,
|
||||||
QUADRANT_SIZE
|
QUADRANT_SIZE
|
||||||
};
|
};
|
||||||
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
|
||||||
|
|
||||||
quadrantIndex++;
|
SDL_Rect destRect;
|
||||||
if (quadrantIndex >= 4) {
|
while (1) {
|
||||||
tileIndex++;
|
int tileX = tileIndex16 % ATLAS_TILES_PER_ROW;
|
||||||
quadrantIndex = 0;
|
int tileY = tileIndex16 / ATLAS_TILES_PER_ROW;
|
||||||
|
|
||||||
|
int dx = (quadrantIndex16 % 2) * QUADRANT_SIZE;
|
||||||
|
int dy = (quadrantIndex16 / 2) * QUADRANT_SIZE;
|
||||||
|
destRect.x = tileX * TILE_SIZE + dx;
|
||||||
|
destRect.y = tileY * TILE_SIZE + dy;
|
||||||
|
destRect.w = QUADRANT_SIZE;
|
||||||
|
destRect.h = QUADRANT_SIZE;
|
||||||
|
if (isIntersecting(destRect)) {
|
||||||
|
tileIndex16 = tileIndex32;
|
||||||
|
tileIndex32++;
|
||||||
|
quadrantIndex16 = 0;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SDL_RenderCopy(renderer, srcTexture, &sourceRect, &destRect);
|
||||||
|
|
||||||
|
quadrantIndex16++;
|
||||||
|
if (quadrantIndex16 >= 4) {
|
||||||
|
tileIndex16 = tileIndex32;
|
||||||
|
tileIndex32 += 1;
|
||||||
|
quadrantIndex16 = 0;
|
||||||
|
|
||||||
|
// Ensure 32x32 allocator skips this tile
|
||||||
|
if (tileIndex32 <= tileIndex16) {
|
||||||
|
tileIndex32 = tileIndex16 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, oldTarget);
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
|
storeRect(destRect);
|
||||||
|
printf("Rect X:%d, Y: %d, W: %d, H: %d\n", destRect.x, destRect.y, destRect.w, destRect.h);
|
||||||
return destRect;
|
return destRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
||||||
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
||||||
SDL_SetRenderTarget(renderer, atlasTexture);
|
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||||
// If we’re not at the start of a tile, skip to the next clean one
|
|
||||||
if (quadrantIndex != 0) {
|
|
||||||
tileIndex++;
|
|
||||||
quadrantIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tileX = tileIndex % ATLAS_TILES_PER_ROW;
|
int tileX = tileIndex32 % ATLAS_TILES_PER_ROW;
|
||||||
int tileY = tileIndex / ATLAS_TILES_PER_ROW;
|
int tileY = tileIndex32 / ATLAS_TILES_PER_ROW;
|
||||||
|
|
||||||
SDL_Rect destRect = {
|
SDL_Rect destRect = {
|
||||||
tileX * TILE_SIZE,
|
tileX * TILE_SIZE,
|
||||||
@@ -58,23 +105,30 @@ SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
|||||||
TILE_SIZE,
|
TILE_SIZE,
|
||||||
TILE_SIZE
|
TILE_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
||||||
|
|
||||||
tileIndex++; // Move to next tile
|
tileIndex32++;
|
||||||
// quadrantIndex stays 0 — new tile is fresh
|
|
||||||
SDL_SetRenderTarget(renderer, oldTarget);
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
|
storeRect(destRect);
|
||||||
|
printf("Rect X:%d, Y: %d, W: %d, H: %d\n", destRect.x, destRect.y, destRect.w, destRect.h);
|
||||||
return destRect;
|
return destRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAtlas(SDL_Renderer *renderer) {
|
void initAtlas(SDL_Renderer *renderer) {
|
||||||
|
|
||||||
|
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
||||||
|
|
||||||
|
atlasTexture = SDL_CreateTexture(renderer,
|
||||||
|
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
||||||
|
ATLAS_SIZE, ATLAS_SIZE);
|
||||||
// Clear atlas with transparent
|
// Clear atlas with transparent
|
||||||
SDL_SetRenderTarget(renderer, atlasTexture);
|
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
|
|
||||||
|
|
||||||
atlasTexture = SDL_CreateTexture(renderer,
|
|
||||||
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
|
||||||
ATLAS_SIZE, ATLAS_SIZE);
|
|
||||||
}
|
}
|
211
util/audio.c
211
util/audio.c
@@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
AudioData audioData;
|
AudioData audioData;
|
||||||
|
|
||||||
|
#define MAX_MIDI_EVENTS 1024
|
||||||
|
MidiEvent midiEvents[MAX_MIDI_EVENTS];
|
||||||
|
int midiEventCount = 0;
|
||||||
|
int nextMidiEvent = 0;
|
||||||
|
|
||||||
uint16_t getAvailableChannel() {
|
uint16_t getAvailableChannel() {
|
||||||
for (uint16_t i = 0; i < NUM_SYNTH_VOICES; i++) {
|
for (uint16_t i = 0; i < NUM_SYNTH_VOICES; i++) {
|
||||||
if (audioData.synthVoices[i].volume == 0) {
|
if (audioData.synthVoices[i].volume == 0) {
|
||||||
@@ -39,93 +44,209 @@ static void compute_stereo_gains(float pan, float *outL, float *outR) {
|
|||||||
// e.g. *outL *= 0.7071f; *outR *= 0.7071f;
|
// e.g. *outL *= 0.7071f; *outR *= 0.7071f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This callback now writes stereo frames: interleaved L/R floats.
|
// Improved audio callback with anti-clipping and smooth fade-out
|
||||||
void audio_callback(void *userdata, Uint8 *stream, int len) {
|
void audio_callback(void *userdata, Uint8 *stream, int len) {
|
||||||
AudioData *audio = (AudioData *) userdata;
|
AudioData *audio = (AudioData *) userdata;
|
||||||
|
|
||||||
// 'len' is total bytes; each sample‐frame is 2 floats (L+R), i.e. 2 * sizeof(float).
|
int frames = len / (2 * sizeof(float)); // Stereo frame count
|
||||||
int frames = len / (2 * sizeof(float));
|
|
||||||
|
float elapsedSec = audio->totalSamples / SAMPLE_RATE;
|
||||||
|
audio->totalSamples += frames;
|
||||||
|
|
||||||
|
while (nextMidiEvent < midiEventCount &&
|
||||||
|
midiEvents[nextMidiEvent].timeSec <= elapsedSec) {
|
||||||
|
|
||||||
|
MidiEvent *ev = &midiEvents[nextMidiEvent];
|
||||||
|
|
||||||
|
if (ev->type == 0 && ev->velocity > 0) {
|
||||||
|
// Note On
|
||||||
|
for (int i = NUM_SYNTH_VOICES - 4; i < NUM_SYNTH_VOICES; ++i) {
|
||||||
|
SynthVoice *v = &audio->synthVoices[i];
|
||||||
|
if (v->volume == 0) {
|
||||||
|
float freq = 440.0f * powf(2.0f, (ev->note - 69) / 12.0f);
|
||||||
|
v->frequency = (uint16_t) freq;
|
||||||
|
v->volume = ev->velocity * 2;
|
||||||
|
v->waveform = WAVE_SQUARE;
|
||||||
|
v->smoothedAmp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Note Off
|
||||||
|
for (int i = NUM_SYNTH_VOICES - 4; i < NUM_SYNTH_VOICES; ++i) {
|
||||||
|
SynthVoice *v = &audio->synthVoices[i];
|
||||||
|
float freq = 440.0f * powf(2.0f, (ev->note - 69) / 12.0f);
|
||||||
|
if ((uint16_t)freq == v->frequency) {
|
||||||
|
v->volume = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextMidiEvent++;
|
||||||
|
}
|
||||||
|
|
||||||
// Zero out the entire output buffer (silence)
|
|
||||||
// We’ll accumulate into it.
|
|
||||||
// Each float is 4 bytes, so total floats = 2 * frames.
|
|
||||||
float *outBuf = (float *) stream;
|
float *outBuf = (float *) stream;
|
||||||
for (int i = 0; i < 2 * frames; ++i) {
|
for (int i = 0; i < 2 * frames; ++i) {
|
||||||
outBuf[i] = 0.0f;
|
outBuf[i] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precompute the listener center
|
|
||||||
float listenerCx = audio->playerRect->x + audio->playerRect->w * 0.5f;
|
float listenerCx = audio->playerRect->x + audio->playerRect->w * 0.5f;
|
||||||
|
|
||||||
// For each synth voice, mix into the stereo buffer
|
int *voiceCounts = calloc(frames, sizeof(int));
|
||||||
|
|
||||||
for (int v = 0; v < NUM_SYNTH_VOICES; v++) {
|
for (int v = 0; v < NUM_SYNTH_VOICES; v++) {
|
||||||
SynthVoice *voice = &audio->synthVoices[v];
|
SynthVoice *voice = &audio->synthVoices[v];
|
||||||
if (voice->volume == 0 || voice->frequency == 0) {
|
|
||||||
continue; // skip silent or inactive voices
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute source center X
|
if ((voice->volume == 0 && voice->smoothedAmp < 0.001f) || voice->frequency == 0)
|
||||||
float sourceCx = voice->sourceRect.x + voice->sourceRect.w * 0.5f;
|
continue;
|
||||||
|
|
||||||
|
float sourceCx = voice->sourceRect.x + TILE_SIZE * 0.5f;
|
||||||
float dx = sourceCx - listenerCx;
|
float dx = sourceCx - listenerCx;
|
||||||
|
float pan = fmaxf(-1.0f, fminf(+1.0f, dx / audio->maxPanDistance));
|
||||||
// Normalize for pan. If |dx| >= maxPanDistance → full left or full right.
|
|
||||||
float pan = dx / audio->maxPanDistance;
|
|
||||||
if (pan < -1.0f) pan = -1.0f;
|
|
||||||
if (pan > +1.0f) pan = +1.0f;
|
|
||||||
|
|
||||||
float gainL, gainR;
|
float gainL, gainR;
|
||||||
compute_stereo_gains(pan, &gainL, &gainR);
|
compute_stereo_gains(pan, &gainL, &gainR);
|
||||||
|
gainL *= 0.7071f;
|
||||||
|
gainR *= 0.7071f;
|
||||||
|
|
||||||
// Optional: You could also attenuate overall volume with distance
|
float dist = fabsf(dx);
|
||||||
// float dist = fabsf(dx);
|
float distanceAtten = 1.0f - fminf(dist / audio->maxPanDistance, 1.0f);
|
||||||
// float distanceAtten = 1.0f - fminf(dist / audio->maxPanDistance, 1.0f);
|
float targetAmp = (voice->volume / 255.0f) * distanceAtten;
|
||||||
// float finalVolume = (voice->volume / 255.0f) * distanceAtten;
|
|
||||||
// But for now, we’ll just use voice->volume for amplitude.
|
|
||||||
|
|
||||||
float amp = (voice->volume / 255.0f);
|
double phaseInc = ((double) voice->frequency * 256.0) / (double) SAMPLE_RATE;
|
||||||
|
|
||||||
// Phase increment per sample‐frame:
|
|
||||||
// (freq * 256) / SAMPLE_RATE tells how many phase steps per mono-sample.
|
|
||||||
// Because we’re writing stereo, we still advance phase once per frame.
|
|
||||||
uint8_t phaseInc = (uint8_t)((voice->frequency * 256) / SAMPLE_RATE);
|
|
||||||
|
|
||||||
// Mix into each frame
|
|
||||||
for (int i = 0; i < frames; i++) {
|
for (int i = 0; i < frames; i++) {
|
||||||
float t = (float) voice->phase / 255.0f * 2.0f - 1.0f;
|
voice->smoothedAmp += (targetAmp - voice->smoothedAmp) * SMOOTHING_FACTOR;
|
||||||
|
float amp = voice->smoothedAmp;
|
||||||
|
|
||||||
|
double norm = voice->phase / 256.0;
|
||||||
|
double t = norm * 2.0 - 1.0;
|
||||||
float sample;
|
float sample;
|
||||||
|
|
||||||
switch (voice->waveform) {
|
switch (voice->waveform) {
|
||||||
default:
|
|
||||||
case WAVE_SINE:
|
|
||||||
sample = sinf(voice->phase * 2.0f * M_PI / 256.0f);
|
|
||||||
break;
|
|
||||||
case WAVE_SQUARE:
|
case WAVE_SQUARE:
|
||||||
sample = (t >= 0.0f) ? 1.0f : -1.0f;
|
sample = (t >= 0.0) ? 1.0f : -1.0f;
|
||||||
break;
|
break;
|
||||||
case WAVE_SAWTOOTH:
|
case WAVE_SAWTOOTH:
|
||||||
sample = t;
|
sample = (float) t;
|
||||||
break;
|
break;
|
||||||
case WAVE_TRIANGLE:
|
case WAVE_TRIANGLE:
|
||||||
sample = (t < 0.0f) ? -t : t;
|
sample = (float) ((t < 0.0) ? -t : t);
|
||||||
break;
|
break;
|
||||||
case WAVE_NOISE:
|
case WAVE_NOISE:
|
||||||
sample = ((float) rand() / RAND_MAX) * 2.0f - 1.0f;
|
sample = ((float) rand() / (float) RAND_MAX) * 2.0f - 1.0f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sample = (float) sin(norm * 2.0 * M_PI);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
voice->phase += phaseInc;
|
voice->phase += phaseInc;
|
||||||
|
if (voice->phase >= 256.0) voice->phase -= 256.0;
|
||||||
|
else if (voice->phase < 0.0) voice->phase += 256.0;
|
||||||
|
|
||||||
// Interleaved index: left = 2*i, right = 2*i + 1
|
|
||||||
int idxL = 2 * i;
|
int idxL = 2 * i;
|
||||||
int idxR = 2 * i + 1;
|
int idxR = 2 * i + 1;
|
||||||
|
|
||||||
// Accumulate into buffer
|
|
||||||
outBuf[idxL] += sample * amp * gainL;
|
outBuf[idxL] += sample * amp * gainL;
|
||||||
outBuf[idxR] += sample * amp * gainR;
|
outBuf[idxR] += sample * amp * gainR;
|
||||||
|
voiceCounts[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < frames; ++i) {
|
||||||
|
int count = voiceCounts[i];
|
||||||
|
if (count > 0) {
|
||||||
|
outBuf[2 * i + 0] /= count;
|
||||||
|
outBuf[2 * i + 1] /= count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(voiceCounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t read_be_uint32(const uint8_t *data) {
|
||||||
|
return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t read_be_uint16(const uint8_t *data) {
|
||||||
|
return (data[0]<<8) | data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t read_vlq(const uint8_t **ptr) {
|
||||||
|
uint32_t value = 0;
|
||||||
|
const uint8_t *p = *ptr;
|
||||||
|
while (*p & 0x80) {
|
||||||
|
value = (value << 7) | (*p++ & 0x7F);
|
||||||
|
}
|
||||||
|
value = (value << 7) | (*p++ & 0x7F);
|
||||||
|
*ptr = p;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_midi_file(const char *path) {
|
||||||
|
FILE *f = fopen(path, "rb");
|
||||||
|
if (!f) return;
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long size = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
uint8_t *data = malloc(size);
|
||||||
|
fread(data, 1, size, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
const uint8_t *ptr = data;
|
||||||
|
if (memcmp(ptr, "MThd", 4) != 0) return;
|
||||||
|
ptr += 8; // skip header length
|
||||||
|
uint16_t format = read_be_uint16(ptr); ptr += 2;
|
||||||
|
uint16_t nTracks = read_be_uint16(ptr); ptr += 2;
|
||||||
|
uint16_t ppqn = read_be_uint16(ptr); ptr += 2;
|
||||||
|
|
||||||
|
if (format != 0 || nTracks != 1) {
|
||||||
|
printf("Only Type 0 MIDI supported\n");
|
||||||
|
free(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(ptr, "MTrk", 4) != 0) return;
|
||||||
|
uint32_t trackLen = read_be_uint32(ptr+4);
|
||||||
|
ptr += 8;
|
||||||
|
const uint8_t *trackEnd = ptr + trackLen;
|
||||||
|
|
||||||
|
float curTime = 0.0f;
|
||||||
|
uint32_t tempo = 500000; // default: 120 BPM
|
||||||
|
uint8_t lastStatus = 0;
|
||||||
|
|
||||||
|
while (ptr < trackEnd && midiEventCount < MAX_MIDI_EVENTS) {
|
||||||
|
uint32_t delta = read_vlq(&ptr);
|
||||||
|
curTime += (delta * (tempo / 1000000.0f)) / ppqn;
|
||||||
|
|
||||||
|
uint8_t status = *ptr;
|
||||||
|
if (status < 0x80) status = lastStatus;
|
||||||
|
else ptr++;
|
||||||
|
|
||||||
|
lastStatus = status;
|
||||||
|
|
||||||
|
if (status == 0xFF) {
|
||||||
|
uint8_t metaType = *ptr++;
|
||||||
|
uint32_t len = read_vlq(&ptr);
|
||||||
|
if (metaType == 0x51 && len == 3) {
|
||||||
|
tempo = (ptr[0]<<16 | ptr[1]<<8 | ptr[2]);
|
||||||
|
}
|
||||||
|
ptr += len;
|
||||||
|
} else if ((status & 0xF0) == 0x90 || (status & 0xF0) == 0x80) {
|
||||||
|
uint8_t note = *ptr++;
|
||||||
|
uint8_t vel = *ptr++;
|
||||||
|
midiEvents[midiEventCount++] = (MidiEvent){
|
||||||
|
.timeSec = curTime,
|
||||||
|
.type = (status & 0xF0) == 0x90 ? 0 : 1,
|
||||||
|
.note = note,
|
||||||
|
.velocity = vel
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ptr += 2; // skip unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: We did not normalize by active voices here, because each voice already
|
free(data);
|
||||||
// uses its own volume. If you still want an automatic “divide by N active voices”,
|
|
||||||
// you would need to track active voices per‐frame, which is relatively expensive.
|
|
||||||
// In practice, you manage the volume per voice so clipping doesn’t occur.
|
|
||||||
}
|
}
|
17
util/audio.h
17
util/audio.h
@@ -9,9 +9,18 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "../tiles/tile.h"
|
||||||
|
|
||||||
#define SAMPLE_RATE 44100
|
#define SAMPLE_RATE 44100
|
||||||
#define NUM_SYNTH_VOICES 256
|
#define NUM_SYNTH_VOICES 256
|
||||||
|
#define SMOOTHING_FACTOR 0.001f
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float timeSec; // When to trigger this event
|
||||||
|
uint8_t type; // 0 = Note On, 1 = Note Off
|
||||||
|
uint8_t note;
|
||||||
|
uint8_t velocity;
|
||||||
|
} MidiEvent;
|
||||||
|
|
||||||
typedef enum Waveform {
|
typedef enum Waveform {
|
||||||
WAVE_SINE,
|
WAVE_SINE,
|
||||||
@@ -23,16 +32,18 @@ typedef enum Waveform {
|
|||||||
|
|
||||||
typedef struct SynthVoice {
|
typedef struct SynthVoice {
|
||||||
Waveform waveform;
|
Waveform waveform;
|
||||||
uint8_t phase;
|
double phase;
|
||||||
uint16_t frequency;
|
uint16_t frequency;
|
||||||
uint8_t volume;
|
uint8_t volume;
|
||||||
SDL_Rect sourceRect;
|
MiniRect sourceRect;
|
||||||
|
float smoothedAmp; // a float that holds the exponentially smoothed amplitude
|
||||||
} SynthVoice;
|
} SynthVoice;
|
||||||
|
|
||||||
typedef struct AudioData {
|
typedef struct AudioData {
|
||||||
SynthVoice synthVoices[NUM_SYNTH_VOICES];
|
SynthVoice synthVoices[NUM_SYNTH_VOICES];
|
||||||
SDL_Rect *playerRect;
|
SDL_Rect *playerRect;
|
||||||
float maxPanDistance;
|
float maxPanDistance;
|
||||||
|
uint64_t totalSamples;
|
||||||
} AudioData;
|
} AudioData;
|
||||||
|
|
||||||
extern AudioData audioData;
|
extern AudioData audioData;
|
||||||
@@ -41,4 +52,6 @@ void audio_callback(void *userdata, Uint8 *stream, int len);
|
|||||||
|
|
||||||
uint16_t getAvailableChannel();
|
uint16_t getAvailableChannel();
|
||||||
|
|
||||||
|
void load_midi_file(const char *path);
|
||||||
|
|
||||||
#endif //RISCB_AUDIO_H
|
#endif //RISCB_AUDIO_H
|
||||||
|
@@ -46,7 +46,7 @@ void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t
|
|||||||
string++;
|
string++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SDL_RenderCopy(renderer, font.texture[*string], &charRect, &outRect);
|
SDL_RenderCopy(renderer, font.texture[*string], &charRect, &outRect); //TODO CONSIDER FONTS IN ONE ATLAS
|
||||||
outRect.x += charRect.w + 1;
|
outRect.x += charRect.w + 1;
|
||||||
string++;
|
string++;
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,7 @@ volatile bool running = true;
|
|||||||
|
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
bool itemViewing = false;
|
bool itemViewing = false;
|
||||||
|
bool renderAtlas = false;
|
||||||
|
|
||||||
//The surface contained by the window
|
//The surface contained by the window
|
||||||
SDL_Renderer *mainRenderer = NULL;
|
SDL_Renderer *mainRenderer = NULL;
|
||||||
|
@@ -30,6 +30,7 @@ typedef enum OrientDirection{
|
|||||||
|
|
||||||
extern bool debugMode;
|
extern bool debugMode;
|
||||||
extern bool itemViewing;
|
extern bool itemViewing;
|
||||||
|
extern bool renderAtlas;
|
||||||
|
|
||||||
SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle);
|
SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user