mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-22 17:49:43 +01:00
Add Textbook
A relevant paragraph copied from the original commit history: The idea is that we store all strings somewhere managed, and then the hashmap only needs pointers to those strings. For storing strings, I created a `Textbook` structure, which consists of one or more 50 KB "pages" (allocated as needed) on which you can simply write strings in both languages back-to-back with `textbook_store(textbook, text)` and get pointers to each of them. (I was originally going to just use one big buffer and realloc to double the size when filled up, but then the hashmap would be full of dangling pointers...) When needed, like when switching to a different language, an entire textbook can be freed at once. This commit is part of rewritten history of the localization branch. The original (unsquashed) commit history can be found here: https://github.com/Dav999-v/VVVVVV/tree/localization-orig
This commit is contained in:
parent
b148950367
commit
0ed2cb1bc0
3 changed files with 148 additions and 0 deletions
|
@ -104,6 +104,7 @@ set(VVV_SRC
|
|||
src/DeferCallbacks.c
|
||||
src/GlitchrunnerMode.c
|
||||
src/Network.c
|
||||
src/Textbook.c
|
||||
src/ThirdPartyDeps.c
|
||||
src/VFormat.c
|
||||
src/Vlogging.c
|
||||
|
|
111
desktop_version/src/Textbook.c
Normal file
111
desktop_version/src/Textbook.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "Textbook.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "Vlogging.h"
|
||||
|
||||
void textbook_init(Textbook* textbook)
|
||||
{
|
||||
textbook->pages_used = 0;
|
||||
textbook->protect = false;
|
||||
}
|
||||
|
||||
void textbook_clear(Textbook* textbook)
|
||||
{
|
||||
if (textbook->protect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (short p = 0; p < textbook->pages_used; p++)
|
||||
{
|
||||
SDL_free(textbook->page[p]);
|
||||
}
|
||||
textbook->pages_used = 0;
|
||||
}
|
||||
|
||||
void textbook_set_protected(Textbook* textbook, bool protect)
|
||||
{
|
||||
/* A protected textbook is silently not cleared when requested.
|
||||
* Not a memory leak as long as you unprotect and clear at some point. */
|
||||
textbook->protect = protect;
|
||||
}
|
||||
|
||||
const void* textbook_store_raw(Textbook* textbook, const void* data, size_t data_len)
|
||||
{
|
||||
if (data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data_len > TEXTBOOK_PAGE_SIZE)
|
||||
{
|
||||
vlog_warn(
|
||||
"Cannot store data of %ld bytes in Textbook, max page size is %d",
|
||||
data_len,
|
||||
TEXTBOOK_PAGE_SIZE
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find a suitable page to place our text on */
|
||||
short found_page = -1;
|
||||
for (short p = 0; p < textbook->pages_used; p++)
|
||||
{
|
||||
size_t free = TEXTBOOK_PAGE_SIZE - textbook->page_len[p];
|
||||
|
||||
if (data_len <= free)
|
||||
{
|
||||
found_page = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_page == -1)
|
||||
{
|
||||
/* Create a new page then */
|
||||
found_page = textbook->pages_used;
|
||||
|
||||
if (found_page >= TEXTBOOK_MAX_PAGES)
|
||||
{
|
||||
vlog_warn(
|
||||
"Textbook is full! %hd pages used (%d chars per page)",
|
||||
textbook->pages_used,
|
||||
TEXTBOOK_PAGE_SIZE
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
textbook->page[found_page] = (char*) SDL_malloc(TEXTBOOK_PAGE_SIZE);
|
||||
if (textbook->page[found_page] == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
textbook->page_len[found_page] = 0;
|
||||
textbook->pages_used++;
|
||||
}
|
||||
|
||||
size_t cursor = textbook->page_len[found_page];
|
||||
char* added_text = &textbook->page[found_page][cursor];
|
||||
SDL_memcpy(added_text, data, data_len);
|
||||
textbook->page_len[found_page] += data_len;
|
||||
|
||||
return added_text;
|
||||
}
|
||||
|
||||
const char* textbook_store(Textbook* textbook, const char* text)
|
||||
{
|
||||
if (text == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (text[0] == '\0')
|
||||
{
|
||||
/* Don't go and store a single null terminator when we have one right here for you: */
|
||||
return "";
|
||||
}
|
||||
|
||||
return textbook_store_raw(textbook, text, SDL_strlen(text)+1);
|
||||
}
|
36
desktop_version/src/Textbook.h
Normal file
36
desktop_version/src/Textbook.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef TEXTBOOK_H
|
||||
#define TEXTBOOK_H
|
||||
|
||||
#include <SDL_stdinc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* The purpose of a Textbook is to store, potentially, a lot of text on a pile that shouldn't
|
||||
* go anywhere until we change languages or (for example) unload an entire level's text. */
|
||||
#define TEXTBOOK_MAX_PAGES 1000
|
||||
#define TEXTBOOK_PAGE_SIZE 50000
|
||||
typedef struct _Textbook
|
||||
{
|
||||
char* page[TEXTBOOK_MAX_PAGES];
|
||||
size_t page_len[TEXTBOOK_MAX_PAGES];
|
||||
|
||||
short pages_used;
|
||||
bool protect;
|
||||
} Textbook;
|
||||
|
||||
void textbook_init(Textbook* textbook);
|
||||
void textbook_clear(Textbook* textbook);
|
||||
void textbook_set_protected(Textbook* textbook, bool protect);
|
||||
const void* textbook_store_raw(Textbook* textbook, const void* data, size_t data_len);
|
||||
const char* textbook_store(Textbook* textbook, const char* text);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* TEXTBOOK_H */
|
Loading…
Reference in a new issue