summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2024-01-21 21:01:00 +0000
committerMichael Smith <mikesmiffy128@gmail.com>2024-01-21 21:01:00 +0000
commit506f095bcb528468f25a637977efcc408590ae67 (patch)
tree2f0228fddc9fc31f3ff895703d60cf26bc8e8cab
parent374ae0fbc44db36d9abb6b5b1fe065bc3949e201 (diff)
Add a half-decent custom crosshair
-rwxr-xr-xcompile2
-rw-r--r--compile.bat2
-rw-r--r--src/hexcolour.c85
-rw-r--r--src/hexcolour.h36
-rw-r--r--src/portalcolours.c47
-rw-r--r--src/xhair.c88
6 files changed, 222 insertions, 38 deletions
diff --git a/compile b/compile
index abdd5a7..bcda4ec 100755
--- a/compile
+++ b/compile
@@ -70,6 +70,7 @@ src="\
gamedata.c
gameinfo.c
gameserver.c
+ hexcolour.c
hook.c
hud.c
kvsys.c
@@ -79,6 +80,7 @@ src="\
nosleep.c
portalcolours.c
sst.c
+ xhair.c
x86.c"
if [ "$dbg" = 1 ]; then src="$src \
dbg.c
diff --git a/compile.bat b/compile.bat
index 97bbb6f..a50dbb0 100644
--- a/compile.bat
+++ b/compile.bat
@@ -77,6 +77,7 @@ setlocal DisableDelayedExpansion
:+ gamedata.c
:+ gameinfo.c
:+ gameserver.c
+:+ hexcolour.c
:+ hook.c
:+ hud.c
:+ kvsys.c
@@ -88,6 +89,7 @@ setlocal DisableDelayedExpansion
:+ portalcolours.c
:+ rinput.c
:+ sst.c
+:+ xhair.c
:+ x86.c
:: just tack these on, whatever (repeated condition because of expansion memes)
if "%dbg%"=="1" set src=%src% src/dbg.c
diff --git a/src/hexcolour.c b/src/hexcolour.c
new file mode 100644
index 0000000..7d0ad43
--- /dev/null
+++ b/src/hexcolour.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "intdefs.h"
+
+void hexcolour_rgb(uchar out[static 4], const char *s) {
+ const char *p = s;
+ for (uchar *q = out; q - out < 3; ++q) {
+ if (*p >= '0' && *p <= '9') {
+ *q = *p++ - '0' << 4;
+ }
+ else if ((*p | 32) >= 'a' && (*p | 32) <= 'f') {
+ *q = 10 + (*p++ | 32) - 'a' << 4;
+ }
+ else {
+ // screw it, just fall back on white, I guess.
+ // note: this also handles *p == '\0' so we don't overrun the string
+ memset(out, 255, 4); // should be a single mov
+ return;
+ }
+ // repetitive unrolled nonsense
+ if (*p >= '0' && *p <= '9') {
+ *q |= *p++ - '0';
+ }
+ else if ((*p | 32) >= 'a' && (*p | 32) <= 'f') {
+ *q |= 10 + (*p++ | 32) - 'a';
+ }
+ else {
+ memset(out, 255, 4); // should be a single mov
+ return;
+ }
+ }
+ //out[3] = 255; // never changes!
+}
+
+void hexcolour_rgba(uchar out[static 4], const char *s) {
+ const char *p = s;
+ // same again but with 4 pairs of digits instead of 3!
+ for (uchar *q = out; q - out < 4; ++q) {
+ if (*p >= '0' && *p <= '9') {
+ *q = *p++ - '0' << 4;
+ }
+ else if ((*p | 32) >= 'a' && (*p | 32) <= 'f') {
+ *q = 10 + (*p++ | 32) - 'a' << 4;
+ }
+ else {
+ if (q - out == 3 && !*p) {
+ // ONLY if both the last alpha digits are missing: use provided
+ // RGB at full opacity. otherwise same white fallback as before.
+ out[3] = 255;
+ return;
+ }
+ memset(out, 255, 4);
+ return;
+ }
+ // even more repetitive unrolled nonsense
+ if (*p >= '0' && *p <= '9') {
+ *q |= *p++ - '0';
+ }
+ else if ((*p | 32) >= 'a' && (*p | 32) <= 'f') {
+ *q |= 10 + (*p++ | 32) - 'a';
+ }
+ else {
+ memset(out, 255, 4);
+ return;
+ }
+ }
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/hexcolour.h b/src/hexcolour.h
new file mode 100644
index 0000000..def95f4
--- /dev/null
+++ b/src/hexcolour.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "intdefs.h"
+
+/*
+ * Parses a user-provided RGB hex string, writing the RGBA bytes to out. May or
+ * may not modify the alpha byte; it is assumed to always be set to 255. That
+ * probably sounds dumb but makes sense for our specific use cases.
+ *
+ * Falls back on white if the input isn't valid. This also makes sense for our
+ * use cases.
+ */
+void hexcolour_rgb(uchar out[static 4], const char *s);
+
+/*
+ * Parses a user-provided RGBA hex string, writing the RGBA bytes to out.
+ * If both the alpha digits are missing, provides full opacity instead. If the
+ * value is malformed in some other way, falls back on solid white.
+ */
+void hexcolour_rgba(uchar out[static 4], const char *s);
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/portalcolours.c b/src/portalcolours.c
index 0eb3a30..3167c0b 100644
--- a/src/portalcolours.c
+++ b/src/portalcolours.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
+ * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,8 +19,9 @@
#include "con_.h"
#include "engineapi.h"
#include "errmsg.h"
-#include "gametype.h"
#include "feature.h"
+#include "gametype.h"
+#include "hexcolour.h"
#include "hook.h"
#include "intdefs.h"
#include "mem.h"
@@ -34,55 +35,25 @@ REQUIRE_GLOBAL(clientlib)
// It's like the thing Portal Tools does, but at runtime!
-DEF_CVAR_UNREG(sst_portal_colour0, "Crosshair colour for gravity beam (hex)",
+DEF_CVAR_UNREG(sst_portal_colour0, "Crosshair colour for gravity beam (RGB hex)",
"F2CAA7", CON_ARCHIVE | CON_HIDDEN)
-DEF_CVAR_UNREG(sst_portal_colour1, "Crosshair colour for left portal (hex)",
+DEF_CVAR_UNREG(sst_portal_colour1, "Crosshair colour for left portal (RGB hex)",
"40A0FF", CON_ARCHIVE | CON_HIDDEN)
-DEF_CVAR_UNREG(sst_portal_colour2, "Crosshair colour for right portal (hex)",
+DEF_CVAR_UNREG(sst_portal_colour2, "Crosshair colour for right portal (RGB hex)",
"FFA020", CON_ARCHIVE | CON_HIDDEN)
static struct rgba colours[3] = {
{242, 202, 167, 255}, {64, 160, 255, 255}, {255, 160, 32, 255}};
-static void hexparse(uchar out[static 4], const char *s) {
- const char *p = s;
- for (uchar *q = out; q - out < 3; ++q) {
- if (*p >= '0' && *p <= '9') {
- *q = *p++ - '0' << 4;
- }
- else if ((*p | 32) >= 'a' && (*p | 32) <= 'f') {
- *q = 10 + (*p++ | 32) - 'a' << 4;
- }
- else {
- // screw it, just fall back on white, I guess.
- // note: this also handles *p == '\0' so we don't overrun the string
- memset(out, 255, 4); // write 4 rather than 3, prolly faster?
- return;
- }
- // repetitive unrolled nonsense
- if (*p >= '0' && *p <= '9') {
- *q |= *p++ - '0';
- }
- else if ((*p | 32) >= 'a' && (*p | 32) <= 'f') {
- *q |= 10 + (*p++ | 32) - 'a';
- }
- else {
- memset(out, 255, 4);
- return;
- }
- }
- //out[3] = 255; // never changes!
-}
-
static void colourcb(struct con_var *v) {
// this is stupid and ugly and has no friends, too bad!
if (v == sst_portal_colour0) {
- hexparse(colours[0].bytes, con_getvarstr(v));
+ hexcolour_rgb(colours[0].bytes, con_getvarstr(v));
}
else if (v == sst_portal_colour1) {
- hexparse(colours[1].bytes, con_getvarstr(v));
+ hexcolour_rgb(colours[1].bytes, con_getvarstr(v));
}
else /* sst_portal_colour2 */ {
- hexparse(colours[2].bytes, con_getvarstr(v));
+ hexcolour_rgb(colours[2].bytes, con_getvarstr(v));
}
}
diff --git a/src/xhair.c b/src/xhair.c
new file mode 100644
index 0000000..e2f7bfb
--- /dev/null
+++ b/src/xhair.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "con_.h"
+#include "engineapi.h"
+#include "feature.h"
+#include "hexcolour.h"
+#include "hud.h"
+#include "intdefs.h"
+
+FEATURE("crosshair drawing")
+REQUIRE(hud)
+
+DEF_CVAR(sst_xhair, "Enable custom crosshair", 0, CON_ARCHIVE | CON_HIDDEN)
+DEF_CVAR(sst_xhair_colour, "Colour for alternative crosshair (RGBA hex)",
+ "FFFFFF", CON_ARCHIVE | CON_HIDDEN)
+DEF_CVAR_MIN(sst_xhair_thickness, "Thickness of custom crosshair in pixels", 2,
+ 1, CON_ARCHIVE | CON_HIDDEN)
+DEF_CVAR_MIN(sst_xhair_size, "Length of lines in custom crosshair in pixels", 8,
+ 0, CON_ARCHIVE | CON_HIDDEN)
+DEF_CVAR_MIN(sst_xhair_gap, "Gap between lines in custom crosshair in pixels",
+ 16, 0, CON_ARCHIVE | CON_HIDDEN)
+DEF_CVAR(sst_xhair_dot, "Whether to draw dot in middle of custom crosshair",
+ 1, CON_ARCHIVE | CON_HIDDEN)
+DEF_CVAR(sst_xhair_outline, "Whether to draw outline around custom crosshair",
+ 0, CON_ARCHIVE | CON_HIDDEN)
+
+static struct rgba colour = {255, 255, 255, 255};
+
+static void colourcb(struct con_var *v) {
+ hexcolour_rgba(colour.bytes, con_getvarstr(v));
+}
+
+static inline void drawrect(int x0, int y0, int x1, int y1, struct rgba colour,
+ bool outline) {
+ hud_drawrect(x0, y0, x1, y1, colour, true);
+ if (outline) hud_drawrect(x0, y0, x1, y1, (struct rgba){.a = 255}, false);
+}
+HANDLE_EVENT(HudPaint, void) {
+ if (!con_getvari(sst_xhair)) return;
+ int w, h;
+ hud_screensize(&w, &h);
+ int thick = con_getvari(sst_xhair_thickness);
+ int thick1 = (thick + 1) / 2, thick2 = thick - thick1;
+ int sz = con_getvari(sst_xhair_size);
+ int gap = con_getvari(sst_xhair_gap);
+ int gap1 = (gap + 1) / 2, gap2 = gap - gap1;
+ int x = w / 2, y = h / 2;
+ bool ol = !!con_getvari(sst_xhair_outline);
+ if (sz) {
+ drawrect(x - thick1, y - sz - gap1, x + thick2, y - gap1, colour, ol);
+ drawrect(x - thick1, y + gap2, x + thick2, y + sz + gap2, colour, ol);
+ drawrect(x - sz - gap1, y - thick1, x - gap1, y + thick2, colour, ol);
+ drawrect(x + gap2, y - thick1, x + sz + gap2, y + thick2, colour, ol);
+ }
+ if (con_getvari(sst_xhair_dot) && (gap >= thick || ol)) {
+ drawrect(x - thick1, y - thick1, x + thick2, y + thick2, colour, ol);
+ }
+}
+
+INIT {
+ sst_xhair->base.flags &= ~CON_HIDDEN;
+ sst_xhair_colour->base.flags &= ~CON_HIDDEN;
+ sst_xhair_colour->cb = &colourcb;
+ sst_xhair_thickness->base.flags &= ~CON_HIDDEN;
+ sst_xhair_size->base.flags &= ~CON_HIDDEN;
+ sst_xhair_gap->base.flags &= ~CON_HIDDEN;
+ sst_xhair_dot->base.flags &= ~CON_HIDDEN;
+ sst_xhair_outline->base.flags &= ~CON_HIDDEN;
+ return true;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80