2012-07-27 19:11:45 +02:00
|
|
|
/*
|
2019-08-03 19:43:48 +02:00
|
|
|
* This software is licensed under the terms of the MIT License.
|
2017-02-11 04:52:08 +01:00
|
|
|
* See COPYING for further information.
|
2012-07-27 19:11:45 +02:00
|
|
|
* ---
|
2019-01-23 21:10:43 +01:00
|
|
|
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
2019-07-03 20:00:56 +02:00
|
|
|
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
2012-07-27 19:11:45 +02:00
|
|
|
*/
|
|
|
|
|
2017-11-25 20:45:11 +01:00
|
|
|
#include "taisei.h"
|
|
|
|
|
2012-08-04 03:30:40 +02:00
|
|
|
#include "random.h"
|
2019-11-13 01:24:01 +01:00
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
#include <time.h>
|
2012-07-27 19:11:45 +02:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
static RandomState *rng_active_state;
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
uint64_t splitmix64(uint64_t *state) {
|
|
|
|
// from http://xoshiro.di.unimi.it/splitmix64.c
|
2012-07-27 19:11:45 +02:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
uint64_t z = (*state += 0x9e3779b97f4a7c15);
|
|
|
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
|
|
|
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
|
|
|
return z ^ (z >> 31);
|
|
|
|
}
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-12-05 17:45:32 +01:00
|
|
|
uint32_t splitmix32(uint32_t *state) {
|
|
|
|
uint32_t z = (*state += 0x9e3779b9);
|
|
|
|
z = (z ^ (z >> 15)) * 0x85ebca6b;
|
|
|
|
z = (z ^ (z >> 13)) * 0xc2b2ae3d;
|
|
|
|
return z ^ (z >> 16);
|
|
|
|
}
|
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
uint64_t makeseed(void) {
|
2019-11-22 07:25:09 +01:00
|
|
|
static uint64_t s = 69;
|
2019-03-09 17:19:42 +01:00
|
|
|
return splitmix64(&s) ^ SDL_GetPerformanceCounter();
|
|
|
|
}
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
static inline uint64_t rotl(uint64_t x, int k) {
|
|
|
|
return (x << k) | (x >> (64 - k));
|
|
|
|
}
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
static uint64_t xoshiro256plus(uint64_t s[4]) {
|
|
|
|
// from http://xoshiro.di.unimi.it/xoshiro256plus.c
|
2012-07-27 19:11:45 +02:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
const uint64_t result_plus = s[0] + s[3];
|
|
|
|
const uint64_t t = s[1] << 17;
|
2017-02-05 21:16:50 +01:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
s[2] ^= s[0];
|
|
|
|
s[3] ^= s[1];
|
|
|
|
s[1] ^= s[2];
|
|
|
|
s[0] ^= s[3];
|
|
|
|
s[2] ^= t;
|
|
|
|
s[3] = rotl(s[3], 45);
|
2012-07-27 19:11:45 +02:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
return result_plus;
|
|
|
|
}
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
void rng_init(RandomState *rng, uint64_t seed) {
|
|
|
|
memset(rng, 0, sizeof(*rng));
|
|
|
|
rng_seed(rng, seed);
|
2019-03-09 17:19:42 +01:00
|
|
|
}
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
void rng_seed(RandomState *rng, uint64_t seed) {
|
|
|
|
rng->state[0] = splitmix64(&seed);
|
|
|
|
rng->state[1] = splitmix64(&seed);
|
|
|
|
rng->state[2] = splitmix64(&seed);
|
|
|
|
rng->state[3] = splitmix64(&seed);
|
2019-03-09 17:19:42 +01:00
|
|
|
}
|
2017-12-04 04:26:27 +01:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
void rng_make_active(RandomState *rng) {
|
|
|
|
rng_active_state = rng;
|
2017-12-04 04:26:27 +01:00
|
|
|
}
|
2017-02-05 21:16:50 +01:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
rng_val_t rng_next_p(RandomState *rng) {
|
|
|
|
assert(!rng->locked);
|
|
|
|
return (rng_val_t) { xoshiro256plus(rng->state) };
|
2017-12-04 04:26:27 +01:00
|
|
|
}
|
2017-02-05 21:16:50 +01:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
rng_val_t rng_next(void) {
|
|
|
|
return rng_next_p(rng_active_state);
|
2012-07-27 19:11:45 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
void rng_nextn(size_t n, rng_val_t v[n]) {
|
|
|
|
for(size_t i = 0; i < n; ++i) {
|
|
|
|
v[i] = rng_next();
|
|
|
|
}
|
2012-07-27 19:11:45 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
/*
|
|
|
|
* Output conversion functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint64_t vrng_u64(rng_val_t v) {
|
|
|
|
return v._value;
|
2012-07-27 19:11:45 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
int64_t vrng_i64(rng_val_t v) {
|
|
|
|
return (int64_t)v._value;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t vrng_u32(rng_val_t v) {
|
|
|
|
return v._value >> 32;
|
2012-07-27 19:11:45 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
int32_t vrng_i32(rng_val_t v) {
|
|
|
|
return (int32_t)(v._value >> 32);
|
2019-11-12 01:58:22 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
double vrng_f64(rng_val_t v) {
|
|
|
|
return (v._value >> 11) * 0x1.0p-53;
|
|
|
|
}
|
|
|
|
|
|
|
|
double vrng_f64s(rng_val_t v) {
|
2019-11-12 01:58:22 +01:00
|
|
|
DoubleBits db;
|
2019-11-13 01:24:01 +01:00
|
|
|
db.val = vrng_f64((rng_val_t) { v._value << 1 });
|
|
|
|
db.bits |= v._value & (UINT64_C(1) << 63);
|
2019-11-12 01:58:22 +01:00
|
|
|
return db.val;
|
2019-03-09 17:19:42 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
float vrng_f32(rng_val_t v) {
|
|
|
|
return (v._value >> 40) * 0x1.0p-24f;
|
2019-03-09 17:19:42 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
float vrng_f32s(rng_val_t v) {
|
|
|
|
FloatBits fb;
|
|
|
|
fb.val = vrng_f32((rng_val_t) { v._value << 1 });
|
|
|
|
fb.bits |= vrng_u32(v) & (1 << 31);
|
|
|
|
return fb.val;
|
2019-11-12 01:58:22 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
bool vrng_bool(rng_val_t v) {
|
|
|
|
return v._value >> 63;
|
2019-11-12 01:58:22 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
double vrng_f64_sign(rng_val_t v) {
|
|
|
|
return bits_to_double((UINT64_C(0x3FF) << 52) | (v._value & (UINT64_C(1) << 63)));
|
2019-11-12 01:58:22 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
float vrng_f32_sign(rng_val_t v) {
|
|
|
|
return bits_to_float((0x7f << 23) | (vrng_u32(v) & (1 << 31)));
|
2012-07-27 20:59:24 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
double vrng_f64_range(rng_val_t v, double rmin, double rmax) {
|
|
|
|
return vrng_f64(v) * (rmax - rmin) + rmin;
|
|
|
|
}
|
|
|
|
|
|
|
|
float vrng_f32_range(rng_val_t v, float rmin, float rmax) {
|
|
|
|
return vrng_f32(v) * (rmax - rmin) + rmin;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t vrng_i64_range(rng_val_t v, int64_t rmin, int64_t rmax) {
|
|
|
|
// NOTE: strictly speaking non-uniform distribution in the general case, but seems good enough for small numbers.
|
|
|
|
int64_t period = rmax - rmin;
|
|
|
|
assume(period > 0);
|
|
|
|
return (int64_t)(v._value % (uint64_t)period) + rmin;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t vrng_i32_range(rng_val_t v, int32_t rmin, int32_t rmax) {
|
|
|
|
// NOTE: strictly speaking non-uniform distribution in the general case, but seems good enough for small numbers.
|
|
|
|
int32_t period = rmax - rmin;
|
|
|
|
assume(period > 0);
|
|
|
|
return (int32_t)(vrng_u32(v) % (uint32_t)period) + rmin;
|
|
|
|
}
|
|
|
|
|
|
|
|
double vrng_f64_angle(rng_val_t v) {
|
|
|
|
return vrng_f64(v) * (M_PI * 2.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
float vrng_f32_angle(rng_val_t v) {
|
|
|
|
return vrng_f32(v) * (float)(M_PI * 2.0f);
|
|
|
|
}
|
|
|
|
|
2019-12-18 15:19:13 +01:00
|
|
|
cmplx vrng_dir(rng_val_t v) {
|
2019-11-13 01:24:01 +01:00
|
|
|
return cdir(vrng_f64_angle(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool vrng_f64_chance(rng_val_t v, double chance) {
|
|
|
|
return vrng_f64(v) < chance;
|
|
|
|
}
|
2012-08-04 02:49:12 +02:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
bool vrng_f32_chance(rng_val_t v, float chance) {
|
|
|
|
return vrng_f32(v) < chance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deprecated APIs; to be removed
|
|
|
|
*/
|
|
|
|
|
2019-11-29 08:54:50 +01:00
|
|
|
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
uint32_t tsrand_p(RandomState *rng) {
|
|
|
|
return vrng_u32(rng_next_p(rng));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t tsrand64_p(RandomState *rng) {
|
|
|
|
return vrng_u64(rng_next_p(rng));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t tsrand(void) {
|
|
|
|
return rng_u32();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t tsrand64(void) {
|
|
|
|
return rng_u64();
|
|
|
|
}
|
|
|
|
|
|
|
|
double frand(void) {
|
|
|
|
return rng_f64();
|
|
|
|
}
|
|
|
|
|
|
|
|
double nfrand(void) {
|
|
|
|
return rng_f64s();
|
|
|
|
}
|
|
|
|
|
|
|
|
static rng_val_t tsrand_array[TSRAND_ARRAY_LIMIT];
|
2012-08-04 03:30:40 +02:00
|
|
|
static int tsrand_array_elems;
|
2017-02-05 21:16:50 +01:00
|
|
|
static uint64_t tsrand_fillflags = 0;
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
noreturn static void tsrand_error(const char *file, const char *func, uint line, const char *fmt, ...) {
|
2017-02-05 21:16:50 +01:00
|
|
|
char buf[2048] = { 0 };
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
2017-03-13 17:03:51 +01:00
|
|
|
log_fatal("%s(): %s [%s:%u]", func, buf, file, line);
|
2019-11-13 01:24:01 +01:00
|
|
|
UNREACHABLE;
|
2017-02-05 21:16:50 +01:00
|
|
|
}
|
|
|
|
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
#define TSRANDERR(...) tsrand_error(file, __func__, line, __VA_ARGS__)
|
2017-02-05 21:16:50 +01:00
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
void _tsrand_fill_p(RandomState *rnd, int amount, const char *file, uint line) {
|
2017-02-05 21:16:50 +01:00
|
|
|
if(tsrand_fillflags) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
TSRANDERR("Some indices left unused from the previous call");
|
2017-02-05 21:16:50 +01:00
|
|
|
return;
|
|
|
|
}
|
2012-08-04 02:49:12 +02:00
|
|
|
|
2012-08-04 03:30:40 +02:00
|
|
|
tsrand_array_elems = amount;
|
2019-03-09 17:19:42 +01:00
|
|
|
tsrand_fillflags = (UINT64_C(1) << amount) - 1;
|
2017-02-05 21:16:50 +01:00
|
|
|
|
|
|
|
for(int i = 0; i < amount; ++i) {
|
2019-11-13 01:24:01 +01:00
|
|
|
tsrand_array[i] = rng_next_p(rnd);
|
2017-02-05 21:16:50 +01:00
|
|
|
}
|
2012-08-04 02:49:12 +02:00
|
|
|
}
|
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
void _tsrand_fill(int amount, const char *file, uint line) {
|
2019-11-13 01:24:01 +01:00
|
|
|
_tsrand_fill_p(rng_active_state, amount, file, line);
|
2012-08-04 02:49:12 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
static rng_val_t _tsrand_val_a(int idx, const char *file, uint line) {
|
2017-02-05 21:16:50 +01:00
|
|
|
if(idx >= tsrand_array_elems || idx < 0) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
TSRANDERR("Index out of range (%i / %i)", idx, tsrand_array_elems);
|
2017-02-05 21:16:50 +01:00
|
|
|
}
|
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
if(tsrand_fillflags & (UINT64_C(1) << idx)) {
|
|
|
|
tsrand_fillflags &= ~(UINT64_C(1) << idx);
|
2017-02-05 21:16:50 +01:00
|
|
|
return tsrand_array[idx];
|
|
|
|
}
|
|
|
|
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
TSRANDERR("Index %i used multiple times", idx);
|
2012-08-04 02:49:12 +02:00
|
|
|
}
|
|
|
|
|
2019-03-09 17:19:42 +01:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
uint64_t _tsrand64_a(int idx, const char *file, uint line) {
|
|
|
|
return vrng_u64(_tsrand_val_a(idx, file, line));
|
2012-08-04 02:49:12 +02:00
|
|
|
}
|
2012-08-04 02:56:51 +02:00
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
uint32_t _tsrand_a(int idx, const char *file, uint line) {
|
|
|
|
return vrng_u32(_tsrand_val_a(idx, file, line));
|
2012-08-04 02:56:51 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
double _afrand(int idx, const char *file, uint line) {
|
|
|
|
return vrng_f64(_tsrand_val_a(idx, file, line));
|
2017-02-05 21:16:50 +01:00
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:01 +01:00
|
|
|
double _anfrand(int idx, const char *file, uint line) {
|
|
|
|
return vrng_f64s(_tsrand_val_a(idx, file, line));
|
2017-02-05 21:16:50 +01:00
|
|
|
}
|