mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 18:15:28 -04:00
Simplify altering default builtin colours, and loading options representing colours
Also improve String_Append to deliberately crash the game when attempting to append to an uninitialised string in MSVC debug builds
This commit is contained in:
parent
7bbfd61f63
commit
39b09a9202
@ -20,6 +20,29 @@ Some general guidelines to keep in mind when it comes to `cc_string` strings:
|
|||||||
- Strings are not garbage collected or reference counted<br>
|
- Strings are not garbage collected or reference counted<br>
|
||||||
(i.e. you are responsible for managing the lifetime of strings)
|
(i.e. you are responsible for managing the lifetime of strings)
|
||||||
|
|
||||||
|
## Usage examples
|
||||||
|
|
||||||
|
Initialisating a string from readonly text:
|
||||||
|
```C
|
||||||
|
cc_string str = String_FromConst("ABC");
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialising a string from temporary memory on the stack:
|
||||||
|
```C
|
||||||
|
// str will be able to store at most 200 characters in it
|
||||||
|
char strBuffer[200];
|
||||||
|
cc_string str = String_FromArray(strBuffer);
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialising a string from persistent memory on the heap:
|
||||||
|
```C
|
||||||
|
// str will be able to store at most 200 characters in it
|
||||||
|
char* str = Mem_Alloc(1, 200, "String buffer");
|
||||||
|
cc_string str = String_Init(str, 0, 200);
|
||||||
|
```
|
||||||
|
|
||||||
|
# Converting to/from other string representations
|
||||||
|
|
||||||
## C String conversion
|
## C String conversion
|
||||||
|
|
||||||
### C string -> cc_string
|
### C string -> cc_string
|
||||||
@ -106,13 +129,15 @@ void SetWorkingDir(cc_string* title) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## API
|
# API
|
||||||
|
|
||||||
I'm lazy so I will just link to [String.h](/src/String.h)
|
I'm lazy so I will just link to [String.h](/src/String.h)
|
||||||
|
|
||||||
If you'd rather I provided a more detailed reference here, please let me know.
|
If you'd rather I provided a more detailed reference here, please let me know.
|
||||||
|
|
||||||
# Extra details
|
TODO
|
||||||
|
|
||||||
|
# Comparisons to other string implementations
|
||||||
|
|
||||||
## C comparison
|
## C comparison
|
||||||
|
|
||||||
@ -202,10 +227,7 @@ string::compare -> String_Compare
|
|||||||
std::sprintf -> String_Format1/2/3/4
|
std::sprintf -> String_Format1/2/3/4
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Detailed lifetime examples
|
||||||
|
|
||||||
|
|
||||||
## Lifetime examples
|
|
||||||
|
|
||||||
Managing the lifetime of strings is important, as not properly managing them can cause issues.
|
Managing the lifetime of strings is important, as not properly managing them can cause issues.
|
||||||
|
|
||||||
|
23
src/Chat.c
23
src/Chat.c
@ -415,19 +415,18 @@ static struct ChatCommand GpuInfoCommand = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void RenderTypeCommand_Execute(const cc_string* args, int argsCount) {
|
static void RenderTypeCommand_Execute(const cc_string* args, int argsCount) {
|
||||||
int flags;
|
char strBuffer[256];
|
||||||
if (!argsCount) {
|
cc_string safeStr = String_FromArray(strBuffer);
|
||||||
Chat_AddRaw("&e/client: &cYou didn't specify a new render type."); return;
|
cc_string unsafeStr;
|
||||||
}
|
|
||||||
|
|
||||||
flags = EnvRenderer_CalcFlags(args);
|
Options_SetInt("xyz", 123456);
|
||||||
if (flags >= 0) {
|
Options_Get("xyz", &safeStr, "");
|
||||||
EnvRenderer_SetMode(flags);
|
Options_UNSAFE_Get("xyz", &unsafeStr);
|
||||||
Options_Set(OPT_RENDER_TYPE, args);
|
|
||||||
Chat_Add1("&e/client: &fRender type is now %s.", args);
|
Options_Reload();
|
||||||
} else {
|
|
||||||
Chat_Add1("&e/client: &cUnrecognised render type &f\"%s\"&c.", args);
|
Chat_Add1("Safe: %s", &safeStr);
|
||||||
}
|
Chat_Add1("Unsafe: %s", &unsafeStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ChatCommand RenderTypeCommand = {
|
static struct ChatCommand RenderTypeCommand = {
|
||||||
|
@ -633,26 +633,39 @@ static void DefaultPngProcess(struct Stream* stream, const cc_string* name) {
|
|||||||
static struct TextureEntry default_entry = { "default.png", DefaultPngProcess };
|
static struct TextureEntry default_entry = { "default.png", DefaultPngProcess };
|
||||||
|
|
||||||
|
|
||||||
static void InitHexEncodedColor(int i, int hex, cc_uint8 lo, cc_uint8 hi) {
|
/* The default 16 colours are the CGA 16 color palette (without special brown colour) */
|
||||||
Drawer2D.Colors[i] = BitmapColor_RGB(
|
/* See https://en.wikipedia.org/wiki/Color_Graphics_Adapter#With_an_RGBI_monitor for reference */
|
||||||
lo * ((hex >> 2) & 1) + hi * (hex >> 3),
|
/* The 16 hex colours below were produced from the following formula: */
|
||||||
lo * ((hex >> 1) & 1) + hi * (hex >> 3),
|
/* R = 191 * ((hex >> 2) & 1) + 64 * (hex >> 3) */
|
||||||
lo * ((hex >> 0) & 1) + hi * (hex >> 3));
|
/* G = 191 * ((hex >> 1) & 1) + 64 * (hex >> 3) */
|
||||||
}
|
/* B = 191 * ((hex >> 0) & 1) + 64 * (hex >> 3) */
|
||||||
|
static const BitmapCol defaults_0_9[] = {
|
||||||
|
BitmapColor_RGB( 0, 0, 0), /* 0 */
|
||||||
|
BitmapColor_RGB( 0, 0, 191), /* 1 */
|
||||||
|
BitmapColor_RGB( 0, 191, 0), /* 2 */
|
||||||
|
BitmapColor_RGB( 0, 191, 191), /* 3 */
|
||||||
|
BitmapColor_RGB(191, 0, 0), /* 4 */
|
||||||
|
BitmapColor_RGB(191, 0, 191), /* 5 */
|
||||||
|
BitmapColor_RGB(191, 191, 0), /* 6 */
|
||||||
|
BitmapColor_RGB(191, 191, 191), /* 7 */
|
||||||
|
BitmapColor_RGB( 64, 64, 64), /* 8 */
|
||||||
|
BitmapColor_RGB( 64, 64, 255) /* 9 */
|
||||||
|
};
|
||||||
|
static const BitmapCol defaults_a_f[] = {
|
||||||
|
BitmapColor_RGB( 64, 255, 64), /* A */
|
||||||
|
BitmapColor_RGB( 64, 255, 255), /* B */
|
||||||
|
BitmapColor_RGB(255, 64, 64), /* C */
|
||||||
|
BitmapColor_RGB(255, 64, 255), /* D */
|
||||||
|
BitmapColor_RGB(255, 255, 64), /* E */
|
||||||
|
BitmapColor_RGB(255, 255, 255), /* F */
|
||||||
|
};
|
||||||
|
|
||||||
static void OnReset(void) {
|
static void OnReset(void) {
|
||||||
int i;
|
Mem_Set(Drawer2D.Colors, 0, sizeof(Drawer2D.Colors));
|
||||||
for (i = 0; i < DRAWER2D_MAX_COLORS; i++) {
|
|
||||||
Drawer2D.Colors[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i <= 9; i++) {
|
Mem_Copy(&Drawer2D.Colors['0'], defaults_0_9, sizeof(defaults_0_9));
|
||||||
InitHexEncodedColor('0' + i, i, 191, 64);
|
Mem_Copy(&Drawer2D.Colors['a'], defaults_a_f, sizeof(defaults_a_f));
|
||||||
}
|
Mem_Copy(&Drawer2D.Colors['A'], defaults_a_f, sizeof(defaults_a_f));
|
||||||
for (i = 10; i <= 15; i++) {
|
|
||||||
InitHexEncodedColor('a' + (i - 10), i, 191, 64);
|
|
||||||
InitHexEncodedColor('A' + (i - 10), i, 191, 64);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnInit(void) {
|
static void OnInit(void) {
|
||||||
|
@ -328,9 +328,7 @@ const struct LauncherTheme Launcher_NordicTheme = {
|
|||||||
|
|
||||||
CC_NOINLINE static void ParseColor(const char* key, BitmapCol* color) {
|
CC_NOINLINE static void ParseColor(const char* key, BitmapCol* color) {
|
||||||
cc_uint8 rgb[3];
|
cc_uint8 rgb[3];
|
||||||
cc_string value;
|
if (!Options_GetColor(key, rgb)) return;
|
||||||
if (!Options_UNSAFE_Get(key, &value)) return;
|
|
||||||
if (!PackedCol_TryParseHex(&value, rgb)) return;
|
|
||||||
|
|
||||||
*color = BitmapColor_RGB(rgb[0], rgb[1], rgb[2]);
|
*color = BitmapColor_RGB(rgb[0], rgb[1], rgb[2]);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "Errors.h"
|
#include "Errors.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "PackedCol.h"
|
||||||
|
|
||||||
struct StringsBuffer Options;
|
struct StringsBuffer Options;
|
||||||
static struct StringsBuffer changedOpts;
|
static struct StringsBuffer changedOpts;
|
||||||
@ -137,6 +138,19 @@ int Options_GetEnum(const char* key, int defValue, const char* const* names, int
|
|||||||
return Utils_ParseEnum(&str, defValue, names, namesCount);
|
return Utils_ParseEnum(&str, defValue, names, namesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cc_bool Options_GetColor(const char* key, cc_uint8* rgb) {
|
||||||
|
cc_string value, parts[3];
|
||||||
|
if (!Options_UNSAFE_Get(key, &value)) return false;
|
||||||
|
if (PackedCol_TryParseHex(&value, rgb)) return true;
|
||||||
|
|
||||||
|
/* Try parsing as R,G,B instead */
|
||||||
|
return String_UNSAFE_Split(&value, ',', parts, 3)
|
||||||
|
&& Convert_ParseUInt8(&parts[0], &rgb[0])
|
||||||
|
&& Convert_ParseUInt8(&parts[1], &rgb[1])
|
||||||
|
&& Convert_ParseUInt8(&parts[2], &rgb[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Options_SetBool(const char* keyRaw, cc_bool value) {
|
void Options_SetBool(const char* keyRaw, cc_bool value) {
|
||||||
static const cc_string str_true = String_FromConst("True");
|
static const cc_string str_true = String_FromConst("True");
|
||||||
static const cc_string str_false = String_FromConst("False");
|
static const cc_string str_false = String_FromConst("False");
|
||||||
|
@ -123,6 +123,9 @@ CC_API float Options_GetFloat(const char* key, float min, float max, float defV
|
|||||||
/* Returns value of given option as an integer, or defalt value if could not be converted. */
|
/* Returns value of given option as an integer, or defalt value if could not be converted. */
|
||||||
/* NOTE: Conversion is done by going through all elements of names, returning index of a match. */
|
/* NOTE: Conversion is done by going through all elements of names, returning index of a match. */
|
||||||
CC_API int Options_GetEnum(const char* key, int defValue, const char* const* names, int namesCount);
|
CC_API int Options_GetEnum(const char* key, int defValue, const char* const* names, int namesCount);
|
||||||
|
/* Attempts to parse the value of the given option into an RGB (3 byte) colour. */
|
||||||
|
/* Returns whether the option was actually found and could be parsed into a colour. */
|
||||||
|
cc_bool Options_GetColor(const char* key, cc_uint8* rgb);
|
||||||
|
|
||||||
/* Sets value of given option to either "true" or "false". */
|
/* Sets value of given option to either "true" or "false". */
|
||||||
CC_API void Options_SetBool(const char* keyRaw, cc_bool value);
|
CC_API void Options_SetBool(const char* keyRaw, cc_bool value);
|
||||||
|
@ -146,6 +146,13 @@ int String_CaselessEqualsConst(const cc_string* a, const char* b) {
|
|||||||
|
|
||||||
|
|
||||||
void String_Append(cc_string* str, char c) {
|
void String_Append(cc_string* str, char c) {
|
||||||
|
/* MSVC in debug mode will initialise all variables on the stack with 0xCC by default */
|
||||||
|
/* So if a string is being passed with CC in all its fields, then it's probably invalid */
|
||||||
|
#if _MSC_VER && _DEBUG
|
||||||
|
if (str->length == 0xCCCC && str->capacity == 0xCCCC)
|
||||||
|
Logger_Abort("String must be initialised before calling String_Append");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (str->length == str->capacity) return;
|
if (str->length == str->capacity) return;
|
||||||
str->buffer[str->length++] = c;
|
str->buffer[str->length++] = c;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user