26 #include "../client.h"
30 #include "../renderer/r_light.h"
31 #include "../renderer/r_particle.h"
32 #include "../../shared/parse.h"
34 #define MAX_MAPPARTICLES 1024
35 #define MAX_TIMEDPARTICLES 16
37 #define PTL_INTENSITY_TO_RADIUS 256
39 static cvar_t* cl_particleweather;
72 #define V_VECS ((1 << V_FLOAT) | (1 << V_POS) | (1 << V_VECTOR) | (1 << V_COLOR))
73 #define PTL_ONLY_ONE_TYPE (1<<31)
74 #define V_UNTYPED 0x7FFF
128 "push",
"pop",
"kpop",
136 "spawn",
"nspawn",
"tnspawn",
"child"
210 #define MAX_PTLDEFS 256
211 #define MAX_PTLCMDS (MAX_PTLDEFS * 32)
219 #define MAX_PCMD_DATA (MAX_PTLCMDS * 8)
227 #define MAX_STACK_DEPTH 8
228 #define MAX_STACK_DATA 512
253 if (tp->
n != tp->
max)
265 Com_Printf(
"Could not spawn timed particles due to overflow\n");
288 mp->
wait[0] = wait[0] * 1000;
289 mp->
wait[1] = wait[1] * 1000;
304 const char* imageName;
306 if (a->
name[0] !=
'+')
309 imageName =
va(
"%s%c%c", a->
name + 1, a->
frame / 10 +
'0', a->
frame % 10 +
'0');
312 Com_Printf(
"CL_ParticleLoadArt: Could not load image: '%s'\n", imageName);
349 if (i < r_numParticlesArt)
383 return (
byte*)pcmdData + cmd->
ref;
394 for (
int stackIdx = 0; cmd->
cmd !=
PC_END; cmd++) {
399 if (cmd->
ref > RSTACK)
406 e = (
byte*) stackPtr[--stackIdx] - cmdStack;
408 i = RSTACK - cmd->
ref;
411 cmdData = stackPtr[stackIdx];
412 cmd->
type = stackType[stackIdx];
415 if ((1 << stackType[stackIdx]) &
V_VECS) {
417 cmdData = (
float*) stackPtr[stackIdx] + (i - 1);
432 stackPtr[stackIdx] = &cmdStack[e];
433 stackType[stackIdx] = cmd->
type;
444 if (offsetof(
ptl_t, pic) == -cmd->
ref) {
445 if (stackType[--stackIdx] !=
V_STRING)
448 e = (
byte*) stackPtr[stackIdx] - cmdStack;
451 if (offsetof(
ptl_t, model) == -cmd->
ref) {
452 if (stackType[--stackIdx] !=
V_STRING)
455 e = (
byte*) stackPtr[stackIdx] - cmdStack;
458 if (offsetof(
ptl_t, program) == -cmd->
ref) {
459 if (stackType[--stackIdx] !=
V_STRING)
464 e = (
byte*) stackPtr[stackIdx] - cmdStack;
481 type = stackType[stackIdx - 1];
482 if (!((1 << type) &
V_VECS))
486 if (type != cmd->
type)
491 for (i = 0; i < n; i++) {
493 arg = -(*((
float*) cmdData + i));
495 arg = *((
float*) cmdData + i);
496 *((
float*) stackPtr[stackIdx - 1] + i) += arg;
506 type = stackType[stackIdx - 1];
507 if (!((1 << type) & V_VECS))
510 n = type - V_FLOAT + 1;
512 if (type > V_FLOAT && cmd->
type > V_FLOAT) {
514 if (type != cmd->
type)
517 for (i = 0; i < n; i++) {
519 arg = 1.0 / (*((
float*) cmdData + i));
521 arg = *((
float*) cmdData + i);
522 *((
float*) stackPtr[stackIdx - 1] + i) *= arg;
527 if (cmd->
type > V_FLOAT)
532 arg = 1.0 / (*(
float*) cmdData);
534 arg = *(
float*) cmdData;
535 for (i = 0; i < n; i++)
536 *((
float*) stackPtr[stackIdx - 1] +
i) *= arg;
541 if (cmd->
type != V_FLOAT)
543 stackPtr[stackIdx] = &cmdStack[e];
544 stackType[stackIdx] = cmd->
type;
545 *(
float*) stackPtr[stackIdx++] = sin(*(
float*) cmdData * (2 *
M_PI));
550 if (cmd->
type != V_FLOAT)
552 stackPtr[stackIdx] = &cmdStack[e];
553 stackType[stackIdx] = cmd->
type;
554 *(
float*) stackPtr[stackIdx++] = sin(*(
float*) cmdData * (2 *
M_PI));
559 if (cmd->
type != V_FLOAT)
561 stackPtr[stackIdx] = &cmdStack[e];
562 stackType[stackIdx] = cmd->
type;
563 *(
float*) stackPtr[stackIdx++] = sin(*(
float*) cmdData * (2 *
M_PI));
569 stackPtr[stackIdx] = &cmdStack[e];
570 stackType[stackIdx] = cmd->
type;
572 n = cmd->
type - V_FLOAT + 1;
575 for (i = 0; i < n; i++)
576 *((
float*) stackPtr[stackIdx] +
i) = *((
float*) cmdData +
i) *
frand();
578 for (i = 0; i < n; i++)
579 *((
float*) stackPtr[stackIdx] +
i) = *((
float*) cmdData +
i) *
crand();
581 e += n *
sizeof(float);
594 for (i = 0; i < n; i++) {
595 if (!((1 << stackType[--stackIdx]) & V_VECS))
597 j += stackType[stackIdx] - V_FLOAT + 1;
603 stackType[stackIdx++] = V_FLOAT + j - 1;
623 type = stackType[--stackIdx];
626 n = *(
int*) stackPtr[stackIdx];
629 type = stackType[--stackIdx];
632 i = *(
int*) stackPtr[stackIdx];
637 e -= 2 *
sizeof(
int);
646 type = stackType[--stackIdx];
650 n = *(
int*) stackPtr[stackIdx];
653 for (i = 0; i < n; i++) {
713 Com_Printf(
"Particle definition \"%s\" not found\n", name);
723 if (i == r_numParticles) {
763 Com_DPrintf(
DEBUG_CLIENT,
"Particle %s does not have a tps nor a life set - this is only valid for projectile particles\n",
796 for (
int i = onlyAlpha ? 3 : 0;
i < 4;
i++)
800 for (
int i = onlyAlpha ? 3 : 0;
i < 4;
i++)
801 color[
i] *= (1.0 - frac);
804 for (
int i = onlyAlpha ? 3 : 0;
i < 4;
i++)
805 color[
i] *= sin(frac *
M_PI);
809 for (
int i = onlyAlpha ? 3 : 0;
i < 4;
i++)
810 color[
i] *= frac * 2;
812 for (
int i = onlyAlpha ? 3 : 0;
i < 4;
i++)
813 color[
i] *= (1.0 - frac) * 2;
859 const float epsilonPos = 3.0f;
860 const float epsilonBBox = 1.0f;
865 return ptlCache.
trace;
873 return ptlCache.
trace;
927 const AABB ptlbox(-size, -size, -size, size, size, size);
1031 if (tp->
n >= tp->
max)
1069 if (token[0] ==
'}')
1082 if (token[0] ==
'}')
1085 if (!afterwards && keyname[0] !=
'-')
1087 if (afterwards && keyname[0] !=
'+')
1090 char*
key = keyname + 1;
1092 for (pp = pps; pp->
string; pp++) {
1104 else if (
Q_streq(key,
"model"))
1106 else if (
Q_streq(key,
"program")) {
1166 if (!*text || *token !=
'{') {
1167 Com_Printf(
"CL_ParsePtlCmds: particle cmds \"%s\" without body ignored\n", name);
1171 const char* errhead =
"CL_ParsePtlCmds: unexpected end of file";
1183 if (
Q_streq(token, pc_strings[i])) {
1187 pc = &ptlCmd[numPtlCmds++];
1201 if (token[0] ==
'#') {
1203 if (token[1] ==
'.')
1204 pc->
ref -= (token[2] -
'0');
1208 if (token[0] ==
'*') {
1209 char baseComponentToken[
MAX_VAR];
1215 Q_strncpyz(baseComponentToken, token,
sizeof(baseComponentToken));
1218 int len = strlen(baseComponentToken);
1221 if (len >= 2 && baseComponentToken[len - 2] ==
'.') {
1222 baseComponentToken[len - 2] = 0;
1226 for (pp = pps; pp->
string; pp++)
1231 Com_Printf(
"CL_ParsePtlCmds: bad reference \"%s\" specified (particle %s)\n", token, name);
1237 if ((pc_types[i] & ~PTL_ONLY_ONE_TYPE) != pp->
type) {
1238 Com_Printf(
"CL_ParsePtlCmds: bad type in var \"%s\" (PTL_ONLY_ONE_TYPE) specified (particle %s) (ptl type: %i (pc_type: %i), string: %s)\n", token, name, pp->
type, pc_types[i], pc_strings[i]);
1243 Com_Printf(
"CL_ParsePtlCmds: bad type in var \"%s\" specified (particle %s) (ptl type: %i (pc_type: %i), string: %s)\n", token, name, pp->
type, pc_types[i], pc_strings[i]);
1251 const int component = (baseComponentToken[len - 1] -
'1');
1253 if (component > 3) {
1254 Com_Printf(
"CL_ParsePtlCmds: bad component value - it's bigger than 3: %i (particle %s)\n", component, name);
1260 pc->
ref = -((
int)pp->
ofs) - component *
sizeof(float);
1263 Com_Printf(
"CL_ParsePtlCmds: can't get components of a non-vector type (particle %s)\n", name);
1279 j = pc_types[
i] & ~PTL_ONLY_ONE_TYPE;
1285 if (j >= V_NUM_TYPES || !((1 << j) & pc_types[
i])) {
1286 Com_Printf(
"CL_ParsePtlCmds: bad type \"%s\" specified (particle %s)\n", token, name);
1301 pc->
ref = (
int) (pcmdPos - pcmdData);
1308 if (i < PC_NUM_PTLCMDS)
1311 for (pp = pps; pp->
string; pp++)
1321 pc = &ptlCmd[numPtlCmds++];
1326 pc->
ref = (
int) (pcmdPos - pcmdData);
1329 pc = &ptlCmd[numPtlCmds++];
1337 Com_Printf(
"CL_ParsePtlCmds: unknown token \"%s\" ignored (particle %s)\n", token, name);
1344 pc = &ptlCmd[numPtlCmds++];
1361 if (
Q_streq(name, ptlDef[i].name))
1365 if (i < numPtlDefs) {
1366 Com_Printf(
"CL_ParseParticle: particle def \"%s\" with same name found, reset first one\n", name);
1371 pd = &ptlDef[numPtlDefs++];
1373 Com_Printf(
"CL_ParseParticle: max particle definitions reached - skip the current one: '%s'\n", name);
1384 if (!*text || *token !=
'{') {
1385 Com_Printf(
"CL_ParseParticle: particle def \"%s\" without body ignored\n", name);
1386 if (i == numPtlDefs)
1391 const char* errhead =
"CL_ParseParticle: unexpected end of file (particle ";
1412 if (i == PF_NUM_PTLFUNCS)
1413 Com_Printf(
"CL_ParseParticle: unknown token \"%s\" ignored (particle %s)\n", token, name);
1419 Com_Printf(
"CL_ParseParticle: particle definition %s without init function ignored\n", name);
1420 if (i == numPtlDefs)
1429 static void PTL_DebugSpawnMarker_f (
void)
1437 worldOrigin[0] = atof(
Cmd_Argv(1));
1438 worldOrigin[1] = atof(
Cmd_Argv(2));
1439 worldOrigin[2] = atof(
Cmd_Argv(3));
1444 static void PTL_DebugList_f (
void)
1455 const char* value =
"";
1456 if (
Q_streq(pp->string,
"image") && p->
pic) {
1489 Cmd_AddCommand(
"debug_spawnmarker", PTL_DebugSpawnMarker_f,
"Spawn a marker particle in the world at a given location");
pc_s
particle commands - see pc_strings
#define Vector2NotEmpty(a)
bool Q_strnull(const char *string)
const char * Cmd_Argv(int arg)
Returns a given argument.
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
#define VectorCopy(src, dest)
CASSERT(lengthof(pf_strings)==PF_NUM_PTLFUNCS)
static char const *const pc_strings[]
particle commands - see pc_t
r_program_t * R_LoadProgram(const char *name, programInitFunc_t init, programUseFunc_t use)
#define PTL_ONLY_ONE_TYPE
QGL_EXTERN GLint GLenum type
void VectorMA(const vec3_t veca, const float scale, const vec3_t vecb, vec3_t outVector)
Sets vector_out (vc) to vevtor1 (va) + scale * vector2 (vb)
valueTypes_t
possible values for parsing functions
#define PTL_INTENSITY_TO_RADIUS
void R_InitParticleProgram(r_program_t *prog)
void R_AddLight(const vec3_t origin, float radius, const vec3_t color)
Create light to be rendered in the current frame (will be removed before the next) ...
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
static ptlArt_t r_particlesArt[MAX_PTL_ART]
static const vec3_t scale
void CL_AddMapParticle(const char *ptl, const vec3_t origin, const vec2_t wait, const char *info, int levelflags)
Spawns the map particle.
ptl_t * CL_ParticleSpawn(const char *name, int levelFlags, const vec3_t s, const vec3_t v, const vec3_t a)
Spawn a new particle to the map.
static cvar_t * cl_particleweather
static void CL_Fading(vec4_t color, fade_t fade, float frac, bool onlyAlpha)
Color fade function.
#define VectorNegate(src, dest)
const image_t * R_FindPics(const char *name)
Searches for an image in the image array.
static timedParticle_t timedParticles[MAX_TIMEDPARTICLES]
static ptlDef_t ptlDef[MAX_PTLDEFS]
static const size_t pf_values[]
particle functions offsets - see pf_strings and pf_t
static byte pcmdData[MAX_PCMD_DATA]
static void CL_ParticleFunction(ptl_t *p, ptlCmd_t *cmd)
static mapParticle_t mapParticles[MAX_MAPPARTICLES]
void set(const AABB &other)
Copies the values from the given aabb.
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
static byte cmdStack[MAX_STACK_DATA]
static void CL_ParticleLoadArt(ptlArt_t *a)
Loads the image or model for a given particle art.
ptl_t r_particleArray[MAX_PTLS]
#define VectorScale(in, scale, out)
trace_t CL_Trace(const Line &traceLine, const AABB &box, const le_t *passle, le_t *passle2, int contentmask, int worldLevel)
Moves the given mins/maxs volume through the world from start to end.
void Com_Error(int code, const char *fmt,...)
static void CL_ParticleSpawnTimed(const char *name, ptl_t *parent, bool children, int deltaTime, int n)
Will spawn a n particles deltaTime ms after the parent was spawned.
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
void CL_ParticleRegisterArt(void)
#define Vector4Set(v, r, g, b, a)
QGL_EXTERN GLuint GLsizei GLsizei * length
void CL_ParticleCheckRounds(void)
checks whether a particle is still active in the current round
void R_UseParticleProgram(r_program_t *prog)
const char *const vt_names[]
possible values for parsing functions
enum pf_s pf_t
particle functions enums - see pf_strings and pf_values
int Com_SetValue(void *base, const void *set, valueTypes_t type, int ofs, size_t size)
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
static int r_numParticlesArt
const char * Com_ValueToStr(const void *base, const valueTypes_t type, const int ofs)
static ptlCmd_t ptlCmd[MAX_PTLCMDS]
struct mapParticle_s mapParticle_t
map particles
const char * Com_EParse(const char **text, const char *errhead, const char *errinfo, char *target, size_t size)
Parsing function that prints an error message when there is no text in the buffer.
static ptlArt_t * CL_ParticleGetArt(const char *name, int frame, artType_t type)
Register art (pics, models) for each particle.
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
ptlDef_t * CL_ParticleGet(const char *name)
model_t * R_FindModel(const char *name)
Tries to load a model.
#define VectorNotEmpty(a)
static void CL_ParticleRun2(ptl_t *p)
Prepares the particle rendering, calculate new position, velocity and all the other particle values t...
void R_AddSustainedLight(const vec3_t org, float radius, const vec3_t color, float sustain)
static void * CL_ParticleCommandGetDataLocation(ptl_t *p, const ptlCmd_t *cmd)
Determine the memory location where the command accesses and stores its data.
static char const *const pf_strings[]
valid particle functions - see pf_t and pf_values
int Com_EParseValue(void *base, const char *token, valueTypes_t type, int ofs, size_t size)
#define VectorAdd(a, b, dest)
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
enum artType_s artType_t
particle art type
float frand(void)
Return random values between 0 and 1.
QGL_EXTERN GLuint GLchar GLuint * len
static const unsigned int pc_types[PC_NUM_PTLCMDS]
particle commands parameter and types
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
void CL_ParseParticle(const char *name, const char **text)
Parses particle definitions from UFO-script files.
void CL_ParticleFree(ptl_t *p)
Free a particle and all it's children.
static const value_t pps[]
particle script values
static byte stackType[MAX_STACK_DEPTH]
static void * stackPtr[MAX_STACK_DEPTH]
#define MEMBER_SIZEOF(TYPE, MEMBER)
float crand(void)
Return random values between -1 and 1.
static trace_t PTL_Trace(ptl_t *ptl, const AABB &aabb)
Particle tracing with caching.
static void CL_ParticleRunTimed(void)
Called every frame and checks whether a timed particle should be spawned.
static void CL_ParsePtlCmds(const char *name, const char **text)
struct ptlTraceCache_s ptlTraceCache_t
void * Com_AlignPtr(const void *memory, valueTypes_t type)
Align a memory to use a natural address for the data type we will write.
void PTL_InitStartup(void)
Clears particle data.
int VectorCompareEps(const vec3_t v1, const vec3_t v2, float epsilon)
Compare two vectors that may have an epsilon difference but still be the same vectors.
static void CL_RunMapParticles(void)
#define MAX_TIMEDPARTICLES
static SDL_Joystick * stick
QGL_EXTERN int GLboolean GLfloat * v
pf_s
particle functions enums - see pf_strings and pf_values
static void CL_ParseMapParticle(ptl_t *ptl, const char *es, bool afterwards)
Parses particle used on maps.
struct timedParticle_s timedParticle_t
void CL_ParticleRun(void)
General system for particle running during the game.
int CL_Milliseconds(void)
enum pc_s pc_t
particle commands - see pc_strings