Skip to content

Commit

Permalink
Restore crosshair functionality from old SvenBXT
Browse files Browse the repository at this point in the history
  • Loading branch information
ScriptedSnark committed Sep 3, 2024
1 parent 6e658af commit 208a6f3
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ set(CLIENT_FILES
cl_dll/cdll_int.h
cl_dll/hud.cpp
cl_dll/hud.h
cl_dll/hud_crosshair.cpp
cl_dll/hud_crosshair.h
cl_dll/hud_jumpspeed.cpp
cl_dll/hud_jumpspeed.h
cl_dll/hud_origin.cpp
Expand All @@ -34,6 +36,8 @@ set(CLIENT_FILES
cl_dll/hud_timer.h
cl_dll/hud_viewangles.cpp
cl_dll/hud_viewangles.h
cl_dll/opengl_utils.cpp
cl_dll/opengl_utils.hpp
cl_dll/parsemsg.cpp
cl_dll/parsemsg.h
cl_dll/view.cpp
Expand Down Expand Up @@ -85,6 +89,8 @@ if( COMPILER_GNU )
_vsnprintf=vsnprintf
_snwprintf=swprintf
)

set(OPENGL_LIBRARY GL)
elseif( COMPILER_MSVC )

# Disable "unsafe" warnings
Expand All @@ -93,6 +99,8 @@ elseif( COMPILER_MSVC )
_CRT_SECURE_NO_WARNINGS
_SCL_SECURE_NO_WARNINGS
)

set(OPENGL_LIBRARY opengl32)
endif()

if (COMPILER_GNU)
Expand All @@ -114,9 +122,11 @@ set(THREADS_PREFER_PTHREAD_FLAG TRUE)

# Modules
find_package(Threads REQUIRED)
find_package(OpenGL REQUIRED)

# Link with dependencies
target_link_libraries(SvenBXT
Threads::Threads
funchook-static
${OPENGL_LIBRARY}
)
5 changes: 5 additions & 0 deletions src/SvenBXT.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
#include <fstream>
#include <thread>

// GL
#include <GL/GL.h>

#include "external/funchook/include/funchook.h"

#ifdef PLATFORM_WINDOWS
Expand Down Expand Up @@ -69,6 +72,7 @@ extern server_t* sv;
#include "cl_dll/hud.h"
#include "cl_dll/parsemsg.h"
#include "cl_dll/view.h"
#include "cl_dll/opengl_utils.hpp"

#include "engine/gl_screen.h"

Expand All @@ -81,6 +85,7 @@ extern server_t* sv;
#include "cl_dll/hud_origin.h"
#include "cl_dll/hud_timer.h"
#include "cl_dll/hud_jumpspeed.h"
#include "cl_dll/hud_crosshair.h"

#ifdef PLATFORM_WINDOWS
#define FASTCALL __fastcall
Expand Down
1 change: 1 addition & 0 deletions src/cl_dll/hud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void CBXTHud::Init(void)
RegisterHUDElement<CHudOrigin>();
RegisterHUDElement<CHudTimer>();
RegisterHUDElement<CHudJumpspeed>();
RegisterHUDElement<CHudCrosshair>();

