Fix texture caching, file browser segfault, and compiler warnings
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
+105
-47
@@ -102,6 +102,12 @@ typedef struct {
|
||||
float panStartViewEnd;
|
||||
Vector2 panStartPos;
|
||||
|
||||
// Cached visible texture
|
||||
Texture2D visibleTexture;
|
||||
int cachedVisibleStart;
|
||||
int cachedVisibleEnd;
|
||||
bool visibleTextureValid;
|
||||
|
||||
// Display settings
|
||||
float amplitudeFloorDb;
|
||||
float amplitudeCeilingDb;
|
||||
@@ -578,12 +584,17 @@ static void LoadSelectedFile(void)
|
||||
app.freqSelectionStart = 0.0f;
|
||||
app.freqSelectionEnd = 1.0f;
|
||||
app.showFileBrowser = false;
|
||||
// Invalidate visible texture cache
|
||||
if (app.visibleTexture.id != 0) UnloadTexture(app.visibleTexture);
|
||||
app.visibleTexture = (Texture2D){ 0 };
|
||||
app.visibleTextureValid = false;
|
||||
TraceLog(LOG_INFO, "Loaded: %s", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawFileBrowser(void)
|
||||
{
|
||||
// Draw semi-transparent overlay first
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, 0.85f));
|
||||
|
||||
float bw = 650, bh = 550;
|
||||
@@ -600,6 +611,7 @@ static void DrawFileBrowser(void)
|
||||
|
||||
char displayPath[300];
|
||||
strncpy(displayPath, app.browserPath, sizeof(displayPath) - 1);
|
||||
displayPath[sizeof(displayPath) - 1] = '\0';
|
||||
if (strlen(displayPath) > 60) sprintf(displayPath, "...%s", app.browserPath + strlen(app.browserPath) - 57);
|
||||
DrawText(displayPath, bx + 20, by + 51, 14, LIGHTGRAY);
|
||||
|
||||
@@ -613,41 +625,55 @@ static void DrawFileBrowser(void)
|
||||
DrawRectangle(lx, ly, lw, lh, (Color){ 25, 25, 35, 255 });
|
||||
DrawRectangleLinesEx((Rectangle){ lx, ly, lw, lh }, 1, GRAY);
|
||||
|
||||
// Handle empty directory
|
||||
int visibleItems = (int)(lh / 26);
|
||||
if (app.browserFileCount > visibleItems) {
|
||||
float sh = (float)visibleItems / app.browserFileCount * lh;
|
||||
float sy = ly + (float)app.browserScroll / (app.browserFileCount - visibleItems) * (lh - sh);
|
||||
DrawRectangle(lx + lw - 10, sy, 8, sh, GRAY);
|
||||
if (visibleItems < 1) visibleItems = 1;
|
||||
|
||||
if (app.browserFileCount <= 0 || !app.browserFiles) {
|
||||
DrawText("(No WAV files in directory)", lx + 20, ly + lh/2 - 10, 14, GRAY);
|
||||
} else {
|
||||
if (app.browserFileCount > visibleItems) {
|
||||
float sh = (float)visibleItems / app.browserFileCount * lh;
|
||||
if (sh < 10) sh = 10;
|
||||
float sy = ly + (float)app.browserScroll / (app.browserFileCount - visibleItems) * (lh - sh);
|
||||
DrawRectangle(lx + lw - 10, sy, 8, sh, GRAY);
|
||||
}
|
||||
|
||||
int startItem = app.browserScroll;
|
||||
int endItem = startItem + visibleItems + 1;
|
||||
if (endItem > app.browserFileCount) endItem = app.browserFileCount;
|
||||
|
||||
for (int i = startItem; i < endItem; i++) {
|
||||
if (i < 0 || i >= app.browserFileCount || !app.browserFiles[i] || !app.browserIsDir) continue;
|
||||
|
||||
float iy = ly + (i - startItem) * 26 + 2;
|
||||
bool hovered = CheckCollisionPointRec((Vector2){ GetMouseX(), GetMouseY() }, (Rectangle){ lx + 2, iy, lw - 14, 24 });
|
||||
|
||||
if (i == app.browserSelected) DrawRectangle(lx + 2, iy, lw - 14, 24, (Color){ 50, 70, 120, 180 });
|
||||
else if (hovered) DrawRectangle(lx + 2, iy, lw - 14, 24, (Color){ 60, 60, 80, 100 });
|
||||
|
||||
const char* icon = app.browserIsDir[i] ? "[DIR]" : "[WAV]";
|
||||
Color iconCol = app.browserIsDir[i] ? (Color){ 255, 220, 80, 255 } : (Color){ 80, 200, 120, 255 };
|
||||
DrawText(icon, lx + 8, iy + 5, 13, iconCol);
|
||||
DrawText(app.browserFiles[i], lx + 55, iy + 5, 14, WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
int startItem = app.browserScroll;
|
||||
int endItem = startItem + visibleItems + 1;
|
||||
if (endItem > app.browserFileCount) endItem = app.browserFileCount;
|
||||
|
||||
for (int i = startItem; i < endItem; i++) {
|
||||
float iy = ly + (i - startItem) * 26 + 2;
|
||||
bool hovered = CheckCollisionPointRec((Vector2){ GetMouseX(), GetMouseY() }, (Rectangle){ lx + 2, iy, lw - 14, 24 });
|
||||
|
||||
if (i == app.browserSelected) DrawRectangle(lx + 2, iy, lw - 14, 24, (Color){ 50, 70, 120, 180 });
|
||||
else if (hovered) DrawRectangle(lx + 2, iy, lw - 14, 24, (Color){ 60, 60, 80, 100 });
|
||||
|
||||
const char* icon = app.browserIsDir[i] ? "[DIR]" : "[WAV]";
|
||||
Color iconCol = app.browserIsDir[i] ? (Color){ 255, 220, 80, 255 } : (Color){ 80, 200, 120, 255 };
|
||||
DrawText(icon, lx + 8, iy + 5, 13, iconCol);
|
||||
DrawText(app.browserFiles[i], lx + 55, iy + 5, 14, WHITE);
|
||||
}
|
||||
|
||||
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){ lx, ly, lw - 10, lh })) {
|
||||
// Scroll with mouse wheel
|
||||
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){ lx, ly, lw - 10, lh }) && app.browserFileCount > 0) {
|
||||
int wheel = GetMouseWheelMove();
|
||||
if (wheel > 0) app.browserScroll--;
|
||||
if (wheel < 0) app.browserScroll++;
|
||||
if (app.browserScroll < 0) app.browserScroll = 0;
|
||||
if (app.browserScroll > app.browserFileCount - visibleItems) app.browserScroll = app.browserFileCount - visibleItems;
|
||||
int maxScroll = app.browserFileCount - visibleItems;
|
||||
if (maxScroll < 0) maxScroll = 0;
|
||||
if (app.browserScroll > maxScroll) app.browserScroll = maxScroll;
|
||||
}
|
||||
|
||||
// Handle clicks
|
||||
if (CheckCollisionPointRec(GetMousePosition(), upBtn) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) NavigateToParentDirectory();
|
||||
|
||||
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){ lx, ly, lw - 10, lh }) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
||||
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){ lx, ly, lw - 10, lh }) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && app.browserFileCount > 0) {
|
||||
int clicked = app.browserScroll + (int)((GetMouseY() - ly) / 26);
|
||||
if (clicked >= 0 && clicked < app.browserFileCount) {
|
||||
app.browserSelected = clicked;
|
||||
@@ -669,13 +695,13 @@ static void DrawFileBrowser(void)
|
||||
DrawRectangleRec(cancelBtn, (Color){ 100, 40, 40, 255 });
|
||||
DrawText("ESC Cancel", cancelBtn.x + 18, cancelBtn.y + 12, 16, WHITE);
|
||||
|
||||
if (IsKeyPressed(KEY_ENTER) && app.browserSelected >= 0) LoadSelectedFile();
|
||||
if (IsKeyPressed(KEY_ENTER) && app.browserSelected >= 0 && app.browserFileCount > 0) LoadSelectedFile();
|
||||
if (IsKeyPressed(KEY_ESCAPE)) app.showFileBrowser = false;
|
||||
if (IsKeyPressed(KEY_UP) && app.browserSelected > 0) {
|
||||
if (IsKeyPressed(KEY_UP) && app.browserSelected > 0 && app.browserFileCount > 0) {
|
||||
app.browserSelected--;
|
||||
if (app.browserSelected < app.browserScroll) app.browserScroll = app.browserSelected;
|
||||
}
|
||||
if (IsKeyPressed(KEY_DOWN) && app.browserSelected < app.browserFileCount - 1) {
|
||||
if (IsKeyPressed(KEY_DOWN) && app.browserSelected < app.browserFileCount - 1 && app.browserFileCount > 0) {
|
||||
app.browserSelected++;
|
||||
if (app.browserSelected >= app.browserScroll + visibleItems) app.browserScroll = app.browserSelected - visibleItems + 1;
|
||||
}
|
||||
@@ -832,6 +858,10 @@ int main(int argc, char* argv[])
|
||||
app.amplitudeCeilingDb = 0.0f;
|
||||
app.showFileBrowser = false;
|
||||
app.isBrowsing = false;
|
||||
app.visibleTexture = (Texture2D){ 0 };
|
||||
app.cachedVisibleStart = -1;
|
||||
app.cachedVisibleEnd = -1;
|
||||
app.visibleTextureValid = false;
|
||||
|
||||
GenerateColormapTexture();
|
||||
ScanDirectory(GetWorkingDirectory());
|
||||
@@ -864,6 +894,10 @@ int main(int argc, char* argv[])
|
||||
app.loaded = true;
|
||||
app.stftComputed = false;
|
||||
app.viewStart = 0.0f; app.viewEnd = 1.0f;
|
||||
// Invalidate visible texture cache
|
||||
if (app.visibleTexture.id != 0) UnloadTexture(app.visibleTexture);
|
||||
app.visibleTexture = (Texture2D){ 0 };
|
||||
app.visibleTextureValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -965,30 +999,30 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
// Selection
|
||||
Rectangle bounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 };
|
||||
Rectangle selBounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 };
|
||||
Vector2 mousePos = GetMousePosition();
|
||||
|
||||
if (app.loaded && !app.showFileBrowser && CheckCollisionPointRec(mousePos, bounds)) {
|
||||
if (app.loaded && !app.showFileBrowser && CheckCollisionPointRec(mousePos, selBounds)) {
|
||||
bool shiftHeld = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && !app.isPanning) {
|
||||
if (shiftHeld) {
|
||||
app.isFreqSelecting = true;
|
||||
float t = 1.0f - (mousePos.y - bounds.y) / bounds.height;
|
||||
float t = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
|
||||
app.freqSelectionStart = Clamp(t, 0.0f, 1.0f);
|
||||
app.freqSelectionEnd = app.freqSelectionStart;
|
||||
} else if (!IsKeyDown(KEY_LEFT_ALT) && !IsKeyDown(KEY_RIGHT_ALT)) {
|
||||
app.isTimeSelecting = true;
|
||||
app.timeSelectionStart = Clamp((mousePos.x - bounds.x) / bounds.width, 0.0f, 1.0f);
|
||||
app.timeSelectionStart = Clamp((mousePos.x - selBounds.x) / selBounds.width, 0.0f, 1.0f);
|
||||
app.timeSelectionEnd = app.timeSelectionStart;
|
||||
}
|
||||
}
|
||||
|
||||
if (app.isTimeSelecting && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
||||
app.timeSelectionEnd = Clamp((mousePos.x - bounds.x) / bounds.width, 0.0f, 1.0f);
|
||||
app.timeSelectionEnd = Clamp((mousePos.x - selBounds.x) / selBounds.width, 0.0f, 1.0f);
|
||||
}
|
||||
if (app.isFreqSelecting && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
|
||||
float t = 1.0f - (mousePos.y - bounds.y) / bounds.height;
|
||||
float t = 1.0f - (mousePos.y - selBounds.y) / selBounds.height;
|
||||
app.freqSelectionEnd = Clamp(t, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -1026,15 +1060,26 @@ int main(int argc, char* argv[])
|
||||
BeginDrawing();
|
||||
ClearBackground((Color){ 30, 30, 30, 255 });
|
||||
|
||||
if (app.showFileBrowser) DrawFileBrowser();
|
||||
Rectangle viewBounds = { 100, 50, GetScreenWidth() - 150, GetScreenHeight() - 150 };
|
||||
|
||||
// Draw spectrogram first (background)
|
||||
if (app.loaded && app.stftComputed) {
|
||||
|
||||
// Calculate visible region
|
||||
int visibleStart = (int)(app.viewStart * app.spectrogramImage.width);
|
||||
int visibleEnd = (int)(app.viewEnd * app.spectrogramImage.width);
|
||||
int visibleWidth = visibleEnd - visibleStart;
|
||||
|
||||
if (visibleWidth > 0 && visibleStart >= 0) {
|
||||
// Invalidate cache if view changed or texture not valid
|
||||
bool cacheInvalid = !app.visibleTextureValid ||
|
||||
visibleStart != app.cachedVisibleStart ||
|
||||
visibleEnd != app.cachedVisibleEnd ||
|
||||
visibleWidth <= 0;
|
||||
|
||||
if (cacheInvalid && visibleWidth > 0 && visibleStart >= 0) {
|
||||
// Free old texture if exists
|
||||
if (app.visibleTexture.id != 0) UnloadTexture(app.visibleTexture);
|
||||
|
||||
// Create a sub-image for the visible region
|
||||
Image visibleImage = GenImageColor(visibleWidth, app.spectrogramImage.height, BLACK);
|
||||
Color* srcPixels = (Color*)app.spectrogramImage.data;
|
||||
@@ -1046,21 +1091,27 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
Texture2D visibleTexture = LoadTextureFromImage(visibleImage);
|
||||
DrawTexturePro(visibleTexture,
|
||||
(Rectangle){ 0, 0, visibleWidth, app.spectrogramImage.height },
|
||||
bounds, (Vector2){ 0, 0 }, 0.0f, WHITE);
|
||||
|
||||
UnloadTexture(visibleTexture);
|
||||
app.visibleTexture = LoadTextureFromImage(visibleImage);
|
||||
UnloadImage(visibleImage);
|
||||
|
||||
app.cachedVisibleStart = visibleStart;
|
||||
app.cachedVisibleEnd = visibleEnd;
|
||||
app.visibleTextureValid = true;
|
||||
}
|
||||
|
||||
if (app.showGrid) DrawSpectrogramGrid(bounds, 10, 8, Fade(GRAY, 0.3f));
|
||||
DrawSelection(bounds);
|
||||
DrawLabels(bounds);
|
||||
DrawText("Spectrogram", bounds.x, bounds.y - 30, 20, LIGHTGRAY);
|
||||
// Draw cached texture
|
||||
if (app.visibleTextureValid && app.visibleTexture.id != 0) {
|
||||
DrawTexturePro(app.visibleTexture,
|
||||
(Rectangle){ 0, 0, visibleWidth, app.spectrogramImage.height },
|
||||
viewBounds, (Vector2){ 0, 0 }, 0.0f, WHITE);
|
||||
}
|
||||
|
||||
if (app.showGrid) DrawSpectrogramGrid(viewBounds, 10, 8, Fade(GRAY, 0.3f));
|
||||
DrawSelection(viewBounds);
|
||||
DrawLabels(viewBounds);
|
||||
DrawText("Spectrogram", viewBounds.x, viewBounds.y - 30, 20, LIGHTGRAY);
|
||||
DrawText(TextFormat("Frequency (Hz) - Max: %d", app.signal.sampleRate / 2),
|
||||
bounds.x - 50, bounds.y + bounds.height / 2 - 10, 14, Fade(LIGHTGRAY, 0.7f));
|
||||
viewBounds.x - 50, viewBounds.y + viewBounds.height / 2 - 10, 14, Fade(LIGHTGRAY, 0.7f));
|
||||
} else if (!app.showFileBrowser) {
|
||||
const char* msg1 = "Press 'O' for file browser or drag & drop WAV";
|
||||
const char* msg2 = "Or use command line: ./rspektrum <file.wav>";
|
||||
@@ -1070,7 +1121,11 @@ int main(int argc, char* argv[])
|
||||
DrawText(msg2, GetScreenWidth() / 2 - t2.x / 2, GetScreenHeight() / 2 - t2.y / 2 + 15, 18, GRAY);
|
||||
}
|
||||
|
||||
DrawInfo(bounds);
|
||||
// Draw file browser on top (if active)
|
||||
if (app.showFileBrowser) DrawFileBrowser();
|
||||
|
||||
// Draw UI info and FPS (always on top)
|
||||
DrawInfo(viewBounds);
|
||||
DrawFPS(GetScreenWidth() - 100, 10);
|
||||
EndDrawing();
|
||||
}
|
||||
@@ -1078,6 +1133,9 @@ int main(int argc, char* argv[])
|
||||
TraceLog(LOG_INFO, "Shutting down...");
|
||||
if (AudioPlaybackSound.frameCount != 0) UnloadSound(AudioPlaybackSound);
|
||||
if (app.stftComputed) { FreeSTFT(&app.stft); UnloadImage(app.spectrogramImage); UnloadTexture(app.spectrogramTexture); }
|
||||
if (app.visibleTexture.id != 0) UnloadTexture(app.visibleTexture);
|
||||
app.visibleTexture = (Texture2D){ 0 };
|
||||
app.visibleTextureValid = false;
|
||||
UnloadTexture(colormapTexture);
|
||||
FreeBrowserFiles();
|
||||
FreeSignal(&app.signal);
|
||||
|
||||
Reference in New Issue
Block a user