init
This commit is contained in:
@@ -0,0 +1,596 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include "font.h"
|
||||
#include "cpustatusui.h"
|
||||
#include "decoder.h"
|
||||
#include "goertzel.h"
|
||||
#include "texteditor.h"
|
||||
#include "hexdump.h"
|
||||
|
||||
//The window we'll be rendering to
|
||||
SDL_Window *window = NULL;
|
||||
volatile bool running = true;
|
||||
|
||||
//The surface contained by the window
|
||||
SDL_Renderer *renderer = NULL;
|
||||
#define SCREEN_WIDTH 1280
|
||||
#define SCREEN_HEIGHT 720
|
||||
|
||||
const int targetFPS = 60;
|
||||
const int delayNeeded = 1000 / targetFPS;
|
||||
|
||||
|
||||
SDL_Texture *cpuStateTexture;
|
||||
int selectedModemSetting = 0;
|
||||
|
||||
#define biggerFont fonts[0]
|
||||
#define smallFont fonts[1]
|
||||
#define smallerFont fonts[2]
|
||||
|
||||
#define fontCount 3
|
||||
|
||||
BitmapFont fonts[fontCount];
|
||||
|
||||
static const char *tx_state_name(TxState state) {
|
||||
switch (state) {
|
||||
case TX_IDLE: return "IDLE";
|
||||
case TX_PREAMBLE: return "PREAMBLE";
|
||||
case TX_SYNC: return "SYNC";
|
||||
case TX_DATA: return "DATA";
|
||||
case TX_END: return "END";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static const char *rx_state_name(RxState state) {
|
||||
switch (state) {
|
||||
case RX_SEARCH: return "SEARCH";
|
||||
case RX_ALIGN: return "ALIGN";
|
||||
case RX_SYNC: return "SYNC";
|
||||
case RX_LOCKED: return "LOCKED";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static const char *setting_name(int setting) {
|
||||
switch (setting) {
|
||||
case 0: return "DATA START";
|
||||
case 1: return "DATA END";
|
||||
case 2: return "SPACING";
|
||||
case 3: return "SYMBOL";
|
||||
case 4: return "CLOCK0";
|
||||
case 5: return "CLOCK1";
|
||||
case 6: return "OUT DEVICE";
|
||||
case 7: return "IN DEVICE";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static void apply_modem_settings(void) {
|
||||
SDL_LockAudioDevice(dev);
|
||||
SDL_LockAudioDevice(inputDev);
|
||||
|
||||
stopEncoder(&encoder);
|
||||
|
||||
encoder.clock0 = goertzel_bin_freq(
|
||||
encoder.clock0,
|
||||
SAMPLE_RATE,
|
||||
encoder.symbolSamples);
|
||||
encoder.clock1 = goertzel_bin_freq(
|
||||
encoder.clock1,
|
||||
SAMPLE_RATE,
|
||||
encoder.symbolSamples);
|
||||
|
||||
decoder.bitCount = encoder.bitCount;
|
||||
decoder.startFreq = encoder.startFreq;
|
||||
decoder.endFreq = encoder.endFreq;
|
||||
decoder.dataSpacing = encoder.dataSpacing;
|
||||
decoder.symbolSamples = encoder.symbolSamples;
|
||||
decoder.clock0 = encoder.clock0;
|
||||
decoder.clock1 = encoder.clock1;
|
||||
decoder_rebuild_tones(&decoder);
|
||||
|
||||
SDL_UnlockAudioDevice(inputDev);
|
||||
SDL_UnlockAudioDevice(dev);
|
||||
}
|
||||
|
||||
static void adjust_modem_setting(int delta) {
|
||||
switch (selectedModemSetting) {
|
||||
case 0:
|
||||
if ((int)encoder.startFreq + delta * 50 >= 200)
|
||||
encoder.startFreq += delta * 50;
|
||||
break;
|
||||
case 1:
|
||||
if ((int)encoder.endFreq + delta * 50 >= 200)
|
||||
encoder.endFreq += delta * 50;
|
||||
break;
|
||||
case 2:
|
||||
if ((int)encoder.dataSpacing + delta * 5 >= 25)
|
||||
encoder.dataSpacing += delta * 5;
|
||||
break;
|
||||
case 3:
|
||||
if ((int)encoder.symbolSamples + delta * 48 >= 240)
|
||||
encoder.symbolSamples += delta * 48;
|
||||
break;
|
||||
case 4:
|
||||
if ((int)encoder.clock0 + delta * 50 >= 500)
|
||||
encoder.clock0 += delta * 50;
|
||||
break;
|
||||
case 5:
|
||||
if ((int)encoder.clock1 + delta * 50 >= 500)
|
||||
encoder.clock1 += delta * 50;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
// Device selection handled separately
|
||||
break;
|
||||
}
|
||||
|
||||
apply_modem_settings();
|
||||
}
|
||||
|
||||
static void render_modem_text(SDL_Renderer *renderer) {
|
||||
char line[256];
|
||||
|
||||
snprintf(
|
||||
line,
|
||||
sizeof(line),
|
||||
"TX %-8s BYTE %u/%u BIT %u PRE %u SYNC %u",
|
||||
tx_state_name(encoder.state),
|
||||
encoder.byteIndex,
|
||||
encoder.bufferSize,
|
||||
encoder.bitIndex,
|
||||
encoder.preambleSymbols,
|
||||
encoder.syncIndex);
|
||||
renderText(renderer, smallerFont, line, 10, 8);
|
||||
|
||||
snprintf(
|
||||
line,
|
||||
sizeof(line),
|
||||
"RX %-8s BYTES %u LAST %02X BESTSYNC %d/4 PHASE %d",
|
||||
rx_state_name(decoder.rxState),
|
||||
decoder.bufferSize,
|
||||
decoder.lastDecodedByte,
|
||||
decoder.bestSyncScore,
|
||||
decoder.bestSyncPhase);
|
||||
renderText(renderer, smallerFont, line, 10, 22);
|
||||
|
||||
snprintf(
|
||||
line,
|
||||
sizeof(line),
|
||||
"CLK E0 %.5f E1 %.5f R %.1f HIST %02X/%u",
|
||||
decoder.clockEnergy0,
|
||||
decoder.clockEnergy1,
|
||||
decoder.clockRatio,
|
||||
decoder.clockHistory,
|
||||
decoder.clockCount);
|
||||
renderText(renderer, smallerFont, line, 10, 36);
|
||||
|
||||
// Settings display with highlighting
|
||||
const char *settingStr = setting_name(selectedModemSetting);
|
||||
snprintf(
|
||||
line,
|
||||
sizeof(line),
|
||||
">> %s START %u END %u SPACE %u SYM %u CLK %u/%u [F8 SELECT] [+/- CHANGE]",
|
||||
settingStr,
|
||||
encoder.startFreq,
|
||||
encoder.endFreq,
|
||||
encoder.dataSpacing,
|
||||
encoder.symbolSamples,
|
||||
encoder.clock0,
|
||||
encoder.clock1);
|
||||
|
||||
// Highlight the settings line with a colored background
|
||||
SDL_Rect settingsBG = {5, 48, 1270, 14};
|
||||
SDL_SetRenderDrawColor(renderer, 64, 80, 96, 128);
|
||||
SDL_RenderFillRect(renderer, &settingsBG);
|
||||
|
||||
renderText(renderer, smallerFont, line, 10, 50);
|
||||
}
|
||||
|
||||
static void render_tone_bars(SDL_Renderer *renderer) {
|
||||
const int tones = decoder.bitCount * 2 + 2;
|
||||
const int x = 500;
|
||||
const int y = 560;
|
||||
const int maxHeight = 72;
|
||||
const int barWidth = 8;
|
||||
const int gap = 4;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
|
||||
SDL_Rect frame = {x - 4, y - maxHeight - 4, tones * (barWidth + gap) + 4, maxHeight + 24};
|
||||
SDL_RenderDrawRect(renderer, &frame);
|
||||
|
||||
for (int i = 0; i < tones; i++) {
|
||||
float ratio = 0.0f;
|
||||
if (decoder.maxEnergy > 0.0f)
|
||||
ratio = decoder.energies[i] / decoder.maxEnergy;
|
||||
if (ratio > 1.0f)
|
||||
ratio = 1.0f;
|
||||
|
||||
SDL_Rect barRect;
|
||||
barRect.w = barWidth;
|
||||
barRect.h = (int)(ratio * maxHeight);
|
||||
barRect.x = x + i * (barWidth + gap);
|
||||
barRect.y = y - barRect.h;
|
||||
|
||||
if (i >= decoder.bitCount * 2)
|
||||
SDL_SetRenderDrawColor(renderer, 255, 192, 64, 255);
|
||||
else if (i & 1)
|
||||
SDL_SetRenderDrawColor(renderer, 80, 180, 255, 255);
|
||||
else
|
||||
SDL_SetRenderDrawColor(renderer, 80, 255, 140, 255);
|
||||
|
||||
SDL_RenderFillRect(renderer, &barRect);
|
||||
}
|
||||
|
||||
char label[128];
|
||||
snprintf(label, sizeof(label), "TONE ENERGY: BIT0..BIT7, CLOCK0, CLOCK1");
|
||||
renderText(renderer, smallerFont, label, x, y + 6);
|
||||
}
|
||||
|
||||
|
||||
int render() {
|
||||
SDL_SetRenderDrawColor(renderer, 32, 32, 32, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
|
||||
SDL_Rect rect2;
|
||||
rect2.x = 100;
|
||||
rect2.y = 46;
|
||||
rect2.w = 0;
|
||||
rect2.h = 0;
|
||||
|
||||
if (cpuStateTexture) {
|
||||
SDL_QueryTexture(cpuStateTexture, NULL, NULL, &rect2.w, &rect2.h);
|
||||
|
||||
SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2);
|
||||
}
|
||||
|
||||
render_modem_text(renderer);
|
||||
render_tone_bars(renderer);
|
||||
|
||||
for (int i = 0; i < editorCount; i++) {
|
||||
editor_render(&editors[i], renderer, &encoder, i, activeEditorIndex == i, cursorShown);
|
||||
}
|
||||
frames++;
|
||||
if (!(frames % 60)) {
|
||||
cursorShown = !cursorShown;
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init() {
|
||||
//Initialize SDL
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
||||
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
|
||||
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Initialize SDL_ttf
|
||||
if (TTF_Init() == -1) {
|
||||
printf("SDL_ttf could not initialize! SDL_ttf Error: %s\n", TTF_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Create window
|
||||
window = SDL_CreateWindow("RISC-B simulator", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
|
||||
SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||
if (window == NULL) {
|
||||
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
//Get window surface
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (renderer == NULL) {
|
||||
printf("Renderer could not be created SDL_Error: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create OpenGL context
|
||||
SDL_GLContext glContext = SDL_GL_CreateContext(window);
|
||||
if (!glContext) {
|
||||
fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Use OpenGL context
|
||||
SDL_GL_MakeCurrent(window, glContext); // Make sure OpenGL context is current before any OpenGL rendering
|
||||
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
biggerFont = prepText(renderer, 16, "PublicPixel.ttf", 255, 255, 255, 255);
|
||||
smallFont = prepText(renderer, 12, "PublicPixel.ttf", 255, 255, 255, 255);
|
||||
smallerFont = prepText(renderer, 8, "PublicPixel.ttf", 255, 255, 255, 255);
|
||||
init_editor(&transmitEditor, &smallFont, 10, 80, renderer, 35, 1000, 28, false);
|
||||
init_editor(&receivedEditor, &smallFont, 500, 80, renderer, 35, 1000, 28, false);
|
||||
|
||||
initAudioEncoder();
|
||||
initAudioDecoder(renderer);
|
||||
strcpy(encoder.buffer, "Hello there\nThis is just a test message\n");
|
||||
|
||||
encoder.bufferSize = strlen(encoder.buffer);
|
||||
|
||||
updateDump(&transmitEditor, renderer);
|
||||
|
||||
|
||||
SDL_Rect viewport = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
||||
SDL_RenderSetViewport(renderer, &viewport);
|
||||
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int processEvent(SDL_Event e) {
|
||||
if (e.type == SDL_QUIT) { return 0; }
|
||||
else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
int newWidth = e.window.data1;
|
||||
int newHeight = e.window.data2;
|
||||
|
||||
for (int editorIndex = 0; editorIndex < editorCount; editorIndex++) {
|
||||
generate_string_display(&editors[editorIndex], renderer);
|
||||
}
|
||||
//updateState(true);
|
||||
|
||||
// Adjust the viewport to match the new window size;
|
||||
SDL_Rect viewport = {0, 0, newWidth, newHeight};
|
||||
SDL_RenderSetViewport(renderer, &viewport);
|
||||
} else if (e.type == SDL_KEYDOWN) {
|
||||
int keySym = ConvertKPToNonKP(e.key.keysym.sym);
|
||||
int keyMod = e.key.keysym.mod;
|
||||
cursorShown = true;
|
||||
bool moved = false;
|
||||
switch (keySym) {
|
||||
case SDLK_UP:
|
||||
move_cursor_relative(&activeEditor, -1, 0, false, renderer);
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
encoder.byteIndex--;
|
||||
}
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_PAGEUP:
|
||||
move_cursor_relative(&activeEditor, -activeEditor.displayLineCount, -1, true, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
move_cursor_relative(&activeEditor, 1, 0, false, renderer);
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
encoder.byteIndex++;
|
||||
}
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_PAGEDOWN:
|
||||
move_cursor_relative(&activeEditor, activeEditor.displayLineCount, 0, true, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
move_cursor_relative(&activeEditor, 0, -1, false, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
move_cursor(&activeEditor, 0, 0, false, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
}
|
||||
move_cursor(&activeEditor, activeEditor.cursor_line, 0, false, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
move_cursor_relative(&activeEditor, 0, 1, false, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_END:
|
||||
int lineLen = strlen(activeEditor.lines[activeEditor.cursor_line].text);
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
move_cursor(&activeEditor, activeEditor.maxLines - 1, lineLen, false, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
}
|
||||
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
||||
moved = true;
|
||||
break;
|
||||
case SDLK_d:
|
||||
if (keyMod & KMOD_CTRL && !activeEditor.readOnly) {
|
||||
insert_line_rel(&activeEditor, renderer);
|
||||
memset(activeEditor.lines[activeEditor.cursor_line].text, 0, activeEditor.max_line_width);
|
||||
strcpy(activeEditor.lines[activeEditor.cursor_line].text,
|
||||
activeEditor.lines[activeEditor.cursor_line - 1].text);
|
||||
activeEditor.lines[activeEditor.cursor_line].active = 1;
|
||||
move_cursor_relative(&activeEditor, 0, activeEditor.max_line_width, false, renderer);
|
||||
generate_string_display(&activeEditor, renderer);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDLK_ESCAPE:
|
||||
stopEncoder(&encoder);
|
||||
break;
|
||||
|
||||
case SDLK_s:
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
FILE *fptr;
|
||||
char fname[20];
|
||||
snprintf(fname, sizeof(fname), "data%lu.bin", time(NULL));
|
||||
fptr = fopen(fname, "wb");
|
||||
unsigned int sizeBuffer = sizeof(encoder.buffer);
|
||||
if (encoder.bufferSize < sizeBuffer) {
|
||||
sizeBuffer = encoder.bufferSize;
|
||||
}
|
||||
fwrite(encoder.buffer, sizeBuffer, 1, fptr);
|
||||
fclose(fptr);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDLK_l:
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
FILE *fptr;
|
||||
char fname[20];
|
||||
sscanf(editors[0].lines[editors[0].cursor_line].text, "%s", fname);
|
||||
fptr = fopen(fname, "rb");
|
||||
if (fptr) {
|
||||
memset(encoder.buffer, 0, sizeof(encoder.buffer));
|
||||
encoder.bufferSize = fread(
|
||||
encoder.buffer,
|
||||
1,
|
||||
sizeof(encoder.buffer),
|
||||
fptr);
|
||||
fclose(fptr);
|
||||
updateDump(&transmitEditor, renderer);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
if (!activeEditor.readOnly) {
|
||||
remove_character(&activeEditor, false, renderer);
|
||||
moved = true;
|
||||
}
|
||||
break;
|
||||
case SDLK_DELETE:
|
||||
if (keyMod & KMOD_CTRL) {
|
||||
memset(encoder.buffer, 0, sizeof(encoder.buffer));
|
||||
encoder.bufferSize = 0;
|
||||
updateDump(&transmitEditor, renderer);
|
||||
|
||||
} else if (keyMod & KMOD_ALT) {
|
||||
memset(decoder.buffer, 0, sizeof(decoder.buffer));
|
||||
decoder.bufferSize = 0;
|
||||
updateDump(&receivedEditor, renderer);
|
||||
|
||||
} else {
|
||||
if (!activeEditor.readOnly) {
|
||||
remove_character(&activeEditor, true, renderer);
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
break;
|
||||
case SDLK_F5:
|
||||
updateDump(&transmitEditor, renderer);
|
||||
break;
|
||||
case SDLK_F7:
|
||||
startEncoder(&encoder);
|
||||
break;
|
||||
case SDLK_F8:
|
||||
selectedModemSetting++;
|
||||
if (selectedModemSetting >= 8)
|
||||
selectedModemSetting = 0;
|
||||
break;
|
||||
case SDLK_PLUS:
|
||||
case SDLK_EQUALS:
|
||||
adjust_modem_setting(1);
|
||||
break;
|
||||
case SDLK_MINUS:
|
||||
adjust_modem_setting(-1);
|
||||
break;
|
||||
case SDLK_INSERT:
|
||||
activeEditor.overwrite = !activeEditor.overwrite;
|
||||
break;
|
||||
case SDLK_RETURN2:
|
||||
if (!activeEditor.readOnly) {
|
||||
insert_line_rel(&activeEditor, renderer);
|
||||
moved = true;
|
||||
}
|
||||
break;
|
||||
case SDLK_TAB:
|
||||
activeEditorIndex++;
|
||||
if (activeEditorIndex >= editorCount) {
|
||||
activeEditorIndex = 0;
|
||||
}
|
||||
activeEditor = editors[activeEditorIndex];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (e.type == SDL_TEXTINPUT) {
|
||||
for (int i = 0; e.text.text[i] != '\0'; i++) { // Iterate over the input string
|
||||
char keySym = e.text.text[i];
|
||||
|
||||
if (!activeEditor.readOnly && activeEditor.cursor_pos <= activeEditor.max_line_width) {
|
||||
if (keySym >= 32 && keySym <= 126) { // Printable ASCII range
|
||||
if (keySym > 0x60 && keySym < 0x7b) { // Convert lowercase to uppercase
|
||||
keySym -= 0x20;
|
||||
}
|
||||
if (activeEditor.cursor_pos < activeEditor.max_line_width) {
|
||||
insert_character(&activeEditor, keySym, renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
|
||||
SDL_Rect viewport;
|
||||
SDL_RenderGetViewport(renderer, &viewport);
|
||||
|
||||
SDL_Rect mouset;
|
||||
mouset.w = 1;
|
||||
mouset.h = 1;
|
||||
SDL_GetMouseState(&mouset.x, &mouset.y);
|
||||
// Translate mouse coordinates to viewport space
|
||||
SDL_Rect mouse;
|
||||
mouse.w = 1;
|
||||
mouse.h = 1;
|
||||
mouse.x = ((mouset.x - viewport.x) * SCREEN_WIDTH) / viewport.w;
|
||||
mouse.y = (mouset.y - viewport.y) * SCREEN_HEIGHT / viewport.h;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int status = init();
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//Hack to get window to stay up
|
||||
SDL_Event e;
|
||||
Uint64 start;
|
||||
Uint64 end;
|
||||
while (running) {
|
||||
start = SDL_GetTicks64();
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
running = processEvent(e);
|
||||
}
|
||||
|
||||
updateDump(&receivedEditor, decoder.renderer);
|
||||
status = render();
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
end = SDL_GetTicks64();
|
||||
const unsigned long timeNeeded = end - start;
|
||||
if (timeNeeded < delayNeeded) {
|
||||
SDL_Delay(delayNeeded - timeNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < editorCount; i++) {
|
||||
destroy_editor(&editors[i]);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < fontCount; i++) {
|
||||
destroyFont(&fonts[i]);
|
||||
}
|
||||
|
||||
puts(SDL_GetError());
|
||||
|
||||
if (cpuStateTexture) SDL_DestroyTexture(cpuStateTexture);
|
||||
|
||||
if (renderer) SDL_DestroyRenderer(renderer);
|
||||
if (window) SDL_DestroyWindow(window);
|
||||
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user