for (CBXTHudBase* i : m_vecHudList)
{
Expand Down
186 changes: 186 additions & 0 deletions src/cl_dll/hud_crosshair.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#include "SvenBXT.h"

int CHudCrosshair::Init()
{
m_iFlags |= HUD_ACTIVE;

// OpenGL crosshair cvars
bxt_cross = CVAR_CREATE("sbxt_cross", "0", 0);
bxt_cross_color = CVAR_CREATE("sbxt_cross_color", "", 0);
bxt_cross_alpha = CVAR_CREATE("sbxt_cross_alpha", "255", 0);
bxt_cross_thickness = CVAR_CREATE("sbxt_cross_thickness", "2", 0);
bxt_cross_size = CVAR_CREATE("sbxt_cross_size", "10", 0);
bxt_cross_gap = CVAR_CREATE("sbxt_cross_gap", "3", 0);
bxt_cross_outline = CVAR_CREATE("sbxt_cross_outline", "0", 0);
bxt_cross_circle_radius = CVAR_CREATE("sbxt_cross_circle_radius", "0", 0);
bxt_cross_dot_color = CVAR_CREATE("sbxt_cross_dot_color", "", 0);
bxt_cross_dot_size = CVAR_CREATE("sbxt_cross_dot_size", "0", 0);
bxt_cross_top_line = CVAR_CREATE("sbxt_cross_top_line", "1", 0);
bxt_cross_bottom_line = CVAR_CREATE("sbxt_cross_bottom_line", "1", 0);
bxt_cross_left_line = CVAR_CREATE("sbxt_cross_left_line", "1", 0);
bxt_cross_right_line = CVAR_CREATE("sbxt_cross_right_line", "1", 0);

return 0;
}

int CHudCrosshair::VidInit()
{
return 1;
}

int CHudCrosshair::Draw(float time)
{
if (!bxt_cross->value)
return 0;

float old_circle_radius = 0;
std::vector<Vector2D> circle_points;

float r = 0.0f, g = 0.0f, b = 0.0f;
std::istringstream ss(bxt_cross_color->string);
ss >> r >> g >> b;

static float crosshairColor[3];
crosshairColor[0] = r;
crosshairColor[1] = g;
crosshairColor[2] = b;

float alpha = bxt_cross_alpha->value / 255.0f;

Vector2D center(static_cast<float>(ScreenWidth) / 2.0f, static_cast<float>(ScreenHeight) / 2.0f);

GLUtils gl;

// Draw the outline.
if (bxt_cross_outline->value > 0.0f)
{
gl.color(0.0f, 0.0f, 0.0f, alpha);
gl.line_width(bxt_cross_outline->value);

auto size = bxt_cross_size->value;
auto gap = bxt_cross_gap->value;
auto half_thickness = bxt_cross_thickness->value / 2.0f;
auto half_width = bxt_cross_outline->value / 2.0f;
auto offset = half_thickness + half_width;

// Top line
if (bxt_cross_top_line->value)
{
gl.line(Vector2D(center.x - offset, center.y - gap - size), Vector2D(center.x + offset, center.y - gap - size));
gl.line(Vector2D(center.x + half_thickness, center.y - gap - size + half_width), Vector2D(center.x + half_thickness, center.y - gap - half_width));
gl.line(Vector2D(center.x + offset, center.y - gap), Vector2D(center.x - offset, center.y - gap));
gl.line(Vector2D(center.x - half_thickness, center.y - gap - half_width), Vector2D(center.x - half_thickness, center.y - gap - size + half_width));
}

// Bottom line
if (bxt_cross_bottom_line->value)
{
gl.line(Vector2D(center.x - offset, center.y + gap + size), Vector2D(center.x + offset, center.y + gap + size));
gl.line(Vector2D(center.x + half_thickness, center.y + gap + size - half_width), Vector2D(center.x + half_thickness, center.y + gap + half_width));
gl.line(Vector2D(center.x + offset, center.y + gap), Vector2D(center.x - offset, center.y + gap));
gl.line(Vector2D(center.x - half_thickness, center.y + gap + half_width), Vector2D(center.x - half_thickness, center.y + gap + size - half_width));
}

// Left line
if (bxt_cross_left_line->value)
{
gl.line(Vector2D(center.x - gap - size, center.y - offset), Vector2D(center.x - gap - size, center.y + offset));
gl.line(Vector2D(center.x - gap - size + half_width, center.y + half_thickness), Vector2D(center.x - gap - half_width, center.y + half_thickness));
gl.line(Vector2D(center.x - gap, center.y + offset), Vector2D(center.x - gap, center.y - offset));
gl.line(Vector2D(center.x - gap - half_width, center.y - half_thickness), Vector2D(center.x - gap - size + half_width, center.y - half_thickness));
}

// Right line
if (bxt_cross_right_line->value)
{
gl.line(Vector2D(center.x + gap + size, center.y - offset), Vector2D(center.x + gap + size, center.y + offset));
gl.line(Vector2D(center.x + gap + size - half_width, center.y + half_thickness), Vector2D(center.x + gap + half_width, center.y + half_thickness));
gl.line(Vector2D(center.x + gap, center.y + offset), Vector2D(center.x + gap, center.y - offset));
gl.line(Vector2D(center.x + gap + half_width, center.y - half_thickness), Vector2D(center.x + gap + size - half_width, center.y - half_thickness));
}

// Dot
if (bxt_cross_dot_size->value > 0.0f)
{
auto size = bxt_cross_dot_size->value;
auto offset = Vector2D(size / 2.0f, size / 2.0f);

gl.line(Vector2D(center.x - offset.x - half_width, center.y - offset.y), Vector2D(center.x + offset.x + half_width, center.y - offset.y));
gl.line(Vector2D(center.x + offset.x, center.y - offset.y + half_width), Vector2D(center.x + offset.x, center.y + offset.y - half_width));
gl.line(Vector2D(center.x - offset.x, center.y - offset.y + half_width), Vector2D(center.x - offset.x, center.y + offset.y - half_width));
gl.line(Vector2D(center.x - offset.x - half_width, center.y + offset.y), Vector2D(center.x + offset.x + half_width, center.y + offset.y));
}
}

if (bxt_cross_color->string[0])
{
gl.color(crosshairColor[0], crosshairColor[1], crosshairColor[2], alpha);
}
else
{
gl.color(0.0f, 255.0f, 0.0f, alpha);
}

// Draw the crosshairs.
if (bxt_cross_thickness->value > 0.0f)
{
gl.line_width(bxt_cross_thickness->value);

auto size = bxt_cross_size->value;
auto gap = bxt_cross_gap->value;

if (bxt_cross_top_line->value)
gl.line(Vector2D(center.x, center.y - gap - size), Vector2D(center.x, center.y - gap));
if (bxt_cross_bottom_line->value)
gl.line(Vector2D(center.x, center.y + gap + size), Vector2D(center.x, center.y + gap));
if (bxt_cross_left_line->value)
gl.line(Vector2D(center.x - gap - size, center.y), Vector2D(center.x - gap, center.y));
if (bxt_cross_right_line->value)
gl.line(Vector2D(center.x + gap + size, center.y), Vector2D(center.x + gap, center.y));
}

// Draw the circle.
if (bxt_cross_circle_radius->value > 0.0f)
{
gl.line_width(1.0f);

auto radius = bxt_cross_circle_radius->value;
if (old_circle_radius != radius)
{
// Recompute the circle points.
circle_points = gl.compute_circle(radius);
old_circle_radius = radius;
}

gl.circle(center, circle_points);
}

// Draw the dot.
if (bxt_cross_dot_size->value > 0.0f)
{
float r = 0.0f, g = 0.0f, b = 0.0f;
std::istringstream ss(bxt_cross_dot_color->string);
ss >> r >> g >> b;

static float crosshairDotColor[2];
crosshairDotColor[0] = r;
crosshairDotColor[1] = g;
crosshairDotColor[2] = b;

if (bxt_cross_dot_color->string[0])
{
gl.color(crosshairDotColor[0], crosshairDotColor[1], crosshairDotColor[2], alpha);
}
else
{
gl.color(255.0f, 0.0f, 0.0f, alpha);
}

auto size = bxt_cross_dot_size->value;
auto offset = Vector2D(size / 2.0f, size / 2.0f);

gl.rectangle(center - offset, center + offset);
}

return 0;
}
45 changes: 45 additions & 0 deletions src/cl_dll/hud_crosshair.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifdef HUD_CROSSHAIR_H_RECURSE_GUARD
#error Recursive header files inclusion detected in hud_crosshair.h
#else //HUD_CROSSHAIR_H_RECURSE_GUARD

#define HUD_CROSSHAIR_H_RECURSE_GUARD

#ifndef HUD_CROSSHAIR_H_GUARD
#define HUD_CROSSHAIR_H_GUARD
#pragma once

#ifdef __cplusplus

class CHudCrosshair: public CBXTHudBase
{
public:
virtual int Init();
virtual int VidInit();
virtual int Draw(float time);

private:
cvar_t* bxt_cross;
cvar_t* bxt_cross_color;
cvar_t* bxt_cross_alpha;
cvar_t* bxt_cross_thickness;
cvar_t* bxt_cross_size;
cvar_t* bxt_cross_gap;
cvar_t* bxt_cross_outline;
cvar_t* bxt_cross_circle_radius;
cvar_t* bxt_cross_dot_color;
cvar_t* bxt_cross_dot_size;
cvar_t* bxt_cross_top_line;
cvar_t* bxt_cross_bottom_line;
cvar_t* bxt_cross_left_line;
cvar_t* bxt_cross_right_line;
};


#else //!__cplusplus
#error C++ compiler required to compile hud_crosshair.h
#endif //__cplusplus

#endif //HUD_CROSSHAIR_H_GUARD

#undef HUD_CROSSHAIR_H_RECURSE_GUARD
#endif //HUD_CROSSHAIR_H_RECURSE_GUARD
76 changes: 76 additions & 0 deletions src/cl_dll/opengl_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "SvenBXT.h"

// From BunnymodXT

GLUtils::GLUtils() {
// Same steps as FillRGBA does.
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

GLUtils::~GLUtils() {
// Reset the line width in case we changed it.
glLineWidth(1.0f);

// Same steps as FillRGBA does.
glColor3f(1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
}

void GLUtils::color(float r, float g, float b, float a) const {
glColor4f(r / 255.0, g / 255.0, b / 255.0, a);
}

void GLUtils::color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) const {
glColor4ub(r, g, b, a);
}

void GLUtils::line_width(float width) const {
glLineWidth(width);
}

void GLUtils::line(const Vector2D& start, const Vector2D& end) const {
glBegin(GL_LINES);
glVertex2f(start.x, start.y);
glVertex2f(end.x, end.y);
glEnd();
}

void GLUtils::circle(const Vector2D& center, const std::vector<Vector2D>& points) const {
glBegin(GL_LINE_STRIP);

for (const auto& point : points)
glVertex2f(center.x + point.x, center.y + point.y);

glVertex2f(center.x + points[0].x, center.y + points[0].y);
glEnd();
}

void GLUtils::rectangle(const Vector2D& corner_a, const Vector2D& corner_b) const {
glBegin(GL_QUADS);
glVertex2f(corner_a.x, corner_a.y);
glVertex2f(corner_a.x, corner_b.y);
glVertex2f(corner_b.x, corner_b.y);
glVertex2f(corner_b.x, corner_a.y);
glEnd();
}

std::vector<Vector2D> GLUtils::compute_circle(float radius) {
// Maximum allowed distance between the circle and the rendered line segment.
constexpr float MAX_ERROR = 0.1f;
const unsigned segment_count =
static_cast<unsigned>(ceil(M_PI / acos((radius - MAX_ERROR) / radius)));

std::vector<Vector2D> points;
points.reserve(segment_count);

for (unsigned i = 0; i < segment_count; ++i) {
float angle = static_cast<float>(M_PI * 2 * i / segment_count);
points.emplace_back(radius * cos(angle), radius * sin(angle));
}

return points;
}
Loading

0 comments on commit 208a6f3

Please sign in to comment.