1) Remove unused functions.
2) Remove dumb global variables.
3) Reformat to Chad coding style.
- 4) Remove MD3 and IQM models.
+ 4) Remove MD5 models.
5) Use TGA instead of PNG?
6) Optimize for speed instead of size?
- Frag messages:
shader 0 "null" [
attribute vec4 vvertex;
void main(void)
- {
+ {
gl_Position = vvertex;
}
] [
void main(void)
- {
+ {
gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
}
]
varying vec2 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = hudmatrix * vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0);
}
]
uniform mat4 hudmatrix;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = hudmatrix * vvertex;
color = vcolor;
}
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
varying vec2 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = hudmatrix * vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor.rgb = color.rgb * texture2D(tex0, texcoord0).rgb;
gl_FragColor.a = color.a;
}
varying vec2 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0);
}
]
uniform mat4 camprojmatrix;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
}
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
varying vec3 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform samplerCube tex0;
void main(void)
- {
+ {
gl_FragColor = color * textureCube(tex0, texcoord0);
}
]
varying vec2 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0);
}
]
uniform mat4 camprojmatrix;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
}
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
attribute vec4 vvertex, vcolor;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = vvertex;
color = vcolor;
}
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
uniform vec2 texgenscroll;
varying vec2 texcoord0, texcoord1;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord0 + texgenscroll;
texcoord1 = vtexcoord1 * @lmcoordscale;
varying vec2 texcoord0, texcoord1;
uniform sampler2D diffusemap, lightmap;
void main(void)
- {
+ {
@(? (>= (strstr $arg1 "alpha") 0) [
vec4 diffuse = texture2D(diffusemap, texcoord0);
diffuse.rgb *= diffuse.a;
uniform vec2 texgenscroll;
varying vec2 texcoord0, texcoord1;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord0 + texgenscroll;
texcoord1 = vtexcoord1 * @lmcoordscale;
uniform vec4 colorparams;
varying vec2 texcoord0, texcoord1;
void main(void)
- {
+ {
@arg3
}
]
attribute vec4 vvertex;
uniform mat4 camprojmatrix;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
}
] [
uniform vec3 fogcolor;
void main(void)
- {
+ {
gl_FragColor = vec4(fogcolor, 1.0);
}
]
attribute vec4 vvertex;
uniform mat4 camprojmatrix;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
}
] [
void main(void)
- {
+ {
gl_FragColor = vec4(0.0);
}
]
uniform mat4 camprojmatrix;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord1 * @lmcoordscale;
}
varying vec2 texcoord0;
uniform sampler2D lightmap;
void main(void)
- {
+ {
gl_FragColor.rgb = vec3(0.0);
gl_FragColor.a = texture2D(lightmap, texcoord0).a;
}
attribute vec4 vvertex;
uniform mat4 camprojmatrix;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
}
] [
uniform vec4 colorparams;
uniform sampler2D lightmap;
void main(void)
- {
+ {
gl_FragColor.rgb = vec3(0.0);
gl_FragColor.a = colorparams.a;
}
uniform vec4 depthscale, depthoffsets;
varying vec4 depthranges;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
depthranges = depthoffsets + gl_Position.w*depthscale;
}
] [
varying vec4 depthranges;
void main(void)
- {
+ {
gl_FragColor = depthranges;
}
]
uniform vec4 depthscale, depthoffsets;
varying vec4 depthranges;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
depthranges = depthoffsets + gl_Position.w*depthscale;
}
] [
varying vec4 depthranges;
void main(void)
- {
+ {
vec4 ranges = vec4(depthranges.x, fract(depthranges.yzw));
ranges.xy -= ranges.yz*vec2(0.00390625, 0.00390625);
gl_FragColor = ranges;
@(if (btopt "G") [result [uniform float millis; varying float pulse;]])
@(if (btopt "r") [result [varying mat3 world;]])
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord0 + texgenscroll;
texcoord1 = vtexcoord1 * @lmcoordscale;
@(if (btopt "r") [result [uniform samplerCube envmap; varying mat3 world;]])
@(if (|| (! (btopt "i")) (btopt "s")) [result [uniform vec4 ambient;]])
void main(void)
- {
+ {
@(if (|| (! (btopt "i")) (btopt "s")) [result [
vec4 lmc = texture2D(lmcolor, texcoord1);
gl_FragColor.a = colorparams.a * lmc.a;
uniform vec4 shadowintensity;
varying vec4 shadowmapvals;
void main(void)
- {
+ {
@(if (>= $numargs 2) [result $arg2] [result [
#define mpos vvertex
]])
shader 0 shadowmapcaster (shadowmapcastervertexshader) [
varying vec4 shadowmapvals;
void main(void)
- {
+ {
gl_FragColor = shadowmapvals;
}
]
uniform vec2 shadowmapbias;
varying vec4 shadowmapvals;
void main(void)
- {
+ {
gl_Position = shadowmatrix * vvertex;
shadowmapvals = vec4(0.0, 0.0, shadowmapbias.y - gl_Position.z, 0.0);
}
] [
varying vec4 shadowmapvals;
void main(void)
- {
+ {
gl_FragColor = shadowmapvals;
}
]
@(if (>= $numargs 2) [result $arg1])
//:fog
void main(void)
- {
+ {
@(if (>= $numargs 2) [result $arg2] [result [
#define mpos vvertex
]])
shader 0 notexturemodel (notexturemodelvertexshader) [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
]])
]])
void main(void)
- {
+ {
@(if (mdlopt "b") [result [
@(skelanim $arg2 (mdlopt "q") (mdlopt "n"))
]] [result [
@(if (mdlopt "n") [result [uniform sampler2D tex3;]])
@(? (mdlopt "a") [uniform float alphatest;])
void main(void)
- {
+ {
vec4 light = texture2D(tex0, texcoord0);
@(? (mdlopt "a") [
varying vec2 texcoordp@(+ $i 2), texcoordn@(+ $i 2);
]])
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
vec2 tcp = vtexcoord0, tcn = vtexcoord0;
]])
uniform sampler2D tex0;
void main(void)
- {
+ {
#define texval(coords) texture2D(tex0, (coords))
vec4 val = texval(texcoord0) * weights[0];
@(loopconcat i $arg2 [
varying vec2 texcoord0;
@arg2
void main(void)
- {
+ {
gl_Position = vvertex; // woohoo, no mvp :)
texcoord0 = vtexcoord0;
@arg1
varying vec2 texcoord0;
@arg2
void main(void)
- {
+ {
vec4 color = texture2D(tex0, texcoord0);
@arg1
}
uniform vec4 params;
varying vec2 t11, t00, t12, t01, t20, t02, t21, t10, t22;
void main(void)
- {
+ {
gl_Position = vvertex;
t11 = vtexcoord0;
vec2 scale = postfxscale*params.x;
uniform sampler2D tex0;
varying vec2 t11, t00, t12, t01, t20, t02, t21, t10, t22;
void main(void)
- {
+ {
vec4 c00 = texture2D(tex0, t00);
vec4 c01 = texture2D(tex0, t01);
vec4 c02 = texture2D(tex0, t02);
uniform vec2 postfxscale;
varying vec2 texcoord0, texcoord1;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0 + vec2(@(if $arg2 -0.5 0.0), @(if $arg3 -0.5 0.0))*postfxscale;
texcoord1 = vtexcoord0 + vec2(@(if $arg2 0.5 0.0), @(if $arg3 0.5 0.0))*postfxscale;
varying vec2 texcoord0, texcoord1;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = 0.5*(texture2D(tex0, texcoord0) + texture2D(tex0, texcoord1));
}
]
uniform vec2 postfxscale;
varying vec2 texcoord0, texcoord1, texcoord2;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
texcoord1 = vtexcoord0 + vec2(@(? $arg2 -1.333 0.0), @(? $arg3 -1.333 0.0))*postfxscale;
uniform sampler2D tex0;
varying vec2 texcoord0, texcoord1, texcoord2;
void main(void)
- {
+ {
gl_FragColor = 0.4*texture2D(tex0, texcoord0) + 0.3*(texture2D(tex0, texcoord1) + texture2D(tex0, texcoord2));
}
]
varying vec2 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0);
}
]
@(screentexcoord 0)
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
}
varying vec2 texcoord0;
uniform sampler2D tex0 @@(loopconcat i $arg2 [result [, tex@(+ $i 1)]]);
void main(void)
- {
+ {
vec4 sample = texture2D(tex0, texcoord0);
@@(loopconcat i $arg2 [result [
@(? $i "bloom +=" "vec4 bloom =") texture2D(tex@(+ $i 1), texcoord0);
varying vec2 texcoord0, texcoord1, texcoord2;
@(if (>= (strstr $arg1 "soft") 0) [result [uniform vec4 depthfxparams; varying vec4 texcoord3; ]])
void main(void)
- {
+ {
vec4 wobble = vec4(vvertex.xyz*(1.0 + 0.5*abs(fract(dot(vvertex.xyz, center) + millis*2.0) - 0.5)), vvertex.w);
@(if (>= (strstr $arg1 "soft") 0) [result [
gl_Position = explosionmatrix * wobble;
@(if (>= (strstr $arg1 "soft") 0) [result [uniform vec4 depthfxparams; varying vec4 texcoord3; ]])
@(if (>= (strstr $arg1 "soft8") 0) [result [uniform vec4 depthfxselect;]])
void main(void)
- {
+ {
vec2 dtc = texcoord0 + texture2D(tex0, texcoord2).xy*0.1; // use color texture as noise to distort texcoords
vec4 diffuse = texture2D(tex0, dtc);
float blend = max(pow(clamp(1.0 - dot(texcoord1, texcoord1), 0.0, 1.0), blendparams.x), blendparams.y);
uniform vec4 colorscale;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor * colorscale;
}
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
varying vec4 color;
@(if (>= (strstr $arg1 "soft") 0) [result [uniform vec4 depthfxparams; varying vec3 texcoord1, surface; ]])
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vtexcoord0;
color = vcolor * colorscale;
@(if (>= (strstr $arg1 "soft") 0) [result [uniform vec4 depthfxparams; varying vec3 texcoord1, surface;]])
@(if (>= (strstr $arg1 "soft8") 0) [result [uniform vec4 depthfxselect;]])
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
@(if (>= (strstr $arg1 "soft") 0) [result [
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
texcoord0 = vec2(dot(texgenS, vvertex), dot(texgenT, vvertex));
varying vec2 texcoord0;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = texture2D(tex0, texcoord0).r * color;
}
]
varying vec4 color;
void main(void)
- {
+ {
gl_Position = prefabmatrix * vvertex;
color = vcolor;
color.rgb *= dot(prefabworld * vnormal, vec3(0.0, -0.447213595, 0.894427191));
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
@(screentexcoord 0)
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
}
varying vec2 texcoord0;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = texture2D(tex0, texcoord0);
}
]
@(screentexcoord 0)
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0;
}
varying vec2 texcoord0;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec3 sample = texture2D(tex0, texcoord0).rgb;
gl_FragColor = vec4(dot(sample, vec3(0.439216, -0.367788, -0.071427)) + 0.501961,
dot(sample, vec3(-0.148224, -0.290992, 0.439216)) + 0.501961,
uniform vec2 moviescale;
varying vec2 texcoord0, texcoord1, texcoord2, texcoord3;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0 + vec2(-1.5, 0.0)*moviescale;
texcoord1 = vtexcoord0 + vec2(-0.5, 0.0)*moviescale;
varying vec2 texcoord0, texcoord1, texcoord2, texcoord3;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec3 sample1 = texture2D(tex0, texcoord0).rgb;
vec3 sample2 = texture2D(tex0, texcoord1).rgb;
vec3 sample3 = texture2D(tex0, texcoord2).rgb;
uniform vec2 moviescale;
varying vec2 texcoord0, texcoord1, texcoord2, texcoord3;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0 + vec2(-3.0, 0.0)*moviescale;
texcoord1 = vtexcoord0 + vec2(-1.0, 0.0)*moviescale;
varying vec2 texcoord0, texcoord1, texcoord2, texcoord3;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec3 sample1 = texture2D(tex0, texcoord0).rgb;
vec3 sample2 = texture2D(tex0, texcoord1).rgb;
vec3 sample3 = texture2D(tex0, texcoord2).rgb;
uniform vec2 moviescale;
varying vec2 texcoord0, texcoord1, texcoord2, texcoord3;
void main(void)
- {
+ {
gl_Position = vvertex;
texcoord0 = vtexcoord0 + vec2(-3.0, 0.0)*moviescale;
texcoord1 = vtexcoord0 + vec2(-1.0, 0.0)*moviescale;
varying vec2 texcoord0, texcoord1, texcoord2, texcoord3;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec3 sample1 = texture2D(tex0, texcoord0).rgb;
vec3 sample2 = texture2D(tex0, texcoord1).rgb;
vec3 sample3 = texture2D(tex0, texcoord2).rgb;
varying vec4 texcoord0;
varying vec2 texcoord1, texcoord2;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
texcoord0 = watermatrix * vvertex;
]])
uniform sampler2D tex1, tex2, tex3;
void main(void)
- {
+ {
vec3 camvec = normalize(camdir);
@(if $specular [result [
vec3 lightvec = normalize(lightdir);
attribute vec4 vvertex;
uniform mat4 camprojmatrix;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
}
] [
void main(void)
- {
+ {
gl_FragColor = vec4(0.0);
}
]
uniform mat4 camprojmatrix;
varying vec3 color;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
}
uniform vec2 depth;
varying vec3 color;
void main(void)
- {
+ {
gl_FragColor.rgb = 0.8*depth.x*color;
gl_FragColor.a = 0.5*depth.y;
}
uniform vec3 texgenS, texgenT;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
texcoord0 = vec2(dot(texgenS, vvertex.xyz), dot(texgenT, vvertex.xyz));
}
varying vec2 texcoord0;
uniform sampler2D tex0, tex1;
void main(void)
- {
+ {
@arg2
}
]
uniform vec4 lavatexgen;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
vec2 tc = mix(vvertex.xz, vvertex.yy, abs(vnormal.xz));
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0) * 2.0;
}
]
uniform vec4 lavatexgen;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vec4(vcolor.rgb*2.0 - 1.0, vcolor.a);
vec2 tc = mix(vvertex.xz, vvertex.yy, abs(vnormal.xz));
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
vec4 glow = texture2D(tex0, texcoord0) * color;
float k = max(glow.r, max(glow.g, glow.b));
gl_FragColor = glow*k*k*32.0;
uniform vec4 waterfalltexgen;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
vec2 tc = mix(vvertex.xz, vvertex.yy, abs(vnormal.xz));
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0);
}
]
varying vec2 texcoord0;
varying vec4 texcoord1;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
vec2 tc = mix(vvertex.xz, vvertex.yy, abs(vnormal.xz));
varying vec2 texcoord0;
varying vec4 texcoord1;
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
vec2 dudv = texture2D(tex2, texcoord0 + 0.2*diffuse.xy + dudvoffset).xy;
vec4 refract = texture2DProj(tex4, texcoord1 + vec4(4.0*dudv, 0.0, 0.0));
varying vec3 camdir;
varying mat3 world;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
camdir = camera - vvertex.xyz;
varying vec3 camdir;
varying mat3 world;
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
vec2 dudv = texture2D(tex2, texcoord0 + 0.2*diffuse.xy + dudvoffset).xy;
vec3 normal = world * (texture2D(tex1, texcoord0 + 0.1*dudv).rgb*2.0 - 1.0);
varying vec3 color, camdir;
varying mat3 world;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
camdir = camera - vvertex.xyz;
varying vec3 color, camdir;
varying mat3 world;
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
vec2 dudv = texture2D(tex2, texcoord0 + 0.2*diffuse.xy + dudvoffset).xy;
vec3 normal = world * (texture2D(tex1, texcoord0 + 0.1*dudv).rgb*2.0 - 1.0);
uniform vec3 camera;
varying vec3 color, rvec, camdir, normal;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
normal = vnormal;
uniform samplerCube tex0;
varying vec3 color, rvec, camdir, normal;
void main(void)
- {
+ {
vec3 camvec = normalize(camdir);
vec3 reflect = textureCube(tex0, rvec).rgb;
uniform vec3 camera;
varying vec3 color, rvec;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
vec3 camdir = camera - vvertex.xyz;
uniform samplerCube tex0;
varying vec3 color, rvec;
void main(void)
- {
+ {
vec3 reflect = textureCube(tex0, rvec).rgb;
const float invfresnel = 0.75;
gl_FragColor.rgb = mix(reflect, color*0.05, invfresnel);
varying vec2 texcoord0, texcoord1;
varying vec2 bounds;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
texcoord0 = vtexcoord0;
varying vec2 bounds;
uniform sampler2D tex0, tex1;
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
diffuse.rgb *= 2.0;
vec4 lm = texture2D(tex1, texcoord1) * color;
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
texcoord0 = vtexcoord0;
varying vec2 texcoord0;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
gl_FragColor = mix(color, diffuse, color.a);
}
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = camprojmatrix * vvertex;
color = vcolor;
texcoord0 = vtexcoord0;
varying vec2 texcoord0;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec4 diffuse = texture2D(tex0, texcoord0);
diffuse.rgb *= 2.0;
gl_FragColor = diffuse * color;
varying vec2 texcoord0;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = skymatrix * vvertex;
texcoord0 = vtexcoord0;
color = vcolor;
varying vec4 color;
uniform sampler2D tex0;
void main(void)
- {
+ {
gl_FragColor = color * texture2D(tex0, texcoord0);
}
]
varying vec4 color;
varying vec2 texcoord0;
void main(void)
- {
+ {
gl_Position = skymatrix * vvertex;
color = vcolor;
texcoord0 = vtexcoord0;
varying vec2 texcoord0;
uniform sampler2D tex0;
void main(void)
- {
+ {
vec4 glare = texture2D(tex0, texcoord0) * color;
gl_FragColor.rgb = vec3(dot(glare.rgb, vec3(10.56, 10.88, 10.56)) - 30.4);
gl_FragColor.a = glare.a;
uniform mat4 skymatrix;
varying vec4 color;
void main(void)
- {
+ {
gl_Position = skymatrix * vvertex;
color = vcolor;
}
] [
varying vec4 color;
void main(void)
- {
+ {
gl_FragColor = color;
}
]
uniform mat4 skymatrix;
varying vec3 camvec;
void main(void)
- {
+ {
gl_Position = skymatrix * vvertex;
camvec = vvertex.xyz;
varying vec3 camvec;
void main(void)
- {
+ {
vec3 camdir = normalize(camvec);
float costheta = dot(camdir, sundir);
CXXFLAGS= -O3 -fomit-frame-pointer -ffast-math
-override CXXFLAGS+= -Wall -Wextra -fsigned-char -fno-exceptions -fno-rtti -Wno-unused-parameter
+override CXXFLAGS+= -Wall -Wextra -fsigned-char -fno-exceptions -fno-rtti
PLATFORM= $(shell uname -s | tr '[:lower:]' '[:upper:]')
PLATFORM_PREFIX= native
engine/rendermodel.o: shared/igame.h engine/world.h engine/octa.h
engine/rendermodel.o: engine/lightmap.h engine/bih.h engine/texture.h
engine/rendermodel.o: engine/model.h engine/ragdoll.h engine/animmodel.h
-engine/rendermodel.o: engine/vertmodel.h engine/skelmodel.h
-engine/rendermodel.o: engine/md3.h engine/md5.h engine/iqm.h
+engine/rendermodel.o: engine/skelmodel.h
+engine/rendermodel.o: engine/md5.h engine/iqm.h
engine/renderparticles.o: engine/engine.h shared/cube.h shared/tools.h
engine/renderparticles.o: shared/geom.h shared/ents.h shared/command.h
engine/renderparticles.o: shared/glexts.h shared/glemu.h shared/iengine.h
engine/renderparticles.o: shared/igame.h engine/world.h engine/octa.h
engine/renderparticles.o: engine/lightmap.h engine/bih.h engine/texture.h
engine/renderparticles.o: engine/model.h engine/rendertarget.h
-engine/renderparticles.o: engine/explosion.h engine/lightning.h
engine/rendertext.o: engine/engine.h shared/cube.h shared/tools.h
engine/rendertext.o: shared/geom.h shared/ents.h shared/command.h
engine/rendertext.o: shared/glexts.h shared/glemu.h shared/iengine.h
static int lastpreview = 0;
-static inline bool throttlepreview(bool loaded)
-{
+static inline bool throttlepreview(bool loaded) {
if(loaded) return true;
if(totalmillis - lastpreview < guipreviewtime) return false;
lastpreview = totalmillis;
return true;
}
-struct gui : g3d_gui
-{
- struct list
- {
+struct gui : g3d_gui {
+ struct list {
int parent, w, h, springs, curspring, column;
};
-
int firstlist, nextlist;
int columns[MAXCOLUMNS];
-
static vector<list> lists;
static float hitx, hity;
static int curdepth, curlist, xsize, ysize, curx, cury;
static bool shouldmergehits, shouldautotab;
-
- static void reset()
- {
+ static void reset() {
lists.setsize(0);
}
-
static int ty, tx, tpos, *tcurrent, tcolor; //tracking tab size and position since uses different layout method...
-
- bool allowautotab(bool on)
- {
+ bool allowautotab(bool on) {
bool oldval = shouldautotab;
shouldautotab = on;
return oldval;
}
-
- void autotab()
- {
- if(tcurrent)
- {
+ void autotab() {
+ if(tcurrent) {
if(layoutpass && !tpos) tcurrent = NULL; //disable tabs because you didn't start with one
if(shouldautotab && !curdepth && (layoutpass ? 0 : cury) + ysize > guiautotab*FONTH) tab(NULL, tcolor);
}
}
-
- bool shouldtab()
- {
- if(tcurrent && shouldautotab)
- {
- if(layoutpass)
- {
+ bool shouldtab() {
+ if(tcurrent && shouldautotab) {
+ if(layoutpass) {
int space = guiautotab*FONTH - ysize;
if(space < 0) return true;
int l = lists[curlist].parent;
- while(l >= 0)
- {
+ while(l >= 0) {
space -= lists[l].h;
if(space < 0) return true;
l = lists[l].parent;
}
}
- else
- {
+ else {
int space = guiautotab*FONTH - cury;
if(ysize > space) return true;
int l = lists[curlist].parent;
- while(l >= 0)
- {
+ while(l >= 0) {
if(lists[l].h > space) return true;
l = lists[l].parent;
}
}
return false;
}
-
bool visible() { return (!tcurrent || tpos==*tcurrent) && !layoutpass; }
-
//tab is always at top of page
- void tab(const char *name, int color)
- {
+ void tab(const char *name, int color) {
if(curdepth != 0) return;
if(color) tcolor = color;
tpos++;
if(!name) name = intstr(tpos);
int w = max(text_width(name) - 2*INSERT, 0);
- if(layoutpass)
- {
+ if(layoutpass) {
ty = max(ty, ysize);
ysize = 0;
}
- else
- {
+ else {
cury = -ysize;
int h = FONTH-2*INSERT,
x1 = curx + tx,
bool hit = tcurrent && windowhit==this && hitx>=x1 && hity>=y1 && hitx<x2 && hity<y2;
if(hit && (!guiclicktab || mousebuttons&G3D_DOWN))
*tcurrent = tpos; //roll-over to switch tab
-
drawskin(x1-skinx[visible()?2:6]*SKIN_SCALE, y1-skiny[1]*SKIN_SCALE, w, h, visible()?10:19, 9, gui2d ? 1 : 2, light, alpha);
text_(name, x1 + (skinx[3]-skinx[2])*SKIN_SCALE - (w ? INSERT : INSERT/2), y1 + (skiny[2]-skiny[1])*SKIN_SCALE - INSERT, tcolor, visible());
}
tx += w + ((skinx[5]-skinx[4]) + (skinx[3]-skinx[2]))*SKIN_SCALE;
}
-
bool ishorizontal() const { return curdepth&1; }
bool isvertical() const { return !ishorizontal(); }
-
- void pushlist()
- {
- if(layoutpass)
- {
- if(curlist>=0)
- {
+ void pushlist() {
+ if(layoutpass) {
+ if(curlist>=0) {
lists[curlist].w = xsize;
lists[curlist].h = ysize;
}
curlist = lists.length()-1;
xsize = ysize = 0;
}
- else
- {
+ else {
curlist = nextlist++;
- if(curlist >= lists.length()) // should never get here unless script code doesn't use same amount of lists in layout and render passes
- {
+ if(curlist >= lists.length()) { // should never get here unless script code doesn't use same amount of lists in layout and render passes {
list &l = lists.add();
l.parent = curlist;
l.springs = 0;
}
list &l = lists[curlist];
l.curspring = 0;
- if(l.springs > 0)
- {
+ if(l.springs > 0) {
if(ishorizontal()) xsize = l.w; else ysize = l.h;
}
- else
- {
+ else {
xsize = l.w;
ysize = l.h;
}
}
curdepth++;
}
-
- void poplist()
- {
+ void poplist() {
if(!lists.inrange(curlist)) return;
list &l = lists[curlist];
- if(layoutpass)
- {
+ if(layoutpass) {
l.w = xsize;
l.h = ysize;
if(l.column >= 0) columns[l.column] = max(columns[l.column], ishorizontal() ? ysize : xsize);
}
curlist = l.parent;
curdepth--;
- if(lists.inrange(curlist))
- {
+ if(lists.inrange(curlist)) {
int w = xsize, h = ysize;
if(ishorizontal()) cury -= h; else curx -= w;
list &p = lists[curlist];
xsize = p.w;
ysize = p.h;
- if(!layoutpass && p.springs > 0)
- {
+ if(!layoutpass && p.springs > 0) {
list &s = lists[p.parent];
if(ishorizontal()) xsize = s.w; else ysize = s.h;
}
layout(w, h);
}
}
-
int text (const char *text, int color, const char *icon) { autotab(); return button_(text, color, icon, false, false); }
int button(const char *text, int color, const char *icon) { autotab(); return button_(text, color, icon, true, false); }
int title (const char *text, int color, const char *icon) { autotab(); return button_(text, color, icon, false, true); }
-
void separator() { autotab(); line_(FONTH/3); }
void progress(float percent) { autotab(); line_((FONTH*4)/5, percent); }
-
//use to set min size (useful when you have progress bars)
void strut(float size) { layout(isvertical() ? int(size*FONTW) : 0, isvertical() ? 0 : int(size*FONTH)); }
//add space between list items
void space(float size) { layout(isvertical() ? 0 : int(size*FONTW), isvertical() ? int(size*FONTH) : 0); }
-
- void spring(int weight)
- {
+ void spring(int weight) {
if(curlist < 0) return;
list &l = lists[curlist];
if(layoutpass) { if(l.parent >= 0) l.springs += weight; return; }
int nextspring = min(l.curspring + weight, l.springs);
if(nextspring <= l.curspring) return;
- if(ishorizontal())
- {
+ if(ishorizontal()) {
int w = xsize - l.w;
layout((w*nextspring)/l.springs - (w*l.curspring)/l.springs, 0);
}
- else
- {
+ else {
int h = ysize - l.h;
layout(0, (h*nextspring)/l.springs - (h*l.curspring)/l.springs);
}
l.curspring = nextspring;
}
-
- void column(int col)
- {
+ void column(int col) {
if(curlist < 0 || !layoutpass || col < 0 || col >= MAXCOLUMNS) return;
list &l = lists[curlist];
l.column = col;
}
-
- int layout(int w, int h)
- {
- if(layoutpass)
- {
- if(ishorizontal())
- {
+ int layout(int w, int h) {
+ if(layoutpass) {
+ if(ishorizontal()) {
xsize += w;
ysize = max(ysize, h);
}
- else
- {
+ else {
xsize = max(xsize, w);
ysize += h;
}
return 0;
}
- else
- {
+ else {
bool hit = ishit(w, h);
if(ishorizontal()) curx += w;
else cury += h;
return (hit && visible()) ? mousebuttons|G3D_ROLLOVER : 0;
}
}
-
- bool mergehits(bool on)
- {
+ bool mergehits(bool on) {
bool oldval = shouldmergehits;
shouldmergehits = on;
return oldval;
}
-
- bool ishit(int w, int h, int x = curx, int y = cury)
- {
+ bool ishit(int w, int h, int x = curx, int y = cury) {
if(shouldmergehits) return windowhit==this && (ishorizontal() ? hitx>=x && hitx<x+w : hity>=y && hity<y+h);
if(ishorizontal()) h = ysize;
else w = xsize;
return windowhit==this && hitx>=x && hity>=y && hitx<x+w && hity<y+h;
}
-
- int image(Texture *t, float scale, const char *overlaid)
- {
+ int image(Texture *t, float scale, const char *overlaid) {
autotab();
if(scale==0) scale = 1;
int size = (int)(scale*2*FONTH)-SHADOW;
if(visible()) icon_(t, overlaid!=NULL, curx, cury, size, ishit(size+SHADOW, size+SHADOW), overlaid);
return layout(size+SHADOW, size+SHADOW);
}
-
- int texture(VSlot &vslot, float scale, bool overlaid)
- {
+ int texture(VSlot &vslot, float scale, bool overlaid) {
autotab();
if(scale==0) scale = 1;
int size = (int)(scale*2*FONTH)-SHADOW;
if(visible()) previewslot(vslot, overlaid, curx, cury, size, ishit(size+SHADOW, size+SHADOW));
return layout(size+SHADOW, size+SHADOW);
}
-
- int playerpreview(int model, int team, int weap, float sizescale, const char *overlaid)
- {
+ int playerpreview(int model, int team, int weap, float sizescale, const char *overlaid) {
autotab();
if(sizescale==0) sizescale = 1;
int size = (int)(sizescale*2*FONTH)-SHADOW;
- if(model>=0 && visible())
- {
+ if(model>=0 && visible()) {
bool hit = ishit(size+SHADOW, size+SHADOW);
float xs = size, ys = size, xi = curx, yi = cury;
- if(overlaid && hit && actionon)
- {
+ if(overlaid && hit && actionon) {
hudnotextureshader->set();
gle::colorf(0, 0, 0, 0.75f);
rect_(xi+SHADOW, yi+SHADOW, xs, ys);
hudshader->set();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- if(overlaid)
- {
- if(hit)
- {
+ if(overlaid) {
+ if(hit) {
hudnotextureshader->set();
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
gle::colorf(1, 0.5f, 0.5f);
}
return layout(size+SHADOW, size+SHADOW);
}
-
- int modelpreview(const char *name, int anim, float sizescale, const char *overlaid, bool throttle)
- {
+ int modelpreview(const char *name, int anim, float sizescale, const char *overlaid, bool throttle) {
autotab();
if(sizescale==0) sizescale = 1;
int size = (int)(sizescale*2*FONTH)-SHADOW;
- if(name[0] && visible() && (!throttle || throttlepreview(modelloaded(name))))
- {
+ if(name[0] && visible() && (!throttle || throttlepreview(modelloaded(name)))) {
bool hit = ishit(size+SHADOW, size+SHADOW);
float xs = size, ys = size, xi = curx, yi = cury;
- if(overlaid && hit && actionon)
- {
+ if(overlaid && hit && actionon) {
hudnotextureshader->set();
gle::colorf(0, 0, 0, 0.75f);
rect_(xi+SHADOW, yi+SHADOW, xs, ys);
glDisable(GL_BLEND);
modelpreview::start(x1, y1, x2-x1, y2-y1, overlaid!=NULL);
model *m = loadmodel(name);
- if(m)
- {
+ if(m) {
entitylight light;
light.color = vec(1, 1, 1);
light.dir = vec(0, -1, 2).normalize();
hudshader->set();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- if(overlaid)
- {
- if(hit)
- {
+ if(overlaid) {
+ if(hit) {
hudnotextureshader->set();
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
gle::colorf(1, 0.5f, 0.5f);
}
return layout(size+SHADOW, size+SHADOW);
}
-
- int prefabpreview(const char *prefab, const vec &color, float sizescale, const char *overlaid, bool throttle)
- {
+ int prefabpreview(const char *prefab, const vec &color, float sizescale, const char *overlaid, bool throttle) {
autotab();
if(sizescale==0) sizescale = 1;
int size = (int)(sizescale*2*FONTH)-SHADOW;
- if(prefab[0] && visible() && (!throttle || throttlepreview(prefabloaded(prefab))))
- {
+ if(prefab[0] && visible() && (!throttle || throttlepreview(prefabloaded(prefab)))) {
bool hit = ishit(size+SHADOW, size+SHADOW);
float xs = size, ys = size, xi = curx, yi = cury;
- if(overlaid && hit && actionon)
- {
+ if(overlaid && hit && actionon) {
hudnotextureshader->set();
gle::colorf(0, 0, 0, 0.75f);
rect_(xi+SHADOW, yi+SHADOW, xs, ys);
hudshader->set();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- if(overlaid)
- {
- if(hit)
- {
+ if(overlaid) {
+ if(hit) {
hudnotextureshader->set();
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
gle::colorf(1, 0.5f, 0.5f);
}
return layout(size+SHADOW, size+SHADOW);
}
-
- void slider(int &val, int vmin, int vmax, int color, const char *label)
- {
+ void slider(int &val, int vmin, int vmax, int color, const char *label) {
autotab();
int x = curx;
int y = cury;
line_((FONTH*2)/3);
- if(visible())
- {
+ if(visible()) {
if(!label) label = intstr(val);
int w = text_width(label);
-
bool hit;
int px, py, offset = vmin < vmax ? clamp(val, vmin, vmax) : clamp(val, vmax, vmin);
- if(ishorizontal())
- {
+ if(ishorizontal()) {
hit = ishit(FONTH, ysize, x, y);
px = x + (FONTH-w)/2;
py = y + (ysize-FONTH) - ((ysize-FONTH)*(offset-vmin))/((vmax==vmin) ? 1 : (vmax-vmin)); //vmin at bottom
}
- else
- {
+ else {
hit = ishit(xsize, FONTH, x, y);
px = x + FONTH/2 - w/2 + ((xsize-w)*(offset-vmin))/((vmax==vmin) ? 1 : (vmax-vmin)); //vmin at left
py = y;
}
-
if(hit) color = 0xFF0000;
text_(label, px, py, color, hit && actionon, hit);
- if(hit && actionon)
- {
+ if(hit && actionon) {
int vnew = (vmin < vmax ? 1 : -1)+vmax-vmin;
if(ishorizontal()) vnew = int((vnew*(y+ysize-FONTH/2-hity))/(ysize-FONTH));
else vnew = int((vnew*(hitx-x-FONTH/2))/(xsize-w));
}
}
}
-
- char *field(const char *name, int color, int length, int height, const char *initval, int initmode)
- {
+ char *field(const char *name, int color, int length, int height, const char *initval, int initmode) {
return field_(name, color, length, height, initval, initmode, FIELDEDIT);
}
-
- char *keyfield(const char *name, int color, int length, int height, const char *initval, int initmode)
- {
+ char *keyfield(const char *name, int color, int length, int height, const char *initval, int initmode) {
return field_(name, color, length, height, initval, initmode, FIELDKEY);
}
-
- char *field_(const char *name, int color, int length, int height, const char *initval, int initmode, int fieldtype = FIELDEDIT)
- {
+ char *field_(const char *name, int color, int length, int height, const char *initval, int initmode, int fieldtype = FIELDEDIT) {
editor *e = useeditor(name, initmode, false, initval); // generate a new editor if necessary
- if(layoutpass)
- {
- if(initval && e->mode==EDITORFOCUSED && (e!=currentfocus() || fieldmode == FIELDSHOW))
- {
+ if(layoutpass) {
+ if(initval && e->mode==EDITORFOCUSED && (e!=currentfocus() || fieldmode == FIELDSHOW)) {
if(strcmp(e->lines[0].text, initval)) e->clear(initval);
}
e->linewrap = (length<0);
e->maxx = (e->linewrap) ? -1 : length;
e->maxy = (height<=0)?1:-1;
e->pixelwidth = abs(length)*FONTW;
- if(e->linewrap && e->maxy==1)
- {
+ if(e->linewrap && e->maxy==1) {
int temp;
text_bounds(e->lines[0].text, temp, e->pixelheight, e->pixelwidth); //only single line editors can have variable height
}
}
int h = e->pixelheight;
int w = e->pixelwidth + FONTW;
-
bool wasvertical = isvertical();
if(wasvertical && e->maxy != 1) pushlist();
-
char *result = NULL;
- if(visible() && !layoutpass)
- {
+ if(visible() && !layoutpass) {
e->rendered = true;
-
bool hit = ishit(w, h);
- if(hit)
- {
- if(mousebuttons&G3D_DOWN) //mouse request focus
- {
+ if(hit) {
+ if(mousebuttons&G3D_DOWN) { //mouse request focus {
if(fieldtype==FIELDKEY) e->clear();
useeditor(name, initmode, true);
e->mark(false);
}
bool editing = (fieldmode != FIELDSHOW) && (e==currentfocus());
if(hit && editing && (mousebuttons&G3D_PRESSED)!=0 && fieldtype==FIELDEDIT) e->hit(int(floor(hitx-(curx+FONTW/2))), int(floor(hity-cury)), (mousebuttons&G3D_DRAGGED)!=0); //mouse request position
- if(editing && ((fieldmode==FIELDCOMMIT) || (fieldmode==FIELDABORT) || !hit)) // commit field if user pressed enter or wandered out of focus
- {
+ if(editing && ((fieldmode==FIELDCOMMIT) || (fieldmode==FIELDABORT) || !hit)) { // commit field if user pressed enter or wandered out of focus {
if(fieldmode==FIELDCOMMIT || (fieldmode!=FIELDABORT && !hit)) result = e->currentline().text;
e->active = (e->mode!=EDITORFOCUSED);
fieldmode = FIELDSHOW;
}
else fieldsactive = true;
-
e->draw(curx+FONTW/2, cury, color, hit && editing);
-
hudnotextureshader->set();
glDisable(GL_BLEND);
if(editing) gle::colorf(1, 0, 0);
hudshader->set();
}
layout(w, h);
-
- if(e->maxy != 1)
- {
+ if(e->maxy != 1) {
int slines = e->limitscrolly();
- if(slines > 0)
- {
+ if(slines > 0) {
int pos = e->scrolly;
slider(e->scrolly, slines, 0, color, NULL);
if(pos != e->scrolly) e->cy = e->scrolly;
}
if(wasvertical) poplist();
}
-
return result;
}
-
- void rect_(float x, float y, float w, float h, bool lines = false)
- {
+ void rect_(float x, float y, float w, float h, bool lines = false) {
gle::defvertex(2);
gle::begin(lines ? GL_LINE_LOOP : GL_TRIANGLE_STRIP);
gle::attribf(x, y);
if(!lines) gle::attribf(x + w, y + h);
xtraverts += gle::end();
}
-
- void rect_(float x, float y, float w, float h, int usetc)
- {
+ void rect_(float x, float y, float w, float h, int usetc) {
gle::defvertex(2);
gle::deftexcoord0();
gle::begin(GL_TRIANGLE_STRIP);
gle::attribf(x + w, y + h); gle::attrib(tc[usetc+2]);
xtraverts += gle::end();
}
-
- void text_(const char *text, int x, int y, int color, bool shadow, bool force = false)
- {
+ void text_(const char *text, int x, int y, int color, bool shadow, bool force = false) {
if(shadow) draw_text(text, x+SHADOW, y+SHADOW, 0x00, 0x00, 0x00, -0xC0);
draw_text(text, x, y, color>>16, (color>>8)&0xFF, color&0xFF, force ? -0xFF : 0xFF);
}
-
- void background(int color, int inheritw, int inherith)
- {
+ void background(int color, int inheritw, int inherith) {
if(layoutpass) return;
hudnotextureshader->set();
gle::colorub(color>>16, (color>>8)&0xFF, color&0xFF, 0x80);
int w = xsize, h = ysize;
- if(inheritw>0)
- {
+ if(inheritw>0) {
int parentw = curlist, parentdepth = 0;
for(;parentdepth < inheritw && lists[parentw].parent>=0; parentdepth++)
parentw = lists[parentw].parent;
list &p = lists[parentw];
w = p.springs > 0 && (curdepth-parentdepth)&1 ? lists[p.parent].w : p.w;
}
- if(inherith>0)
- {
+ if(inherith>0) {
int parenth = curlist, parentdepth = 0;
for(;parentdepth < inherith && lists[parenth].parent>=0; parentdepth++)
parenth = lists[parenth].parent;
rect_(curx, cury, w, h);
hudshader->set();
}
-
- void icon_(Texture *t, bool overlaid, int x, int y, int size, bool hit, const char *title = NULL)
- {
+ void icon_(Texture *t, bool overlaid, int x, int y, int size, bool hit, const char *title = NULL) {
float scale = float(size)/max(t->xs, t->ys); //scale and preserve aspect ratio
float xs = t->xs*scale, ys = t->ys*scale;
x += int((size-xs)/2);
y += int((size-ys)/2);
const vec &color = hit ? vec(1, 0.5f, 0.5f) : (overlaid ? vec(1, 1, 1) : light);
glBindTexture(GL_TEXTURE_2D, t->id);
- if(hit && actionon)
- {
+ if(hit && actionon) {
gle::colorf(0, 0, 0, 0.75f);
rect_(x+SHADOW, y+SHADOW, xs, ys, 0);
}
gle::color(color);
rect_(x, y, xs, ys, 0);
-
- if(overlaid)
- {
+ if(overlaid) {
if(!overlaytex) overlaytex = textureload("data/guioverlay.png", 3);
glBindTexture(GL_TEXTURE_2D, overlaytex->id);
gle::color(light);
if(title) text_(title, x + xs/12, y + ys - ys/12 - FONTH, hit ? 0xFF0000 : 0xFFFFFF, hit && actionon, hit);
}
}
-
- void previewslot(VSlot &vslot, bool overlaid, int x, int y, int size, bool hit)
- {
+ void previewslot(VSlot &vslot, bool overlaid, int x, int y, int size, bool hit) {
Slot &slot = *vslot.slot;
if(slot.sts.empty()) return;
VSlot *layer = NULL;
Texture *t = NULL, *layertex = NULL;
- if(slot.loaded)
- {
+ if(slot.loaded) {
t = slot.sts[0].t;
if(t == notexture) return;
- Slot &slot = *vslot.slot;
- if(vslot.layer)
- {
+ if(vslot.layer) {
layer = &lookupvslot(vslot.layer);
if(!layer->slot->sts.empty()) layertex = layer->slot->sts[0].t;
}
else if(slot.thumbnail && slot.thumbnail != notexture) t = slot.thumbnail;
else return;
float xt = min(1.0f, t->xs/(float)t->ys), yt = min(1.0f, t->ys/(float)t->xs), xs = size, ys = size;
- if(hit && actionon)
- {
+ if(hit && actionon) {
hudnotextureshader->set();
gle::colorf(0, 0, 0, 0.75f);
rect_(x+SHADOW, y+SHADOW, xs, ys);
const vec &color = hit ? vec(1, 0.5f, 0.5f) : (overlaid ? vec(1, 1, 1) : light);
vec2 tc[4] = { vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1) };
float xoff = vslot.offset.x, yoff = vslot.offset.y;
- if(vslot.rotation)
- {
+ if(vslot.rotation) {
const texrotation &r = texrotations[vslot.rotation];
if(r.swapxy) { swap(xoff, yoff); loopk(4) swap(tc[k].x, tc[k].y); }
if(r.flipx) { xoff *= -1; loopk(4) tc[k].x *= -1; }
gle::attribf(x, y+ys); gle::attrib(tc[3]);
gle::attribf(x+xs, y+ys); gle::attrib(tc[2]);
gle::end();
- if(layertex)
- {
+ if(layertex) {
glBindTexture(GL_TEXTURE_2D, layertex->id);
gle::color(vec(color).mul(layer->colorscale));
gle::begin(GL_TRIANGLE_STRIP);
gle::attribf(x+xs, y+ys); gle::attrib(tc[2]);
gle::end();
}
-
hudshader->set();
- if(overlaid)
- {
+ if(overlaid) {
if(!overlaytex) overlaytex = textureload("data/guioverlay.png", 3);
glBindTexture(GL_TEXTURE_2D, overlaytex->id);
gle::color(light);
rect_(x, y, xs, ys, 0);
}
}
-
- void line_(int size, float percent = 1.0f)
- {
- if(visible())
- {
+ void line_(int size, float percent = 1.0f) {
+ if(visible()) {
if(!slidertex) slidertex = textureload("data/guislider.png", 3);
glBindTexture(GL_TEXTURE_2D, slidertex->id);
- if(percent < 0.99f)
- {
+ if(percent < 0.99f) {
gle::colorf(light.x, light.y, light.z, 0.375f);
if(ishorizontal())
rect_(curx + FONTH/2 - size/2, cury, size, ysize, 0);
}
layout(ishorizontal() ? FONTH : 0, ishorizontal() ? 0 : FONTH);
}
-
- void textbox(const char *text, int width, int height, int color)
- {
+ void textbox(const char *text, int width, int height, int color) {
width *= FONTW;
height *= FONTH;
int w, h;
if(visible()) draw_text(text, curx, cury, color>>16, (color>>8)&0xFF, color&0xFF, 0xFF, -1, width);
layout(width, height);
}
-
- int button_(const char *text, int color, const char *icon, bool clickable, bool center)
- {
+ int button_(const char *text, int color, const char *icon, bool clickable, bool center) {
const int padding = 10;
int w = 0;
if(icon) w += ICON_SIZE;
if(icon && text) w += padding;
if(text) w += text_width(text);
-
- if(visible())
- {
+ if(visible()) {
bool hit = ishit(w, FONTH);
if(hit && clickable) color = 0xFF0000;
int x = curx;
if(isvertical() && center) x += (xsize-w)/2;
-
- if(icon)
- {
- if(icon[0] != ' ')
- {
+ if(icon) {
+ if(icon[0] != ' ') {
const char *ext = strrchr(icon, '.');
defformatstring(tname, "packages/icons/%s%s", icon, ext ? "" : ".png");
icon_(textureload(tname, 3), false, x, cury, ICON_SIZE, clickable && hit);
}
return layout(w, FONTH);
}
-
static Texture *skintex, *overlaytex, *slidertex;
static const int skinx[], skiny[];
static const struct patch { ushort left, right, top, bottom; uchar flags; } patches[];
-
- static void drawskin(int x, int y, int gapw, int gaph, int start, int n, int passes = 1, const vec &light = vec(1, 1, 1), float alpha = 0.80f)//int vleft, int vright, int vtop, int vbottom, int start, int n)
- {
+ static void drawskin(int x, int y, int gapw, int gaph, int start, int n, int passes = 1, const vec &light = vec(1, 1, 1), float alpha = 0.80f) {//int vleft, int vright, int vtop, int vbottom, int start, int n) {
if(!skintex) skintex = textureload("data/guiskin.png", 3);
glBindTexture(GL_TEXTURE_2D, skintex->id);
int gapx1 = INT_MAX, gapy1 = INT_MAX, gapx2 = INT_MAX, gapy2 = INT_MAX;
float wscale = 1.0f/(SKIN_W*SKIN_SCALE), hscale = 1.0f/(SKIN_H*SKIN_SCALE);
-
- loopj(passes)
- {
+ loopj(passes) {
bool quads = false;
if(passes>1) glDepthFunc(j ? GL_LEQUAL : GL_GREATER);
gle::color(j ? light : vec(1, 1, 1), passes<=1 || j ? alpha : alpha/2); //ghost when its behind something in depth
- loopi(n)
- {
+ loopi(n) {
const patch &p = patches[start+i];
int left = skinx[p.left]*SKIN_SCALE, right = skinx[p.right]*SKIN_SCALE,
top = skiny[p.top]*SKIN_SCALE, bottom = skiny[p.bottom]*SKIN_SCALE;
float tleft = left*wscale, tright = right*wscale,
ttop = top*hscale, tbottom = bottom*hscale;
- if(p.flags&0x1)
- {
+ if(p.flags&0x1) {
gapx1 = left;
gapx2 = right;
}
- else if(left >= gapx2)
- {
+ else if(left >= gapx2) {
left += gapw - (gapx2-gapx1);
right += gapw - (gapx2-gapx1);
}
- if(p.flags&0x10)
- {
+ if(p.flags&0x10) {
gapy1 = top;
gapy2 = bottom;
}
- else if(top >= gapy2)
- {
+ else if(top >= gapy2) {
top += gaph - (gapy2-gapy1);
bottom += gaph - (gapy2-gapy1);
}
-
//multiple tiled quads if necessary rather than a single stretched one
int ystep = bottom-top;
int yo = y+top;
- while(ystep > 0)
- {
- if(p.flags&0x10 && yo+ystep-(y+top) > gaph)
- {
+ while(ystep > 0) {
+ if(p.flags&0x10 && yo+ystep-(y+top) > gaph) {
ystep = gaph+y+top-yo;
tbottom = ttop+ystep*hscale;
}
int xstep = right-left;
int xo = x+left;
float tright2 = tright;
- while(xstep > 0)
- {
- if(p.flags&0x01 && xo+xstep-(x+left) > gapw)
- {
+ while(xstep > 0) {
+ if(p.flags&0x01 && xo+xstep-(x+left) > gapw) {
xstep = gapw+x+left-xo;
tright = tleft+xstep*wscale;
}
- if(!quads)
- {
+ if(!quads) {
quads = true;
gle::defvertex(2);
gle::deftexcoord0();
}
if(passes>1) glDepthFunc(GL_ALWAYS);
}
-
vec origin, scale, *savedorigin;
float dist;
g3d_callback *cb;
bool gui2d;
-
static float basescale, maxscale;
static bool passthrough;
static float alpha;
static vec light;
-
- void adjustscale()
- {
+ void adjustscale() {
int w = xsize + (skinx[2]-skinx[1])*SKIN_SCALE + (skinx[10]-skinx[9])*SKIN_SCALE, h = ysize + (skiny[9]-skiny[7])*SKIN_SCALE;
if(tcurrent) h += ((skiny[5]-skiny[1])-(skiny[3]-skiny[2]))*SKIN_SCALE + FONTH-2*INSERT;
else h += (skiny[6]-skiny[3])*SKIN_SCALE;
-
float aspect = forceaspect ? 1.0f/forceaspect : float(screenh)/float(screenw), fit = 1.0f;
if(w*aspect*basescale>1.0f) fit = 1.0f/(w*aspect*basescale);
if(h*basescale*fit>maxscale) fit *= maxscale/(h*basescale*fit);
origin = vec(0.5f-((w-xsize)/2 - (skinx[2]-skinx[1])*SKIN_SCALE)*aspect*scale.x*fit, 0.5f + (0.5f*h-(skiny[9]-skiny[7])*SKIN_SCALE)*scale.y*fit, 0);
scale = vec(aspect*scale.x*fit, scale.y*fit, 1);
}
-
- void start(int starttime, float initscale, int *tab, bool allowinput)
- {
- if(gui2d)
- {
+ void start(int starttime, float initscale, int *tab, bool allowinput) {
+ if(gui2d) {
initscale *= 0.025f;
if(allowinput) hascursor = true;
}
tcurrent = tab;
tcolor = 0xFFFFFF;
pushlist();
- if(layoutpass)
- {
+ if(layoutpass) {
firstlist = nextlist = curlist;
memset(columns, 0, sizeof(columns));
}
- else
- {
+ else {
if(tcurrent && !*tcurrent) tcurrent = NULL;
cury = -ysize;
curx = -xsize/2;
-
- if(gui2d)
- {
+ if(gui2d) {
hudmatrix.ortho(0, 1, 1, 0, -1, 1);
hudmatrix.translate(origin);
hudmatrix.scale(scale);
-
light = vec(1, 1, 1);
}
- else
- {
+ else {
float yaw = atan2f(origin.y-camera1->o.y, origin.x-camera1->o.x);
hudmatrix = camprojmatrix;
hudmatrix.translate(origin);
hudmatrix.rotate_around_z(yaw - 90*RAD);
hudmatrix.rotate_around_x(-90*RAD);
hudmatrix.scale(-scale.x, scale.y, scale.z);
-
vec dir;
lightreaching(origin, light, dir, false, 0, 0.5f);
float intensity = vec(yaw, 0.0f).dot(dir);
light.mul(1.0f + max(intensity, 0.0f));
}
-
resethudmatrix();
hudshader->set();
-
drawskin(curx-skinx[2]*SKIN_SCALE, cury-skiny[6]*SKIN_SCALE, xsize, ysize, 0, 9, gui2d ? 1 : 2, light, alpha);
if(!tcurrent) drawskin(curx-skinx[5]*SKIN_SCALE, cury-skiny[6]*SKIN_SCALE, xsize, 0, 9, 1, gui2d ? 1 : 2, light, alpha);
}
}
-
- void adjusthorizontalcolumn(int col, int i)
- {
+ void adjusthorizontalcolumn(int col, int i) {
int h = columns[col], dh = 0;
- for(int d = 1; i >= 0; d ^= 1)
- {
+ for(int d = 1; i >= 0; d ^= 1) {
list &p = lists[i];
if(d&1) { dh = h - p.h; if(dh <= 0) break; p.h = h; }
else { p.h += dh; h = p.h; }
}
ysize += max(dh, 0);
}
-
- void adjustverticalcolumn(int col, int i)
- {
+ void adjustverticalcolumn(int col, int i) {
int w = columns[col], dw = 0;
- for(int d = 0; i >= 0; d ^= 1)
- {
+ for(int d = 0; i >= 0; d ^= 1) {
list &p = lists[i];
if(d&1) { p.w += dw; w = p.w; }
else { dw = w - p.w; if(dw <= 0) break; p.w = w; }
}
xsize = max(xsize, w);
}
-
- void adjustcolumns()
- {
- if(lists.inrange(curlist))
- {
+ void adjustcolumns() {
+ if(lists.inrange(curlist)) {
list &l = lists[curlist];
if(l.column >= 0) columns[l.column] = max(columns[l.column], ishorizontal() ? ysize : xsize);
}
int parent = -1, depth = 0;
- for(int i = firstlist; i < lists.length(); i++)
- {
+ for(int i = firstlist; i < lists.length(); i++) {
list &l = lists[i];
if(l.parent > parent) { parent = l.parent; depth++; }
- else if(l.parent < parent)
- {
- while(parent > l.parent && depth > 0)
- {
+ else if(l.parent < parent) {
+ while(parent > l.parent && depth > 0) {
parent = lists[parent].parent;
depth--;
}
}
- if(l.column >= 0)
- {
+ if(l.column >= 0) {
if(depth&1) adjusthorizontalcolumn(l.column, i);
else adjustverticalcolumn(l.column, i);
}
}
}
-
- void end()
- {
- if(layoutpass)
- {
+ void end() {
+ if(layoutpass) {
adjustcolumns();
xsize = max(tx, xsize);
ysize = max(ty, ysize);
ysize = max(ysize, (skiny[7]-skiny[6])*SKIN_SCALE);
if(tcurrent) *tcurrent = max(1, min(*tcurrent, tpos));
if(gui2d) adjustscale();
- if(!windowhit && !passthrough)
- {
+ if(!windowhit && !passthrough) {
float dist = 0;
- if(gui2d)
- {
+ if(gui2d) {
hitx = (cursorx - origin.x)/scale.x;
hity = (cursory - origin.y)/scale.y;
}
- else
- {
+ else {
plane p;
p.toplane(vec(origin).sub(camera1->o).set(2, 0).normalize(), origin);
- if(p.rayintersect(camera1->o, camdir, dist) && dist>=0)
- {
+ if(p.rayintersect(camera1->o, camdir, dist) && dist>=0) {
vec hitpos(camdir);
hitpos.mul(dist).add(camera1->o).sub(origin);
hitx = vec(-p.y, p.x, 0).dot(hitpos)/scale.x;
}
}
if((mousebuttons & G3D_PRESSED) && (fabs(hitx-firstx) > 2 || fabs(hity - firsty) > 2)) mousebuttons |= G3D_DRAGGED;
- if(dist>=0 && hitx>=-xsize/2 && hitx<=xsize/2 && hity<=0)
- {
+ if(dist>=0 && hitx>=-xsize/2 && hitx<=xsize/2 && hity<=0) {
if(hity>=-ysize || (tcurrent && hity>=-ysize-(FONTH-2*INSERT)-((skiny[6]-skiny[1])-(skiny[3]-skiny[2]))*SKIN_SCALE && hitx<=tx-xsize/2))
windowhit = this;
}
}
}
- else
- {
+ else {
if(tcurrent && tx<xsize) drawskin(curx+tx-skinx[5]*SKIN_SCALE, -ysize-skiny[6]*SKIN_SCALE, xsize-tx, FONTH, 9, 1, gui2d ? 1 : 2, light, alpha);
}
poplist();
}
-
- void draw()
- {
+ void draw() {
cb->gui(*this, layoutpass);
}
};
//chop skin into a grid
const int gui::skiny[] = {0, 7, 21, 34, 43, 48, 56, 104, 111, 117, 128},
- gui::skinx[] = {0, 11, 23, 37, 105, 119, 137, 151, 215, 229, 246, 256};
+ gui::skinx[] = {0, 11, 23, 37, 105, 119, 137, 151, 215, 229, 246, 256};
//Note: skinx[3]-skinx[2] = skinx[7]-skinx[6]
// skinx[5]-skinx[4] = skinx[9]-skinx[8]
-const gui::patch gui::patches[] =
-{ //arguably this data can be compressed - it depends on what else needs to be skinned in the future
- {1,2,3,6, 0}, // body
- {2,9,5,6, 0x01},
- {9,10,3,6, 0},
-
- {1,2,6,7, 0x10},
- {2,9,6,7, 0x11},
- {9,10,6,7, 0x10},
-
- {1,2,7,9, 0},
- {2,9,7,9, 0x01},
- {9,10,7,9, 0},
-
- {5,6,3,5, 0x01}, // top
-
- {2,3,1,2, 0}, // selected tab
- {3,4,1,2, 0x01},
- {4,5,1,2, 0},
- {2,3,2,3, 0x10},
- {3,4,2,3, 0x11},
- {4,5,2,3, 0x10},
- {2,3,3,5, 0},
- {3,4,3,5, 0x01},
- {4,5,3,5, 0},
-
- {6,7,1,2, 0}, // deselected tab
- {7,8,1,2, 0x01},
- {8,9,1,2, 0},
- {6,7,2,3, 0x10},
- {7,8,2,3, 0x11},
- {8,9,2,3, 0x10},
- {6,7,3,5, 0},
- {7,8,3,5, 0x01},
- {8,9,3,5, 0},
+const gui::patch gui::patches[] = {
+ //arguably this data can be compressed - it depends on what else needs to be skinned in the future {
+ { 1,2,3,6, 0}, // body {
+ { 2,9,5,6, 0x01},
+ { 9,10,3,6, 0},
+ { 1,2,6,7, 0x10},
+ { 2,9,6,7, 0x11},
+ { 9,10,6,7, 0x10},
+ { 1,2,7,9, 0},
+ { 2,9,7,9, 0x01},
+ { 9,10,7,9, 0},
+ { 5,6,3,5, 0x01}, // top
+ { 2,3,1,2, 0}, // selected tab {
+ { 3,4,1,2, 0x01},
+ { 4,5,1,2, 0},
+ { 2,3,2,3, 0x10},
+ { 3,4,2,3, 0x11},
+ { 4,5,2,3, 0x10},
+ { 2,3,3,5, 0},
+ { 3,4,3,5, 0x01},
+ { 4,5,3,5, 0},
+ { 6,7,1,2, 0}, // deselected tab {
+ { 7,8,1,2, 0x01},
+ { 8,9,1,2, 0},
+ { 6,7,2,3, 0x10},
+ { 7,8,2,3, 0x11},
+ { 8,9,2,3, 0x10},
+ { 6,7,3,5, 0},
+ { 7,8,3,5, 0x01},
+ { 8,9,3,5, 0},
};
vector<gui::list> gui::lists;
VARP(guipushdist, 1, 4, 64);
-bool g3d_input(const char *str, int len)
-{
+bool g3d_input(const char *str, int len) {
editor *e = currentfocus();
if(fieldmode == FIELDKEY || fieldmode == FIELDSHOW || !e) return false;
-
e->input(str, len);
return true;
}
-bool g3d_key(int code, bool isdown)
-{
+bool g3d_key(int code, bool isdown) {
editor *e = currentfocus();
- if(fieldmode == FIELDKEY)
- {
- switch(code)
- {
+ if(fieldmode == FIELDKEY) {
+ switch(code) {
case SDLK_ESCAPE:
if(isdown) fieldmode = FIELDCOMMIT;
return true;
}
const char *keyname = getkeyname(code);
- if(keyname && isdown)
- {
+ if(keyname && isdown) {
if(e->lines.length()!=1 || !e->lines[0].empty()) e->insert(" ");
e->insert(keyname);
}
return true;
}
-
if(code==-1 && g3d_windowhit(isdown, true)) return true;
else if(code==-3 && g3d_windowhit(isdown, false)) return true;
-
- if(fieldmode == FIELDSHOW || !e)
- {
- if(windowhit) switch(code)
- {
+ if(fieldmode == FIELDSHOW || !e) {
+ if(windowhit) switch(code) {
case -4: // window "management"
- if(isdown)
- {
- if(windowhit->gui2d)
- {
+ if(isdown) {
+ if(windowhit->gui2d) {
vec origin = *guis2d.last().savedorigin;
int i = windowhit - &guis2d[0];
for(int j = guis2d.length()-1; j > i; j--) *guis2d[j].savedorigin = *guis2d[j-1].savedorigin;
*windowhit->savedorigin = origin;
- if(guis2d.length() > 1)
- {
+ if(guis2d.length() > 1) {
if(camera1->o.dist(*windowhit->savedorigin) <= camera1->o.dist(*guis2d.last().savedorigin))
windowhit->savedorigin->add(camdir);
}
}
return true;
case -5:
- if(isdown)
- {
- if(windowhit->gui2d)
- {
+ if(isdown) {
+ if(windowhit->gui2d) {
vec origin = *guis2d[0].savedorigin;
loopj(guis2d.length()-1) *guis2d[j].savedorigin = *guis2d[j + 1].savedorigin;
*guis2d.last().savedorigin = origin;
- if(guis2d.length() > 1)
- {
+ if(guis2d.length() > 1) {
if(camera1->o.dist(*guis2d.last().savedorigin) >= camera1->o.dist(*guis2d[0].savedorigin))
guis2d.last().savedorigin->sub(camdir);
}
}
return true;
}
-
return false;
}
- switch(code)
- {
+ switch(code) {
case SDLK_ESCAPE: //cancel editing without commit
if(isdown) fieldmode = FIELDABORT;
return true;
return true;
}
-void g3d_cursorpos(float &x, float &y)
-{
+void g3d_cursorpos(float &x, float &y) {
if(guis2d.length()) { x = cursorx; y = cursory; }
else x = y = 0.5f;
}
-void g3d_resetcursor()
-{
+void g3d_resetcursor() {
cursorx = cursory = 0.5f;
}
FVARP(guisens, 1e-3f, 1, 1e3f);
-bool g3d_movecursor(int dx, int dy)
-{
+bool g3d_movecursor(int dx, int dy) {
if(!guis2d.length() || !hascursor) return false;
const float CURSORSCALE = 500.0f;
cursorx = max(0.0f, min(1.0f, cursorx+guisens*dx*(screenh/(screenw*CURSORSCALE))));
VARNP(guifollow, useguifollow, 0, 1, 1);
VARNP(gui2d, usegui2d, 0, 1, 1);
-void g3d_addgui(g3d_callback *cb, vec &origin, int flags)
-{
+void g3d_addgui(g3d_callback *cb, vec &origin, int flags) {
bool gui2d = flags&GUI_FORCE_2D || (flags&GUI_2D && usegui2d) || mainmenu;
if(!gui2d && flags&GUI_FOLLOW && useguifollow) origin.z = player->o.z-(player->eyeheight-1);
gui &g = (gui2d ? guis2d : guis3d).add();
g.gui2d = gui2d;
}
-void g3d_limitscale(float scale)
-{
+void g3d_limitscale(float scale) {
gui::maxscale = scale;
}
static inline bool g3d_sort(const gui &a, const gui &b) { return a.dist < b.dist; }
-bool g3d_windowhit(bool on, bool act)
-{
+bool g3d_windowhit(bool on, bool act) {
extern int cleargui(int n);
- if(act)
- {
- if(actionon || windowhit)
- {
+ if(act) {
+ if(actionon || windowhit) {
if(on) { firstx = gui::hitx; firsty = gui::hity; }
mousebuttons |= (actionon=on) ? G3D_DOWN : G3D_UP;
}
return (guis2d.length() && hascursor) || (windowhit && !windowhit->gui2d);
}
-void g3d_render()
-{
+void g3d_render() {
windowhit = NULL;
if(actionon) mousebuttons |= G3D_PRESSED;
-
gui::reset();
guis2d.shrink(0);
guis3d.shrink(0);
-
// call all places in the engine that may want to render a gui from here, they call g3d_addgui()
extern void g3d_texturemenu();
-
if(!mainmenu) g3d_texturemenu();
g3d_mainmenu();
if(!mainmenu) game::g3d_gamemenus();
-
guis2d.sort(g3d_sort);
guis3d.sort(g3d_sort);
-
readyeditors();
fieldsactive = false;
-
hascursor = false;
-
layoutpass = true;
loopv(guis2d) guis2d[i].draw();
loopv(guis3d) guis3d[i].draw();
layoutpass = false;
-
- if(guis3d.length())
- {
+ if(guis3d.length()) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glDepthMask(GL_FALSE);
-
loopvrev(guis3d) guis3d[i].draw();
-
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glDisable(GL_DEPTH_TEST);
-
glDisable(GL_BLEND);
}
}
-void g3d_render2d()
-{
- if(guis2d.length())
- {
+void g3d_render2d() {
+ if(guis2d.length()) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
loopvrev(guis2d) guis2d[i].draw();
-
glDisable(GL_BLEND);
}
-
flusheditors();
if(!fieldsactive) fieldmode = FIELDSHOW; //didn't draw any fields, so lose focus - mainly for menu closed
textinput(fieldmode!=FIELDSHOW, TI_GUI);
keyrepeat(fieldmode!=FIELDSHOW, KR_GUI);
-
mousebuttons = 0;
}
-void consolebox(int x1, int y1, int x2, int y2)
-{
+void consolebox(int x1, int y1, int x2, int y2) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
float bw = x2 - x1, bh = y2 - y1, aspect = bw/bh, sh = bh, sw = sh*aspect;
bw *= float(4*FONTH)/(SKIN_H*SKIN_SCALE);
-VARFP(bumpmodels, 0, 1, 1, preloadmodelshaders(true));
+VARFP(bumpmodels, 0, 1, 1, preloadmodelshaders());
VARP(fullbrightmodels, 0, 0, 200);
-struct animmodel : model
-{
- struct animspec
- {
+struct animmodel : model {
+ struct animspec {
int frame, range;
float speed;
int priority;
};
-
- struct animpos
- {
+ struct animpos {
int anim, fr1, fr2;
float t;
-
- void setframes(const animinfo &info)
- {
+ void setframes(const animinfo &info) {
anim = info.anim;
- if(info.range<=1)
- {
+ if(info.range<=1) {
fr1 = 0;
t = 0;
}
- else
- {
+ else {
int time = info.anim&ANIM_SETTIME ? info.basetime : lastmillis-info.basetime;
fr1 = (int)(time/info.speed); // round to full frames
t = (time-fr1*info.speed)/info.speed; // progress of the frame, value from 0.0f to 1.0f
}
- if(info.anim&ANIM_LOOP)
- {
+ if(info.anim&ANIM_LOOP) {
fr1 = fr1%info.range+info.frame;
fr2 = fr1+1;
if(fr2>=info.frame+info.range) fr2 = info.frame;
}
- else
- {
+ else {
fr1 = min(fr1, info.range-1)+info.frame;
fr2 = min(fr1+1, info.frame+info.range-1);
}
- if(info.anim&ANIM_REVERSE)
- {
+ if(info.anim&ANIM_REVERSE) {
fr1 = (info.frame+info.range-1)-(fr1-info.frame);
fr2 = (info.frame+info.range-1)-(fr2-info.frame);
}
}
-
bool operator==(const animpos &a) const { return fr1==a.fr1 && fr2==a.fr2 && (fr1==fr2 || t==a.t); }
bool operator!=(const animpos &a) const { return fr1!=a.fr1 || fr2!=a.fr2 || (fr1!=fr2 && t!=a.t); }
};
-
struct part;
-
- struct animstate
- {
+ struct animstate {
part *owner;
animpos cur, prev;
float interp;
-
bool operator==(const animstate &a) const { return cur==a.cur && (interp<1 ? interp==a.interp && prev==a.prev : a.interp>=1); }
bool operator!=(const animstate &a) const { return cur!=a.cur || (interp<1 ? interp!=a.interp || prev!=a.prev : a.interp<1); }
};
-
struct linkedpart;
struct mesh;
-
- struct shaderparams
- {
+ struct shaderparams {
float spec, ambient, fullbright, scrollu, scrollv, alphatest;
-
shaderparams() : spec(1.0f), ambient(0.3f), fullbright(0), scrollu(0), scrollv(0), alphatest(0.9f) {}
};
-
- struct shaderparamskey
- {
+ struct shaderparamskey {
static hashtable<shaderparams, shaderparamskey> keys;
static int firstversion, lastversion;
-
int version;
-
shaderparamskey() : version(-1) {}
-
- bool checkversion()
- {
+ bool checkversion() {
if(version >= firstversion) return true;
version = lastversion;
- if(++lastversion <= 0)
- {
+ if(++lastversion <= 0) {
enumerate(keys, shaderparamskey, key, key.version = -1);
firstversion = 0;
lastversion = 1;
}
return false;
}
-
- static inline void invalidate()
- {
+ static inline void invalidate() {
firstversion = lastversion;
}
};
-
- struct skin : shaderparams
- {
+ struct skin : shaderparams {
part *owner;
Texture *tex, *masks, *normalmap;
Shader *shader;
bool alphablend, cullface;
shaderparamskey *key;
-
skin() : owner(0), tex(notexture), masks(notexture), normalmap(NULL), shader(NULL), alphablend(true), cullface(true), key(NULL) {}
-
bool masked() const { return masks != notexture; }
bool bumpmapped() { return normalmap && bumpmodels; }
bool tangents() { return bumpmapped(); }
bool alphatested() const { return alphatest > 0 && tex->type&Texture::ALPHA; }
-
- void setkey()
- {
+ void setkey() {
key = &shaderparamskey::keys[*this];
}
-
- void setshaderparams(mesh *m, const animstate *as)
- {
+ void setshaderparams(mesh *m, const animstate *as) {
if(!Shader::lastshader) return;
-
float mincolor = as->cur.anim&ANIM_FULLBRIGHT ? fullbrightmodels/100.0f : 0.0f;
- if(fullbright)
- {
+ if(fullbright) {
gle::colorf(fullbright/2, fullbright/2, fullbright/2, transparent);
}
- else
- {
+ else {
gle::color(vec(lightcolor).max(mincolor), transparent);
}
-
if(key->checkversion() && Shader::lastshader->owner == key) return;
Shader::lastshader->owner = key;
-
if(alphatested()) LOCALPARAMF(alphatest, alphatest);
-
- if(fullbright)
- {
+ if(fullbright) {
LOCALPARAMF(lightscale, 0, 0, 2);
}
- else
- {
+ else {
float bias = max(mincolor-1.0f, 0.2f), scale = 0.5f*max(0.8f-bias, 0.0f),
minshade = scale*max(ambient, mincolor);
LOCALPARAMF(lightscale, scale - minshade, scale, minshade + bias);
}
LOCALPARAMF(texscroll, scrollu*lastmillis/1000.0f, scrollv*lastmillis/1000.0f);
}
-
- Shader *loadshader()
- {
+ Shader *loadshader() {
#define DOMODELSHADER(name, body) \
do { \
static Shader *name##shader = NULL; \
#define LOADMODELSHADER(name) DOMODELSHADER(name, return name##shader)
#define SETMODELSHADER(m, name) DOMODELSHADER(name, (m)->setshader(name##shader))
if(shader) return shader;
-
string opts;
int optslen = 0;
if(alphatested()) opts[optslen++] = 'a';
if(masked()) opts[optslen++] = 'm';
if(!fullbright && (masked() || spec>=0.01f)) opts[optslen++] = 's';
opts[optslen++] = '\0';
-
defformatstring(name, "model%s", opts);
shader = generateshader(name, "modelshader \"%s\"", opts);
return shader;
}
-
- void cleanup()
- {
+ void cleanup() {
if(shader && shader->standard) shader = NULL;
}
-
- void preloadBIH()
- {
+ void preloadBIH() {
if(tex->type&Texture::ALPHA && !tex->alphamask) loadalphamask(tex);
}
-
- void preloadshader(bool force)
- {
- if(force) cleanup();
+ void preloadshader() {
+ //~if(force) cleanup();
loadshader();
}
-
- void setshader(mesh *m, const animstate *as)
- {
+ void setshader(mesh *m, const animstate *as) {
m->setshader(loadshader());
}
-
- void bind(mesh *b, const animstate *as)
- {
+ void bind(mesh *b, const animstate *as) {
if(!cullface && enablecullface) { glDisable(GL_CULL_FACE); enablecullface = false; }
else if(cullface && !enablecullface) { glEnable(GL_CULL_FACE); enablecullface = true; }
-
- if(as->cur.anim&ANIM_NOSKIN)
- {
+ if(as->cur.anim&ANIM_NOSKIN) {
if(enablealphablend) { glDisable(GL_BLEND); enablealphablend = false; }
if(shadowmapping) SETMODELSHADER(b, shadowmapcaster);
else /*if(as->cur.anim&ANIM_SHADOW)*/ SETMODELSHADER(b, notexturemodel);
setshader(b, as);
setshaderparams(b, as);
int activetmu = 0;
- if(tex!=lasttex)
- {
+ if(tex!=lasttex) {
glBindTexture(GL_TEXTURE_2D, tex->id);
lasttex = tex;
}
- if(bumpmapped() && normalmap !=lastnormalmap)
- {
+ if(bumpmapped() && normalmap !=lastnormalmap) {
glActiveTexture_(GL_TEXTURE3);
activetmu = 3;
glBindTexture(GL_TEXTURE_2D, normalmap->id);
lastnormalmap = normalmap;
}
- if(tex->type&Texture::ALPHA)
- {
- if(alphablend)
- {
- if(!enablealphablend)
- {
+ if(tex->type&Texture::ALPHA) {
+ if(alphablend) {
+ if(!enablealphablend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
enablealphablend = true;
else if(enablealphablend) { glDisable(GL_BLEND); enablealphablend = false; }
}
else if(enablealphablend && transparent>=1) { glDisable(GL_BLEND); enablealphablend = false; }
- if(masked() && masks!=lastmasks)
- {
+ if(masked() && masks!=lastmasks) {
glActiveTexture_(GL_TEXTURE1);
activetmu = 1;
glBindTexture(GL_TEXTURE_2D, masks->id);
if(activetmu != 0) glActiveTexture_(GL_TEXTURE0);
}
};
-
struct meshgroup;
-
- struct mesh
- {
+ struct mesh {
meshgroup *group;
char *name;
bool noclip;
-
- mesh() : group(NULL), name(NULL), noclip(false)
- {
+ mesh() : group(NULL), name(NULL), noclip(false) {
}
-
- virtual ~mesh()
- {
+ virtual ~mesh() {
DELETEA(name);
}
-
virtual void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) {}
-
virtual void genBIH(BIH::mesh &m) {}
- void genBIH(skin &s, vector<BIH::mesh> &bih, const matrix4x3 &t)
- {
+ void genBIH(skin &s, vector<BIH::mesh> &bih, const matrix4x3 &t) {
BIH::mesh &m = bih.add();
m.xform = t;
m.tex = s.tex;
if(noclip) m.flags |= BIH::MESH_NOCLIP;
if(s.cullface) m.flags |= BIH::MESH_CULLFACE;
genBIH(m);
- while(bih.last().numtris > BIH::mesh::MAXTRIS)
- {
+ while(bih.last().numtris > BIH::mesh::MAXTRIS) {
BIH::mesh &overflow = bih.dup();
overflow.tris += BIH::mesh::MAXTRIS;
overflow.numtris -= BIH::mesh::MAXTRIS;
bih[bih.length()-2].numtris = BIH::mesh::MAXTRIS;
}
}
-
- virtual void setshader(Shader *s)
- {
+ virtual void setshader(Shader *s) {
s->set();
}
-
- template<class V, class T> void smoothnorms(V *verts, int numverts, T *tris, int numtris, float limit, bool areaweight)
- {
+ template<class V, class T> void smoothnorms(V *verts, int numverts, T *tris, int numtris, float limit, bool areaweight) {
hashtable<vec, int> share;
int *next = new int[numverts];
for(int i=0;i<numverts;++i)next[i]=-1;
//~memset(next, -1, numverts*sizeof(int));
- loopi(numverts)
- {
+ loopi(numverts) {
V &v = verts[i];
v.norm = vec(0, 0, 0);
int idx = share.access(v.pos, i);
if(idx != i) { next[i] = next[idx]; next[idx] = i; }
}
- loopi(numtris)
- {
+ loopi(numtris) {
T &t = tris[i];
V &v1 = verts[t.vert[0]], &v2 = verts[t.vert[1]], &v3 = verts[t.vert[2]];
vec norm;
vec *norms = new vec[numverts];
for(int i=0;i<numverts;++i)norms[i]=vec(0,0,0);
//~memclear(norms, numverts);
- loopi(numverts)
- {
+ loopi(numverts) {
V &v = verts[i];
norms[i].add(v.norm);
- if(next[i] >= 0)
- {
+ if(next[i] >= 0) {
float vlimit = limit*v.norm.magnitude();
- for(int j = next[i]; j >= 0; j = next[j])
- {
+ for(int j = next[i]; j >= 0; j = next[j]) {
V &o = verts[j];
- if(v.norm.dot(o.norm) >= vlimit*o.norm.magnitude())
- {
+ if(v.norm.dot(o.norm) >= vlimit*o.norm.magnitude()) {
norms[i].add(o.norm);
norms[j].add(v.norm);
}
delete[] next;
delete[] norms;
}
-
- template<class V, class T> void buildnorms(V *verts, int numverts, T *tris, int numtris, bool areaweight)
- {
+ template<class V, class T> void buildnorms(V *verts, int numverts, T *tris, int numtris, bool areaweight) {
loopi(numverts) verts[i].norm = vec(0, 0, 0);
- loopi(numtris)
- {
+ loopi(numtris) {
T &t = tris[i];
V &v1 = verts[t.vert[0]], &v2 = verts[t.vert[1]], &v3 = verts[t.vert[2]];
vec norm;
}
loopi(numverts) verts[i].norm.normalize();
}
-
- template<class V, class T> void buildnorms(V *verts, int numverts, T *tris, int numtris, bool areaweight, int numframes)
- {
+ template<class V, class T> void buildnorms(V *verts, int numverts, T *tris, int numtris, bool areaweight, int numframes) {
if(!numverts) return;
loopi(numframes) buildnorms(&verts[i*numverts], numverts, tris, numtris, areaweight);
}
-
- static inline void fixqtangent(quat &q, float bt)
- {
+ static inline void fixqtangent(quat &q, float bt) {
static const float bias = -1.5f/65535, biasscale = sqrtf(1 - bias*bias);
- if(bt < 0)
- {
+ if(bt < 0) {
if(q.w >= 0) q.neg();
if(q.w > bias) { q.mul3(biasscale); q.w = bias; }
}
else if(q.w < 0) q.neg();
}
-
- template<class V> static inline void calctangent(V &v, const vec &n, const vec &t, float bt)
- {
+ template<class V> static inline void calctangent(V &v, const vec &n, const vec &t, float bt) {
matrix3 m;
m.c = n;
m.a = t;
fixqtangent(q, bt);
v.tangent = q;
}
-
- template<class B, class V, class TC, class T> void calctangents(B *bumpverts, V *verts, TC *tcverts, int numverts, T *tris, int numtris, bool areaweight)
- {
+ template<class B, class V, class TC, class T> void calctangents(B *bumpverts, V *verts, TC *tcverts, int numverts, T *tris, int numtris, bool areaweight) {
vec *tangent = new vec[2*numverts], *bitangent = tangent+numverts;
for(int i=0;i<2*numverts;++i)tangent[i]=vec(0,0,0);
//~memclear(tangent, 2*numverts);
- loopi(numtris)
- {
+ loopi(numtris) {
const T &t = tris[i];
const vec &e0 = verts[t.vert[0]].pos;
vec e1 = vec(verts[t.vert[1]].pos).sub(e0), e2 = vec(verts[t.vert[2]].pos).sub(e0);
-
const vec2 &tc0 = tcverts[t.vert[0]].tc,
&tc1 = tcverts[t.vert[1]].tc,
&tc2 = tcverts[t.vert[2]].tc;
vec u(e2), v(e2);
u.mul(v1).sub(vec(e1).mul(v2));
v.mul(u1).sub(vec(e1).mul(u2));
-
- if(vec().cross(e2, e1).dot(vec().cross(v, u)) >= 0)
- {
+ if(vec().cross(e2, e1).dot(vec().cross(v, u)) >= 0) {
u.neg();
v.neg();
}
-
- if(!areaweight)
- {
+ if(!areaweight) {
u.normalize();
v.normalize();
}
-
- loopj(3)
- {
+ loopj(3) {
tangent[t.vert[j]].sub(u);
bitangent[t.vert[j]].add(v);
}
}
- loopi(numverts)
- {
+ loopi(numverts) {
const vec &n = verts[i].norm,
&t = tangent[i],
&bt = bitangent[i];
}
delete[] tangent;
}
-
- template<class B, class V, class TC, class T> void calctangents(B *bumpverts, V *verts, TC *tcverts, int numverts, T *tris, int numtris, bool areaweight, int numframes)
- {
+ template<class B, class V, class TC, class T> void calctangents(B *bumpverts, V *verts, TC *tcverts, int numverts, T *tris, int numtris, bool areaweight, int numframes) {
loopi(numframes) calctangents(&bumpverts[i*numverts], &verts[i*numverts], tcverts, numverts, tris, numtris, areaweight);
}
};
-
- struct meshgroup
- {
+ struct meshgroup {
meshgroup *next;
int shared;
char *name;
vector<mesh *> meshes;
-
- meshgroup() : next(NULL), shared(0), name(NULL)
- {
+ meshgroup() : next(NULL), shared(0), name(NULL) {
}
-
- virtual ~meshgroup()
- {
+ virtual ~meshgroup() {
DELETEA(name);
meshes.deletecontents();
DELETEP(next);
}
-
virtual int findtag(const char *name) { return -1; }
virtual void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n) {}
-
- void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m)
- {
+ void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) {
loopv(meshes) meshes[i]->calcbb(bbmin, bbmax, m);
}
-
- void genBIH(vector<skin> &skins, vector<BIH::mesh> &bih, const matrix4x3 &t)
- {
+ void genBIH(vector<skin> &skins, vector<BIH::mesh> &bih, const matrix4x3 &t) {
loopv(meshes) meshes[i]->genBIH(skins[i], bih, t);
}
-
virtual void *animkey() { return this; }
virtual int totalframes() const { return 1; }
bool hasframe(int i) const { return i>=0 && i<totalframes(); }
bool hasframes(int i, int n) const { return i>=0 && i+n<=totalframes(); }
int clipframes(int i, int n) const { return min(n, totalframes() - i); }
-
virtual void cleanup() {}
virtual void preload(part *p) {}
virtual void render(const animstate *as, float pitch, const vec &axis, const vec &forward, dynent *d, part *p) {}
-
- void bindpos(GLuint ebuf, GLuint vbuf, void *v, int stride)
- {
- if(lastebuf!=ebuf)
- {
+ void bindpos(GLuint ebuf, GLuint vbuf, void *v, int stride) {
+ if(lastebuf!=ebuf) {
gle::bindebo(ebuf);
lastebuf = ebuf;
}
- if(lastvbuf!=vbuf)
- {
+ if(lastvbuf!=vbuf) {
gle::bindvbo(vbuf);
if(!lastvbuf) gle::enablevertex();
gle::vertexpointer(stride, v);
lastvbuf = vbuf;
}
}
-
- void bindtc(void *v, int stride)
- {
- if(!enabletc)
- {
+ void bindtc(void *v, int stride) {
+ if(!enabletc) {
gle::enabletexcoord0();
enabletc = true;
}
- if(lasttcbuf!=lastvbuf)
- {
+ if(lasttcbuf!=lastvbuf) {
gle::texcoord0pointer(stride, v);
lasttcbuf = lastvbuf;
}
}
-
- void bindnormals(void *v, int stride)
- {
- if(!enablenormals)
- {
+ void bindnormals(void *v, int stride) {
+ if(!enablenormals) {
gle::enablenormal();
enablenormals = true;
}
- if(lastnbuf!=lastvbuf)
- {
+ if(lastnbuf!=lastvbuf) {
gle::normalpointer(stride, v);
lastnbuf = lastvbuf;
}
}
-
- void bindtangents(void *v, int stride)
- {
- if(!enabletangents)
- {
+ void bindtangents(void *v, int stride) {
+ if(!enabletangents) {
gle::enabletangent();
enabletangents = true;
}
- if(lastxbuf!=lastvbuf)
- {
+ if(lastxbuf!=lastvbuf) {
gle::tangentpointer(stride, v, GL_SHORT);
lastxbuf = lastvbuf;
}
}
-
- void bindbones(void *wv, void *bv, int stride)
- {
- if(!enablebones)
- {
+ void bindbones(void *wv, void *bv, int stride) {
+ if(!enablebones) {
gle::enableboneweight();
gle::enableboneindex();
enablebones = true;
}
- if(lastbbuf!=lastvbuf)
- {
+ if(lastbbuf!=lastvbuf) {
gle::boneweightpointer(stride, wv);
gle::boneindexpointer(stride, bv);
lastbbuf = lastvbuf;
}
}
};
-
virtual meshgroup *loadmeshes(const char *name, va_list args) { return NULL; }
-
- meshgroup *sharemeshes(const char *name, ...)
- {
+ meshgroup *sharemeshes(const char *name, ...) {
static hashnameset<meshgroup *> meshgroups;
- if(!meshgroups.access(name))
- {
+ if(!meshgroups.access(name)) {
va_list args;
va_start(args, name);
meshgroup *group = loadmeshes(name, args);
}
return meshgroups[name];
}
-
- struct linkedpart
- {
+ struct linkedpart {
part *p;
int tag, anim, basetime;
vec translate;
vec *pos;
matrix4 matrix;
-
linkedpart() : p(NULL), tag(-1), anim(-1), basetime(0), translate(0, 0, 0), pos(NULL) {}
};
-
- struct part
- {
+ struct part {
animmodel *model;
int index;
meshgroup *meshes;
int numanimparts;
float pitchscale, pitchoffset, pitchmin, pitchmax;
vec translate;
-
- part(animmodel *model, int index = 0) : model(model), index(index), meshes(NULL), numanimparts(1), pitchscale(1), pitchoffset(0), pitchmin(0), pitchmax(0), translate(0, 0, 0)
- {
+ part(animmodel *model, int index = 0) : model(model), index(index), meshes(NULL), numanimparts(1), pitchscale(1), pitchoffset(0), pitchmin(0), pitchmax(0), translate(0, 0, 0) {
loopk(MAXANIMPARTS) anims[k] = NULL;
}
- virtual ~part()
- {
+ virtual ~part() {
loopk(MAXANIMPARTS) DELETEA(anims[k]);
}
-
- virtual void cleanup()
- {
+ virtual void cleanup() {
if(meshes) meshes->cleanup();
loopv(skins) skins[i].cleanup();
}
-
- void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m)
- {
+ void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) {
matrix4x3 t = m;
t.scale(model->scale);
t.translate(translate);
meshes->calcbb(bbmin, bbmax, t);
- loopv(links)
- {
+ loopv(links) {
matrix4x3 n;
meshes->concattagtransform(this, links[i].tag, m, n);
n.translate(links[i].translate, model->scale);
links[i].p->calcbb(bbmin, bbmax, n);
}
}
-
- void genBIH(vector<BIH::mesh> &bih, const matrix4x3 &m)
- {
+ void genBIH(vector<BIH::mesh> &bih, const matrix4x3 &m) {
matrix4x3 t = m;
t.scale(model->scale);
t.translate(translate);
meshes->genBIH(skins, bih, t);
- loopv(links)
- {
+ loopv(links) {
matrix4x3 n;
meshes->concattagtransform(this, links[i].tag, m, n);
n.translate(links[i].translate, model->scale);
links[i].p->genBIH(bih, n);
}
}
-
- bool link(part *p, const char *tag, const vec &translate = vec(0, 0, 0), int anim = -1, int basetime = 0, vec *pos = NULL)
- {
+ bool link(part *p, const char *tag, const vec &translate = vec(0, 0, 0), int anim = -1, int basetime = 0, vec *pos = NULL) {
int i = meshes ? meshes->findtag(tag) : -1;
- if(i<0)
- {
+ if(i<0) {
loopv(links) if(links[i].p && links[i].p->link(p, tag, translate, anim, basetime, pos)) return true;
return false;
}
l.pos = pos;
return true;
}
-
- bool unlink(part *p)
- {
+ bool unlink(part *p) {
loopvrev(links) if(links[i].p==p) { links.remove(i, 1); return true; }
loopv(links) if(links[i].p && links[i].p->unlink(p)) return true;
return false;
}
-
- void initskins(Texture *tex = notexture, Texture *masks = notexture, int limit = 0)
- {
- if(!limit)
- {
+ void initskins(Texture *tex = notexture, Texture *masks = notexture, int limit = 0) {
+ if(!limit) {
if(!meshes) return;
limit = meshes->meshes.length();
}
- while(skins.length() < limit)
- {
+ while(skins.length() < limit) {
skin &s = skins.add();
s.owner = this;
s.tex = tex;
s.masks = masks;
}
}
-
- bool tangents()
- {
+ bool tangents() {
loopv(skins) if(skins[i].tangents()) return true;
return false;
}
-
- void preloadBIH()
- {
+ void preloadBIH() {
loopv(skins) skins[i].preloadBIH();
}
-
- void preloadshaders(bool force)
- {
- loopv(skins) skins[i].preloadshader(force);
+ void preloadshaders() {
+ loopv(skins) skins[i].preloadshader();
}
-
- void preloadmeshes()
- {
+ void preloadmeshes() {
if(meshes) meshes->preload(this);
}
-
- virtual void getdefaultanim(animinfo &info, int anim, uint varseed, dynent *d)
- {
+ virtual void getdefaultanim(animinfo &info, int anim, uint varseed, dynent *d) {
(void) anim; (void) varseed; (void) d;
info.frame = 0;
info.range = 1;
}
-
- bool calcanim(int animpart, int anim, int basetime, int basetime2, dynent *d, int interp, animinfo &info, int &aitime)
- {
+ bool calcanim(int animpart, int anim, int basetime, int basetime2, dynent *d, int interp, animinfo &info, int &aitime) {
uint varseed = uint((size_t)d);
info.anim = anim;
info.basetime = basetime;
info.varseed = varseed;
info.speed = anim&ANIM_SETSPEED ? basetime2 : 100.0f;
- if((anim&ANIM_INDEX)==ANIM_ALL)
- {
+ if((anim&ANIM_INDEX)==ANIM_ALL) {
info.frame = 0;
info.range = meshes->totalframes();
}
- else
- {
+ else {
animspec *spec = NULL;
- if(anims[animpart])
- {
+ if(anims[animpart]) {
int primaryidx = anim&ANIM_INDEX;
- if(primaryidx < NUMANIMS)
- {
+ if(primaryidx < NUMANIMS) {
vector<animspec> &primary = anims[animpart][primaryidx];
if(primary.length()) spec = &primary[uint(varseed + basetime)%primary.length()];
}
- if((anim>>ANIM_SECONDARY)&(ANIM_INDEX|ANIM_DIR))
- {
+ if((anim>>ANIM_SECONDARY)&(ANIM_INDEX|ANIM_DIR)) {
int secondaryidx = (anim>>ANIM_SECONDARY)&ANIM_INDEX;
- if(secondaryidx < NUMANIMS)
- {
+ if(secondaryidx < NUMANIMS) {
vector<animspec> &secondary = anims[animpart][secondaryidx];
if(secondary.length())
{
}
}
}
- if(spec)
- {
+ if(spec) {
info.frame = spec->frame;
info.range = spec->range;
if(spec->speed>0) info.speed = 1000.0f/spec->speed;
}
else getdefaultanim(info, anim, uint(varseed + info.basetime), d);
}
-
info.anim &= (1<<ANIM_SECONDARY)-1;
info.anim |= anim&ANIM_FLAGS;
- if((info.anim&ANIM_CLAMP) != ANIM_CLAMP)
- {
- if(info.anim&(ANIM_LOOP|ANIM_START|ANIM_END))
- {
+ if((info.anim&ANIM_CLAMP) != ANIM_CLAMP) {
+ if(info.anim&(ANIM_LOOP|ANIM_START|ANIM_END)) {
info.anim &= ~ANIM_SETTIME;
if(!info.basetime) info.basetime = -((int)(size_t)d&0xFFF);
}
- if(info.anim&(ANIM_START|ANIM_END))
- {
+ if(info.anim&(ANIM_START|ANIM_END)) {
if(info.anim&ANIM_END) info.frame += info.range-1;
info.range = 1;
}
}
-
- if(!meshes->hasframes(info.frame, info.range))
- {
+ if(!meshes->hasframes(info.frame, info.range)) {
if(!meshes->hasframe(info.frame)) return false;
info.range = meshes->clipframes(info.frame, info.range);
}
-
- if(d && interp>=0)
- {
+ if(d && interp>=0) {
animinterpinfo &ai = d->animinterp[interp];
if((info.anim&ANIM_CLAMP)==ANIM_CLAMP) aitime = min(aitime, int(info.range*info.speed*0.5e-3f));
void *ak = meshes->animkey();
- if(d->ragdoll && !(anim&ANIM_RAGDOLL))
- {
+ if(d->ragdoll && !(anim&ANIM_RAGDOLL)) {
ai.prev.range = ai.cur.range = 0;
ai.lastswitch = -1;
}
- else if(ai.lastmodel!=ak || ai.lastswitch<0 || lastmillis-d->lastrendered>aitime)
- {
+ else if(ai.lastmodel!=ak || ai.lastswitch<0 || lastmillis-d->lastrendered>aitime) {
ai.prev = ai.cur = info;
ai.lastswitch = lastmillis-aitime*2;
}
- else if(ai.cur!=info)
- {
+ else if(ai.cur!=info) {
if(lastmillis-ai.lastswitch>aitime/2) ai.prev = ai.cur;
ai.cur = info;
ai.lastswitch = lastmillis;
}
return true;
}
-
- void render(int anim, int basetime, int basetime2, float pitch, const vec &axis, const vec &forward, dynent *d)
- {
+ void render(int anim, int basetime, int basetime2, float pitch, const vec &axis, const vec &forward, dynent *d) {
animstate as[MAXANIMPARTS];
render(anim, basetime, basetime2, pitch, axis, forward, d, as);
}
-
- void render(int anim, int basetime, int basetime2, float pitch, const vec &axis, const vec &forward, dynent *d, animstate *as)
- {
- if(!(anim&ANIM_REUSE)) loopi(numanimparts)
- {
+ void render(int anim, int basetime, int basetime2, float pitch, const vec &axis, const vec &forward, dynent *d, animstate *as) {
+ if(!(anim&ANIM_REUSE)) loopi(numanimparts) {
animinfo info;
int interp = d && index+numanimparts<=MAXANIMPARTS ? index+i : -1, aitime = animationinterpolationtime;
if(!calcanim(i, anim, basetime, basetime2, d, interp, info, aitime)) return;
p.owner = this;
p.cur.setframes(info);
p.interp = 1;
- if(interp>=0 && d->animinterp[interp].prev.range>0)
- {
+ if(interp>=0 && d->animinterp[interp].prev.range>0) {
int diff = lastmillis-d->animinterp[interp].lastswitch;
- if(diff<aitime)
- {
+ if(diff<aitime) {
p.prev.setframes(d->animinterp[interp].prev);
p.interp = diff/float(aitime);
}
}
}
-
vec oaxis, oforward;
matrixstack[matrixpos].transposedtransformnormal(axis, oaxis);
float pitchamount = pitchscale*pitch + pitchoffset;
if((pitchmin || pitchmax) && pitchmin <= pitchmax) pitchamount = clamp(pitchamount, pitchmin, pitchmax);
if(as->cur.anim&ANIM_NOPITCH || (as->interp < 1 && as->prev.anim&ANIM_NOPITCH))
pitchamount *= (as->cur.anim&ANIM_NOPITCH ? 0 : as->interp) + (as->interp < 1 && as->prev.anim&ANIM_NOPITCH ? 0 : 1-as->interp);
- if(pitchamount)
- {
+ if(pitchamount) {
++matrixpos;
matrixstack[matrixpos] = matrixstack[matrixpos-1];
matrixstack[matrixpos].rotate(pitchamount*RAD, oaxis);
}
matrixstack[matrixpos].transposedtransformnormal(forward, oforward);
-
- if(!(anim&ANIM_NORENDER))
- {
+ if(!(anim&ANIM_NORENDER)) {
matrix4 modelmatrix;
modelmatrix.mul(shadowmapping ? shadowmatrix : camprojmatrix, matrixstack[matrixpos]);
if(model->scale!=1) modelmatrix.scale(model->scale);
if(!translate.iszero()) modelmatrix.translate(translate);
GLOBALPARAM(modelmatrix, modelmatrix);
-
- if(!(anim&ANIM_NOSKIN))
- {
+ if(!(anim&ANIM_NOSKIN)) {
vec odir, ocampos;
matrixstack[matrixpos].transposedtransformnormal(lightdir, odir);
GLOBALPARAM(lightdir, odir);
GLOBALPARAM(modelcamera, ocampos);
}
}
-
meshes->render(as, pitch, oaxis, oforward, d, this);
-
- if(!(anim&ANIM_REUSE))
- {
- loopv(links)
- {
+ if(!(anim&ANIM_REUSE)) {
+ loopv(links) {
linkedpart &link = links[i];
link.matrix.translate(links[i].translate, model->scale);
-
matrixpos++;
matrixstack[matrixpos].mul(matrixstack[matrixpos-1], link.matrix);
-
if(link.pos) *link.pos = matrixstack[matrixpos].gettranslation();
-
- if(!link.p)
- {
+ if(!link.p) {
matrixpos--;
continue;
}
-
int nanim = anim, nbasetime = basetime, nbasetime2 = basetime2;
- if(link.anim>=0)
- {
+ if(link.anim>=0) {
nanim = link.anim | (anim&ANIM_FLAGS);
nbasetime = link.basetime;
nbasetime2 = 0;
}
link.p->render(nanim, nbasetime, nbasetime2, pitch, axis, forward, d);
-
matrixpos--;
}
}
-
if(pitchamount) matrixpos--;
}
-
- void setanim(int animpart, int num, int frame, int range, float speed, int priority = 0)
- {
+ void setanim(int animpart, int num, int frame, int range, float speed, int priority = 0) {
if(animpart<0 || animpart>=MAXANIMPARTS) return;
- if(frame<0 || range<=0 || !meshes || !meshes->hasframes(frame, range))
- {
+ if(frame<0 || range<=0 || !meshes || !meshes->hasframes(frame, range)) {
conoutf(CON_ERROR, "invalid frame %d, range %d in model %s", frame, range, model->name);
return;
}
spec.speed = speed;
spec.priority = priority;
}
-
- virtual void loaded()
- {
+ virtual void loaded() {
meshes->shared++;
loopv(skins) skins[i].setkey();
}
};
-
- enum
- {
+ enum {
LINK_TAG = 0,
LINK_COOP,
LINK_REUSE
};
-
virtual int linktype(animmodel *m) const { (void) m; return LINK_TAG; }
-
- void render(int anim, int basetime, int basetime2, float pitch, const vec &axis, const vec &forward, dynent *d, modelattach *a)
- {
+ void render(int anim, int basetime, int basetime2, float pitch, const vec &axis, const vec &forward, dynent *d, modelattach *a) {
int numtags = 0;
- if(a)
- {
+ if(a) {
int index = parts.last()->index + parts.last()->numanimparts;
- for(int i = 0; a[i].tag; i++)
- {
+ for(int i = 0; a[i].tag; i++) {
numtags++;
-
animmodel *m = (animmodel *)a[i].m;
- if(!m)
- {
+ if(!m) {
if(a[i].pos) link(NULL, a[i].tag, vec(0, 0, 0), 0, 0, a[i].pos);
continue;
}
part *p = m->parts[0];
- switch(linktype(m))
- {
+ switch(linktype(m)) {
case LINK_TAG:
p->index = link(p, a[i].tag, vec(0, 0, 0), a[i].anim, a[i].basetime, a[i].pos) ? index : -1;
break;
-
case LINK_COOP:
p->index = index;
break;
-
default:
continue;
}
index += p->numanimparts;
}
}
-
animstate as[MAXANIMPARTS];
parts[0]->render(anim, basetime, basetime2, pitch, axis, forward, d, as);
-
- if(a) for(int i = numtags-1; i >= 0; i--)
- {
+ if(a) for(int i = numtags-1; i >= 0; i--) {
animmodel *m = (animmodel *)a[i].m;
- if(!m)
- {
+ if(!m) {
if(a[i].pos) unlink(NULL);
continue;
}
part *p = m->parts[0];
- switch(linktype(m))
- {
+ switch(linktype(m)) {
case LINK_TAG:
if(p->index >= 0) unlink(p);
p->index = 0;
break;
-
case LINK_COOP:
p->render(anim, basetime, basetime2, pitch, axis, forward, d);
p->index = 0;
break;
-
case LINK_REUSE:
p->render(anim | ANIM_REUSE, basetime, basetime2, pitch, axis, forward, d, as);
break;
}
}
}
-
- void render(int anim, int basetime, int basetime2, const vec &o, float yaw, float pitch, dynent *d, modelattach *a, const vec &color, const vec &dir, float trans)
- {
+ void render(int anim, int basetime, int basetime2, const vec &o, float yaw, float pitch, dynent *d, modelattach *a, const vec &color, const vec &dir, float trans) {
yaw += spinyaw*lastmillis/1000.0f;
pitch += offsetpitch + spinpitch*lastmillis/1000.0f;
-
vec axis(0, -1, 0), forward(1, 0, 0);
-
matrixpos = 0;
matrixstack[0].identity();
- if(!d || !d->ragdoll || anim&ANIM_RAGDOLL)
- {
+ if(!d || !d->ragdoll || anim&ANIM_RAGDOLL) {
matrixstack[0].settranslation(o);
matrixstack[0].rotate_around_z(yaw*RAD);
matrixstack[0].transformnormal(vec(axis), axis);
if(offsetyaw) matrixstack[0].rotate_around_z(offsetyaw*RAD);
}
else pitch = 0;
-
- if(anim&ANIM_NORENDER)
- {
+ if(anim&ANIM_NORENDER) {
render(anim, basetime, basetime2, pitch, axis, forward, d, a);
if(d) d->lastrendered = lastmillis;
return;
}
-
- if(!(anim&ANIM_NOSKIN))
- {
+ if(!(anim&ANIM_NOSKIN)) {
transparent = trans;
lightdir = dir;
lightcolor = color;
}
-
- if(depthoffset && !enabledepthoffset)
- {
+ if(depthoffset && !enabledepthoffset) {
enablepolygonoffset(GL_POLYGON_OFFSET_FILL);
enabledepthoffset = true;
}
-
- if(transparent<1)
- {
- if(anim&ANIM_GHOST)
- {
+ if(transparent<1) {
+ if(anim&ANIM_GHOST) {
glDepthFunc(GL_GREATER);
glDepthMask(GL_FALSE);
}
- else if(alphadepth)
- {
+ else if(alphadepth) {
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
render(anim|ANIM_NOSKIN, basetime, basetime2, pitch, axis, forward, d, a);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
glDepthFunc(GL_LEQUAL);
}
-
- if(!enablealphablend)
- {
+ if(!enablealphablend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
enablealphablend = true;
}
}
-
render(anim, basetime, basetime2, pitch, axis, forward, d, a);
-
- if(transparent<1 && (alphadepth || anim&ANIM_GHOST))
- {
+ if(transparent<1 && (alphadepth || anim&ANIM_GHOST)) {
glDepthFunc(GL_LESS);
if(anim&ANIM_GHOST) glDepthMask(GL_TRUE);
}
-
if(d) d->lastrendered = lastmillis;
}
-
vector<part *> parts;
-
- animmodel(const char *name) : model(name)
- {
+ animmodel(const char *name) : model(name) {
}
-
- ~animmodel()
- {
+ ~animmodel() {
parts.deletecontents();
}
-
- void cleanup()
- {
+ void cleanup() {
loopv(parts) parts[i]->cleanup();
}
-
virtual void flushpart() {}
-
- part &addpart()
- {
+ part &addpart() {
flushpart();
part *p = new part(this, parts.length());
parts.add(p);
return *p;
}
-
- void initmatrix(matrix4x3 &m)
- {
+ void initmatrix(matrix4x3 &m) {
m.identity();
if(offsetyaw) m.rotate_around_z(offsetyaw*RAD);
if(offsetpitch) m.rotate_around_y(-offsetpitch*RAD);
}
-
- void genBIH(vector<BIH::mesh> &bih)
- {
+ void genBIH(vector<BIH::mesh> &bih) {
if(parts.empty()) return;
matrix4x3 m;
initmatrix(m);
parts[0]->genBIH(bih, m);
}
-
- void preloadBIH()
- {
+ void preloadBIH() {
model::preloadBIH();
if(bih) loopv(parts) parts[i]->preloadBIH();
}
-
- BIH *setBIH()
- {
+ BIH *setBIH() {
if(bih) return bih;
vector<BIH::mesh> meshes;
genBIH(meshes);
bih = new BIH(meshes);
return bih;
}
-
- bool link(part *p, const char *tag, const vec &translate = vec(0, 0, 0), int anim = -1, int basetime = 0, vec *pos = NULL)
- {
+ bool link(part *p, const char *tag, const vec &translate = vec(0, 0, 0), int anim = -1, int basetime = 0, vec *pos = NULL) {
if(parts.empty()) return false;
return parts[0]->link(p, tag, translate, anim, basetime, pos);
}
-
- bool unlink(part *p)
- {
+ bool unlink(part *p) {
if(parts.empty()) return false;
return parts[0]->unlink(p);
}
-
virtual bool flipy() const { return false; }
virtual bool loadconfig() { return false; }
virtual bool loaddefaultparts() { return false; }
virtual void startload() {}
virtual void endload() {}
-
- bool load()
- {
+ bool load() {
startload();
bool success = loadconfig() && parts.length(); // configured model, will call the model commands below
if(!success)
flushpart();
endload();
if(flipy()) translate.y = -translate.y;
-
if(!success) return false;
loopv(parts) if(!parts[i]->meshes) return false;
-
loaded();
return true;
}
-
- void preloadshaders(bool force)
- {
- loopv(parts) parts[i]->preloadshaders(force);
+ void preloadshaders() {
+ loopv(parts) parts[i]->preloadshaders();
}
-
- void preloadmeshes()
- {
+ void preloadmeshes() {
loopv(parts) parts[i]->preloadmeshes();
}
-
- void setshader(Shader *shader)
- {
+ void setshader(Shader *shader) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].shader = shader;
}
-
- void setspec(float spec)
- {
+ void setspec(float spec) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].spec = spec;
}
-
- void setambient(float ambient)
- {
+ void setambient(float ambient) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].ambient = ambient;
}
-
- void setalphatest(float alphatest)
- {
+ void setalphatest(float alphatest) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].alphatest = alphatest;
}
-
- void setalphablend(bool alphablend)
- {
+ void setalphablend(bool alphablend) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].alphablend = alphablend;
}
-
- void setfullbright(float fullbright)
- {
+ void setfullbright(float fullbright) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].fullbright = fullbright;
}
-
- void setcullface(bool cullface)
- {
+ void setcullface(bool cullface) {
if(parts.empty()) loaddefaultparts();
loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].cullface = cullface;
}
-
- void calcbb(vec ¢er, vec &radius)
- {
+ void calcbb(vec ¢er, vec &radius) {
if(parts.empty()) return;
vec bbmin(1e16f, 1e16f, 1e16f), bbmax(-1e16f, -1e16f, -1e16f);
matrix4x3 m;
center = bbmin;
center.add(radius);
}
-
- virtual void loaded()
- {
+ virtual void loaded() {
scale /= 4;
if(parts.length()) parts[0]->translate = translate;
loopv(parts) parts[i]->loaded();
}
-
static bool enabletc, enablealphablend, enablecullface, enablenormals, enabletangents, enablebones, enabledepthoffset;
static vec lightdir, lightcolor;
static float transparent, lastalphatest;
static Texture *lasttex, *lastmasks, *lastnormalmap;
static int matrixpos;
static matrix4 matrixstack[64];
-
- void startrender()
- {
+ void startrender() {
enabletc = enablealphablend = enablenormals = enabletangents = enablebones = enabledepthoffset = false;
enablecullface = true;
lastalphatest = -1;
transparent = 1;
shaderparamskey::invalidate();
}
-
- static void disablebones()
- {
+ static void disablebones() {
gle::disableboneweight();
gle::disableboneindex();
enablebones = false;
}
-
- static void disabletangents()
- {
+ static void disabletangents() {
gle::disabletangent();
enabletangents = false;
}
-
- static void disabletc()
- {
+ static void disabletc() {
gle::disabletexcoord0();
enabletc = false;
}
-
- static void disablenormals()
- {
+ static void disablenormals() {
gle::disablenormal();
enablenormals = false;
}
-
- static void disablevbo()
- {
+ static void disablevbo() {
if(lastebuf) gle::clearebo();
- if(lastvbuf)
- {
+ if(lastvbuf) {
gle::clearvbo();
gle::disablevertex();
}
if(enablebones) disablebones();
lastvbuf = lasttcbuf = lastxbuf = lastnbuf = lastbbuf = lastebuf = 0;
}
-
- void endrender()
- {
+ void endrender() {
if(lastvbuf || lastebuf) disablevbo();
if(enablealphablend) glDisable(GL_BLEND);
if(!enablecullface) glEnable(GL_CULL_FACE);
int animmodel::matrixpos = 0;
matrix4 animmodel::matrixstack[64];
-static inline uint hthash(const animmodel::shaderparams &k)
-{
+static inline uint hthash(const animmodel::shaderparams &k) {
return memhash(&k, sizeof(k));
}
-static inline bool htcmp(const animmodel::shaderparams &x, const animmodel::shaderparams &y)
-{
+static inline bool htcmp(const animmodel::shaderparams &x, const animmodel::shaderparams &y) {
return !memcmp(&x, &y, sizeof(animmodel::shaderparams));
}
hashtable<animmodel::shaderparams, animmodel::shaderparamskey> animmodel::shaderparamskey::keys;
int animmodel::shaderparamskey::firstversion = 0, animmodel::shaderparamskey::lastversion = 1;
-template<class MDL, class BASE> struct modelloader : BASE
-{
+template<class MDL, class BASE> struct modelloader : BASE {
static MDL *loading;
static string dir;
-
modelloader(const char *name) : BASE(name) {}
-
static bool animated() { return true; }
static bool multiparted() { return true; }
static bool multimeshed() { return true; }
-
- void startload()
- {
+ void startload() {
loading = (MDL *)this;
}
-
- void endload()
- {
+ void endload() {
loading = NULL;
}
-
- bool loadconfig()
- {
+ bool loadconfig() {
formatstring(dir, "packages/models/%s", BASE::name);
defformatstring(cfgname, "packages/models/%s/%s.cfg", BASE::name, MDL::formatname());
-
identflags &= ~IDF_PERSIST;
bool success = execfile(cfgname, false);
identflags |= IDF_PERSIST;
template<class MDL, class BASE> MDL *modelloader<MDL, BASE>::loading = NULL;
template<class MDL, class BASE> string modelloader<MDL, BASE>::dir = {'\0'}; // crashes clang if "" is used here
-template<class MDL, class MESH> struct modelcommands
-{
+template<class MDL, class MESH> struct modelcommands {
typedef struct MDL::part part;
typedef struct MDL::skin skin;
-
- static void setdir(char *name)
- {
+ static void setdir(char *name) {
if(!MDL::loading) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
formatstring(MDL::dir, "packages/models/%s", name);
}
-
#define loopmeshes(meshname, m, body) \
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; } \
part &mdl = *MDL::loading->parts.last(); \
if(!mdl.meshes) return; \
- loopv(mdl.meshes->meshes) \
- { \
+ loopv(mdl.meshes->meshes) { \
+ \
MESH &m = *(MESH *)mdl.meshes->meshes[i]; \
- if(!strcmp(meshname, "*") || (m.name && !strcmp(m.name, meshname))) \
- { \
+ if(!strcmp(meshname, "*") || (m.name && !strcmp(m.name, meshname))) { \
+ \
body; \
} \
}
-
#define loopskins(meshname, s, body) loopmeshes(meshname, m, { skin &s = mdl.skins[i]; body; })
-
- static void setskin(char *meshname, char *tex, char *masks, float *envmapmax, float *envmapmin)
- {(void)envmapmax;(void)envmapmin;
+ static void setskin(char *meshname, char *tex, char *masks, float *envmapmax, float *envmapmin) {
+ (void)envmapmax;(void)envmapmin;
loopskins(meshname, s,
s.tex = textureload(makerelpath(MDL::dir, tex), 0, true, false);
- if(*masks)
- {
+ if(*masks) {
s.masks = textureload(makerelpath(MDL::dir, masks), 0, true, false);
}
);
}
-
- static void setspec(char *meshname, int *percent)
- {
+ static void setspec(char *meshname, int *percent) {
float spec = 1.0f;
if(*percent>0) spec = *percent/100.0f;
else if(*percent<0) spec = 0.0f;
loopskins(meshname, s, s.spec = spec);
}
-
- static void setambient(char *meshname, int *percent)
- {
+ static void setambient(char *meshname, int *percent) {
float ambient = 0.3f;
if(*percent>0) ambient = *percent/100.0f;
else if(*percent<0) ambient = 0.0f;
loopskins(meshname, s, s.ambient = ambient);
}
-
- static void setalphatest(char *meshname, float *cutoff)
- {
+ static void setalphatest(char *meshname, float *cutoff) {
loopskins(meshname, s, s.alphatest = max(0.0f, min(1.0f, *cutoff)));
}
-
- static void setalphablend(char *meshname, int *blend)
- {
+ static void setalphablend(char *meshname, int *blend) {
loopskins(meshname, s, s.alphablend = *blend!=0);
}
-
- static void setcullface(char *meshname, int *cullface)
- {
+ static void setcullface(char *meshname, int *cullface) {
loopskins(meshname, s, s.cullface = *cullface!=0);
}
-
- static void setbumpmap(char *meshname, char *normalmapfile)
- {
+ static void setbumpmap(char *meshname, char *normalmapfile) {
Texture *normalmaptex = textureload(makerelpath(MDL::dir, normalmapfile), 0, true, false);
loopskins(meshname, s, s.normalmap = normalmaptex);
}
-
- static void setfullbright(char *meshname, float *fullbright)
- {
+ static void setfullbright(char *meshname, float *fullbright) {
loopskins(meshname, s, s.fullbright = *fullbright);
}
-
- static void setshader(char *meshname, char *shader)
- {
+ static void setshader(char *meshname, char *shader) {
loopskins(meshname, s, s.shader = lookupshaderbyname(shader));
}
-
- static void setscroll(char *meshname, float *scrollu, float *scrollv)
- {
+ static void setscroll(char *meshname, float *scrollu, float *scrollv) {
loopskins(meshname, s, { s.scrollu = *scrollu; s.scrollv = *scrollv; });
}
-
- static void setnoclip(char *meshname, int *noclip)
- {
+ static void setnoclip(char *meshname, int *noclip) {
loopmeshes(meshname, m, m.noclip = *noclip!=0);
}
-
- static void setlink(int *parent, int *child, char *tagname, float *x, float *y, float *z)
- {
+ static void setlink(int *parent, int *child, char *tagname, float *x, float *y, float *z) {
if(!MDL::loading) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
if(!MDL::loading->parts.inrange(*parent) || !MDL::loading->parts.inrange(*child)) { conoutf(CON_ERROR, "no models loaded to link"); return; }
if(!MDL::loading->parts[*parent]->link(MDL::loading->parts[*child], tagname, vec(*x, *y, *z))) conoutf(CON_ERROR, "could not link model %s", MDL::loading->name);
}
-
- template<class F> void modelcommand(F *fun, const char *suffix, const char *args)
- {
+ template<class F> void modelcommand(F *fun, const char *suffix, const char *args) {
defformatstring(name, "%s%s", MDL::formatname(), suffix);
addcommand(newstring(name), (void (*)())fun, args);
}
-
- modelcommands()
- {
+ modelcommands() {
modelcommand(setdir, "dir", "s");
- if(MDL::multimeshed())
- {
+ if(MDL::multimeshed()) {
modelcommand(setskin, "skin", "sssff");
modelcommand(setspec, "spec", "si");
modelcommand(setambient, "ambient", "si");
#include "engine.h"
-bool BIH::triintersect(const mesh &m, int tidx, const vec &mo, const vec &mray, float maxdist, float &dist, int mode)
-{
+bool BIH::triintersect(const mesh &m, int tidx, const vec &mo, const vec &mray, float maxdist, float &dist, int mode) {
const tri &t = m.tris[tidx];
vec a = m.getpos(t.vert[0]), b = m.getpos(t.vert[1]).sub(a), c = m.getpos(t.vert[2]).sub(a),
n = vec().cross(b, c), r = vec(a).sub(mo), e = vec().cross(r, mray);
float det = mray.dot(n), v, w, f;
- if(det >= 0)
- {
+ if(det >= 0) {
if(!(mode&RAY_SHADOW) && m.flags&MESH_CULLFACE) return false;
v = e.dot(c);
if(v < 0 || v > det) return false;
f = r.dot(n)*m.scale;
if(f < 0 || f > maxdist*det || !det) return false;
}
- else
- {
+ else {
v = e.dot(c);
if(v > 0 || v < det) return false;
w = -e.dot(b);
if(f > 0 || f < maxdist*det) return false;
}
float invdet = 1/det;
- if(m.flags&MESH_ALPHA && (mode&RAY_ALPHAPOLY)==RAY_ALPHAPOLY && (m.tex->alphamask || (lightmapping <= 1 && loadalphamask(m.tex))))
- {
+ if(m.flags&MESH_ALPHA && (mode&RAY_ALPHAPOLY)==RAY_ALPHAPOLY && (m.tex->alphamask || (lightmapping <= 1 && loadalphamask(m.tex)))) {
vec2 at = m.gettc(t.vert[0]), bt = m.gettc(t.vert[1]).sub(at).mul(v*invdet), ct = m.gettc(t.vert[2]).sub(at).mul(w*invdet);
at.add(bt).add(ct);
int si = clamp(int(m.tex->xs * at.x), 0, m.tex->xs-1),
return true;
}
-struct traversestate
-{
+struct traversestate {
BIH::node *node;
float tmin, tmax;
};
-inline bool BIH::traverse(const mesh &m, const vec &o, const vec &ray, const vec &invray, float maxdist, float &dist, int mode, node *curnode, float tmin, float tmax)
-{
+inline bool BIH::traverse(const mesh &m, const vec &o, const vec &ray, const vec &invray, float maxdist, float &dist, int mode, node *curnode, float tmin, float tmax) {
traversestate stack[128];
int stacksize = 0;
ivec order(ray.x>0 ? 0 : 1, ray.y>0 ? 0 : 1, ray.z>0 ? 0 : 1);
vec mo = m.invxform.transform(o), mray = m.invxformnorm.transform(ray);
- for(;;)
- {
+ for(;;) {
int axis = curnode->axis();
int nearidx = order[axis], faridx = nearidx^1;
float nearsplit = (curnode->split[nearidx] - o[axis])*invray[axis],
farsplit = (curnode->split[faridx] - o[axis])*invray[axis];
-
- if(nearsplit <= tmin)
- {
- if(farsplit < tmax)
- {
- if(!curnode->isleaf(faridx))
- {
+ if(nearsplit <= tmin) {
+ if(farsplit < tmax) {
+ if(!curnode->isleaf(faridx)) {
curnode += curnode->childindex(faridx);
tmin = max(tmin, farsplit);
continue;
else if(triintersect(m, curnode->childindex(faridx), mo, mray, maxdist, dist, mode)) return true;
}
}
- else if(curnode->isleaf(nearidx))
- {
+ else if(curnode->isleaf(nearidx)) {
if(triintersect(m, curnode->childindex(nearidx), mo, mray, maxdist, dist, mode)) return true;
- if(farsplit < tmax)
- {
- if(!curnode->isleaf(faridx))
- {
+ if(farsplit < tmax) {
+ if(!curnode->isleaf(faridx)) {
curnode += curnode->childindex(faridx);
tmin = max(tmin, farsplit);
continue;
else if(triintersect(m, curnode->childindex(faridx), mo, mray, maxdist, dist, mode)) return true;
}
}
- else
- {
- if(farsplit < tmax)
- {
- if(!curnode->isleaf(faridx))
- {
- if(stacksize < int(sizeof(stack)/sizeof(stack[0])))
- {
+ else {
+ if(farsplit < tmax) {
+ if(!curnode->isleaf(faridx)) {
+ if(stacksize < int(sizeof(stack)/sizeof(stack[0]))) {
traversestate &save = stack[stacksize++];
save.node = curnode + curnode->childindex(faridx);
save.tmin = max(tmin, farsplit);
save.tmax = tmax;
}
- else
- {
+ else {
if(traverse(m, o, ray, invray, maxdist, dist, mode, curnode + curnode->childindex(nearidx), tmin, min(tmax, nearsplit))) return true;
curnode += curnode->childindex(faridx);
tmin = max(tmin, farsplit);
}
}
-inline bool BIH::traverse(const vec &o, const vec &ray, float maxdist, float &dist, int mode)
-{
+inline bool BIH::traverse(const vec &o, const vec &ray, float maxdist, float &dist, int mode) {
vec invray(ray.x ? 1/ray.x : 1e16f, ray.y ? 1/ray.y : 1e16f, ray.z ? 1/ray.z : 1e16f);
- loopi(nummeshes)
- {
+ loopi(nummeshes) {
mesh &m = meshes[i];
if(!(mode&RAY_SHADOW) && m.flags&MESH_NOCLIP) continue;
float t1 = (m.bbmin.x - o.x)*invray.x,
return false;
}
-void BIH::build(mesh &m, ushort *indices, int numindices, const ivec &vmin, const ivec &vmax)
-{
+void BIH::build(mesh &m, ushort *indices, int numindices, const ivec &vmin, const ivec &vmax) {
int axis = 2;
loopk(2) if(vmax[k] - vmin[k] > vmax[axis] - vmin[axis]) axis = k;
-
ivec leftmin, leftmax, rightmin, rightmax;
int splitleft, splitright;
int left, right;
- loopk(3)
- {
+ loopk(3) {
leftmin = rightmin = ivec(INT_MAX, INT_MAX, INT_MAX);
leftmax = rightmax = ivec(INT_MIN, INT_MIN, INT_MIN);
int split = (vmax[axis] + vmin[axis])/2;
- for(left = 0, right = numindices, splitleft = SHRT_MIN, splitright = SHRT_MAX; left < right;)
- {
+ for(left = 0, right = numindices, splitleft = SHRT_MIN, splitright = SHRT_MAX; left < right;) {
const tribb &tri = m.tribbs[indices[left]];
ivec trimin = ivec(tri.center).sub(ivec(tri.radius)),
trimax = ivec(tri.center).add(ivec(tri.radius));
int amin = trimin[axis], amax = trimax[axis];
- if(max(split - amin, 0) > max(amax - split, 0))
- {
+ if(max(split - amin, 0) > max(amax - split, 0)) {
++left;
splitleft = max(splitleft, amax);
leftmin.min(trimin);
leftmax.max(trimax);
}
- else
- {
+ else {
--right;
swap(indices[left], indices[right]);
splitright = min(splitright, amin);
if(left > 0 && right < numindices) break;
axis = (axis+1)%3;
}
-
- if(!left || right==numindices)
- {
+ if(!left || right==numindices) {
leftmin = rightmin = ivec(INT_MAX, INT_MAX, INT_MAX);
leftmax = rightmax = ivec(INT_MIN, INT_MIN, INT_MIN);
left = right = numindices/2;
splitleft = SHRT_MIN;
splitright = SHRT_MAX;
- loopi(numindices)
- {
+ loopi(numindices) {
const tribb &tri = m.tribbs[indices[i]];
ivec trimin = ivec(tri.center).sub(ivec(tri.radius)),
trimax = ivec(tri.center).add(ivec(tri.radius));
- if(i < left)
- {
+ if(i < left) {
splitleft = max(splitleft, trimax[axis]);
leftmin.min(trimin);
leftmax.max(trimax);
}
- else
- {
+ else {
splitright = min(splitright, trimin[axis]);
rightmin.min(trimin);
rightmax.max(trimax);
}
}
}
-
int offset = m.numnodes++;
node &curnode = m.nodes[offset];
curnode.split[0] = short(splitleft);
curnode.split[1] = short(splitright);
-
if(left==1) curnode.child[0] = (axis<<14) | indices[0];
- else
- {
+ else {
curnode.child[0] = (axis<<14) | (m.numnodes - offset);
build(m, indices, left, leftmin, leftmax);
}
-
if(numindices-right==1) curnode.child[1] = (1<<15) | (left==1 ? 1<<14 : 0) | indices[right];
- else
- {
+ else {
curnode.child[1] = (left==1 ? 1<<14 : 0) | (m.numnodes - offset);
build(m, &indices[right], numindices-right, rightmin, rightmax);
}
}
BIH::BIH(vector<mesh> &buildmeshes)
- : meshes(NULL), nummeshes(0), nodes(NULL), numnodes(0), tribbs(NULL), numtris(0), bbmin(1e16f, 1e16f, 1e16f), bbmax(-1e16f, -1e16f, -1e16f), center(0, 0, 0), radius(0), entradius(0)
-{
+ : meshes(NULL), nummeshes(0), nodes(NULL), numnodes(0), tribbs(NULL), numtris(0), bbmin(1e16f, 1e16f, 1e16f), bbmax(-1e16f, -1e16f, -1e16f), center(0, 0, 0), radius(0), entradius(0) {
if(buildmeshes.empty()) return;
loopv(buildmeshes) numtris += buildmeshes[i].numtris;
if(!numtris) return;
-
nummeshes = buildmeshes.length();
meshes = new mesh[nummeshes];
memcpy(meshes, buildmeshes.getbuf(), sizeof(mesh)*buildmeshes.length());
tribbs = new tribb[numtris];
tribb *dsttri = tribbs;
- loopi(nummeshes)
- {
+ loopi(nummeshes) {
mesh &m = meshes[i];
m.scale = m.xform.a.magnitude();
m.invscale = 1/m.scale;
m.tribbs = dsttri;
const tri *srctri = m.tris;
vec mmin(1e16f, 1e16f, 1e16f), mmax(-1e16f, -1e16f, -1e16f);
- loopj(m.numtris)
- {
+ loopj(m.numtris) {
vec s0 = m.getpos(srctri->vert[0]), s1 = m.getpos(srctri->vert[1]), s2 = m.getpos(srctri->vert[2]),
v0 = m.xform.transform(s0), v1 = m.xform.transform(s1), v2 = m.xform.transform(s2),
vmin = vec(v0).min(v1).min(v2),
++srctri;
++dsttri;
}
- loopk(3) if(fabs(mmax[k] - mmin[k]) < 0.125f)
- {
+ loopk(3) if(fabs(mmax[k] - mmin[k]) < 0.125f) {
float mid = (mmin[k] + mmax[k]) / 2;
mmin[k] = mid - 0.0625f;
mmax[k] = mid + 0.0625f;
bbmin.min(mmin);
bbmax.max(mmax);
}
-
center = vec(bbmin).add(bbmax).mul(0.5f);
radius = vec(bbmax).sub(bbmin).mul(0.5f).magnitude();
entradius = max(bbmin.squaredlen(), bbmax.squaredlen());
-
nodes = new node[numtris];
node *curnode = nodes;
ushort *indices = new ushort[numtris];
- loopi(nummeshes)
- {
+ loopi(nummeshes) {
mesh &m = meshes[i];
m.nodes = curnode;
loopj(m.numtris) indices[j] = j;
numnodes = int(curnode - nodes);
}
-BIH::~BIH()
-{
+BIH::~BIH() {
delete[] meshes;
delete[] nodes;
delete[] tribbs;
}
-bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist, int mode, float &dist)
-{
+bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist, int mode, float &dist) {
model *m = loadmapmodel(e.attr2);
if(!m) return false;
- if(mode&RAY_SHADOW)
- {
+ if(mode&RAY_SHADOW) {
if(!m->shadow || e.flags&EF_NOSHADOW) return false;
}
else if((mode&RAY_ENTS)!=RAY_ENTS && (!m->collide || e.flags&EF_NOCOLLIDE)) return false;
float v = mo.dot(mray), inside = m->bih->entradius - mo.squaredlen();
if((inside < 0 && v > 0) || inside + v*v < 0) return false;
int yaw = e.attr1;
- if(yaw != 0)
- {
+ if(yaw != 0) {
const vec2 &rot = sincosmod360(-yaw);
mo.rotate_around_z(rot);
mray.rotate_around_z(rot);
-struct BIH
-{
- struct node
- {
+struct BIH {
+ struct node {
short split[2];
ushort child[2];
-
int axis() const { return child[0]>>14; }
int childindex(int which) const { return child[which]&0x3FFF; }
bool isleaf(int which) const { return (child[1]&(1<<(14+which)))!=0; }
};
-
- struct tri
- {
+ struct tri {
ushort vert[3];
};
-
- struct tribb
- {
+ struct tribb {
svec center, radius;
-
- bool outside(const ivec &bo, const ivec &br) const
- {
+ bool outside(const ivec &bo, const ivec &br) const {
return abs(bo.x - center.x) > br.x + radius.x ||
abs(bo.y - center.y) > br.y + radius.y ||
abs(bo.z - center.z) > br.z + radius.z;
}
};
-
enum { MESH_NOCLIP = 1<<0, MESH_ALPHA = 1<<1, MESH_CULLFACE = 1<<2 };
-
- struct mesh
- {
+ struct mesh {
enum { MAXTRIS = 1<<14 };
-
matrix4x3 xform, invxform;
matrix3 xformnorm, invxformnorm;
float scale, invscale;
Texture *tex;
int flags;
vec bbmin, bbmax;
-
mesh() : numnodes(0), numtris(0), tex(NULL), flags(0) {}
-
vec getpos(int i) const { return *(const vec *)(pos + i*posstride); }
vec2 gettc(int i) const { return *(const vec2 *)(tc + i*tcstride); }
};
-
mesh *meshes;
int nummeshes;
node *nodes;
int numtris;
vec bbmin, bbmax, center;
float radius, entradius;
-
BIH(vector<mesh> &buildmeshes);
-
~BIH();
-
void build(mesh &m, ushort *indices, int numindices, const ivec &vmin, const ivec &vmax);
-
bool traverse(const vec &o, const vec &ray, float maxdist, float &dist, int mode);
bool traverse(const mesh &m, const vec &o, const vec &ray, const vec &invray, float maxdist, float &dist, int mode, node *curnode, float tmin, float tmax);
bool triintersect(const mesh &m, int tidx, const vec &mo, const vec &mray, float maxdist, float &dist, int mode);
-
void preload();
};
ENetPeer *curpeer = NULL, *connpeer = NULL;
int connmillis = 0, connattempts = 0, discmillis = 0;
-bool multiplayer(bool msg)
-{
+bool multiplayer(bool msg) {
bool val = curpeer || hasnonlocalclients();
if(val && msg) conoutf(CON_ERROR, "operation not available in multiplayer");
return val;
}
-void setrate(int rate)
-{
+void setrate(int rate) {
if(!curpeer) return;
enet_host_bandwidth_limit(clienthost, rate*1024, rate*1024);
}
VARF(throttle_accel, 0, 2, 32, throttle());
VARF(throttle_decel, 0, 2, 32, throttle());
-void throttle()
-{
+void throttle() {
if(!curpeer) return;
ASSERT(ENET_PEER_PACKET_THROTTLE_SCALE==32);
enet_peer_throttle_configure(curpeer, throttle_interval*1000, throttle_accel, throttle_decel);
}
-bool isconnected(bool attempt, bool local)
-{
+bool isconnected(bool attempt, bool local) {
return curpeer || (attempt && connpeer) || (local && haslocalclients());
}
ICOMMAND(isconnected, "bb", (int *attempt, int *local), intret(isconnected(*attempt > 0, *local != 0) ? 1 : 0));
-const ENetAddress *connectedpeer()
-{
+const ENetAddress *connectedpeer() {
return curpeer ? &curpeer->address : NULL;
}
-ICOMMAND(connectedip, "", (),
-{
+ICOMMAND(connectedip, "", (), {
const ENetAddress *address = connectedpeer();
string hostname;
result(address && enet_address_get_host_ip(address, hostname, sizeof(hostname)) >= 0 ? hostname : "");
});
-ICOMMAND(connectedport, "", (),
-{
+ICOMMAND(connectedport, "", (), {
const ENetAddress *address = connectedpeer();
intret(address ? address->port : -1);
});
-void abortconnect()
-{
+void abortconnect() {
if(!connpeer) return;
game::connectfail();
if(connpeer->state!=ENET_PEER_STATE_DISCONNECTED) enet_peer_reset(connpeer);
SVARP(connectname, "");
VARP(connectport, 0, 0, 0xFFFF);
-void connectserv(const char *servername, int serverport, const char *serverpassword)
-{
- if(connpeer)
- {
+void connectserv(const char *servername, int serverport, const char *serverpassword) {
+ if(connpeer) {
conoutf("aborting connection attempt");
abortconnect();
}
-
if(serverport <= 0) serverport = server::serverport();
-
ENetAddress address;
address.port = serverport;
-
- if(servername)
- {
+ if(servername) {
if(strcmp(servername, connectname)) setsvar("connectname", servername);
if(serverport != connectport) setvar("connectport", serverport);
addserver(servername, serverport, serverpassword && serverpassword[0] ? serverpassword : NULL);
conoutf("attempting to connect to %s:%d", servername, serverport);
- if(!resolverwait(servername, &address))
- {
+ if(!resolverwait(servername, &address)) {
conoutf(CON_ERROR, "\f3could not resolve server %s", servername);
return;
}
}
- else
- {
+ else {
setsvar("connectname", "");
setvar("connectport", 0);
conoutf("attempting to connect over LAN");
address.host = ENET_HOST_BROADCAST;
}
-
- if(!clienthost)
- {
+ if(!clienthost) {
clienthost = enet_host_create(NULL, 2, server::numchannels(), rate*1024, rate*1024);
- if(!clienthost)
- {
+ if(!clienthost) {
conoutf(CON_ERROR, "\f3could not connect to server");
return;
}
clienthost->duplicatePeers = 0;
}
-
connpeer = enet_host_connect(clienthost, &address, server::numchannels(), 0);
enet_host_flush(clienthost);
connmillis = totalmillis;
connattempts = 0;
-
game::connectattempt(servername ? servername : "", serverpassword ? serverpassword : "", address);
}
-void reconnect(const char *serverpassword)
-{
- if(!connectname[0] || connectport <= 0)
- {
+void reconnect(const char *serverpassword) {
+ if(!connectname[0] || connectport <= 0) {
conoutf(CON_ERROR, "no previous connection");
return;
}
-
connectserv(connectname, connectport, serverpassword);
}
-void disconnect(bool async, bool cleanup)
-{
- if(curpeer)
- {
- if(!discmillis)
- {
+void disconnect(bool async, bool cleanup) {
+ if(curpeer) {
+ if(!discmillis) {
enet_peer_disconnect(curpeer, DISC_NONE);
enet_host_flush(clienthost);
discmillis = totalmillis;
}
- if(curpeer->state!=ENET_PEER_STATE_DISCONNECTED)
- {
+ if(curpeer->state!=ENET_PEER_STATE_DISCONNECTED) {
if(async) return;
enet_peer_reset(curpeer);
}
game::gamedisconnect(cleanup);
mainmenu = 1;
}
- if(!connpeer && clienthost)
- {
+ if(!connpeer && clienthost) {
enet_host_destroy(clienthost);
clienthost = NULL;
}
}
-void trydisconnect(bool local)
-{
- if(connpeer)
- {
+void trydisconnect(bool local) {
+ if(connpeer) {
conoutf("aborting connection attempt");
abortconnect();
}
- else if(curpeer)
- {
+ else if(curpeer) {
conoutf("attempting to disconnect...");
disconnect(!discmillis);
}
ICOMMAND(localconnect, "", (), { if(!isconnected()) localconnect(); });
ICOMMAND(localdisconnect, "", (), { if(haslocalclients()) localdisconnect(); });
-void sendclientpacket(ENetPacket *packet, int chan)
-{
+void sendclientpacket(ENetPacket *packet, int chan) {
if(curpeer) enet_peer_send(curpeer, chan, packet);
else localclienttoserver(chan, packet);
}
-void flushclient()
-{
+void flushclient() {
if(clienthost) enet_host_flush(clienthost);
}
-void neterr(const char *s, bool disc)
-{
+void neterr(const char *s, bool disc) {
conoutf(CON_ERROR, "\f3illegal network message (%s)", s);
if(disc) disconnect();
}
-void localservertoclient(int chan, ENetPacket *packet) // processes any updates from the server
-{
+void localservertoclient(int chan, ENetPacket *packet) { // processes any updates from the server {
packetbuf p(packet);
game::parsepacketclient(chan, p);
}
void clientkeepalive() { if(clienthost) enet_host_service(clienthost, NULL, 0); }
-void gets2c() // get updates from the server
-{
+void gets2c() { // get updates from the server {
ENetEvent event;
if(!clienthost) return;
- if(connpeer && totalmillis/3000 > connmillis/3000)
- {
+ if(connpeer && totalmillis/3000 > connmillis/3000) {
conoutf("attempting to connect...");
connmillis = totalmillis;
++connattempts;
- if(connattempts > 3)
- {
+ if(connattempts > 3) {
conoutf(CON_ERROR, "\f3could not connect to server");
abortconnect();
return;
}
}
while(clienthost && enet_host_service(clienthost, &event, 0)>0)
- switch(event.type)
- {
+ switch(event.type) {
case ENET_EVENT_TYPE_CONNECT:
disconnect(false, false);
localdisconnect(false);
if(rate) setrate(rate);
game::gameconnect(true);
break;
-
case ENET_EVENT_TYPE_RECEIVE:
if(discmillis) conoutf("attempting to disconnect...");
else localservertoclient(event.channelID, event.packet);
enet_packet_destroy(event.packet);
break;
-
case ENET_EVENT_TYPE_DISCONNECT:
if(event.data>=DISC_NUM) event.data = DISC_NONE;
- if(event.peer==connpeer)
- {
+ if(event.peer==connpeer) {
conoutf(CON_ERROR, "\f3could not connect to server");
abortconnect();
}
- else
- {
- if(!discmillis || event.data)
- {
+ else {
+ if(!discmillis || event.data) {
const char *msg = disconnectreason(event.data);
if(msg) conoutf(CON_ERROR, "\f3server network error, disconnecting (%s) ...", msg);
else conoutf(CON_ERROR, "\f3server network error, disconnecting...");
disconnect();
}
return;
-
default:
break;
}
int identflags = 0;
-enum
-{
+enum {
MAXARGS = 25,
MAXCOMARGS = 12
};
VARN(numargs, _numargs, MAXARGS, 0, 0);
-static inline void freearg(tagval &v)
-{
- switch(v.type)
- {
+static inline void freearg(tagval &v) {
+ switch(v.type) {
case VAL_STR: delete[] v.s; break;
case VAL_CODE: if(v.code[-1] == CODE_START) delete[] (uchar *)&v.code[-1]; break;
}
}
-static inline void forcenull(tagval &v)
-{
- switch(v.type)
- {
+static inline void forcenull(tagval &v) {
+ switch(v.type) {
case VAL_NULL: return;
}
freearg(v);
v.setnull();
}
-static inline float forcefloat(tagval &v)
-{
+static inline float forcefloat(tagval &v) {
float f = 0.0f;
- switch(v.type)
- {
+ switch(v.type) {
case VAL_INT: f = v.i; break;
case VAL_STR: f = parsefloat(v.s); break;
case VAL_MACRO: f = parsefloat(v.s); break;
return f;
}
-static inline int forceint(tagval &v)
-{
+static inline int forceint(tagval &v) {
int i = 0;
- switch(v.type)
- {
+ switch(v.type) {
case VAL_FLOAT: i = v.f; break;
case VAL_STR: i = parseint(v.s); break;
case VAL_MACRO: i = parseint(v.s); break;
return i;
}
-static inline const char *forcestr(tagval &v)
-{
+static inline const char *forcestr(tagval &v) {
const char *s = "";
- switch(v.type)
- {
+ switch(v.type) {
case VAL_FLOAT: s = floatstr(v.f); break;
case VAL_INT: s = intstr(v.i); break;
case VAL_STR:
return s;
}
-static inline void forcearg(tagval &v, int type)
-{
- switch(type)
- {
+static inline void forcearg(tagval &v, int type) {
+ switch(type) {
case RET_STR: if(v.type != VAL_STR) forcestr(v); break;
case RET_INT: if(v.type != VAL_INT) forceint(v); break;
case RET_FLOAT: if(v.type != VAL_FLOAT) forcefloat(v); break;
}
}
-static inline ident *forceident(tagval &v)
-{
- switch(v.type)
- {
+static inline ident *forceident(tagval &v) {
+ switch(v.type) {
case VAL_IDENT: return v.id;
- case VAL_MACRO:
- {
+ case VAL_MACRO: {
ident *id = newident(v.s, IDF_UNKNOWN);
v.setident(id);
return id;
}
- case VAL_STR:
- {
+ case VAL_STR: {
ident *id = newident(v.s, IDF_UNKNOWN);
delete[] v.s;
v.setident(id);
return dummyident;
}
-void tagval::cleanup()
-{
+void tagval::cleanup() {
freearg(*this);
}
-static inline void freeargs(tagval *args, int &oldnum, int newnum)
-{
+static inline void freeargs(tagval *args, int &oldnum, int newnum) {
for(int i = newnum; i < oldnum; i++) freearg(args[i]);
oldnum = newnum;
}
-static inline void cleancode(ident &id)
-{
- if(id.code)
- {
+static inline void cleancode(ident &id) {
+ if(id.code) {
id.code[0] -= 0x100;
if(int(id.code[0]) < 0x100) delete[] id.code;
id.code = NULL;
}
}
-struct nullval : tagval
-{
+struct nullval : tagval {
nullval() { setnull(); }
} nullval;
tagval noret = nullval, *commandret = &noret;
-void clear_command()
-{
- enumerate(idents, ident, i,
- {
- if(i.type==ID_ALIAS)
- {
+void clear_command() {
+ enumerate(idents, ident, i, {
+ if(i.type==ID_ALIAS) {
DELETEA(i.name);
i.forcenull();
DELETEA(i.code);
});
}
-void clearoverride(ident &i)
-{
+void clearoverride(ident &i) {
if(!(i.flags&IDF_OVERRIDDEN)) return;
- switch(i.type)
- {
+ switch(i.type) {
case ID_ALIAS:
- if(i.valtype==VAL_STR)
- {
+ if(i.valtype==VAL_STR) {
if(!i.val.s[0]) break;
delete[] i.val.s;
}
i.flags &= ~IDF_OVERRIDDEN;
}
-void clearoverrides()
-{
+void clearoverrides() {
enumerate(idents, ident, i, clearoverride(i));
}
static bool initedidents = false;
static vector<ident> *identinits = NULL;
-static inline ident *addident(const ident &id)
-{
- if(!initedidents)
- {
+static inline ident *addident(const ident &id) {
+ if(!initedidents) {
if(!identinits) identinits = new vector<ident>;
identinits->add(id);
return NULL;
return identmap.add(&def);
}
-static bool initidents()
-{
+static bool initidents() {
initedidents = true;
- for(int i = 0; i < MAXARGS; i++)
- {
+ for(int i = 0; i < MAXARGS; i++) {
defformatstring(argname, "arg%d", i+1);
newident(argname, IDF_ARG);
}
dummyident = newident("//dummy", IDF_UNKNOWN);
- if(identinits)
- {
+ if(identinits) {
loopv(*identinits) addident((*identinits)[i]);
DELETEP(identinits);
}
static const char *sourcefile = NULL, *sourcestr = NULL;
-static const char *debugline(const char *p, const char *fmt)
-{
+static const char *debugline(const char *p, const char *fmt) {
if(!sourcestr) return fmt;
int num = 1;
const char *line = sourcestr;
- for(;;)
- {
+ for(;;) {
const char *end = strchr(line, '\n');
if(!end) end = line + strlen(line);
- if(p >= line && p <= end)
- {
+ if(p >= line && p <= end) {
static string buf;
if(sourcefile) formatstring(buf, "%s:%d: %s", sourcefile, num, fmt);
else formatstring(buf, "%d: %s", num, fmt);
return fmt;
}
-static struct identlink
-{
+static struct identlink {
ident *id;
identlink *next;
int usedargs;
VAR(dbgalias, 0, 4, 1000);
-static void debugalias()
-{
+static void debugalias() {
if(!dbgalias) return;
int total = 0, depth = 0;
for(identlink *l = aliasstack; l != &noalias; l = l->next) total++;
- for(identlink *l = aliasstack; l != &noalias; l = l->next)
- {
+ for(identlink *l = aliasstack; l != &noalias; l = l->next) {
ident *id = l->id;
++depth;
if(depth < dbgalias) conoutf(CON_ERROR, " %d) %s", total-depth+1, id->name);
static void debugcode(const char *fmt, ...) PRINTFARGS(1, 2);
-static void debugcode(const char *fmt, ...)
-{
+static void debugcode(const char *fmt, ...) {
if(nodebug) return;
-
va_list args;
va_start(args, fmt);
conoutfv(CON_ERROR, fmt, args);
va_end(args);
-
debugalias();
}
static void debugcodeline(const char *p, const char *fmt, ...) PRINTFARGS(2, 3);
-static void debugcodeline(const char *p, const char *fmt, ...)
-{
+static void debugcodeline(const char *p, const char *fmt, ...) {
if(nodebug) return;
-
va_list args;
va_start(args, fmt);
conoutfv(CON_ERROR, debugline(p, fmt), args);
va_end(args);
-
debugalias();
}
ICOMMAND(nodebug, "e", (uint *body), { nodebug++; executeret(body, *commandret); nodebug--; });
-void addident(ident *id)
-{
+void addident(ident *id) {
addident(*id);
}
-static inline void pusharg(ident &id, const tagval &v, identstack &stack)
-{
+static inline void pusharg(ident &id, const tagval &v, identstack &stack) {
stack.val = id.val;
stack.valtype = id.valtype;
stack.next = id.stack;
cleancode(id);
}
-static inline void poparg(ident &id)
-{
+static inline void poparg(ident &id) {
if(!id.stack) return;
identstack *stack = id.stack;
if(id.valtype == VAL_STR) delete[] id.val.s;
id.stack = stack->next;
}
-ICOMMAND(push, "rte", (ident *id, tagval *v, uint *code),
-{
+ICOMMAND(push, "rte", (ident *id, tagval *v, uint *code), {
if(id->type != ID_ALIAS || id->index < MAXARGS) return;
identstack stack;
pusharg(*id, *v, stack);
poparg(*id);
});
-static inline void pushalias(ident &id, identstack &stack)
-{
- if(id.type == ID_ALIAS && id.index >= MAXARGS)
- {
+static inline void pushalias(ident &id, identstack &stack) {
+ if(id.type == ID_ALIAS && id.index >= MAXARGS) {
pusharg(id, nullval, stack);
id.flags &= ~IDF_UNKNOWN;
}
}
-static inline void popalias(ident &id)
-{
+static inline void popalias(ident &id) {
if(id.type == ID_ALIAS && id.index >= MAXARGS) poparg(id);
}
KEYWORD(local, ID_LOCAL);
-static inline bool checknumber(const char *s)
-{
+static inline bool checknumber(const char *s) {
if(isdigit(s[0])) return true;
- else switch(s[0])
- {
+ else switch(s[0]) {
case '+': case '-': return isdigit(s[1]) || (s[1] == '.' && isdigit(s[2]));
case '.': return isdigit(s[1]) != 0;
default: return false;
}
}
-ident *newident(const char *name, int flags)
-{
+ident *newident(const char *name, int flags) {
ident *id = idents.access(name);
- if(!id)
- {
- if(checknumber(name))
- {
+ if(!id) {
+ if(checknumber(name)) {
debugcode("number %s is not a valid identifier name", name);
return dummyident;
}
return id;
}
-ident *writeident(const char *name, int flags)
-{
+ident *writeident(const char *name, int flags) {
ident *id = newident(name, flags);
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
- {
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) {
pusharg(*id, nullval, aliasstack->argstack[id->index]);
aliasstack->usedargs |= 1<<id->index;
}
return id;
}
-ident *readident(const char *name)
-{
+ident *readident(const char *name) {
ident *id = idents.access(name);
if(id && id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
return NULL;
return id;
}
-void resetvar(char *name)
-{
+void resetvar(char *name) {
ident *id = idents.access(name);
if(!id) return;
if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
COMMAND(resetvar, "s");
-static inline void setarg(ident &id, tagval &v)
-{
- if(aliasstack->usedargs&(1<<id.index))
- {
+static inline void setarg(ident &id, tagval &v) {
+ if(aliasstack->usedargs&(1<<id.index)) {
if(id.valtype == VAL_STR) delete[] id.val.s;
id.setval(v);
cleancode(id);
}
- else
- {
+ else {
pusharg(id, v, aliasstack->argstack[id.index]);
aliasstack->usedargs |= 1<<id.index;
}
}
-static inline void setalias(ident &id, tagval &v)
-{
+static inline void setalias(ident &id, tagval &v) {
if(id.valtype == VAL_STR) delete[] id.val.s;
id.setval(v);
cleancode(id);
id.flags = (id.flags & identflags) | identflags;
}
-static void setalias(const char *name, tagval &v)
-{
+static void setalias(const char *name, tagval &v) {
ident *id = idents.access(name);
- if(id)
- {
- if(id->type == ID_ALIAS)
- {
+ if(id) {
+ if(id->type == ID_ALIAS) {
if(id->index < MAXARGS) setarg(*id, v); else setalias(*id, v);
}
- else
- {
+ else {
debugcode("cannot redefine builtin %s with an alias", id->name);
freearg(v);
}
}
- else if(checknumber(name))
- {
+ else if(checknumber(name)) {
debugcode("cannot alias number %s", name);
freearg(v);
}
- else
- {
+ else {
addident(ident(ID_ALIAS, newstring(name), v, identflags));
}
}
-void alias(const char *name, const char *str)
-{
+void alias(const char *name, const char *str) {
tagval v;
v.setstr(newstring(str));
setalias(name, v);
}
-void alias(const char *name, tagval &v)
-{
+void alias(const char *name, tagval &v) {
setalias(name, v);
}
-ICOMMAND(alias, "st", (const char *name, tagval *v),
-{
+ICOMMAND(alias, "st", (const char *name, tagval *v), {
setalias(name, *v);
v->type = VAL_NULL;
});
// variable's and commands are registered through globals, see cube.h
-int variable(const char *name, int min, int cur, int max, int *storage, identfun fun, int flags)
-{
+int variable(const char *name, int min, int cur, int max, int *storage, identfun fun, int flags) {
addident(ident(ID_VAR, name, min, max, storage, (void *)fun, flags));
return cur;
}
-float fvariable(const char *name, float min, float cur, float max, float *storage, identfun fun, int flags)
-{
+float fvariable(const char *name, float min, float cur, float max, float *storage, identfun fun, int flags) {
addident(ident(ID_FVAR, name, min, max, storage, (void *)fun, flags));
return cur;
}
-char *svariable(const char *name, const char *cur, char **storage, identfun fun, int flags)
-{
+char *svariable(const char *name, const char *cur, char **storage, identfun fun, int flags) {
addident(ident(ID_SVAR, name, storage, (void *)fun, flags));
return newstring(cur);
}
if(!id || id->type!=vartype) return retval;
#define GETVAR(id, name, retval) _GETVAR(id, ID_VAR, name, retval)
#define OVERRIDEVAR(errorval, saveval, resetval, clearval) \
- if(identflags&IDF_OVERRIDDEN || id->flags&IDF_OVERRIDE) \
- { \
- if(id->flags&IDF_PERSIST) \
- { \
+ if(identflags&IDF_OVERRIDDEN || id->flags&IDF_OVERRIDE) { \
+ \
+ if(id->flags&IDF_PERSIST) { \
+ \
debugcode("cannot override persistent variable %s", id->name); \
errorval; \
} \
if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \
else { clearval; } \
} \
- else \
- { \
+ else { \
+ \
if(id->flags&IDF_OVERRIDDEN) { resetval; id->flags &= ~IDF_OVERRIDDEN; } \
clearval; \
}
-void setvar(const char *name, int i, bool dofunc, bool doclamp)
-{
+void setvar(const char *name, int i, bool dofunc, bool doclamp) {
GETVAR(id, name, );
OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
if(doclamp) *id->storage.i = clamp(i, id->minval, id->maxval);
else *id->storage.i = i;
if(dofunc) id->changed();
}
-void setfvar(const char *name, float f, bool dofunc, bool doclamp)
-{
+void setfvar(const char *name, float f, bool dofunc, bool doclamp) {
_GETVAR(id, ID_FVAR, name, );
OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
if(doclamp) *id->storage.f = clamp(f, id->minvalf, id->maxvalf);
else *id->storage.f = f;
if(dofunc) id->changed();
}
-void setsvar(const char *name, const char *str, bool dofunc)
-{
+void setsvar(const char *name, const char *str, bool dofunc) {
_GETVAR(id, ID_SVAR, name, );
OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] *id->storage.s);
*id->storage.s = newstring(str);
if(dofunc) id->changed();
}
-int getvar(const char *name)
-{
+int getvar(const char *name) {
GETVAR(id, name, 0);
return *id->storage.i;
}
-int getvarmin(const char *name)
-{
+int getvarmin(const char *name) {
GETVAR(id, name, 0);
return id->minval;
}
-int getvarmax(const char *name)
-{
+int getvarmax(const char *name) {
GETVAR(id, name, 0);
return id->maxval;
}
-float getfvarmin(const char *name)
-{
+float getfvarmin(const char *name) {
_GETVAR(id, ID_FVAR, name, 0);
return id->minvalf;
}
-float getfvarmax(const char *name)
-{
+float getfvarmax(const char *name) {
_GETVAR(id, ID_FVAR, name, 0);
return id->maxvalf;
}
bool identexists(const char *name) { return idents.access(name)!=NULL; }
ident *getident(const char *name) { return idents.access(name); }
-void touchvar(const char *name)
-{
+void touchvar(const char *name) {
ident *id = idents.access(name);
- if(id) switch(id->type)
- {
+ if(id) switch(id->type) {
case ID_VAR:
case ID_FVAR:
case ID_SVAR:
}
}
-const char *getalias(const char *name)
-{
+const char *getalias(const char *name) {
ident *i = idents.access(name);
return i && i->type==ID_ALIAS && (i->index >= MAXARGS || aliasstack->usedargs&(1<<i->index)) ? i->getstr() : "";
}
ICOMMAND(getalias, "s", (char *s), result(getalias(s)));
-int clampvar(ident *id, int val, int minval, int maxval)
-{
+int clampvar(ident *id, int val, int minval, int maxval) {
if(val < minval) val = minval;
else if(val > maxval) val = maxval;
else return val;
return val;
}
-void setvarchecked(ident *id, int val)
-{
+void setvarchecked(ident *id, int val) {
if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
#ifndef STANDALONE
- else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
+ else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle()) {
#else
- else
+ else {
#endif
- {
OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
if(val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval);
*id->storage.i = val;
}
}
-static inline void setvarchecked(ident *id, tagval *args, int numargs)
-{
+static inline void setvarchecked(ident *id, tagval *args, int numargs) {
int val = forceint(args[0]);
- if(id->flags&IDF_HEX && numargs > 1)
- {
+ if(id->flags&IDF_HEX && numargs > 1) {
val = (val << 16) | (forceint(args[1])<<8);
if(numargs > 2) val |= forceint(args[2]);
}
setvarchecked(id, val);
}
-float clampfvar(ident *id, float val, float minval, float maxval)
-{
+float clampfvar(ident *id, float val, float minval, float maxval) {
if(val < minval) val = minval;
else if(val > maxval) val = maxval;
else return val;
return val;
}
-void setfvarchecked(ident *id, float val)
-{
+void setfvarchecked(ident *id, float val) {
if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
#ifndef STANDALONE
- else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
+ else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle()) {
#else
- else
+ else {
#endif
- {
OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
if(val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf);
*id->storage.f = val;
}
}
-void setsvarchecked(ident *id, const char *val)
-{
+void setsvarchecked(ident *id, const char *val) {
if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
#ifndef STANDALONE
- else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
+ else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle()) {
#else
- else
+ else {
#endif
- {
OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] *id->storage.s);
*id->storage.s = newstring(val);
id->changed();
}
}
-ICOMMAND(set, "rt", (ident *id, tagval *v),
-{
- switch(id->type)
- {
+ICOMMAND(set, "rt", (ident *id, tagval *v), {
+ switch(id->type) {
case ID_ALIAS:
if(id->index < MAXARGS) setarg(*id, *v); else setalias(*id, *v);
v->type = VAL_NULL;
setsvarchecked(id, forcestr(*v));
break;
case ID_COMMAND:
- if(id->flags&IDF_EMUVAR)
- {
+ if(id->flags&IDF_EMUVAR) {
execute(id, v, 1);
v->type = VAL_NULL;
break;
}
});
-bool addcommand(const char *name, identfun fun, const char *args)
-{
+bool addcommand(const char *name, identfun fun, const char *args) {
uint argmask = 0;
int numargs = 0, flags = 0;
bool limit = true;
- for(const char *fmt = args; *fmt; fmt++) switch(*fmt)
- {
+ for(const char *fmt = args; *fmt; fmt++) switch(*fmt) {
case 'i': case 'b': case 'f': case 't': case 'N': case 'D': if(numargs < MAXARGS) numargs++; break;
case '$': flags |= IDF_EMUVAR; // fall through
case 's': case 'e': case 'r': if(numargs < MAXARGS) { argmask |= 1<<numargs; numargs++; } break;
return false;
}
-bool addkeyword(int type, const char *name)
-{
+bool addkeyword(int type, const char *name) {
addident(ident(type, name, "", 0, 0, NULL));
return true;
}
-const char *parsestring(const char *p)
-{
- for(; *p; p++) switch(*p)
- {
+const char *parsestring(const char *p) {
+ for(; *p; p++) switch(*p) {
case '\r':
case '\n':
case '\"':
return p;
}
-int unescapestring(char *dst, const char *src, const char *end)
-{
+int unescapestring(char *dst, const char *src, const char *end) {
char *start = dst;
- while(src < end)
- {
+ while(src < end) {
int c = *src++;
- if(c == '^')
- {
+ if(c == '^') {
if(src >= end) break;
int e = *src++;
- switch(e)
- {
+ switch(e) {
case 'n': *dst++ = '\n'; break;
case 't': *dst++ = '\t'; break;
case 'f': *dst++ = '\f'; break;
return dst - start;
}
-static char *conc(vector<char> &buf, tagval *v, int n, bool space, const char *prefix = NULL, int prefixlen = 0)
-{
- if(prefix)
- {
+static char *conc(vector<char> &buf, tagval *v, int n, bool space, const char *prefix = NULL, int prefixlen = 0) {
+ if(prefix) {
buf.put(prefix, prefixlen);
if(space && n) buf.add(' ');
}
- loopi(n)
- {
+ loopi(n) {
const char *s = "";
int len = 0;
- switch(v[i].type)
- {
+ switch(v[i].type) {
case VAL_INT: s = intstr(v[i].i); break;
case VAL_FLOAT: s = floatstr(v[i].f); break;
case VAL_STR: s = v[i].s; break;
return buf.getbuf();
}
-static char *conc(tagval *v, int n, bool space, const char *prefix, int prefixlen)
-{
+static char *conc(tagval *v, int n, bool space, const char *prefix, int prefixlen) {
static int vlen[MAXARGS];
static char numbuf[3*MAXSTRLEN];
int len = prefixlen, numlen = 0, i = 0;
- for(; i < n; i++) switch(v[i].type)
- {
+ for(; i < n; i++) switch(v[i].type) {
case VAL_MACRO: len += (vlen[i] = v[i].code[-1]>>8); break;
case VAL_STR: len += (vlen[i] = int(strlen(v[i].s))); break;
case VAL_INT:
if(space) len += max(prefix ? i : i-1, 0);
char *buf = newstring(len + numlen);
int offset = 0, numoffset = 0;
- if(prefix)
- {
+ if(prefix) {
memcpy(buf, prefix, prefixlen);
offset += prefixlen;
if(space && i) buf[offset++] = ' ';
}
- loopj(i)
- {
- if(v[j].type == VAL_INT || v[j].type == VAL_FLOAT)
- {
+ loopj(i) {
+ if(v[j].type == VAL_INT || v[j].type == VAL_FLOAT) {
memcpy(&buf[offset], &numbuf[numoffset], vlen[j]);
numoffset += vlen[j];
}
if(space) buf[offset++] = ' ';
}
buf[offset] = '\0';
- if(i < n)
- {
+ if(i < n) {
char *morebuf = conc(&v[i], n-i, space, buf, offset);
delete[] buf;
return morebuf;
return buf;
}
-static inline char *conc(tagval *v, int n, bool space)
-{
+static inline char *conc(tagval *v, int n, bool space) {
return conc(v, n, space, NULL, 0);
}
-static inline char *conc(tagval *v, int n, bool space, const char *prefix)
-{
+static inline char *conc(tagval *v, int n, bool space, const char *prefix) {
return conc(v, n, space, prefix, strlen(prefix));
}
-static inline void skipcomments(const char *&p)
-{
- for(;;)
- {
+static inline void skipcomments(const char *&p) {
+ for(;;) {
p += strspn(p, " \t\r");
if(p[0]!='/' || p[1]!='/') break;
p += strcspn(p, "\n\0");
}
}
-static inline char *cutstring(const char *&p, int &len)
-{
+static inline char *cutstring(const char *&p, int &len) {
p++;
const char *end = parsestring(p);
char *s = newstring(end - p);
return s;
}
-static inline const char *parseword(const char *p)
-{
+static inline const char *parseword(const char *p) {
const int maxbrak = 100;
static char brakstack[maxbrak];
int brakdepth = 0;
- for(;; p++)
- {
+ for(;; p++) {
p += strcspn(p, "\"/;()[] \t\r\n\0");
- switch(p[0])
- {
+ switch(p[0]) {
case '"': case ';': case ' ': case '\t': case '\r': case '\n': case '\0': return p;
case '/': if(p[1] == '/') return p; break;
case '[': case '(': if(brakdepth >= maxbrak) return p; brakstack[brakdepth++] = p[0]; break;
return p;
}
-static inline char *cutword(const char *&p, int &len)
-{
+static inline char *cutword(const char *&p, int &len) {
const char *word = p;
p = parseword(p);
len = p-word;
return newstring(word, len);
}
-static inline void compilestr(vector<uint> &code, const char *word, int len, bool macro = false)
-{
- if(len <= 3 && !macro)
- {
+static inline void compilestr(vector<uint> &code, const char *word, int len, bool macro = false) {
+ if(len <= 3 && !macro) {
uint op = CODE_VALI|RET_STR;
for(int i = 0; i < len; i++) op |= uint(uchar(word[i]))<<((i+1)*8);
code.add(op);
code.add((macro ? CODE_MACRO : CODE_VAL|RET_STR)|(len<<8));
code.put((const uint *)word, len/sizeof(uint));
size_t endlen = len%sizeof(uint);
- union
- {
+ union {
char c[sizeof(uint)];
uint u;
} end;
code.add(end.u);
}
-static inline void compilestr(vector<uint> &code, const char *word = NULL)
-{
+static inline void compilestr(vector<uint> &code, const char *word = NULL) {
if(!word) { code.add(CODE_VALI|RET_STR); return; }
compilestr(code, word, int(strlen(word)));
}
-static inline void compileint(vector<uint> &code, int i)
-{
+static inline void compileint(vector<uint> &code, int i) {
if(i >= -0x800000 && i <= 0x7FFFFF)
code.add(CODE_VALI|RET_INT|(i<<8));
- else
- {
+ else {
code.add(CODE_VAL|RET_INT);
code.add(i);
}
}
-static inline void compilenull(vector<uint> &code)
-{
+static inline void compilenull(vector<uint> &code) {
code.add(CODE_VALI|RET_NULL);
}
-static inline void compileblock(vector<uint> &code)
-{
+static inline void compileblock(vector<uint> &code) {
int start = code.length();
code.add(CODE_BLOCK);
code.add(CODE_OFFSET|((start+2)<<8));
code[start] |= uint(code.length() - (start + 1))<<8;
}
-static inline void compileident(vector<uint> &code, ident *id)
-{
+static inline void compileident(vector<uint> &code, ident *id) {
code.add((id->index < MAXARGS ? CODE_IDENTARG : CODE_IDENT)|(id->index<<8));
}
-static inline void compileident(vector<uint> &code, const char *word = NULL)
-{
+static inline void compileident(vector<uint> &code, const char *word = NULL) {
compileident(code, word ? newident(word, IDF_UNKNOWN) : dummyident);
}
-static inline void compileint(vector<uint> &code, const char *word = NULL)
-{
+static inline void compileint(vector<uint> &code, const char *word = NULL) {
return compileint(code, word ? parseint(word) : 0);
}
-static inline void compilefloat(vector<uint> &code, float f)
-{
+static inline void compilefloat(vector<uint> &code, float f) {
if(int(f) == f && f >= -0x800000 && f <= 0x7FFFFF)
code.add(CODE_VALI|RET_FLOAT|(int(f)<<8));
- else
- {
+ else {
union { float f; uint u; } conv;
conv.f = f;
code.add(CODE_VAL|RET_FLOAT);
}
}
-static inline void compilefloat(vector<uint> &code, const char *word = NULL)
-{
+static inline void compilefloat(vector<uint> &code, const char *word = NULL) {
return compilefloat(code, word ? parsefloat(word) : 0.0f);
}
static bool compilearg(vector<uint> &code, const char *&p, int wordtype);
static void compilestatements(vector<uint> &code, const char *&p, int rettype, int brak = '\0');
-static inline void compileval(vector<uint> &code, int wordtype, char *word, int wordlen)
-{
- switch(wordtype)
- {
+static inline void compileval(vector<uint> &code, int wordtype, char *word, int wordlen) {
+ switch(wordtype) {
case VAL_STR: compilestr(code, word, wordlen, true); break;
case VAL_ANY: compilestr(code, word, wordlen); break;
case VAL_FLOAT: compilefloat(code, word); break;
case VAL_INT: compileint(code, word); break;
- case VAL_CODE:
- {
+ case VAL_CODE: {
int start = code.length();
code.add(CODE_BLOCK);
code.add(CODE_OFFSET|((start+2)<<8));
static bool compileword(vector<uint> &code, const char *&p, int wordtype, char *&word, int &wordlen);
-static void compilelookup(vector<uint> &code, const char *&p, int ltype)
-{
+static void compilelookup(vector<uint> &code, const char *&p, int ltype) {
char *lookup = NULL;
int lookuplen = 0;
- switch(*++p)
- {
+ switch(*++p) {
case '(':
case '[':
if(!compileword(code, p, VAL_STR, lookup, lookuplen)) goto invalid;
case '\"':
lookup = cutstring(p, lookuplen);
goto lookupid;
- default:
- {
+ default: {
lookup = cutword(p, lookuplen);
if(!lookup) goto invalid;
lookupid:
ident *id = newident(lookup, IDF_UNKNOWN);
- if(id) switch(id->type)
- {
+ if(id) switch(id->type) {
case ID_VAR: code.add(CODE_IVAR|((ltype >= VAL_ANY ? VAL_INT : ltype)<<CODE_RET)|(id->index<<8)); goto done;
case ID_FVAR: code.add(CODE_FVAR|((ltype >= VAL_ANY ? VAL_FLOAT : ltype)<<CODE_RET)|(id->index<<8)); goto done;
case ID_SVAR: code.add(CODE_SVAR|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
case ID_ALIAS: code.add((id->index < MAXARGS ? CODE_LOOKUPARG : CODE_LOOKUP)|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
- case ID_COMMAND:
- {
+ case ID_COMMAND: {
int comtype = CODE_COM, numargs = 0;
code.add(CODE_ENTER);
- for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
- {
+ for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt) {
case 's': compilestr(code, NULL, 0, true); numargs++; break;
case 'i': compileint(code); numargs++; break;
case 'b': compileint(code, INT_MIN); numargs++; break;
code.add(CODE_LOOKUPU|((ltype < VAL_ANY ? ltype<<CODE_RET : 0)));
done:
delete[] lookup;
- switch(ltype)
- {
+ switch(ltype) {
case VAL_CODE: code.add(CODE_COMPILE); break;
case VAL_IDENT: code.add(CODE_IDENTU); break;
}
return;
invalid:
- switch(ltype)
- {
+ switch(ltype) {
case VAL_NULL: case VAL_ANY: compilenull(code); break;
default: compileval(code, ltype, NULL, 0); break;
}
}
-static bool compileblockstr(vector<uint> &code, const char *str, const char *end, bool macro)
-{
+static bool compileblockstr(vector<uint> &code, const char *str, const char *end, bool macro) {
int start = code.length();
code.add(macro ? CODE_MACRO : CODE_VAL|RET_STR);
char *buf = (char *)code.reserve((end-str)/sizeof(uint)+1).buf;
int len = 0;
- while(str < end)
- {
+ while(str < end) {
int n = strcspn(str, "\r/\"@]\0");
memcpy(&buf[len], str, n);
len += n;
str += n;
- switch(*str)
- {
+ switch(*str) {
case '\r': str++; break;
- case '\"':
- {
+ case '\"': {
const char *start = str;
str = parsestring(str+1);
if(*str=='\"') str++;
break;
}
case '/':
- if(str[1] == '/')
- {
+ if(str[1] == '/') {
size_t comment = strcspn(str, "\n\0");
- if (iscubepunct(str[2]))
- {
+ if (iscubepunct(str[2])) {
memcpy(&buf[len], str, comment);
len += comment;
}
return true;
}
-static bool compileblocksub(vector<uint> &code, const char *&p)
-{
+static bool compileblocksub(vector<uint> &code, const char *&p) {
char *lookup = NULL;
int lookuplen = 0;
- switch(*p)
- {
+ switch(*p) {
case '(':
if(!compilearg(code, p, VAL_STR)) return false;
break;
case '\"':
lookup = cutstring(p, lookuplen);
goto lookupid;
- default:
- {
- {
+ default: {
+ {
const char *start = p;
while(iscubealnum(*p) || *p=='_') p++;
lookuplen = p-start;
}
lookupid:
ident *id = newident(lookup, IDF_UNKNOWN);
- if(id) switch(id->type)
- {
+ if(id) switch(id->type) {
case ID_VAR: code.add(CODE_IVAR|RET_STR|(id->index<<8)); goto done;
case ID_FVAR: code.add(CODE_FVAR|RET_STR|(id->index<<8)); goto done;
case ID_SVAR: code.add(CODE_SVAR|RET_STR|(id->index<<8)); goto done;
return true;
}
-static void compileblock(vector<uint> &code, const char *&p, int wordtype)
-{
+static void compileblock(vector<uint> &code, const char *&p, int wordtype) {
const char *line = p, *start = p;
int concs = 0;
- for(int brak = 1; brak;)
- {
+ for(int brak = 1; brak;) {
p += strcspn(p, "@\"/[]\0");
int c = *p++;
- switch(c)
- {
+ switch(c) {
case '\0':
debugcodeline(line, "missing \"]\"");
p--;
break;
case '[': brak++; break;
case ']': brak--; break;
- case '@':
- {
+ case '@': {
const char *esc = p;
while(*p == '@') p++;
int level = p - (esc - 1);
if(brak > level) continue;
else if(brak < level) debugcodeline(line, "too many @s");
if(!concs) code.add(CODE_ENTER);
- if(concs + 2 > MAXARGS)
- {
+ if(concs + 2 > MAXARGS) {
code.add(CODE_CONCW|RET_STR|(concs<<8));
concs = 1;
}
}
}
done:
- if(p-1 > start)
- {
- if(!concs) switch(wordtype)
- {
- case VAL_CODE:
- {
+ if(p-1 > start) {
+ if(!concs) switch(wordtype) {
+ case VAL_CODE: {
p = start;
int inst = code.length();
code.add(CODE_BLOCK);
code[inst] |= uint(code.length() - (inst + 1))<<8;
return;
}
- case VAL_IDENT:
- {
+ case VAL_IDENT: {
char *name = newstring(start, p-1-start);
compileident(code, name);
delete[] name;
compileblockstr(code, start, p-1, concs > 0);
if(concs > 1) concs++;
}
- if(concs)
- {
+ if(concs) {
code.add(CODE_CONCM|(wordtype < VAL_ANY ? wordtype<<CODE_RET : RET_STR)|(concs<<8));
code.add(CODE_EXIT|(wordtype < VAL_ANY ? wordtype<<CODE_RET : RET_STR));
}
- switch(wordtype)
- {
+ switch(wordtype) {
case VAL_CODE: if(!concs && p-1 <= start) compileblock(code); else code.add(CODE_COMPILE); break;
case VAL_IDENT: if(!concs && p-1 <= start) compileident(code); else code.add(CODE_IDENTU); break;
case VAL_STR: case VAL_NULL: case VAL_ANY:
if(!concs && p-1 <= start) compilestr(code);
break;
default:
- if(!concs)
- {
+ if(!concs) {
if(p-1 <= start) compileval(code, wordtype, NULL, 0);
else code.add(CODE_FORCE|(wordtype<<CODE_RET));
}
}
}
-static bool compileword(vector<uint> &code, const char *&p, int wordtype, char *&word, int &wordlen)
-{
+static bool compileword(vector<uint> &code, const char *&p, int wordtype, char *&word, int &wordlen) {
skipcomments(p);
- switch(*p)
- {
+ switch(*p) {
case '\"': word = cutstring(p, wordlen); break;
case '$': compilelookup(code, p, wordtype); return true;
case '(':
code.add(CODE_ENTER);
compilestatements(code, p, VAL_ANY, ')');
code.add(CODE_EXIT|(wordtype < VAL_ANY ? wordtype<<CODE_RET : 0));
- switch(wordtype)
- {
+ switch(wordtype) {
case VAL_CODE: code.add(CODE_COMPILE); break;
case VAL_IDENT: code.add(CODE_IDENTU); break;
}
return word!=NULL;
}
-static inline bool compilearg(vector<uint> &code, const char *&p, int wordtype)
-{
+static inline bool compilearg(vector<uint> &code, const char *&p, int wordtype) {
char *word = NULL;
int wordlen = 0;
bool more = compileword(code, p, wordtype, word, wordlen);
if(!more) return false;
- if(word)
- {
+ if(word) {
compileval(code, wordtype, word, wordlen);
delete[] word;
}
return true;
}
-static void compilestatements(vector<uint> &code, const char *&p, int rettype, int brak)
-{
+static void compilestatements(vector<uint> &code, const char *&p, int rettype, int brak) {
const char *line = p;
char *idname = NULL;
int idlen = 0;
ident *id = NULL;
int numargs = 0;
- for(;;)
- {
+ for(;;) {
skipcomments(p);
idname = NULL;
bool more = compileword(code, p, VAL_ANY, idname, idlen);
if(!more) goto endstatement;
skipcomments(p);
- if(p[0] == '=') switch(p[1])
- {
+ if(p[0] == '=') switch(p[1]) {
case '/':
if(p[2] != '/') break;
[[fallthrough]];
[[fallthrough]];
case '\0':
p++;
- if(idname)
- {
+ if(idname) {
id = newident(idname, IDF_UNKNOWN);
- if(id) switch(id->type)
- {
+ if(id) switch(id->type) {
case ID_ALIAS:
if(!(more = compilearg(code, p, VAL_ANY))) compilestr(code);
code.add((id->index < MAXARGS ? CODE_ALIASARG : CODE_ALIAS)|(id->index<<8));
}
compilecommand:
numargs = 0;
- if(!idname)
- {
+ if(!idname) {
noid:
while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++;
code.add(CODE_CALLU);
}
- else
- {
+ else {
id = idents.access(idname);
- if(!id)
- {
+ if(!id) {
if(!checknumber(idname)) { compilestr(code, idname, idlen); delete[] idname; goto noid; }
char *end = idname;
int val = int(strtoul(idname, &end, 0));
else compileint(code, val);
code.add(CODE_RESULT);
}
- else switch(id->type)
- {
+ else switch(id->type) {
case ID_ALIAS:
while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++;
code.add((id->index < MAXARGS ? CODE_CALLARG : CODE_CALL)|(id->index<<8));
break;
- case ID_COMMAND:
- {
+ case ID_COMMAND: {
int comtype = CODE_COM, fakeargs = 0;
bool rep = false;
- for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
- {
+ for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt) {
case 's':
if(more) more = compilearg(code, p, VAL_STR);
- if(!more)
- {
+ if(!more) {
if(rep) break;
compilestr(code, NULL, 0, true);
fakeargs++;
}
- else if(!fmt[1])
- {
+ else if(!fmt[1]) {
int numconc = 0;
while(numargs + numconc < MAXARGS && (more = compilearg(code, p, VAL_STR))) numconc++;
if(numconc > 0) code.add(CODE_CONC|RET_STR|((numconc+1)<<8));
case 'C': comtype = CODE_COMC; if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++; numargs = 1; goto endfmt;
case 'V': comtype = CODE_COMV; if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++; numargs = 2; goto endfmt;
case '1': case '2': case '3': case '4':
- if(more && numargs < MAXARGS)
- {
+ if(more && numargs < MAXARGS) {
int numrep = *fmt-'0'+1;
fmt -= numrep;
rep = true;
break;
case ID_SVAR:
if(!(more = compilearg(code, p, VAL_STR))) code.add(CODE_PRINT|(id->index<<8));
- else
- {
+ else {
int numconc = 0;
while(numconc+1 < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numconc++;
if(numconc > 0) code.add(CODE_CONC|RET_STR|((numconc+1)<<8));
if(more) while(compilearg(code, p, VAL_ANY)) code.add(CODE_POP);
p += strcspn(p, ")];/\n\0");
int c = *p++;
- switch(c)
- {
+ switch(c) {
case '\0':
if(c != brak) debugcodeline(line, "missing \"%c\"", brak);
p--;
return;
-
case ')':
case ']':
if(c == brak) return;
debugcodeline(line, "unexpected \"%c\"", c);
break;
-
case '/':
if(*p == '/') p += strcspn(p, "\n\0");
goto endstatement;
}
}
-static void compilemain(vector<uint> &code, const char *p, int rettype = VAL_ANY)
-{
+static void compilemain(vector<uint> &code, const char *p, int rettype = VAL_ANY) {
code.add(CODE_START);
compilestatements(code, p, VAL_ANY);
code.add(CODE_EXIT|(rettype < VAL_ANY ? rettype<<CODE_RET : 0));
}
-uint *compilecode(const char *p)
-{
+uint *compilecode(const char *p) {
vector<uint> buf;
buf.reserve(64);
compilemain(buf, p);
return code;
}
-void keepcode(uint *code)
-{
+void keepcode(uint *code) {
if(!code) return;
- switch(*code&CODE_OP_MASK)
- {
+ switch(*code&CODE_OP_MASK) {
case CODE_START:
*code += 0x100;
return;
}
- switch(code[-1]&CODE_OP_MASK)
- {
+ switch(code[-1]&CODE_OP_MASK) {
case CODE_START:
code[-1] += 0x100;
break;
}
}
-void freecode(uint *code)
-{
+void freecode(uint *code) {
if(!code) return;
- switch(*code&CODE_OP_MASK)
- {
+ switch(*code&CODE_OP_MASK) {
case CODE_START:
*code -= 0x100;
if(int(*code) < 0x100) delete[] code;
return;
}
- switch(code[-1]&CODE_OP_MASK)
- {
+ switch(code[-1]&CODE_OP_MASK) {
case CODE_START:
code[-1] -= 0x100;
if(int(code[-1]) < 0x100) delete[] &code[-1];
}
}
-void printvar(ident *id, int i)
-{
+void printvar(ident *id, int i) {
if(i < 0) conoutf(CON_INFO, id->index, "%s = %d", id->name, i);
else if(id->flags&IDF_HEX && id->maxval==0xFFFFFF)
conoutf(CON_INFO, id->index, "%s = 0x%.6X (%d, %d, %d)", id->name, i, (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF);
conoutf(CON_INFO, id->index, id->flags&IDF_HEX ? "%s = 0x%X" : "%s = %d", id->name, i);
}
-void printfvar(ident *id, float f)
-{
+void printfvar(ident *id, float f) {
conoutf(CON_INFO, id->index, "%s = %s", id->name, floatstr(f));
}
-void printsvar(ident *id, const char *s)
-{
+void printsvar(ident *id, const char *s) {
conoutf(CON_INFO, id->index, strchr(s, '"') ? "%s = [%s]" : "%s = \"%s\"", id->name, s);
}
template <class V>
-static void printvar(ident *id, int type, V &val)
-{
- switch(type)
- {
+static void printvar(ident *id, int type, V &val) {
+ switch(type) {
case VAL_INT: printvar(id, val.getint()); break;
case VAL_FLOAT: printfvar(id, val.getfloat()); break;
default: printsvar(id, val.getstr()); break;
}
}
-void printvar(ident *id)
-{
- switch(id->type)
- {
+void printvar(ident *id) {
+ switch(id->type) {
case ID_VAR: printvar(id, *id->storage.i); break;
case ID_FVAR: printfvar(id, *id->storage.f); break;
case ID_SVAR: printsvar(id, *id->storage.s); break;
case ID_ALIAS: printvar(id, id->valtype, *id); break;
case ID_COMMAND:
- if(id->flags&IDF_EMUVAR)
- {
+ if(id->flags&IDF_EMUVAR) {
tagval result;
executeret(id, NULL, 0, true, result);
printvar(id, result.type, result);
typedef void (__cdecl *comfun12)(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *);
typedef void (__cdecl *comfunv)(tagval *, int);
-static const uint *skipcode(const uint *code, tagval &result)
-{
+static const uint *skipcode(const uint *code, tagval &result) {
int depth = 0;
- for(;;)
- {
+ for(;;) {
uint op = *code++;
- switch(op&0xFF)
- {
+ switch(op&0xFF) {
case CODE_MACRO:
- case CODE_VAL|RET_STR:
- {
+ case CODE_VAL|RET_STR: {
uint len = op>>8;
code += len/sizeof(uint) + 1;
continue;
}
- case CODE_BLOCK:
- {
+ case CODE_BLOCK: {
uint len = op>>8;
code += len;
continue;
++depth;
continue;
case CODE_EXIT|RET_NULL: case CODE_EXIT|RET_STR: case CODE_EXIT|RET_INT: case CODE_EXIT|RET_FLOAT:
- if(depth <= 0)
- {
+ if(depth <= 0) {
forcearg(result, op&CODE_RET_MASK);
return code;
}
}
}
-static inline void callcommand(ident *id, tagval *args, int numargs, bool lookup = false)
-{
+static inline void callcommand(ident *id, tagval *args, int numargs, bool lookup = false) {
int i = -1, fakeargs = 0;
bool rep = false;
- for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
- {
+ for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt) {
case 'i': if(++i >= numargs) { if(rep) break; args[i].setint(0); fakeargs++; } else forceint(args[i]); break;
case 'b': if(++i >= numargs) { if(rep) break; args[i].setint(INT_MIN); fakeargs++; } else forceint(args[i]); break;
case 'f': if(++i >= numargs) { if(rep) break; args[i].setfloat(0.0f); fakeargs++; } else forcefloat(args[i]); break;
case 's': if(++i >= numargs) { if(rep) break; args[i].setstr(newstring("")); fakeargs++; } else forcestr(args[i]); break;
case 't': if(++i >= numargs) { if(rep) break; args[i].setnull(); fakeargs++; } break;
case 'e':
- if(++i >= numargs)
- {
+ if(++i >= numargs) {
if(rep) break;
static uint buf[2] = { CODE_START + 0x100, CODE_EXIT };
args[i].setcode(buf);
fakeargs++;
}
- else
- {
+ else {
vector<uint> buf;
buf.reserve(64);
compilemain(buf, numargs <= i ? "" : args[i].getstr());
}
#define ARG(n) (id->argmask&(1<<n) ? (void *)args[n].s : (void *)&args[n].i)
#define CALLCOM(n) \
- switch(n) \
- { \
+ switch(n) { \
+ \
case 0: ((comfun)id->fun)(); break; \
case 1: ((comfun1)id->fun)(ARG(0)); break; \
case 2: ((comfun2)id->fun)(ARG(0), ARG(1)); break; \
#define MAXRUNDEPTH 255
static int rundepth = 0;
-static const uint *runcode(const uint *code, tagval &result)
-{
+static const uint *runcode(const uint *code, tagval &result) {
result.setnull();
- if(rundepth >= MAXRUNDEPTH)
- {
+ if(rundepth >= MAXRUNDEPTH) {
debugcode("exceeded recursion limit");
return skipcode(code, result);
}
int numargs = 0;
tagval args[MAXARGS+1], *prevret = commandret;
commandret = &result;
- for(;;)
- {
+ for(;;) {
uint op = *code++;
- switch(op&0xFF)
- {
+ switch(op&0xFF) {
case CODE_START: case CODE_OFFSET: continue;
-
case CODE_POP:
freearg(args[--numargs]);
continue;
case CODE_PRINT:
printvar(identmap[op>>8]);
continue;
- case CODE_LOCAL:
- {
+ case CODE_LOCAL: {
identstack locals[MAXARGS];
freearg(result);
loopi(numargs) pushalias(*args[i].id, locals[i]);
loopi(numargs) popalias(*args[i].id);
goto exit;
}
-
- case CODE_MACRO:
- {
+ case CODE_MACRO: {
uint len = op>>8;
args[numargs++].setmacro(code);
code += len/sizeof(uint) + 1;
continue;
}
-
- case CODE_VAL|RET_STR:
- {
+ case CODE_VAL|RET_STR: {
uint len = op>>8;
args[numargs++].setstr(newstring((const char *)code, len));
code += len/sizeof(uint) + 1;
continue;
}
- case CODE_VALI|RET_STR:
- {
+ case CODE_VALI|RET_STR: {
char s[4] = { char((op>>8)&0xFF), char((op>>16)&0xFF), char((op>>24)&0xFF), '\0' };
args[numargs++].setstr(newstring(s));
continue;
case CODE_VALI|RET_INT: args[numargs++].setint(int(op)>>8); continue;
case CODE_VAL|RET_FLOAT: args[numargs++].setfloat(*(const float *)code++); continue;
case CODE_VALI|RET_FLOAT: args[numargs++].setfloat(float(int(op)>>8)); continue;
-
case CODE_FORCE|RET_STR: forcestr(args[numargs-1]); continue;
case CODE_FORCE|RET_INT: forceint(args[numargs-1]); continue;
case CODE_FORCE|RET_FLOAT: forcefloat(args[numargs-1]); continue;
-
case CODE_RESULT|RET_NULL: case CODE_RESULT|RET_STR: case CODE_RESULT|RET_INT: case CODE_RESULT|RET_FLOAT:
litval:
freearg(result);
args[0].setnull();
freeargs(args, numargs, 0);
continue;
-
- case CODE_BLOCK:
- {
+ case CODE_BLOCK: {
uint len = op>>8;
args[numargs++].setcode(code+1);
code += len;
continue;
}
- case CODE_COMPILE:
- {
+ case CODE_COMPILE: {
tagval &arg = args[numargs-1];
vector<uint> buf;
- switch(arg.type)
- {
+ switch(arg.type) {
case VAL_INT: buf.reserve(8); buf.add(CODE_START); compileint(buf, arg.i); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
case VAL_FLOAT: buf.reserve(8); buf.add(CODE_START); compilefloat(buf, arg.f); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
case VAL_STR: case VAL_MACRO: buf.reserve(64); compilemain(buf, arg.s); freearg(arg); break;
buf.disown();
continue;
}
-
case CODE_IDENT:
args[numargs++].setident(identmap[op>>8]);
continue;
- case CODE_IDENTARG:
- {
+ case CODE_IDENTARG: {
ident *id = identmap[op>>8];
- if(!(aliasstack->usedargs&(1<<id->index)))
- {
+ if(!(aliasstack->usedargs&(1<<id->index))) {
pusharg(*id, nullval, aliasstack->argstack[id->index]);
aliasstack->usedargs |= 1<<id->index;
}
args[numargs++].setident(id);
continue;
}
- case CODE_IDENTU:
- {
+ case CODE_IDENTU: {
tagval &arg = args[numargs-1];
ident *id = arg.type == VAL_STR || arg.type == VAL_MACRO ? newident(arg.s, IDF_UNKNOWN) : dummyident;
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
- {
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) {
pusharg(*id, nullval, aliasstack->argstack[id->index]);
aliasstack->usedargs |= 1<<id->index;
}
arg.setident(id);
continue;
}
-
case CODE_LOOKUPU|RET_STR:
#define LOOKUPU(aval, sval, ival, fval, nval) { \
tagval &arg = args[numargs-1]; \
if(arg.type != VAL_STR && arg.type != VAL_MACRO) continue; \
id = idents.access(arg.s); \
- if(id) switch(id->type) \
- { \
+ if(id) switch(id->type) { \
+ \
case ID_ALIAS: \
if(id->flags&IDF_UNKNOWN) break; \
freearg(arg); \
case ID_SVAR: freearg(arg); sval; continue; \
case ID_VAR: freearg(arg); ival; continue; \
case ID_FVAR: freearg(arg); fval; continue; \
- case ID_COMMAND: \
- { \
+ case ID_COMMAND: { \
+ \
freearg(arg); \
arg.setnull(); \
commandret = &arg; \
LOOKUP(id->getval(args[numargs++]));
case CODE_LOOKUPARG|RET_NULL:
LOOKUPARG(id->getval(args[numargs++]), args[numargs++].setnull());
-
case CODE_SVAR|RET_STR: case CODE_SVAR|RET_NULL: args[numargs++].setstr(newstring(*identmap[op>>8]->storage.s)); continue;
case CODE_SVAR|RET_INT: args[numargs++].setint(parseint(*identmap[op>>8]->storage.s)); continue;
case CODE_SVAR|RET_FLOAT: args[numargs++].setfloat(parsefloat(*identmap[op>>8]->storage.s)); continue;
case CODE_SVAR1: setsvarchecked(identmap[op>>8], args[0].s); freeargs(args, numargs, 0); continue;
-
case CODE_IVAR|RET_INT: case CODE_IVAR|RET_NULL: args[numargs++].setint(*identmap[op>>8]->storage.i); continue;
case CODE_IVAR|RET_STR: args[numargs++].setstr(newstring(intstr(*identmap[op>>8]->storage.i))); continue;
case CODE_IVAR|RET_FLOAT: args[numargs++].setfloat(float(*identmap[op>>8]->storage.i)); continue;
case CODE_IVAR1: setvarchecked(identmap[op>>8], args[0].i); numargs = 0; continue;
case CODE_IVAR2: setvarchecked(identmap[op>>8], (args[0].i<<16)|(args[1].i<<8)); numargs = 0; continue;
case CODE_IVAR3: setvarchecked(identmap[op>>8], (args[0].i<<16)|(args[1].i<<8)|args[2].i); numargs = 0; continue;
-
case CODE_FVAR|RET_FLOAT: case CODE_FVAR|RET_NULL: args[numargs++].setfloat(*identmap[op>>8]->storage.f); continue;
case CODE_FVAR|RET_STR: args[numargs++].setstr(newstring(floatstr(*identmap[op>>8]->storage.f))); continue;
case CODE_FVAR|RET_INT: args[numargs++].setint(int(*identmap[op>>8]->storage.f)); continue;
case CODE_FVAR1: setfvarchecked(identmap[op>>8], args[0].f); numargs = 0; continue;
-
case CODE_COM|RET_NULL: case CODE_COM|RET_STR: case CODE_COM|RET_FLOAT: case CODE_COM|RET_INT:
id = identmap[op>>8];
#ifndef STANDALONE
goto forceresult;
case CODE_COMC|RET_NULL: case CODE_COMC|RET_STR: case CODE_COMC|RET_FLOAT: case CODE_COMC|RET_INT:
id = identmap[op>>8];
- forcenull(result);
- {
+ forcenull(result); {
vector<char> buf;
buf.reserve(MAXSTRLEN);
((comfun1)id->fun)(conc(buf, args, numargs, true));
}
goto forceresult;
-
case CODE_CONC|RET_NULL: case CODE_CONC|RET_STR: case CODE_CONC|RET_FLOAT: case CODE_CONC|RET_INT:
- case CODE_CONCW|RET_NULL: case CODE_CONCW|RET_STR: case CODE_CONCW|RET_FLOAT: case CODE_CONCW|RET_INT:
- {
+ case CODE_CONCW|RET_NULL: case CODE_CONCW|RET_STR: case CODE_CONCW|RET_FLOAT: case CODE_CONCW|RET_INT: {
int numconc = op>>8;
char *s = conc(&args[numargs-numconc], numconc, (op&CODE_OP_MASK)==CODE_CONC);
freeargs(args, numargs, numargs-numconc);
forcearg(args[numargs-1], op&CODE_RET_MASK);
continue;
}
-
- case CODE_CONCM|RET_NULL: case CODE_CONCM|RET_STR: case CODE_CONCM|RET_FLOAT: case CODE_CONCM|RET_INT:
- {
+ case CODE_CONCM|RET_NULL: case CODE_CONCM|RET_STR: case CODE_CONCM|RET_FLOAT: case CODE_CONCM|RET_INT: {
int numconc = op>>8;
char *s = conc(&args[numargs-numconc], numconc, false);
freeargs(args, numargs, numargs-numconc);
forcearg(result, op&CODE_RET_MASK);
continue;
}
-
case CODE_ALIAS:
setalias(*identmap[op>>8], args[--numargs]);
freeargs(args, numargs, 0);
setalias(args[0].s, args[--numargs]);
freeargs(args, numargs, 0);
continue;
-
case CODE_CALL|RET_NULL: case CODE_CALL|RET_STR: case CODE_CALL|RET_FLOAT: case CODE_CALL|RET_INT:
#define CALLALIAS(offset) { \
identstack argstack[MAXARGS]; \
}
forcenull(result);
id = identmap[op>>8];
- if(id->flags&IDF_UNKNOWN)
- {
+ if(id->flags&IDF_UNKNOWN) {
debugcode("unknown command: %s", id->name);
goto forceresult;
}
if(!(aliasstack->usedargs&(1<<id->index))) goto forceresult;
CALLALIAS(0);
continue;
-
case CODE_CALLU|RET_NULL: case CODE_CALLU|RET_STR: case CODE_CALLU|RET_FLOAT: case CODE_CALLU|RET_INT:
if(args[0].type != VAL_STR) goto litval;
id = idents.access(args[0].s);
- if(!id)
- {
+ if(!id) {
noid:
if(checknumber(args[0].s)) goto litval;
debugcode("unknown command: %s", args[0].s);
goto forceresult;
}
forcenull(result);
- switch(id->type)
- {
+ switch(id->type) {
case ID_COMMAND:
freearg(args[0]);
callcommand(id, args+1, numargs-1);
forcearg(result, op&CODE_RET_MASK);
numargs = 0;
continue;
- case ID_LOCAL:
- {
+ case ID_LOCAL: {
identstack locals[MAXARGS];
freearg(args[0]);
loopj(numargs-1) pushalias(*forceident(args[j+1]), locals[j]);
return code;
}
-void executeret(const uint *code, tagval &result)
-{
+void executeret(const uint *code, tagval &result) {
runcode(code, result);
}
-void executeret(const char *p, tagval &result)
-{
+void executeret(const char *p, tagval &result) {
vector<uint> code;
code.reserve(64);
compilemain(code, p, VAL_ANY);
if(int(code[0]) >= 0x100) code.disown();
}
-void executeret(ident *id, tagval *args, int numargs, bool lookup, tagval &result)
-{
+void executeret(ident *id, tagval *args, int numargs, bool lookup, tagval &result) {
result.setnull();
++rundepth;
tagval *prevret = commandret;
commandret = &result;
if(rundepth > MAXRUNDEPTH) debugcode("exceeded recursion limit");
- else if(id) switch(id->type)
- {
+ else if(id) switch(id->type) {
default:
if(!id->fun) break;
// fall-through
case ID_COMMAND:
- if(numargs < id->numargs)
- {
+ if(numargs < id->numargs) {
tagval buf[MAXARGS];
memcpy(buf, args, numargs*sizeof(tagval));
callcommand(id, buf, numargs, lookup);
--rundepth;
}
-char *executestr(const uint *code)
-{
+char *executestr(const uint *code) {
tagval result;
runcode(code, result);
if(result.type == VAL_NULL) return NULL;
return result.s;
}
-char *executestr(const char *p)
-{
+char *executestr(const char *p) {
tagval result;
executeret(p, result);
if(result.type == VAL_NULL) return NULL;
return result.s;
}
-char *executestr(ident *id, tagval *args, int numargs, bool lookup)
-{
+char *executestr(ident *id, tagval *args, int numargs, bool lookup) {
tagval result;
executeret(id, args, numargs, lookup, result);
if(result.type == VAL_NULL) return NULL;
return result.s;
}
-char *execidentstr(const char *name, bool lookup)
-{
+char *execidentstr(const char *name, bool lookup) {
ident *id = idents.access(name);
return id ? executestr(id, NULL, 0, lookup) : NULL;
}
-int execute(const uint *code)
-{
+int execute(const uint *code) {
tagval result;
runcode(code, result);
int i = result.getint();
return i;
}
-int execute(const char *p)
-{
+int execute(const char *p) {
vector<uint> code;
code.reserve(64);
compilemain(code, p, VAL_INT);
return i;
}
-int execute(ident *id, tagval *args, int numargs, bool lookup)
-{
+int execute(ident *id, tagval *args, int numargs, bool lookup) {
tagval result;
executeret(id, args, numargs, lookup, result);
int i = result.getint();
return i;
}
-int execident(const char *name, int noid, bool lookup)
-{
+int execident(const char *name, int noid, bool lookup) {
ident *id = idents.access(name);
return id ? execute(id, NULL, 0, lookup) : noid;
}
-static inline bool getbool(const char *s)
-{
- switch(s[0])
- {
+static inline bool getbool(const char *s) {
+ switch(s[0]) {
case '+': case '-':
- switch(s[1])
- {
+ switch(s[1]) {
case '0': break;
case '.': return !isdigit(s[2]) || parsefloat(s) != 0;
default: return true;
}
// fall through
- case '0':
- {
+ case '0': {
char *end;
int val = int(strtoul((char *)s, &end, 0));
if(val) return true;
- switch(*end)
- {
+ switch(*end) {
case 'e': case '.': return parsefloat(s) != 0;
default: return false;
}
}
}
-static inline bool getbool(const tagval &v)
-{
- switch(v.type)
- {
+static inline bool getbool(const tagval &v) {
+ switch(v.type) {
case VAL_FLOAT: return v.f!=0;
case VAL_INT: return v.i!=0;
case VAL_STR: case VAL_MACRO: return getbool(v.s);
}
}
-bool executebool(const uint *code)
-{
+bool executebool(const uint *code) {
tagval result;
runcode(code, result);
bool b = getbool(result);
return b;
}
-bool executebool(const char *p)
-{
+bool executebool(const char *p) {
tagval result;
executeret(p, result);
bool b = getbool(result);
return b;
}
-bool executebool(ident *id, tagval *args, int numargs, bool lookup)
-{
+bool executebool(ident *id, tagval *args, int numargs, bool lookup) {
tagval result;
executeret(id, args, numargs, lookup, result);
bool b = getbool(result);
return b;
}
-bool execidentbool(const char *name, bool noid, bool lookup)
-{
+bool execidentbool(const char *name, bool noid, bool lookup) {
ident *id = idents.access(name);
return id ? executebool(id, NULL, 0, lookup) : noid;
}
-bool execfile(const char *cfgfile, bool msg)
-{
+bool execfile(const char *cfgfile, bool msg) {
string s;
copystring(s, cfgfile);
char *buf = loadfile(path(s), NULL);
- if(!buf)
- {
+ if(!buf) {
if(msg) conoutf(CON_ERROR, "could not read \"%s\"", cfgfile);
return false;
}
}
ICOMMAND(exec, "sb", (char *file, int *msg), intret(execfile(file, *msg != 0) ? 1 : 0));
-const char *escapestring(const char *s)
-{
+const char *escapestring(const char *s) {
static vector<char> strbuf[3];
static int stridx = 0;
stridx = (stridx + 1)%3;
vector<char> &buf = strbuf[stridx];
buf.setsize(0);
buf.add('"');
- for(; *s; s++) switch(*s)
- {
+ for(; *s; s++) switch(*s) {
case '\n': buf.put("^n", 2); break;
case '\t': buf.put("^t", 2); break;
case '\f': buf.put("^f", 2); break;
}
ICOMMAND(escape, "s", (char *s), result(escapestring(s)));
-ICOMMAND(unescape, "s", (char *s),
-{
+ICOMMAND(unescape, "s", (char *s), {
int len = strlen(s);
char *d = newstring(len);
d[unescapestring(d, s, &s[len])] = '\0';
stringret(d);
});
-const char *escapeid(const char *s)
-{
+const char *escapeid(const char *s) {
const char *end = s + strcspn(s, "\"/;()[]@ \f\t\r\n\0");
return *end ? escapestring(s) : s;
}
-bool validateblock(const char *s)
-{
+bool validateblock(const char *s) {
const int maxbrak = 100;
static char brakstack[maxbrak];
int brakdepth = 0;
- for(; *s; s++) switch(*s)
- {
+ for(; *s; s++) switch(*s) {
case '[': case '(': if(brakdepth >= maxbrak) return false; brakstack[brakdepth++] = *s; break;
case ']': if(brakdepth <= 0 || brakstack[--brakdepth] != '[') return false; break;
case ')': if(brakdepth <= 0 || brakstack[--brakdepth] != '(') return false; break;
}
#ifndef STANDALONE
-void writecfg(const char *name)
-{
+void writecfg(const char *name) {
stream *f = openutf8file(path(name && name[0] ? name : game::savedconfig(), true), "w");
if(!f) return;
f->printf("// automatically written on exit, DO NOT MODIFY\n// delete this file to have %s overwrite these settings\n// modify settings in game, or put settings in %s to override anything\n\n", game::defaultconfig(), game::autoexec());
vector<ident *> ids;
enumerate(idents, ident, id, ids.add(&id));
ids.sortname();
- loopv(ids)
- {
+ loopv(ids) {
ident &id = *ids[i];
- if(id.flags&IDF_PERSIST) switch(id.type)
- {
+ if(id.flags&IDF_PERSIST) switch(id.type) {
case ID_VAR: f->printf("%s %d\n", escapeid(id), *id.storage.i); break;
case ID_FVAR: f->printf("%s %s\n", escapeid(id), floatstr(*id.storage.f)); break;
case ID_SVAR: f->printf("%s %s\n", escapeid(id), escapestring(*id.storage.s)); break;
f->printf("\n");
writebinds(f);
f->printf("\n");
- loopv(ids)
- {
+ loopv(ids) {
ident &id = *ids[i];
- if(id.type==ID_ALIAS && id.flags&IDF_PERSIST && !(id.flags&IDF_OVERRIDDEN)) switch(id.valtype)
- {
+ if(id.type==ID_ALIAS && id.flags&IDF_PERSIST && !(id.flags&IDF_OVERRIDDEN)) switch(id.valtype) {
case VAL_STR:
if(!id.val.s[0]) break;
if(!validateblock(id.val.s)) { f->printf("%s = %s\n", escapeid(id), escapestring(id.val.s)); break; }
COMMAND(writecfg, "s");
#endif
-void changedvars()
-{
+void changedvars() {
vector<ident *> ids;
enumerate(idents, ident, id, if(id.flags&IDF_OVERRIDDEN) ids.add(&id));
ids.sortname();
static string retbuf[4];
static int retidx = 0;
-const char *intstr(int v)
-{
+const char *intstr(int v) {
retidx = (retidx + 1)%4;
intformat(retbuf[retidx], v);
return retbuf[retidx];
}
-void intret(int v)
-{
+void intret(int v) {
commandret->setint(v);
}
-const char *floatstr(float v)
-{
+const char *floatstr(float v) {
retidx = (retidx + 1)%4;
floatformat(retbuf[retidx], v);
return retbuf[retidx];
}
-void floatret(float v)
-{
+void floatret(float v) {
commandret->setfloat(v);
}
ICOMMAND(if, "tee", (tagval *cond, uint *t, uint *f), executeret(getbool(*cond) ? t : f, *commandret));
ICOMMAND(?, "ttt", (tagval *cond, tagval *t, tagval *f), result(*(getbool(*cond) ? t : f)));
-ICOMMAND(pushif, "rte", (ident *id, tagval *v, uint *code),
-{
+ICOMMAND(pushif, "rte", (ident *id, tagval *v, uint *code), {
if(id->type != ID_ALIAS || id->index < MAXARGS) return;
- if(getbool(*v))
- {
+ if(getbool(*v)) {
identstack stack;
pusharg(*id, *v, stack);
v->type = VAL_NULL;
}
});
-void loopiter(ident *id, identstack &stack, const tagval &v)
-{
- if(id->stack != &stack)
- {
+void loopiter(ident *id, identstack &stack, const tagval &v) {
+ if(id->stack != &stack) {
pusharg(*id, v, stack);
id->flags &= ~IDF_UNKNOWN;
}
- else
- {
+ else {
if(id->valtype == VAL_STR) delete[] id->val.s;
cleancode(*id);
id->setval(v);
}
}
-void loopend(ident *id, identstack &stack)
-{
+void loopend(ident *id, identstack &stack) {
if(id->stack == &stack) poparg(*id);
}
-static inline void setiter(ident &id, int i, identstack &stack)
-{
- if(id.stack == &stack)
- {
- if(id.valtype != VAL_INT)
- {
+static inline void setiter(ident &id, int i, identstack &stack) {
+ if(id.stack == &stack) {
+ if(id.valtype != VAL_INT) {
if(id.valtype == VAL_STR) delete[] id.val.s;
cleancode(id);
id.valtype = VAL_INT;
}
id.val.i = i;
}
- else
- {
+ else {
tagval t;
t.setint(i);
pusharg(id, t, stack);
id.flags &= ~IDF_UNKNOWN;
}
}
-ICOMMAND(loop, "rie", (ident *id, int *n, uint *body),
-{
+ICOMMAND(loop, "rie", (ident *id, int *n, uint *body), {
if(*n <= 0 || id->type!=ID_ALIAS) return;
identstack stack;
- loopi(*n)
- {
+ loopi(*n) {
setiter(*id, i, stack);
execute(body);
}
poparg(*id);
});
-ICOMMAND(loopwhile, "riee", (ident *id, int *n, uint *cond, uint *body),
-{
+ICOMMAND(loopwhile, "riee", (ident *id, int *n, uint *cond, uint *body), {
if(*n <= 0 || id->type!=ID_ALIAS) return;
identstack stack;
- loopi(*n)
- {
+ loopi(*n) {
setiter(*id, i, stack);
if(!executebool(cond)) break;
execute(body);
});
ICOMMAND(while, "ee", (uint *cond, uint *body), while(executebool(cond)) execute(body));
-char *loopconc(ident *id, int n, uint *body, bool space)
-{
+char *loopconc(ident *id, int n, uint *body, bool space) {
identstack stack;
vector<char> s;
- loopi(n)
- {
+ loopi(n) {
setiter(*id, i, stack);
tagval v;
executeret(body, v);
return newstring(s.getbuf(), s.length()-1);
}
-ICOMMAND(loopconcat, "rie", (ident *id, int *n, uint *body),
-{
+ICOMMAND(loopconcat, "rie", (ident *id, int *n, uint *body), {
if(*n > 0 && id->type==ID_ALIAS) commandret->setstr(loopconc(id, *n, body, true));
});
-ICOMMAND(loopconcatword, "rie", (ident *id, int *n, uint *body),
-{
+ICOMMAND(loopconcatword, "rie", (ident *id, int *n, uint *body), {
if(*n > 0 && id->type==ID_ALIAS) commandret->setstr(loopconc(id, *n, body, false));
});
-void concat(tagval *v, int n)
-{
+void concat(tagval *v, int n) {
commandret->setstr(conc(v, n, true));
}
COMMAND(concat, "V");
-void concatword(tagval *v, int n)
-{
+void concatword(tagval *v, int n) {
commandret->setstr(conc(v, n, false));
}
COMMAND(concatword, "V");
-void append(ident *id, tagval *v, bool space)
-{
+void append(ident *id, tagval *v, bool space) {
if(id->type != ID_ALIAS || v->type == VAL_NULL) return;
- if(id->valtype == VAL_NULL)
- {
+ if(id->valtype == VAL_NULL) {
noprefix:
if(id->index < MAXARGS) setarg(*id, *v); else setalias(*id, *v);
v->type = VAL_NULL;
}
- else
- {
+ else {
const char *prefix = id->getstr();
if(!prefix[0]) goto noprefix;
tagval r;
ICOMMAND(append, "rt", (ident *id, tagval *v), append(id, v, true));
ICOMMAND(appendword, "rt", (ident *id, tagval *v), append(id, v, false));
-void result(tagval &v)
-{
+void result(tagval &v) {
*commandret = v;
v.type = VAL_NULL;
}
-void stringret(char *s)
-{
+void stringret(char *s) {
commandret->setstr(s);
}
-void result(const char *s)
-{
+void result(const char *s) {
commandret->setstr(newstring(s));
}
-ICOMMAND(result, "t", (tagval *v),
-{
+ICOMMAND(result, "t", (tagval *v), {
*commandret = *v;
v->type = VAL_NULL;
});
-void format(tagval *args, int numargs)
-{
+void format(tagval *args, int numargs) {
vector<char> s;
const char *f = args[0].getstr();
- while(*f)
- {
+ while(*f) {
int c = *f++;
- if(c == '%')
- {
+ if(c == '%') {
int i = *f++;
- if(i >= '1' && i <= '9')
- {
+ if(i >= '1' && i <= '9') {
i -= '0';
const char *sub = i < numargs ? args[i].getstr() : "";
while(*sub) s.add(*sub++);
static const char *liststart = NULL, *listend = NULL, *listquotestart = NULL, *listquoteend = NULL;
-static inline void skiplist(const char *&p)
-{
- for(;;)
- {
+static inline void skiplist(const char *&p) {
+ for(;;) {
p += strspn(p, " \t\r\n");
if(p[0]!='/' || p[1]!='/') break;
p += strcspn(p, "\n\0");
}
}
-static bool parselist(const char *&s, const char *&start = liststart, const char *&end = listend, const char *"estart = listquotestart, const char *"eend = listquoteend)
-{
+static bool parselist(const char *&s, const char *&start = liststart, const char *&end = listend, const char *"estart = listquotestart, const char *"eend = listquoteend) {
skiplist(s);
- switch(*s)
- {
+ switch(*s) {
case '"': quotestart = s++; start = s; s = parsestring(s); end = s; if(*s == '"') s++; quoteend = s; break;
case '(': case '[':
quotestart = s;
start = s+1;
- for(int braktype = *s++, brak = 1;;)
- {
+ for(int braktype = *s++, brak = 1;;) {
s += strcspn(s, "\"/;()[]\0");
int c = *s++;
- switch(c)
- {
+ switch(c) {
case '\0': s--; quoteend = end = s; return true;
case '"': s = parsestring(s); if(*s == '"') s++; break;
case '/': if(*s == '/') s += strcspn(s, "\n\0"); break;
return true;
}
-void explodelist(const char *s, vector<char *> &elems, int limit)
-{
+void explodelist(const char *s, vector<char *> &elems, int limit) {
const char *start, *end;
while((limit < 0 || elems.length() < limit) && parselist(s, start, end))
elems.add(newstring(start, end-start));
}
-char *indexlist(const char *s, int pos)
-{
+char *indexlist(const char *s, int pos) {
loopi(pos) if(!parselist(s)) return newstring("");
const char *start, *end;
return parselist(s, start, end) ? newstring(start, end-start) : newstring("");
}
-int listlen(const char *s)
-{
+int listlen(const char *s) {
int n = 0;
while(parselist(s)) n++;
return n;
}
ICOMMAND(listlen, "s", (char *s), intret(listlen(s)));
-void at(tagval *args, int numargs)
-{
+void at(tagval *args, int numargs) {
if(!numargs) return;
const char *start = args[0].getstr(), *end = start + strlen(start);
- for(int i = 1; i < numargs; i++)
- {
+ for(int i = 1; i < numargs; i++) {
const char *list = start;
int pos = args[i].getint();
for(; pos > 0; pos--) if(!parselist(list)) break;
}
COMMAND(at, "si1V");
-void substr(char *s, int *start, int *count, int *numargs)
-{
+void substr(char *s, int *start, int *count, int *numargs) {
int len = strlen(s), offset = clamp(*start, 0, len);
commandret->setstr(newstring(&s[offset], *numargs >= 3 ? clamp(*count, 0, len - offset) : len - offset));
}
COMMAND(substr, "siiN");
-void chopstr(char *s, int *lim, char *ellipsis)
-{
+void chopstr(char *s, int *lim, char *ellipsis) {
int len = strlen(s), maxlen = abs(*lim);
- if(len > maxlen)
- {
+ if(len > maxlen) {
int elen = strlen(ellipsis);
maxlen = max(maxlen, elen);
char *chopped = newstring(maxlen);
- if(*lim < 0)
- {
+ if(*lim < 0) {
memcpy(chopped, ellipsis, elen);
memcpy(&chopped[elen], &s[len - (maxlen - elen)], maxlen - elen);
}
- else
- {
+ else {
memcpy(chopped, s, maxlen - elen);
memcpy(&chopped[maxlen - elen], ellipsis, elen);
}
}
COMMAND(chopstr, "sis");
-void sublist(const char *s, int *skip, int *count, int *numargs)
-{
+void sublist(const char *s, int *skip, int *count, int *numargs) {
int offset = max(*skip, 0), len = *numargs >= 3 ? max(*count, 0) : -1;
loopi(offset) if(!parselist(s)) break;
if(len < 0) { if(offset > 0) skiplist(s); commandret->setstr(newstring(s)); return; }
}
COMMAND(sublist, "siiN");
-ICOMMAND(stripcolors, "s", (char *s),
-{
+ICOMMAND(stripcolors, "s", (char *s), {
int len = strlen(s);
char *d = newstring(len);
filtertext(d, s, true, false, len);
stringret(d);
});
-static inline void setiter(ident &id, char *val, identstack &stack)
-{
- if(id.stack == &stack)
- {
+static inline void setiter(ident &id, char *val, identstack &stack) {
+ if(id.stack == &stack) {
if(id.valtype == VAL_STR) delete[] id.val.s;
else id.valtype = VAL_STR;
cleancode(id);
id.val.s = val;
}
- else
- {
+ else {
tagval t;
t.setstr(val);
pusharg(id, t, stack);
}
}
-void listfind(ident *id, const char *list, const uint *body)
-{
+void listfind(ident *id, const char *list, const uint *body) {
if(id->type!=ID_ALIAS) { intret(-1); return; }
identstack stack;
int n = -1;
- for(const char *s = list, *start, *end; parselist(s, start, end);)
- {
+ for(const char *s = list, *start, *end; parselist(s, start, end);) {
++n;
char *val = newstring(start, end-start);
setiter(*id, val, stack);
}
COMMAND(listfind, "rse");
-void looplist(ident *id, const char *list, const uint *body)
-{
+void looplist(ident *id, const char *list, const uint *body) {
if(id->type!=ID_ALIAS) return;
identstack stack;
int n = 0;
- for(const char *s = list, *start, *end; parselist(s, start, end); n++)
- {
+ for(const char *s = list, *start, *end; parselist(s, start, end); n++) {
char *val = newstring(start, end-start);
setiter(*id, val, stack);
execute(body);
}
COMMAND(looplist, "rse");
-void loopsublist(ident *id, const char *list, int *skip, int *count, const uint *body)
-{
+void loopsublist(ident *id, const char *list, int *skip, int *count, const uint *body) {
if(id->type!=ID_ALIAS) return;
identstack stack;
int n = 0, offset = max(*skip, 0), len = *count < 0 ? INT_MAX : offset + *count;
- for(const char *s = list, *start, *end; parselist(s, start, end) && n < len; n++) if(n >= offset)
- {
+ for(const char *s = list, *start, *end; parselist(s, start, end) && n < len; n++) if(n >= offset) {
char *val = newstring(start, end-start);
setiter(*id, val, stack);
execute(body);
}
COMMAND(loopsublist, "rsiie");
-void looplistconc(ident *id, const char *list, const uint *body, bool space)
-{
+void looplistconc(ident *id, const char *list, const uint *body, bool space) {
if(id->type!=ID_ALIAS) return;
identstack stack;
vector<char> r;
int n = 0;
- for(const char *s = list, *start, *end; parselist(s, start, end); n++)
- {
+ for(const char *s = list, *start, *end; parselist(s, start, end); n++) {
char *val = newstring(start, end-start);
setiter(*id, val, stack);
-
if(n && space) r.add(' ');
-
tagval v;
executeret(body, v);
const char *vstr = v.getstr();
ICOMMAND(looplistconcat, "rse", (ident *id, char *list, uint *body), looplistconc(id, list, body, true));
ICOMMAND(looplistconcatword, "rse", (ident *id, char *list, uint *body), looplistconc(id, list, body, false));
-void listfilter(ident *id, const char *list, const uint *body)
-{
+void listfilter(ident *id, const char *list, const uint *body) {
if(id->type!=ID_ALIAS) return;
identstack stack;
vector<char> r;
int n = 0;
- for(const char *s = list, *start, *end, *quotestart, *quoteend; parselist(s, start, end, quotestart, quoteend); n++)
- {
+ for(const char *s = list, *start, *end, *quotestart, *quoteend; parselist(s, start, end, quotestart, quoteend); n++) {
char *val = newstring(start, end-start);
setiter(*id, val, stack);
-
- if(executebool(body))
- {
+ if(executebool(body)) {
if(r.length()) r.add(' ');
r.put(quotestart, quoteend-quotestart);
}
}
COMMAND(listfilter, "rse");
-void prettylist(const char *s, const char *conj)
-{
+void prettylist(const char *s, const char *conj) {
vector<char> p;
const char *start, *end;
- for(int len = listlen(s), n = 0; parselist(s, start, end); n++)
- {
+ for(int len = listlen(s), n = 0; parselist(s, start, end); n++) {
p.put(start, end - start);
- if(n+1 < len)
- {
+ if(n+1 < len) {
if(len > 2 || !conj[0]) p.add(',');
- if(n+2 == len && conj[0])
- {
+ if(n+2 == len && conj[0]) {
p.add(' ');
p.put(conj, strlen(conj));
}
}
COMMAND(prettylist, "ss");
-int listincludes(const char *list, const char *needle, int needlelen)
-{
+int listincludes(const char *list, const char *needle, int needlelen) {
int offset = 0;
- for(const char *s = list, *start, *end; parselist(s, start, end);)
- {
+ for(const char *s = list, *start, *end; parselist(s, start, end);) {
int len = end - start;
if(needlelen == len && !strncmp(needle, start, len)) return offset;
offset++;
}
ICOMMAND(indexof, "ss", (char *list, char *elem), intret(listincludes(list, elem, strlen(elem))));
-char *listdel(const char *s, const char *del)
-{
+char *listdel(const char *s, const char *del) {
vector<char> p;
- for(const char *start, *end, *qstart, *qend; parselist(s, start, end, qstart, qend);)
- {
- if(listincludes(del, start, end-start) < 0)
- {
+ for(const char *start, *end, *qstart, *qend; parselist(s, start, end, qstart, qend);) {
+ if(listincludes(del, start, end-start) < 0) {
if(!p.empty()) p.add(' ');
p.put(qstart, qend-qstart);
}
}
ICOMMAND(listdel, "ss", (char *list, char *del), commandret->setstr(listdel(list, del)));
-void listsplice(const char *s, const char *vals, int *skip, int *count)
-{
+void listsplice(const char *s, const char *vals, int *skip, int *count) {
int offset = max(*skip, 0), len = max(*count, 0);
const char *list = s, *start, *end, *qstart, *qend = s;
loopi(offset) if(!parselist(s, start, end, qstart, qend)) break;
vector<char> p;
if(qend > list) p.put(list, qend-list);
- if(*vals)
- {
+ if(*vals) {
if(!p.empty()) p.add(' ');
p.put(vals, strlen(vals));
}
loopi(len) if(!parselist(s)) break;
skiplist(s);
- switch(*s)
- {
+ switch(*s) {
case '\0': case ')': case ']': break;
default:
if(!p.empty()) p.add(' ');
}
COMMAND(listsplice, "ssii");
-ICOMMAND(loopfiles, "rsse", (ident *id, char *dir, char *ext, uint *body),
-{
+ICOMMAND(loopfiles, "rsse", (ident *id, char *dir, char *ext, uint *body), {
if(id->type!=ID_ALIAS) return;
identstack stack;
vector<char *> files;
listfiles(dir, ext[0] ? ext : NULL, files);
- loopvrev(files)
- {
+ loopvrev(files) {
char *file = files[i];
bool redundant = false;
loopj(i) if(!strcmp(files[j], file)) { redundant = true; break; }
if(redundant) delete[] files.removeunordered(i);
}
- loopv(files)
- {
+ loopv(files) {
char *file = files[i];
- if(i)
- {
+ if(i) {
if(id->valtype == VAL_STR) delete[] id->val.s;
else id->valtype = VAL_STR;
id->val.s = file;
}
- else
- {
+ else {
tagval t;
t.setstr(file);
pusharg(*id, t, stack);
if(files.length()) poparg(*id);
});
-void findfile_(char *name)
-{
+void findfile_(char *name) {
string fname;
copystring(fname, name);
path(fname);
}
COMMANDN(findfile, findfile_, "s");
-struct sortitem
-{
+struct sortitem {
const char *str, *quotestart, *quoteend;
};
-struct sortfun
-{
+struct sortfun {
ident *x, *y;
uint *body;
-
- bool operator()(const sortitem &xval, const sortitem &yval)
- {
+ bool operator()(const sortitem &xval, const sortitem &yval) {
if(x->valtype != VAL_MACRO) x->valtype = VAL_MACRO;
cleancode(*x);
x->val.code = (const uint *)xval.str;
}
};
-void sortlist(char *list, ident *x, ident *y, uint *body)
-{
+void sortlist(char *list, ident *x, ident *y, uint *body) {
if(x == y || x->type != ID_ALIAS || y->type != ID_ALIAS) return;
-
vector<sortitem> items;
int macrolen = strlen(list), total = 0;
char *macros = newstring(list, macrolen);
const char *curlist = list, *start, *end, *quotestart, *quoteend;
- while(parselist(curlist, start, end, quotestart, quoteend))
- {
+ while(parselist(curlist, start, end, quotestart, quoteend)) {
macros[end - list] = '\0';
sortitem item = { ¯os[start - list], quotestart, quoteend };
items.add(item);
total += int(quoteend - quotestart);
}
-
identstack xstack, ystack;
pusharg(*x, nullval, xstack); x->flags &= ~IDF_UNKNOWN;
pusharg(*y, nullval, ystack); y->flags &= ~IDF_UNKNOWN;
-
sortfun f = { x, y, body };
items.sort(f);
-
poparg(*x);
poparg(*y);
-
char *sorted = macros;
int sortedlen = total + max(items.length() - 1, 0);
- if(macrolen < sortedlen)
- {
+ if(macrolen < sortedlen) {
delete[] macros;
sorted = newstring(sortedlen);
}
-
int offset = 0;
- loopv(items)
- {
+ loopv(items) {
sortitem &item = items[i];
int len = int(item.quoteend - item.quotestart);
if(i) sorted[offset++] = ' ';
offset += len;
}
sorted[offset] = '\0';
-
commandret->setstr(sorted);
}
COMMAND(sortlist, "srre");
ICOMMAND(|~, "ii", (int *a, int *b), intret(*a | ~*b));
ICOMMAND(<<, "ii", (int *a, int *b), intret(*b < 32 ? *a << max(*b, 0) : 0));
ICOMMAND(>>, "ii", (int *a, int *b), intret(*a >> clamp(*b, 0, 31)));
-ICOMMAND(&&, "e1V", (tagval *args, int numargs),
-{
+ICOMMAND(&&, "e1V", (tagval *args, int numargs), {
if(!numargs) intret(1);
- else loopi(numargs)
- {
+ else loopi(numargs) {
if(i) freearg(*commandret);
executeret(args[i].code, *commandret);
if(!getbool(*commandret)) break;
}
});
-ICOMMAND(||, "e1V", (tagval *args, int numargs),
-{
+ICOMMAND(||, "e1V", (tagval *args, int numargs), {
if(!numargs) intret(0);
- else loopi(numargs)
- {
+ else loopi(numargs) {
if(i) freearg(*commandret);
executeret(args[i].code, *commandret);
if(getbool(*commandret)) break;
ICOMMAND(log2, "f", (float *a), floatret(log(*a)/M_LN2));
ICOMMAND(log10, "f", (float *a), floatret(log10(*a)));
ICOMMAND(exp, "f", (float *a), floatret(exp(*a)));
-ICOMMAND(min, "V", (tagval *args, int numargs),
-{
+ICOMMAND(min, "V", (tagval *args, int numargs), {
int val = numargs > 0 ? args[numargs - 1].getint() : 0;
loopi(numargs - 1) val = min(val, args[i].getint());
intret(val);
});
-ICOMMAND(max, "V", (tagval *args, int numargs),
-{
+ICOMMAND(max, "V", (tagval *args, int numargs), {
int val = numargs > 0 ? args[numargs - 1].getint() : 0;
loopi(numargs - 1) val = max(val, args[i].getint());
intret(val);
});
-ICOMMAND(minf, "V", (tagval *args, int numargs),
-{
+ICOMMAND(minf, "V", (tagval *args, int numargs), {
float val = numargs > 0 ? args[numargs - 1].getfloat() : 0.0f;
loopi(numargs - 1) val = min(val, args[i].getfloat());
floatret(val);
});
-ICOMMAND(maxf, "V", (tagval *args, int numargs),
-{
+ICOMMAND(maxf, "V", (tagval *args, int numargs), {
float val = numargs > 0 ? args[numargs - 1].getfloat() : 0.0f;
loopi(numargs - 1) val = max(val, args[i].getfloat());
floatret(val);
ICOMMAND(floor, "f", (float *n), floatret(floor(*n)));
ICOMMAND(ceil, "f", (float *n), floatret(ceil(*n)));
-ICOMMAND(round, "ff", (float *n, float *k),
-{
+ICOMMAND(round, "ff", (float *n, float *k), {
double step = *k;
double r = *n;
- if(step > 0)
- {
+ if(step > 0) {
r += step * (r < 0 ? -0.5 : 0.5);
r -= fmod(r, step);
}
floatret(float(r));
});
-ICOMMAND(cond, "ee2V", (tagval *args, int numargs),
-{
- for(int i = 0; i < numargs; i += 2)
- {
- if(i+1 < numargs)
- {
- if(executebool(args[i].code))
- {
+ICOMMAND(cond, "ee2V", (tagval *args, int numargs), {
+ for(int i = 0; i < numargs; i += 2) {
+ if(i+1 < numargs) {
+ if(executebool(args[i].code)) {
executeret(args[i+1].code, *commandret);
break;
}
}
- else
- {
+ else {
executeret(args[i].code, *commandret);
break;
}
}
});
#define CASECOMMAND(name, fmt, type, acc, compare) \
- ICOMMAND(name, fmt "te2V", (tagval *args, int numargs), \
- { \
+ ICOMMAND(name, fmt "te2V", (tagval *args, int numargs), { \
+ \
type val = acc; \
int i; \
- for(i = 1; i+1 < numargs; i += 2) \
- { \
- if(compare) \
- { \
+ for(i = 1; i+1 < numargs; i += 2) { \
+ \
+ if(compare) { \
+ \
executeret(args[i+1].code, *commandret); \
return; \
} \
CASECOMMAND(cases, "s", const char *, args[0].getstr(), args[i].type == VAL_NULL || !strcmp(args[i].getstr(), val));
ICOMMAND(rnd, "ii", (int *a, int *b), intret(*a - *b > 0 ? rnd(*a - *b) + *b : *b));
-ICOMMAND(rndstr, "i", (int *len),
-{
+ICOMMAND(rndstr, "i", (int *len), {
int n = clamp(*len, 0, 10000);
char *s = newstring(n);
- for(int i = 0; i < n;)
- {
+ for(int i = 0; i < n;) {
uint r = randomMT();
- for(int j = min(i + 4, n); i < j; i++)
- {
+ for(int j = min(i + 4, n); i < j; i++) {
s[i] = (r%255) + 1;
r /= 255;
}
ICOMMAND(struni, "si", (char *s, int *i), intret(*i > 0 ? (memchr(s, 0, *i) ? 0 : cube2uni(s[*i])) : cube2uni(s[0])));
ICOMMAND(unistr, "i", (int *i), { char *s = newstring(1); s[0] = uni2cube(*i); s[1] = '\0'; stringret(s); });
-int naturalsort(const char *a, const char *b)
-{
- for(;;)
- {
+int naturalsort(const char *a, const char *b) {
+ for(;;) {
int ac = *a, bc = *b;
if(!ac) return bc ? -1 : 0;
else if(!bc) return 1;
- else if(isdigit(ac) && isdigit(bc))
- {
+ else if(isdigit(ac) && isdigit(bc)) {
while(*a == '0') a++;
while(*b == '0') b++;
const char *a0 = a, *b0 = b;
ICOMMAND(naturalsort, "ss", (char *a, char *b), intret(naturalsort(a,b)<=0));
#define STRMAPCOMMAND(name, map) \
- ICOMMAND(name, "s", (char *s), \
- { \
+ ICOMMAND(name, "s", (char *s), { \
+ \
int len = strlen(s); \
char *m = newstring(len); \
loopi(len) m[i] = map(s[i]); \
STRMAPCOMMAND(strlower, cubelower);
STRMAPCOMMAND(strupper, cubeupper);
-char *strreplace(const char *s, const char *oldval, const char *newval)
-{
+char *strreplace(const char *s, const char *oldval, const char *newval) {
vector<char> buf;
-
int oldlen = strlen(oldval);
if(!oldlen) return newstring(s);
- for(;;)
- {
+ for(;;) {
const char *found = strstr(s, oldval);
- if(found)
- {
+ if(found) {
while(s < found) buf.add(*s++);
for(const char *n = newval; *n; n++) buf.add(*n);
s = found + oldlen;
}
- else
- {
+ else {
while(*s) buf.add(*s++);
buf.add('\0');
return newstring(buf.getbuf(), buf.length());
ICOMMAND(strreplace, "sss", (char *s, char *o, char *n), commandret->setstr(strreplace(s, o, n)));
-void strsplice(const char *s, const char *vals, int *skip, int *count)
-{
+void strsplice(const char *s, const char *vals, int *skip, int *count) {
int slen = strlen(s), vlen = strlen(vals),
offset = clamp(*skip, 0, slen),
len = clamp(*count, 0, slen - offset);
#ifndef STANDALONE
ICOMMAND(getmillis, "i", (int *total), intret(*total ? totalmillis : lastmillis));
-struct sleepcmd
-{
+struct sleepcmd {
int delay, millis, flags;
char *command;
};
vector<sleepcmd> sleepcmds;
-void addsleep(int *msec, char *cmd)
-{
+void addsleep(int *msec, char *cmd) {
sleepcmd &s = sleepcmds.add();
s.delay = max(*msec, 1);
s.millis = lastmillis;
COMMANDN(sleep, addsleep, "is");
-void checksleep(int millis)
-{
- loopv(sleepcmds)
- {
+void checksleep(int millis) {
+ loopv(sleepcmds) {
sleepcmd &s = sleepcmds[i];
- if(millis - s.millis >= s.delay)
- {
+ if(millis - s.millis >= s.delay) {
char *cmd = s.command; // execute might create more sleep commands
s.command = NULL;
int oldflags = identflags;
}
}
-void clearsleep(bool clearoverrides)
-{
+void clearsleep(bool clearoverrides) {
int len = 0;
- loopv(sleepcmds) if(sleepcmds[i].command)
- {
+ loopv(sleepcmds) if(sleepcmds[i].command) {
if(clearoverrides && !(sleepcmds[i].flags&IDF_OVERRIDDEN)) sleepcmds[len++] = sleepcmds[i];
else delete[] sleepcmds[i].command;
}
sleepcmds.shrink(len);
}
-void clearsleep_(int *clearoverrides)
-{
+void clearsleep_(int *clearoverrides) {
clearsleep(*clearoverrides!=0 || identflags&IDF_OVERRIDDEN);
}
VARP(contags, 0, 3, 3);
-void conline(int type, const char *sf) // add a line to the console buffer
-{
+void conline(int type, const char *sf) { // add a line to the console buffer {
char *buf = NULL;
- if(type&CON_TAG_MASK) for(int i = conlines.length()-1; i >= max(conlines.length()-contags, 0); i--)
- {
+ if(type&CON_TAG_MASK) for(int i = conlines.length()-1; i >= max(conlines.length()-contags, 0); i--) {
int prev = conlines.removing(i).type;
if(!(prev&CON_TAG_MASK)) break;
- if(type == prev)
- {
+ if(type == prev) {
buf = conlines.remove(i).line;
break;
}
copystring(cl.line, sf, CONSTRLEN);
}
-void conoutfv(int type, const char *fmt, va_list args)
-{
+void conoutfv(int type, const char *fmt, va_list args) {
static char buf[CONSTRLEN];
vformatstring(buf, fmt, args, sizeof(buf));
conline(type, buf);
VAR(fullconsole, 0, 0, 1);
ICOMMAND(toggleconsole, "", (), { fullconsole ^= 1; });
-int rendercommand(int x, int y, int w)
-{
+int rendercommand(int x, int y, int w) {
if(commandmillis < 0) return 0;
-
defformatstring(s, "%s %s", commandprompt ? commandprompt : ">", commandbuf);
int width, height;
text_bounds(s, width, height, w);
int conskip = 0, miniconskip = 0;
-void setconskip(int &skip, int filter, int n)
-{
+void setconskip(int &skip, int filter, int n) {
filter &= CON_FLAGS;
int offset = abs(n), dir = n < 0 ? -1 : 1;
skip = clamp(skip, 0, conlines.length()-1);
- while(offset)
- {
+ while(offset) {
skip += dir;
- if(!conlines.inrange(skip))
- {
+ if(!conlines.inrange(skip)) {
skip = clamp(skip, 0, conlines.length()-1);
return;
}
ICOMMAND(clearconsole, "", (), { while(conlines.length()) delete[] conlines.pop().line; });
-int drawconlines(int conskip, int confade, int conwidth, int conheight, int conoff, int filter, int y = 0, int dir = 1)
-{
+int drawconlines(int conskip, int confade, int conwidth, int conheight, int conoff, int filter, int y = 0, int dir = 1) {
filter &= CON_FLAGS;
int numl = conlines.length(), offset = min(conskip, numl);
-
- if(confade)
- {
- if(!conskip)
- {
+ if(confade) {
+ if(!conskip) {
numl = 0;
loopvrev(conlines) if(totalmillis-conlines[i].outtime < confade*1000) { numl = i+1; break; }
}
else offset--;
}
-
int totalheight = 0;
- loopi(numl) //determine visible height
- {
+ loopi(numl) { //determine visible height {
// shuffle backwards to fill if necessary
int idx = offset+i < numl ? offset+i : --offset;
if(!(conlines[idx].type&filter)) continue;
totalheight += height;
}
if(dir > 0) y = conoff;
- loopi(numl)
- {
+ loopi(numl) {
int idx = offset + (dir > 0 ? numl-i-1 : i);
if(!(conlines[idx].type&filter)) continue;
char *line = conlines[idx].line;
return y+conoff;
}
-int renderconsole(int w, int h, int abovehud) // render buffer taking into account time & scrolling
-{
+int renderconsole(int w, int h, int abovehud) { // render buffer taking into account time & scrolling {
int conpad = fullconsole ? 0 : FONTH/4,
conoff = fullconsole ? FONTH : FONTH/3,
conheight = min(fullconsole ? ((h*fullconsize/100)/FONTH)*FONTH : FONTH*consize, h - 2*(conpad + conoff)),
conwidth = w - 2*(conpad + conoff) - (fullconsole ? 0 : game::clipconsole(w, h));
-
extern void consolebox(int x1, int y1, int x2, int y2);
if(fullconsole) consolebox(conpad, conpad, conwidth+conpad+2*conoff, conheight+conpad+2*conoff);
-
int y = drawconlines(conskip, fullconsole ? 0 : confade, conwidth, conheight, conpad+conoff, fullconsole ? fullconfilter : confilter);
if(!fullconsole && (miniconsize && miniconwidth))
drawconlines(miniconskip, miniconfade, (miniconwidth*(w - 2*(conpad + conoff)))/100, min(FONTH*miniconsize, abovehud - y), conpad+conoff, miniconfilter, abovehud, -1);
// keymap is defined externally in keymap.cfg
-struct keym
-{
- enum
- {
+struct keym {
+ enum {
ACTION_DEFAULT = 0,
ACTION_SPECTATOR,
ACTION_EDITING,
NUMACTIONS
};
-
int code;
char *name;
char *actions[NUMACTIONS];
bool pressed;
-
keym() : code(-1), name(NULL), pressed(false) { loopi(NUMACTIONS) actions[i] = newstring(""); }
~keym() { DELETEA(name); loopi(NUMACTIONS) DELETEA(actions[i]); }
};
hashtable<int, keym> keyms(128);
-void keymap(int *code, char *key)
-{
+void keymap(int *code, char *key) {
if(identflags&IDF_OVERRIDDEN) { conoutf(CON_ERROR, "cannot override keymap %d", *code); return; }
keym &km = keyms[*code];
km.code = *code;
keym *keypressed = NULL;
char *keyaction = NULL;
-const char *getkeyname(int code)
-{
+const char *getkeyname(int code) {
keym *km = keyms.access(code);
return km ? km->name : NULL;
}
-void searchbinds(char *action, int type)
-{
+void searchbinds(char *action, int type) {
vector<char> names;
- enumerate(keyms, keym, km,
- {
- if(!strcmp(km.actions[type], action))
- {
+ enumerate(keyms, keym, km, {
+ if(!strcmp(km.actions[type], action)) {
if(names.length()) names.add(' ');
names.put(km.name, strlen(km.name));
}
result(names.getbuf());
}
-keym *findbind(char *key)
-{
- enumerate(keyms, keym, km,
- {
+keym *findbind(char *key) {
+ enumerate(keyms, keym, km, {
if(!strcasecmp(km.name, key)) return &km;
});
return NULL;
}
-void getbind(char *key, int type)
-{
+void getbind(char *key, int type) {
keym *km = findbind(key);
result(km ? km->actions[type] : "");
}
-void bindkey(char *key, char *action, int state, const char *cmd)
-{
+void bindkey(char *key, char *action, int state, const char *cmd) {
if(identflags&IDF_OVERRIDDEN) { conoutf(CON_ERROR, "cannot override %s \"%s\"", cmd, key); return; }
keym *km = findbind(key);
if(!km) { conoutf(CON_ERROR, "unknown key \"%s\"", key); return; }
ICOMMAND(searchspecbinds, "s", (char *action), searchbinds(action, keym::ACTION_SPECTATOR));
ICOMMAND(searcheditbinds, "s", (char *action), searchbinds(action, keym::ACTION_EDITING));
-void inputcommand(char *init, char *action = NULL, char *prompt = NULL, char *flags = NULL) // turns input to the command line on or off
-{
+void inputcommand(char *init, char *action = NULL, char *prompt = NULL, char *flags = NULL) { // turns input to the command line on or off {
commandmillis = init ? totalmillis : -1;
textinput(commandmillis >= 0, TI_CONSOLE);
keyrepeat(commandmillis >= 0, KR_CONSOLE);
if(action && action[0]) commandaction = newstring(action);
if(prompt && prompt[0]) commandprompt = newstring(prompt);
commandflags = 0;
- if(flags) while(*flags) switch(*flags++)
- {
+ if(flags) while(*flags) switch(*flags++) {
case 'c': commandflags |= CF_COMPLETE; break;
case 'x': commandflags |= CF_EXECUTE; break;
case 's': commandflags |= CF_COMPLETE|CF_EXECUTE; break;
ICOMMAND(saycommand, "C", (char *init), inputcommand(init));
COMMAND(inputcommand, "ssss");
-void pasteconsole()
-{
+void pasteconsole() {
if(!SDL_HasClipboardText()) return;
char *cb = SDL_GetClipboardText();
if(!cb) return;
SDL_free(cb);
}
-struct hline
-{
+struct hline {
char *buf, *action, *prompt;
int flags;
-
hline() : buf(NULL), action(NULL), prompt(NULL), flags(0) {}
- ~hline()
- {
+ ~hline() {
DELETEA(buf);
DELETEA(action);
DELETEA(prompt);
}
-
- void restore()
- {
+ void restore() {
copystring(commandbuf, buf);
if(commandpos >= (int)strlen(commandbuf)) commandpos = -1;
DELETEA(commandaction);
if(prompt) commandprompt = newstring(prompt);
commandflags = flags;
}
-
- bool shouldsave()
- {
+ bool shouldsave() {
return strcmp(commandbuf, buf) ||
(commandaction ? !action || strcmp(commandaction, action) : action!=NULL) ||
(commandprompt ? !prompt || strcmp(commandprompt, prompt) : prompt!=NULL) ||
commandflags != flags;
}
-
- void save()
- {
+ void save() {
buf = newstring(commandbuf);
if(commandaction) action = newstring(commandaction);
if(commandprompt) prompt = newstring(commandprompt);
flags = commandflags;
}
-
- void run()
- {
+ void run() {
if(flags&CF_EXECUTE && buf[0]=='/') execute(buf+1);
- else if(action)
- {
+ else if(action) {
alias("commandbuf", buf);
execute(action);
}
VARP(maxhistory, 0, 1000, 10000);
-void history_(int *n)
-{
+void history_(int *n) {
static bool inhistory = false;
- if(!inhistory && history.inrange(*n))
- {
+ if(!inhistory && history.inrange(*n)) {
inhistory = true;
history[history.length()-*n-1]->run();
inhistory = false;
COMMANDN(history, history_, "i");
-struct releaseaction
-{
+struct releaseaction {
keym *key;
char *action;
};
vector<releaseaction> releaseactions;
-const char *addreleaseaction(char *s)
-{
+const char *addreleaseaction(char *s) {
if(!keypressed) { delete[] s; return NULL; }
releaseaction &ra = releaseactions.add();
ra.key = keypressed;
return keypressed->name;
}
-void onrelease(const char *s)
-{
+void onrelease(const char *s) {
addreleaseaction(newstring(s));
}
COMMAND(onrelease, "s");
-void execbind(keym &k, bool isdown)
-{
- loopv(releaseactions)
- {
+void execbind(keym &k, bool isdown) {
+ loopv(releaseactions) {
releaseaction &ra = releaseactions[i];
- if(ra.key==&k)
- {
+ if(ra.key==&k) {
if(!isdown) execute(ra.action);
delete[] ra.action;
releaseactions.remove(i--);
}
}
- if(isdown)
- {
+ if(isdown) {
int state = keym::ACTION_DEFAULT;
- if(!mainmenu)
- {
+ if(!mainmenu) {
if(editmode) state = keym::ACTION_EDITING;
else if(player->state==CS_SPECTATOR) state = keym::ACTION_SPECTATOR;
}
k.pressed = isdown;
}
-bool consoleinput(const char *str, int len)
-{
+bool consoleinput(const char *str, int len) {
if(commandmillis < 0) return false;
-
resetcomplete();
int cmdlen = (int)strlen(commandbuf), cmdspace = int(sizeof(commandbuf)) - (cmdlen+1);
len = min(len, cmdspace);
- if(commandpos<0)
- {
+ if(commandpos<0) {
memcpy(&commandbuf[cmdlen], str, len);
}
- else
- {
+ else {
memmove(&commandbuf[commandpos+len], &commandbuf[commandpos], cmdlen - commandpos);
memcpy(&commandbuf[commandpos], str, len);
commandpos += len;
}
commandbuf[cmdlen + len] = '\0';
-
return true;
}
-bool consolekey(int code, bool isdown)
-{
+bool consolekey(int code, bool isdown) {
if(commandmillis < 0) return false;
#define MOD_KEYS (KMOD_LCTRL|KMOD_RCTRL)
-
- if(isdown)
- {
- switch(code)
- {
+ if(isdown) {
+ switch(code) {
case SDLK_RETURN:
case SDLK_KP_ENTER:
break;
-
case SDLK_HOME:
if(strlen(commandbuf)) commandpos = 0;
break;
-
case SDLK_END:
commandpos = -1;
break;
-
- case SDLK_DELETE:
- {
+ case SDLK_DELETE: {
int len = (int)strlen(commandbuf);
if(commandpos<0) break;
memmove(&commandbuf[commandpos], &commandbuf[commandpos+1], len - commandpos);
if(commandpos>=len-1) commandpos = -1;
break;
}
-
- case SDLK_BACKSPACE:
- {
+ case SDLK_BACKSPACE: {
int len = (int)strlen(commandbuf), i = commandpos>=0 ? commandpos : len;
if(i<1) break;
memmove(&commandbuf[i-1], &commandbuf[i], len - i + 1);
else if(!commandpos && len<=1) commandpos = -1;
break;
}
-
case SDLK_LEFT:
if(commandpos>0) commandpos--;
else if(commandpos<0) commandpos = (int)strlen(commandbuf)-1;
break;
-
case SDLK_RIGHT:
if(commandpos>=0 && ++commandpos>=(int)strlen(commandbuf)) commandpos = -1;
break;
-
case SDLK_UP:
if(histpos > history.length()) histpos = history.length();
if(histpos > 0) history[--histpos]->restore();
break;
-
case SDLK_DOWN:
if(histpos + 1 < history.length()) history[++histpos]->restore();
break;
-
case SDLK_TAB:
- if(commandflags&CF_COMPLETE)
- {
+ if(commandflags&CF_COMPLETE) {
complete(commandbuf, sizeof(commandbuf), commandflags&CF_EXECUTE ? "/" : NULL);
if(commandpos>=0 && commandpos>=(int)strlen(commandbuf)) commandpos = -1;
}
break;
-
case SDLK_v:
if(SDL_GetModState()&MOD_KEYS) pasteconsole();
break;
}
}
- else
- {
- if(code==SDLK_RETURN || code==SDLK_KP_ENTER)
- {
+ else {
+ if(code==SDLK_RETURN || code==SDLK_KP_ENTER) {
hline *h = NULL;
- if(commandbuf[0])
- {
- if(history.empty() || history.last()->shouldsave())
- {
- if(maxhistory && history.length() >= maxhistory)
- {
+ if(commandbuf[0]) {
+ if(history.empty() || history.last()->shouldsave()) {
+ if(maxhistory && history.length() >= maxhistory) {
loopi(history.length()-maxhistory+1) delete history[i];
history.remove(0, history.length()-maxhistory+1);
}
inputcommand(NULL);
if(h) h->run();
}
- else if(code==SDLK_ESCAPE)
- {
+ else if(code==SDLK_ESCAPE) {
histpos = history.length();
inputcommand(NULL);
}
}
-
return true;
}
-void processtextinput(const char *str, int len)
-{
+void processtextinput(const char *str, int len) {
if(!g3d_input(str, len))
consoleinput(str, len);
}
-void processkey(int code, bool isdown, int modstate)
-{
- switch(code)
- {
+void processkey(int code, bool isdown, int modstate) {
+ switch(code) {
case SDLK_LGUI: case SDLK_RGUI:
return;
}
keym *haskey = keyms.access(code);
if(haskey && haskey->pressed) execbind(*haskey, isdown); // allow pressed keys to release
- else if(!g3d_key(code, isdown)) // 3D GUI mouse button intercept
- {
- if(!consolekey(code, isdown))
- {
+ else if(!g3d_key(code, isdown)) { // 3D GUI mouse button intercept {
+ if(!consolekey(code, isdown)) {
if(modstate&KMOD_GUI) return;
if(haskey) execbind(*haskey, isdown);
}
}
}
-void clear_console()
-{
+void clear_console() {
keyms.clear();
}
-void writebinds(stream *f)
-{
+void writebinds(stream *f) {
static const char * const cmds[3] = { "bind", "specbind", "editbind" };
vector<keym *> binds;
enumerate(keyms, keym, km, binds.add(&km));
binds.sortname();
- loopj(3)
- {
- loopv(binds)
- {
+ loopj(3) {
+ loopv(binds) {
keym &km = *binds[i];
- if(*km.actions[j])
- {
+ if(*km.actions[j]) {
if(validateblock(km.actions[j])) f->printf("%s %s [%s]\n", cmds[j], escapestring(km.name), km.actions[j]);
else f->printf("%s %s %s\n", cmds[j], escapestring(km.name), escapestring(km.actions[j]));
}
enum { FILES_DIR = 0, FILES_VAR, FILES_LIST };
-struct fileskey
-{
+struct fileskey {
int type;
const char *dir, *ext;
-
fileskey() {}
fileskey(int type, const char *dir, const char *ext) : type(type), dir(dir), ext(ext) {}
};
-static void cleanfilesdir(char *dir)
-{
+static void cleanfilesdir(char *dir) {
int dirlen = (int)strlen(dir);
while(dirlen > 0 && (dir[dirlen-1] == '/' || dir[dirlen-1] == '\\'))
dir[--dirlen] = '\0';
}
-struct filesval
-{
+struct filesval {
int type;
char *dir, *ext;
vector<char *> files;
int millis;
-
filesval(int type, const char *dir, const char *ext) : type(type), dir(newstring(dir)), ext(ext && ext[0] ? newstring(ext) : NULL), millis(-1) {}
~filesval() { DELETEA(dir); DELETEA(ext); files.deletearrays(); }
-
- void update()
- {
+ void update() {
if((type!=FILES_DIR && type!=FILES_VAR) || millis >= commandmillis) return;
files.deletearrays();
- if(type==FILES_VAR)
- {
+ if(type==FILES_VAR) {
string buf;
buf[0] = '\0';
- if(ident *id = readident(dir)) switch(id->type)
- {
+ if(ident *id = readident(dir)) switch(id->type) {
case ID_SVAR: copystring(buf, *id->storage.s); break;
case ID_ALIAS: copystring(buf, id->getstr()); break;
}
}
};
-static inline bool htcmp(const fileskey &x, const fileskey &y)
-{
+static inline bool htcmp(const fileskey &x, const fileskey &y) {
return x.type==y.type && !strcmp(x.dir, y.dir) && (x.ext == y.ext || (x.ext && y.ext && !strcmp(x.ext, y.ext)));
}
-static inline uint hthash(const fileskey &k)
-{
+static inline uint hthash(const fileskey &k) {
return hthash(k.dir);
}
void resetcomplete() { completesize = 0; }
-void addcomplete(char *command, int type, char *dir, char *ext)
-{
- if(identflags&IDF_OVERRIDDEN)
- {
+void addcomplete(char *command, int type, char *dir, char *ext) {
+ if(identflags&IDF_OVERRIDDEN) {
conoutf(CON_ERROR, "cannot override complete %s", command);
return;
}
- if(!dir[0])
- {
+ if(!dir[0]) {
filesval **hasfiles = completions.access(command);
if(hasfiles) *hasfiles = NULL;
return;
}
if(type==FILES_DIR) cleanfilesdir(dir);
- if(ext)
- {
+ if(ext) {
if(strchr(ext, '*')) ext[0] = '\0';
if(!ext[0]) ext = NULL;
}
fileskey key(type, dir, ext);
filesval **val = completefiles.access(key);
- if(!val)
- {
+ if(!val) {
filesval *f = new filesval(type, dir, ext);
if(type==FILES_LIST) explodelist(dir, f->files);
val = &completefiles[fileskey(type, f->dir, f->ext)];
else completions[newstring(command)] = *val;
}
-void addfilecomplete(char *command, char *dir, char *ext)
-{
+void addfilecomplete(char *command, char *dir, char *ext) {
addcomplete(command, FILES_DIR, dir, ext);
}
-void addvarcomplete(char *command, char *var, char *ext)
-{
+void addvarcomplete(char *command, char *var, char *ext) {
addcomplete(command, FILES_VAR, var, ext);
}
-void addlistcomplete(char *command, char *list)
-{
+void addlistcomplete(char *command, char *list) {
addcomplete(command, FILES_LIST, list, NULL);
}
COMMANDN(varcomplete, addvarcomplete, "sss");
COMMANDN(listcomplete, addlistcomplete, "ss");
-void complete(char *s, int maxlen, const char *cmdprefix)
-{
+void complete(char *s, int maxlen, const char *cmdprefix) {
int cmdlen = 0;
- if(cmdprefix)
- {
+ if(cmdprefix) {
cmdlen = strlen(cmdprefix);
if(strncmp(s, cmdprefix, cmdlen)) prependstring(s, cmdprefix, maxlen);
}
if(!s[cmdlen]) return;
if(!completesize) { completesize = (int)strlen(&s[cmdlen]); DELETEA(lastcomplete); }
-
filesval *f = NULL;
- if(completesize)
- {
+ if(completesize) {
char *end = strchr(&s[cmdlen], ' ');
if(end) f = completions.find(stringslice(&s[cmdlen], end), NULL);
}
-
const char *nextcomplete = NULL;
- if(f) // complete using filenames
- {
+ if(f) { // complete using filenames {
int commandsize = strchr(&s[cmdlen], ' ')+1-s;
f->update();
- loopv(f->files)
- {
+ loopv(f->files) {
if(strncmp(f->files[i], &s[commandsize], completesize+cmdlen-commandsize)==0 &&
(!lastcomplete || strcmp(f->files[i], lastcomplete) > 0) && (!nextcomplete || strcmp(f->files[i], nextcomplete) < 0))
nextcomplete = f->files[i];
cmdprefix = s;
cmdlen = commandsize;
}
- else // complete using command names
- {
+ else { // complete using command names {
enumerate(idents, ident, id,
if(strncmp(id.name, &s[cmdlen], completesize)==0 &&
(!lastcomplete || strcmp(id.name, lastcomplete) > 0) && (!nextcomplete || strcmp(id.name, nextcomplete) < 0))
);
}
DELETEA(lastcomplete);
- if(nextcomplete)
- {
+ if(nextcomplete) {
cmdlen = min(cmdlen, maxlen-1);
if(cmdlen) memmove(s, cmdprefix, cmdlen);
copystring(&s[cmdlen], nextcomplete, maxlen-cmdlen);
}
}
-void writecompletions(stream *f)
-{
+void writecompletions(stream *f) {
vector<char *> cmds;
enumeratekt(completions, char *, k, filesval *, v, { if(v) cmds.add(k); });
cmds.sort();
- loopv(cmds)
- {
+ loopv(cmds) {
char *k = cmds[i];
filesval *v = completions[k];
- if(v->type==FILES_LIST)
- {
+ if(v->type==FILES_LIST) {
if(validateblock(v->dir)) f->printf("listcomplete %s [%s]\n", escapeid(k), v->dir);
else f->printf("listcomplete %s %s\n", escapeid(k), escapestring(v->dir));
}
#include "engine.h"
-struct decalvert
-{
+struct decalvert {
vec pos;
bvec4 color;
vec2 tc;
};
-struct decalinfo
-{
+struct decalinfo {
int millis;
bvec color;
ushort startvert, endvert;
};
-enum
-{
+enum {
DF_RND4 = 1<<0,
DF_ROTATE = 1<<1,
DF_INVMOD = 1<<2,
VARFP(maxdecaltris, 1, 1024, 16384, initdecals());
VARP(decalfade, 1000, 10000, 60000);
-struct decalrenderer
-{
+struct decalrenderer {
const char *texname;
int flags, fadeintime, fadeouttime, timetolive;
Texture *tex;
int maxverts, startvert, endvert, lastvert, availverts;
GLuint vbo;
bool dirty;
-
decalrenderer(const char *texname, int flags = 0, int fadeintime = 0, int fadeouttime = 1000, int timetolive = -1)
: texname(texname), flags(flags),
fadeintime(fadeintime), fadeouttime(fadeouttime), timetolive(timetolive),
decals(NULL), maxdecals(0), startdecal(0), enddecal(0),
verts(NULL), maxverts(0), startvert(0), endvert(0), lastvert(0), availverts(0),
vbo(0), dirty(false),
- decalu(0), decalv(0)
- {
+ decalu(0), decalv(0) {
}
-
- ~decalrenderer()
- {
+ ~decalrenderer() {
DELETEA(decals);
DELETEA(verts);
}
-
- void init(int tris)
- {
- if(decals)
- {
+ void init(int tris) {
+ if(decals) {
DELETEA(decals);
maxdecals = startdecal = enddecal = 0;
}
- if(verts)
- {
+ if(verts) {
DELETEA(verts);
maxverts = startvert = endvert = lastvert = availverts = 0;
}
availverts = maxverts - 3;
verts = new decalvert[maxverts];
}
-
- int hasdecals()
- {
+ int hasdecals() {
return enddecal < startdecal ? maxdecals - (startdecal - enddecal) : enddecal - startdecal;
}
-
- void cleanup()
- {
+ void cleanup() {
if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; }
}
-
- void cleardecals()
- {
+ void cleardecals() {
startdecal = enddecal = 0;
startvert = endvert = lastvert = 0;
availverts = maxverts - 3;
dirty = true;
}
-
- int freedecal()
- {
+ int freedecal() {
if(startdecal==enddecal) return 0;
-
decalinfo &d = decals[startdecal];
startdecal++;
if(startdecal >= maxdecals) startdecal = 0;
-
int removed = d.endvert < d.startvert ? maxverts - (d.startvert - d.endvert) : d.endvert - d.startvert;
startvert = d.endvert;
if(startvert==endvert) startvert = endvert = lastvert = 0;
availverts += removed;
-
return removed;
}
-
- void fadedecal(decalinfo &d, uchar alpha)
- {
+ void fadedecal(decalinfo &d, uchar alpha) {
bvec rgb;
if(flags&DF_OVERBRIGHT) rgb = bvec(128, 128, 128);
- else
- {
+ else {
rgb = d.color;
if(flags&(DF_ADD|DF_INVMOD)) rgb.scale(alpha, 255);
}
bvec4 color(rgb, alpha);
-
decalvert *vert = &verts[d.startvert],
*end = &verts[d.endvert < d.startvert ? maxverts : d.endvert];
- while(vert < end)
- {
+ while(vert < end) {
vert->color = color;
vert++;
}
- if(d.endvert < d.startvert)
- {
+ if(d.endvert < d.startvert) {
vert = verts;
end = &verts[d.endvert];
- while(vert < end)
- {
+ while(vert < end) {
vert->color = color;
vert++;
}
}
dirty = true;
}
-
- void clearfadeddecals()
- {
+ void clearfadeddecals() {
int threshold = lastmillis - (timetolive>=0 ? timetolive : decalfade) - fadeouttime;
decalinfo *d = &decals[startdecal],
*end = &decals[enddecal < startdecal ? maxdecals : enddecal];
while(d < end && d->millis <= threshold) d++;
- if(d >= end && enddecal < startdecal)
- {
+ if(d >= end && enddecal < startdecal) {
d = decals;
end = &decals[enddecal];
while(d < end && d->millis <= threshold) d++;
availverts = endvert < startvert ? startvert - endvert - 3 : maxverts - 3 - (endvert - startvert);
dirty = true;
}
-
- void fadeindecals()
- {
+ void fadeindecals() {
if(!fadeintime) return;
decalinfo *d = &decals[enddecal],
*end = &decals[enddecal < startdecal ? 0 : startdecal];
- while(d > end)
- {
+ while(d > end) {
d--;
int fade = lastmillis - d->millis;
if(fade >= fadeintime) return;
fadedecal(*d, (fade<<8)/fadeintime);
}
- if(enddecal < startdecal)
- {
+ if(enddecal < startdecal) {
d = &decals[maxdecals];
end = &decals[startdecal];
- while(d > end)
- {
+ while(d > end) {
d--;
int fade = lastmillis - d->millis;
if(fade >= fadeintime) return;
}
}
}
-
- void fadeoutdecals()
- {
+ void fadeoutdecals() {
decalinfo *d = &decals[startdecal],
*end = &decals[enddecal < startdecal ? maxdecals : enddecal];
int offset = (timetolive>=0 ? timetolive : decalfade) + fadeouttime - lastmillis;
- while(d < end)
- {
+ while(d < end) {
int fade = d->millis + offset;
if(fade >= fadeouttime) return;
fadedecal(*d, (fade<<8)/fadeouttime);
d++;
}
- if(enddecal < startdecal)
- {
+ if(enddecal < startdecal) {
d = decals;
end = &decals[enddecal];
- while(d < end)
- {
+ while(d < end) {
int fade = d->millis + offset;
if(fade >= fadeouttime) return;
fadedecal(*d, (fade<<8)/fadeouttime);
}
}
}
-
- static void setuprenderstate()
- {
+ static void setuprenderstate() {
enablepolygonoffset(GL_POLYGON_OFFSET_FILL);
-
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
-
gle::enablevertex();
gle::enabletexcoord0();
gle::enablecolor();
}
-
- static void cleanuprenderstate()
- {
+ static void cleanuprenderstate() {
gle::clearvbo();
-
gle::disablevertex();
gle::disabletexcoord0();
gle::disablecolor();
-
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
-
disablepolygonoffset(GL_POLYGON_OFFSET_FILL);
}
-
- void render()
- {
+ void render() {
if(startvert==endvert) return;
-
- if(flags&DF_OVERBRIGHT)
- {
+ if(flags&DF_OVERBRIGHT) {
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
SETSHADER(overbrightdecal);
}
- else
- {
+ else {
if(flags&DF_INVMOD) { glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); }
else if(flags&DF_ADD) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); }
else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
if(flags&DF_SATURATE) SETSHADER(saturatedecal);
}
-
glBindTexture(GL_TEXTURE_2D, tex->id);
-
if(!vbo) { glGenBuffers_(1, &vbo); dirty = true; }
gle::bindvbo(vbo);
-
int count = endvert < startvert ? maxverts - startvert : endvert - startvert;
- if(dirty)
- {
+ if(dirty) {
glBufferData_(GL_ARRAY_BUFFER, maxverts*sizeof(decalvert), NULL, GL_STREAM_DRAW);
glBufferSubData_(GL_ARRAY_BUFFER, 0, count*sizeof(decalvert), &verts[startvert]);
- if(endvert < startvert)
- {
+ if(endvert < startvert) {
glBufferSubData_(GL_ARRAY_BUFFER, count*sizeof(decalvert), endvert*sizeof(decalvert), verts);
count += endvert;
}
dirty = false;
}
else if(endvert < startvert) count += endvert;
-
const decalvert *ptr = 0;
gle::vertexpointer(sizeof(decalvert), ptr->pos.v);
gle::texcoord0pointer(sizeof(decalvert), ptr->tc.v);
gle::colorpointer(sizeof(decalvert), ptr->color.v);
-
glDrawArrays(GL_TRIANGLES, 0, count);
xtravertsva += count;
-
extern int intel_vertexarray_bug;
if(intel_vertexarray_bug) glFlush();
}
-
- decalinfo &newdecal()
- {
+ decalinfo &newdecal() {
decalinfo &d = decals[enddecal];
int next = enddecal + 1;
if(next>=maxdecals) next = 0;
dirty = true;
return d;
}
-
ivec bbmin, bbmax;
vec decalcenter, decalnormal, decaltangent, decalbitangent;
float decalradius, decalu, decalv;
bvec4 decalcolor;
-
- void adddecal(const vec ¢er, const vec &dir, float radius, const bvec &color, int info)
- {
+ void adddecal(const vec ¢er, const vec &dir, float radius, const bvec &color, int info) {
if(dir.iszero()) return;
-
int bbradius = int(ceil(radius));
bbmin = ivec(center).sub(bbradius);
bbmax = ivec(center).add(bbradius);
-
decalcolor = bvec4(color, 255);
decalcenter = center;
decalradius = radius;
if(flags&DF_ROTATE) decaltangent.rotate(rnd(360)*RAD, dir);
decaltangent.normalize();
decalbitangent.cross(decaltangent, dir);
- if(flags&DF_RND4)
- {
+ if(flags&DF_RND4) {
decalu = 0.5f*(info&1);
decalv = 0.5f*((info>>1)&1);
}
-
lastvert = endvert;
gentris(worldroot, ivec(0, 0, 0), worldsize>>1);
if(endvert==lastvert) return;
-
decalinfo &d = newdecal();
d.color = color;
d.millis = lastmillis;
d.startvert = lastvert;
d.endvert = endvert;
}
-
- static int clip(const vec *in, int numin, const vec &dir, float below, float above, vec *out)
- {
+ static int clip(const vec *in, int numin, const vec &dir, float below, float above, vec *out) {
int numout = 0;
const vec *p = &in[numin-1];
float pc = dir.dot(*p);
- loopi(numin)
- {
+ loopi(numin) {
const vec &v = in[i];
float c = dir.dot(v);
- if(c < below)
- {
+ if(c < below) {
if(pc > above) out[numout++] = vec(*p).sub(v).mul((above - c)/(pc - c)).add(v);
if(pc > below) out[numout++] = vec(*p).sub(v).mul((below - c)/(pc - c)).add(v);
}
- else if(c > above)
- {
+ else if(c > above) {
if(pc < below) out[numout++] = vec(*p).sub(v).mul((below - c)/(pc - c)).add(v);
if(pc < above) out[numout++] = vec(*p).sub(v).mul((above - c)/(pc - c)).add(v);
}
- else
- {
- if(pc < below)
- {
+ else {
+ if(pc < below) {
if(c > below) out[numout++] = vec(*p).sub(v).mul((below - c)/(pc - c)).add(v);
}
else if(pc > above && c < above) out[numout++] = vec(*p).sub(v).mul((above - c)/(pc - c)).add(v);
}
return numout;
}
-
- void gentris(cube &cu, int orient, const ivec &o, int size, materialsurface *mat = NULL, int vismask = 0)
- {
+ void gentris(cube &cu, int orient, const ivec &o, int size, materialsurface *mat = NULL, int vismask = 0) {
vec pos[MAXFACEVERTS+4] = { vec(0, 0, 0) };
int numverts = 0, numplanes = 1;
vec planes[2] = { vec(0, 0, 0) };
- if(mat)
- {
+ if(mat) {
planes[0] = vec(0, 0, 0);
- switch(orient)
- {
+ switch(orient) {
#define GENFACEORIENT(orient, v0, v1, v2, v3) \
case orient: \
planes[0][dimension(orient)] = dimcoord(orient) ? 1 : -1; \
#undef GENFACEVERT
}
}
- else if(cu.ext && (numverts = cu.ext->surfaces[orient].numverts&MAXFACEVERTS))
- {
+ else if(cu.ext && (numverts = cu.ext->surfaces[orient].numverts&MAXFACEVERTS)) {
vertinfo *verts = cu.ext->verts() + cu.ext->surfaces[orient].verts;
ivec vo = ivec(o).mask(~0xFFF).shl(3);
loopj(numverts) pos[j] = vec(verts[j].getxyz().add(vo)).mul(1/8.0f);
planes[0].cross(pos[0], pos[1], pos[2]).normalize();
- if(numverts >= 4 && !(cu.merged&(1<<orient)) && !flataxisface(cu, orient) && faceconvexity(verts, numverts, size))
- {
+ if(numverts >= 4 && !(cu.merged&(1<<orient)) && !flataxisface(cu, orient) && faceconvexity(verts, numverts, size)) {
planes[1].cross(pos[0], pos[2], pos[3]).normalize();
numplanes++;
}
}
else if(cu.merged&(1<<orient)) return;
- else if(!vismask || (vismask&0x40 && visibleface(cu, orient, o, size, MAT_AIR, (cu.material&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA)))
- {
+ else if(!vismask || (vismask&0x40 && visibleface(cu, orient, o, size, MAT_AIR, (cu.material&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA))) {
ivec v[4];
genfaceverts(cu, orient, v);
int vis = 3, convex = faceconvexity(v, vis), order = convex < 0 ? 1 : 0;
if(convex) { planes[1].cross(pos[0], pos[2], pos[3]).normalize(); numplanes++; }
}
else return;
-
- loopl(numplanes)
- {
+ loopl(numplanes) {
const vec &n = planes[l];
float facing = n.dot(decalnormal);
if(facing <= 0) continue;
vec v1[MAXFACEVERTS+4], v2[MAXFACEVERTS+4];
float ptc = pt.dot(pcenter), pbc = pb.dot(pcenter);
int numv;
- if(numplanes >= 2)
- {
+ if(numplanes >= 2) {
if(l) { pos[1] = pos[2]; pos[2] = pos[3]; }
numv = clip(pos, 3, pt, ptc - decalradius, ptc + decalradius, v1);
if(numv<3) continue;
}
- else
- {
+ else {
numv = clip(pos, numverts, pt, ptc - decalradius, ptc + decalradius, v1);
if(numv<3) continue;
}
dv2 = { v2[1], decalcolor, vec2(pt.dot(v2[1]) + tu, pb.dot(v2[1]) + tv) };
int totalverts = 3*(numv-2);
if(totalverts > maxverts-3) return;
- while(availverts < totalverts)
- {
+ while(availverts < totalverts) {
if(!freedecal()) return;
}
availverts -= totalverts;
- loopk(numv-2)
- {
+ loopk(numv-2) {
verts[endvert++] = dv1;
verts[endvert++] = dv2;
dv2.pos = v2[k+2];
}
}
}
-
- void findmaterials(vtxarray *va)
- {
+ void findmaterials(vtxarray *va) {
materialsurface *matbuf = va->matbuf;
int matsurfs = va->matsurfs;
- loopi(matsurfs)
- {
+ loopi(matsurfs) {
materialsurface &m = matbuf[i];
if(1) { i += m.skip; continue; }
int dim = dimension(m.orient), dc = dimcoord(m.orient);
if(dc ? decalnormal[dim] <= 0 : decalnormal[dim] >= 0) { i += m.skip; continue; }
int c = C[dim], r = R[dim];
- for(;;)
- {
+ for(;;) {
materialsurface &m = matbuf[i];
if(m.o[dim] >= bbmin[dim] && m.o[dim] <= bbmax[dim] &&
m.o[c] + m.csize >= bbmin[c] && m.o[c] <= bbmax[c] &&
- m.o[r] + m.rsize >= bbmin[r] && m.o[r] <= bbmax[r])
- {
+ m.o[r] + m.rsize >= bbmin[r] && m.o[r] <= bbmax[r]) {
static cube dummy;
gentris(dummy, m.orient, m.o, max(m.csize, m.rsize), &m);
}
}
}
}
-
- void findescaped(cube *cu, const ivec &o, int size, int escaped)
- {
- loopi(8)
- {
- if(escaped&(1<<i))
- {
+ void findescaped(cube *cu, const ivec &o, int size, int escaped) {
+ loopi(8) {
+ if(escaped&(1<<i)) {
ivec co(i, o, size);
if(cu[i].children) findescaped(cu[i].children, co, size>>1, cu[i].escaped);
- else
- {
+ else {
int vismask = cu[i].merged;
if(vismask) loopj(6) if(vismask&(1<<j)) gentris(cu[i], j, co, size);
}
}
}
}
-
- void gentris(cube *cu, const ivec &o, int size, int escaped = 0)
- {
+ void gentris(cube *cu, const ivec &o, int size, int escaped = 0) {
int overlap = octaboxoverlap(o, size, bbmin, bbmax);
- loopi(8)
- {
- if(overlap&(1<<i))
- {
+ loopi(8) {
+ if(overlap&(1<<i)) {
ivec co(i, o, size);
if(cu[i].ext && cu[i].ext->va && cu[i].ext->va->matsurfs)
findmaterials(cu[i].ext->va);
if(cu[i].children) gentris(cu[i].children, co, size>>1, cu[i].escaped);
- else
- {
+ else {
int vismask = cu[i].visible;
- if(vismask&0xC0)
- {
+ if(vismask&0xC0) {
if(vismask&0x80) loopj(6) gentris(cu[i], j, co, size, NULL, vismask);
else loopj(6) if(vismask&(1<<j)) gentris(cu[i], j, co, size);
}
}
}
- else if(escaped&(1<<i))
- {
+ else if(escaped&(1<<i)) {
ivec co(i, o, size);
if(cu[i].children) findescaped(cu[i].children, co, size>>1, cu[i].escaped);
- else
- {
+ else {
int vismask = cu[i].merged;
if(vismask) loopj(6) if(vismask&(1<<j)) gentris(cu[i], j, co, size);
}
}
};
-decalrenderer decals[] =
-{
+decalrenderer decals[] = {
decalrenderer("<grey>packages/particles/scorch.png", DF_ROTATE, 500),
decalrenderer("<grey>packages/particles/blood.png", DF_RND4|DF_ROTATE|DF_INVMOD),
decalrenderer("<grey>packages/particles/bullet.png", DF_OVERBRIGHT)
};
-void initdecals()
-{
+void initdecals() {
loopi(sizeof(decals)/sizeof(decals[0])) decals[i].init(maxdecaltris);
}
-void cleardecals()
-{
+void cleardecals() {
loopi(sizeof(decals)/sizeof(decals[0])) decals[i].cleardecals();
}
-void cleanupdecals()
-{
+void cleanupdecals() {
loopi(sizeof(decals)/sizeof(decals[0])) decals[i].cleanup();
}
VARNP(decals, showdecals, 0, 1, 1);
-void renderdecals(bool mainpass)
-{
+void renderdecals(bool mainpass) {
bool rendered = false;
- loopi(sizeof(decals)/sizeof(decals[0]))
- {
+ loopi(sizeof(decals)/sizeof(decals[0])) {
decalrenderer &d = decals[i];
- if(mainpass)
- {
+ if(mainpass) {
d.clearfadeddecals();
d.fadeindecals();
d.fadeoutdecals();
}
if(!showdecals || !d.hasdecals()) continue;
- if(!rendered)
- {
+ if(!rendered) {
rendered = true;
decalrenderer::setuprenderstate();
}
VARP(maxdecaldistance, 1, 512, 10000);
-void adddecal(int type, const vec ¢er, const vec &surface, float radius, const bvec &color, int info)
-{
+void adddecal(int type, const vec ¢er, const vec &surface, float radius, const bvec &color, int info) {
if(!showdecals || type<0 || (size_t)type>=sizeof(decals)/sizeof(decals[0]) || center.dist(camera1->o) - radius > maxdecaldistance) return;
decalrenderer &d = decals[type];
d.adddecal(center, surface, radius, color, info);
VARP(maxdynlights, 0, min(3, MAXDYNLIGHTS), MAXDYNLIGHTS);
VARP(dynlightdist, 0, 1024, 10000);
-struct dynlight
-{
+struct dynlight {
vec o, hud;
float radius, initradius, curradius, dist;
vec color, initcolor, curcolor;
int fade, peak, expire, flags;
physent *owner;
-
- void calcradius()
- {
- if(fade + peak > 0)
- {
+ void calcradius() {
+ if(fade + peak > 0) {
int remaining = expire - lastmillis;
if(flags&DL_EXPAND)
curradius = initradius + (radius - initradius) * (1.0f - remaining/float(fade + peak));
}
else curradius = radius;
}
-
- void calccolor()
- {
+ void calccolor() {
if(flags&DL_FLASH || peak <= 0) curcolor = color;
- else
- {
+ else {
int peaking = expire - lastmillis - fade;
if(peaking <= 0) curcolor = color;
else curcolor.lerp(initcolor, color, 1.0f - float(peaking)/peak);
}
-
float intensity = 1.0f;
- if(fade > 0)
- {
+ if(fade > 0) {
int fading = expire - lastmillis;
if(fading < fade) intensity = float(fading)/fade;
}
vector<dynlight> dynlights;
vector<dynlight *> closedynlights;
-void adddynlight(const vec &o, float radius, const vec &color, int fade, int peak, int flags, float initradius, const vec &initcolor, physent *owner)
-{
+void adddynlight(const vec &o, float radius, const vec &color, int fade, int peak, int flags, float initradius, const vec &initcolor, physent *owner) {
if(!maxdynlights) return;
if(o.dist(camera1->o) > dynlightdist || radius <= 0) return;
-
int insert = 0, expire = fade + peak + lastmillis;
loopvrev(dynlights) if(expire>=dynlights[i].expire) { insert = i+1; break; }
dynlight d;
dynlights.insert(insert, d);
}
-void cleardynlights()
-{
+void cleardynlights() {
int faded = -1;
loopv(dynlights) if(lastmillis<dynlights[i].expire) { faded = i; break; }
if(faded<0) dynlights.setsize(0);
else if(faded>0) dynlights.remove(0, faded);
}
-void removetrackeddynlights(physent *owner)
-{
+void removetrackeddynlights(physent *owner) {
loopvrev(dynlights) if(owner ? dynlights[i].owner == owner : dynlights[i].owner != NULL) dynlights.remove(i);
}
-void updatedynlights()
-{
+void updatedynlights() {
cleardynlights();
game::adddynlights();
-
- loopv(dynlights)
- {
+ loopv(dynlights) {
dynlight &d = dynlights[i];
if(d.owner) game::dynlighttrack(d.owner, d.o, d.hud);
d.calcradius();
}
}
-int finddynlights()
-{
+int finddynlights() {
closedynlights.setsize(0);
if(!maxdynlights) return 0;
physent e;
e.type = ENT_CAMERA;
- loopvj(dynlights)
- {
+ loopvj(dynlights) {
dynlight &d = dynlights[j];
if(d.curradius <= 0) continue;
d.dist = camera1->o.dist(d.o) - d.curradius;
e.o = d.o;
e.radius = e.xradius = e.yradius = e.eyeheight = e.aboveeye = d.curradius;
if(!collide(&e, vec(0, 0, 0), 0, false)) continue;
-
int insert = 0;
loopvrev(closedynlights) if(d.dist >= closedynlights[i]->dist) { insert = i+1; break; }
closedynlights.insert(insert, &d);
return closedynlights.length();
}
-bool getdynlight(int n, vec &o, float &radius, vec &color)
-{
+bool getdynlight(int n, vec &o, float &radius, vec &color) {
if(!closedynlights.inrange(n)) return false;
dynlight &d = *closedynlights[n];
o = d.o;
return true;
}
-void dynlightreaching(const vec &target, vec &color, vec &dir, bool hud)
-{
+void dynlightreaching(const vec &target, vec &color, vec &dir, bool hud) {
vec dyncolor(0, 0, 0);//, dyndir(0, 0, 0);
- loopv(dynlights)
- {
+ loopv(dynlights) {
dynlight &d = dynlights[i];
if(d.curradius<=0) continue;
-
vec ray(hud ? d.hud : d.o);
ray.sub(target);
float mag = ray.squaredlen();
if(mag >= d.curradius*d.curradius) continue;
-
vec color = d.curcolor;
color.mul(1 - sqrtf(mag)/d.curradius);
dyncolor.add(color);
//dyndir.add(ray.mul(intensity/mag));
}
#if 0
- if(!dyndir.iszero())
- {
+ if(!dyndir.iszero()) {
dyndir.normalize();
float x = dyncolor.magnitude(), y = color.magnitude();
- if(x+y>0)
- {
+ if(x+y>0) {
dir.mul(x);
dyndir.mul(y);
dir.add(dyndir).div(x+y);
color.add(dyncolor);
}
-void calcdynlightmask(vtxarray *va)
-{
+void calcdynlightmask(vtxarray *va) {
uint mask = 0;
int offset = 0;
- loopv(closedynlights)
- {
+ loopv(closedynlights) {
dynlight &d = *closedynlights[i];
if(d.o.dist_to_bb(va->geommin, va->geommax) >= d.curradius) continue;
-
mask |= (i+1)<<offset;
offset += DYNLIGHTBITS;
if(offset >= maxdynlights*DYNLIGHTBITS) break;
va->dynlightmask = mask;
}
-int setdynlights(vtxarray *va)
-{
+int setdynlights(vtxarray *va) {
if(closedynlights.empty() || !va->dynlightmask) return 0;
-
extern bool minimizedynlighttcusage();
-
static vec4 posv[MAXDYNLIGHTS];
static vec colorv[MAXDYNLIGHTS];
-
int index = 0;
- for(uint mask = va->dynlightmask; mask; mask >>= DYNLIGHTBITS, index++)
- {
+ for(uint mask = va->dynlightmask; mask; mask >>= DYNLIGHTBITS, index++) {
dynlight &d = *closedynlights[(mask&DYNLIGHTMASK)-1];
-
float scale = 1.0f/d.curradius;
vec origin = vec(d.o).mul(-scale);
-
- if(index>0 && minimizedynlighttcusage())
- {
+ if(index>0 && minimizedynlighttcusage()) {
scale /= posv[0].w;
origin.sub(vec(posv[0]).mul(scale));
}
-
posv[index] = vec4(origin, scale);
colorv[index] = d.curcolor;
}
-
GLOBALPARAMV(dynlightpos, posv, index);
GLOBALPARAMV(dynlightcolor, colorv, index);
-
return index;
}
extern vector<int> entgroup;
// rendertext
-struct font
-{
- struct charinfo
- {
+struct font {
+ struct charinfo {
short x, y, w, h, offsetx, offsety, advance, tex;
};
-
char *name;
vector<Texture *> texs;
vector<charinfo> chars;
int charoffset, defaultw, defaulth, scale;
-
font() : name(NULL) {}
~font() { DELETEA(name); }
};
extern bool isshadowmapreceiver(vtxarray *va);
extern void rendershadowmap();
extern void pushshadowmap();
-extern void popshadowmap();
extern void rendershadowmapreceivers();
extern void guessshadowdir();
extern void hudquad(float x, float y, float w, float h, float tx = 0, float ty = 0, float tw = 1, float th = 1);
extern void writecrosshairs(stream *f);
-namespace modelpreview
-{
+namespace modelpreview {
extern void start(int x, int y, int w, int h, bool background = true);
extern void end();
}
extern int mergefaces(int orient, facebounds *m, int sz);
extern void mincubeface(const cube &cu, int orient, const ivec &o, int size, const facebounds &orig, facebounds &cf, ushort nmat = MAT_AIR, ushort matmask = 0);
-static inline cubeext &ext(cube &c)
-{
+static inline cubeext &ext(cube &c) {
return *(c.ext ? c.ext : newcubeext(c));
}
extern void writecompletions(stream *f);
// main
-enum
-{
+enum {
NOT_INITING = 0,
INIT_GAME,
INIT_LOAD,
};
extern int initing, numcpus;
-enum
-{
+enum {
CHANGE_GFX = 1<<0,
CHANGE_SOUND = 1<<1
};
extern mapmodelinfo *getmminfo(int i);
extern void startmodelquery(occludequery *query);
extern void endmodelquery();
-extern void preloadmodelshaders(bool force = false);
+extern void preloadmodelshaders();
extern void preloadusedmapmodels(bool msg = false, bool bih = false);
-static inline model *loadmapmodel(int n)
-{
+static inline model *loadmapmodel(int n) {
extern vector<mapmodelinfo> mapmodels;
- if(mapmodels.inrange(n))
- {
+ if(mapmodels.inrange(n)) {
model *m = mapmodels[n].m;
return m ? m : loadmodel(NULL, n);
}
+++ /dev/null
-namespace sphere
-{
- struct vert
- {
- vec pos;
- ushort s, t;
- } *verts = NULL;
- GLushort *indices = NULL;
- int numverts = 0, numindices = 0;
- GLuint vbuf = 0, ebuf = 0;
-
- void init(int slices, int stacks)
- {
- numverts = (stacks+1)*(slices+1);
- verts = new vert[numverts];
- float ds = 1.0f/slices, dt = 1.0f/stacks, t = 1.0f;
- loopi(stacks+1)
- {
- float rho = M_PI*(1-t), s = 0.0f, sinrho = i && i < stacks ? sin(rho) : 0, cosrho = !i ? 1 : (i < stacks ? cos(rho) : -1);
- loopj(slices+1)
- {
- float theta = j==slices ? 0 : 2*M_PI*s;
- vert &v = verts[i*(slices+1) + j];
- v.pos = vec(-sin(theta)*sinrho, cos(theta)*sinrho, cosrho);
- v.s = ushort(s*0xFFFF);
- v.t = ushort(t*0xFFFF);
- s += ds;
- }
- t -= dt;
- }
-
- numindices = (stacks-1)*slices*3*2;
- indices = new ushort[numindices];
- GLushort *curindex = indices;
- loopi(stacks)
- {
- loopk(slices)
- {
- int j = i%2 ? slices-k-1 : k;
- if(i)
- {
- *curindex++ = i*(slices+1)+j;
- *curindex++ = (i+1)*(slices+1)+j;
- *curindex++ = i*(slices+1)+j+1;
- }
- if(i+1 < stacks)
- {
- *curindex++ = i*(slices+1)+j+1;
- *curindex++ = (i+1)*(slices+1)+j;
- *curindex++ = (i+1)*(slices+1)+j+1;
- }
- }
- }
-
- if(!vbuf) glGenBuffers_(1, &vbuf);
- gle::bindvbo(vbuf);
- glBufferData_(GL_ARRAY_BUFFER, numverts*sizeof(vert), verts, GL_STATIC_DRAW);
- DELETEA(verts);
-
- if(!ebuf) glGenBuffers_(1, &ebuf);
- gle::bindebo(ebuf);
- glBufferData_(GL_ELEMENT_ARRAY_BUFFER, numindices*sizeof(GLushort), indices, GL_STATIC_DRAW);
- DELETEA(indices);
- }
-
- void enable()
- {
- if(!vbuf) init(12, 6);
-
- gle::bindvbo(vbuf);
- gle::bindebo(ebuf);
-
- gle::vertexpointer(sizeof(vert), &verts->pos);
- gle::texcoord0pointer(sizeof(vert), &verts->s, GL_UNSIGNED_SHORT, 2, GL_TRUE);
- gle::enablevertex();
- gle::enabletexcoord0();
- }
-
- void draw()
- {
- glDrawRangeElements_(GL_TRIANGLES, 0, numverts-1, numindices, GL_UNSIGNED_SHORT, indices);
- xtraverts += numindices;
- glde++;
- }
-
- void disable()
- {
- gle::disablevertex();
- gle::disabletexcoord0();
-
- gle::clearvbo();
- gle::clearebo();
- }
-
- void cleanup()
- {
- if(vbuf) { glDeleteBuffers_(1, &vbuf); vbuf = 0; }
- if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; }
- }
-}
-
-static const float WOBBLE = 1.25f;
-
-struct fireballrenderer : listrenderer
-{
- fireballrenderer(const char *texname)
- : listrenderer(texname, 0, PT_FIREBALL|PT_GLARE|PT_SHADER)
- {}
-
- void startrender()
- {
- SETSHADER(explosion);
- sphere::enable();
- }
-
- void endrender()
- {
- sphere::disable();
- }
-
- void cleanup()
- {
- sphere::cleanup();
- }
-
- void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
- {
- pe.maxfade = max(pe.maxfade, fade);
- pe.extendbb(o, (size+1+pe.ent->attr2)*WOBBLE);
- }
-
- void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
- {
- float pmax = p->val, size = p->fade ? float(ts)/p->fade : 1, psize = p->size + pmax * size;
-
- vec dir = vec(o).sub(camera1->o), s, t;
- float dist = dir.magnitude();
- bool inside = dist <= psize*WOBBLE;
- if(inside)
- {
- s = camright;
- t = camup;
- }
- else
- {
- float mag2 = dir.magnitude2();
- dir.x /= mag2;
- dir.y /= mag2;
- dir.z /= dist;
- s = vec(dir.y, -dir.x, 0);
- t = vec(dir.x*dir.z, dir.y*dir.z, -mag2/dist);
- }
-
- matrix3 rot(lastmillis/1000.0f*143*RAD, vec(1/SQRT3, 1/SQRT3, 1/SQRT3));
- LOCALPARAM(texgenS, rot.transposedtransform(s));
- LOCALPARAM(texgenT, rot.transposedtransform(t));
-
- matrix4 m(rot, o);
- m.scale(psize, psize, inside ? -psize : psize);
- m.mul(camprojmatrix, m);
- LOCALPARAM(explosionmatrix, m);
-
- LOCALPARAM(center, o);
- LOCALPARAMF(millis, lastmillis/1000.0f);
- LOCALPARAMF(blendparams, inside ? 0.5f : 4, inside ? 0.25f : 0);
-
- int passes = inside ? 2 : 1;
- loopi(passes)
- {
- gle::color(p->color, i ? blend/2 : blend);
- if(i) glDepthFunc(GL_GEQUAL);
- sphere::draw();
- if(i) glDepthFunc(GL_LESS);
- }
- }
-};
-
-static fireballrenderer fireballs("packages/particles/explosion.png"), bluefireballs("packages/particles/plasma.png");
-
struct iqm;
-struct iqmheader
-{
+struct iqmheader {
char magic[16];
uint version;
uint filesize;
uint num_extensions, ofs_extensions;
};
-struct iqmmesh
-{
+struct iqmmesh {
uint name;
uint material;
uint first_vertex, num_vertexes;
uint first_triangle, num_triangles;
};
-enum
-{
+enum {
IQM_POSITION = 0,
IQM_TEXCOORD = 1,
IQM_NORMAL = 2,
IQM_CUSTOM = 0x10
};
-enum
-{
+enum {
IQM_BYTE = 0,
IQM_UBYTE = 1,
IQM_SHORT = 2,
IQM_DOUBLE = 8,
};
-struct iqmtriangle
-{
+struct iqmtriangle {
uint vertex[3];
};
-struct iqmjoint
-{
+struct iqmjoint {
uint name;
int parent;
vec pos;
vec size;
};
-struct iqmpose
-{
+struct iqmpose {
int parent;
uint mask;
vec offsetpos;
vec scalesize;
};
-struct iqmanim
-{
+struct iqmanim {
uint name;
uint first_frame, num_frames;
float framerate;
uint flags;
};
-struct iqmvertexarray
-{
+struct iqmvertexarray {
uint type;
uint flags;
uint format;
uint offset;
};
-struct iqm : skelloader<iqm>
-{
+struct iqm : skelloader<iqm> {
iqm(const char *name) : skelloader(name) {}
-
static const char *formatname() { return "iqm"; }
int type() const { return MDL_IQM; }
-
- struct iqmmeshgroup : skelmeshgroup
- {
- iqmmeshgroup()
- {
+ struct iqmmeshgroup : skelmeshgroup {
+ iqmmeshgroup() {
}
-
- bool loadiqmmeshes(const char *filename, const iqmheader &hdr, uchar *buf)
- {
+ bool loadiqmmeshes(const char *filename, const iqmheader &hdr, uchar *buf) {
lilswap((uint *)&buf[hdr.ofs_vertexarrays], hdr.num_vertexarrays*sizeof(iqmvertexarray)/sizeof(uint));
lilswap((uint *)&buf[hdr.ofs_triangles], hdr.num_triangles*sizeof(iqmtriangle)/sizeof(uint));
lilswap((uint *)&buf[hdr.ofs_meshes], hdr.num_meshes*sizeof(iqmmesh)/sizeof(uint));
lilswap((uint *)&buf[hdr.ofs_joints], hdr.num_joints*sizeof(iqmjoint)/sizeof(uint));
-
const char *str = hdr.ofs_text ? (char *)&buf[hdr.ofs_text] : "";
float *vpos = NULL, *vnorm = NULL, *vtan = NULL, *vtc = NULL;
uchar *vindex = NULL, *vweight = NULL;
iqmvertexarray *vas = (iqmvertexarray *)&buf[hdr.ofs_vertexarrays];
- loopi(hdr.num_vertexarrays)
- {
+ loopi(hdr.num_vertexarrays) {
iqmvertexarray &va = vas[i];
- switch(va.type)
- {
+ switch(va.type) {
case IQM_POSITION: if(va.format != IQM_FLOAT || va.size != 3) return false; vpos = (float *)&buf[va.offset]; lilswap(vpos, 3*hdr.num_vertexes); break;
case IQM_NORMAL: if(va.format != IQM_FLOAT || va.size != 3) return false; vnorm = (float *)&buf[va.offset]; lilswap(vnorm, 3*hdr.num_vertexes); break;
case IQM_TANGENT: if(va.format != IQM_FLOAT || va.size != 4) return false; vtan = (float *)&buf[va.offset]; lilswap(vtan, 4*hdr.num_vertexes); break;
}
}
if(!vpos) return false;
-
iqmtriangle *tris = (iqmtriangle *)&buf[hdr.ofs_triangles];
iqmmesh *imeshes = (iqmmesh *)&buf[hdr.ofs_meshes];
iqmjoint *joints = (iqmjoint *)&buf[hdr.ofs_joints];
-
- if(hdr.num_joints)
- {
- if(skel->numbones <= 0)
- {
+ if(hdr.num_joints) {
+ if(skel->numbones <= 0) {
skel->numbones = hdr.num_joints;
skel->bones = new boneinfo[skel->numbones];
- loopi(hdr.num_joints)
- {
+ loopi(hdr.num_joints) {
iqmjoint &j = joints[i];
boneinfo &b = skel->bones[i];
if(!b.name) b.name = newstring(&str[j.name]);
b.parent = j.parent;
- if(skel->shared <= 1)
- {
+ if(skel->shared <= 1) {
j.pos.y = -j.pos.y;
j.orient.x = -j.orient.x;
j.orient.z = -j.orient.z;
}
}
}
-
if(skel->shared <= 1)
skel->linkchildren();
}
-
- loopi(hdr.num_meshes)
- {
+ loopi(hdr.num_meshes) {
iqmmesh &im = imeshes[i];
skelmesh *m = new skelmesh;
m->group = this;
m->name = newstring(&str[im.name]);
m->numverts = im.num_vertexes;
int noblend = -1;
- if(m->numverts)
- {
+ if(m->numverts) {
m->verts = new vert[m->numverts];
if(vtan) m->bumpverts = new bumpvert[m->numverts];
- if(!vindex || !vweight)
- {
+ if(!vindex || !vweight) {
blendcombo c;
c.finalize(0);
noblend = m->addblendcombo(c);
*mtan = vtan ? vtan + 4*fv : NULL,
*mtc = vtc ? vtc + 2*fv : NULL;
uchar *mindex = vindex ? vindex + 4*fv : NULL, *mweight = vweight ? vweight + 4*fv : NULL;
- loopj(im.num_vertexes)
- {
+ loopj(im.num_vertexes) {
vert &v = m->verts[j];
v.pos = vec(mpos[0], -mpos[1], mpos[2]);
mpos += 3;
- if(mtc)
- {
+ if(mtc) {
v.tc = vec2(mtc[0], mtc[1]);
mtc += 2;
}
else v.tc = vec2(0, 0);
- if(mnorm)
- {
+ if(mnorm) {
v.norm = vec(mnorm[0], -mnorm[1], mnorm[2]);
mnorm += 3;
- if(mtan)
- {
+ if(mtan) {
m->calctangent(m->bumpverts[j], v.norm, vec(mtan[0], -mtan[1], mtan[2]), mtan[3]);
mtan += 4;
}
}
else v.norm = vec(0, 0, 0);
- if(noblend < 0)
- {
+ if(noblend < 0) {
blendcombo c;
int sorted = 0;
loopk(4) sorted = c.addweight(sorted, mweight[k], mindex[k]);
m->numtris = im.num_triangles;
if(m->numtris) m->tris = new tri[m->numtris];
iqmtriangle *mtris = tris + im.first_triangle;
- loopj(im.num_triangles)
- {
+ loopj(im.num_triangles) {
tri &t = m->tris[j];
t.vert[0] = mtris->vertex[0] - fv;
t.vert[1] = mtris->vertex[1] - fv;
t.vert[2] = mtris->vertex[2] - fv;
++mtris;
}
- if(!m->numtris || !m->numverts)
- {
+ if(!m->numtris || !m->numverts) {
conoutf(CON_WARN, "empty mesh in %s", filename);
meshes.removeobj(m);
delete m;
}
}
-
sortblendcombos();
-
return true;
}
-
- bool loadiqmanims(const char *filename, const iqmheader &hdr, uchar *buf)
- {
+ bool loadiqmanims(const char *filename, const iqmheader &hdr, uchar *buf) {
lilswap((uint *)&buf[hdr.ofs_poses], hdr.num_poses*sizeof(iqmpose)/sizeof(uint));
lilswap((uint *)&buf[hdr.ofs_anims], hdr.num_anims*sizeof(iqmanim)/sizeof(uint));
lilswap((ushort *)&buf[hdr.ofs_frames], hdr.num_frames*hdr.num_framechannels);
-
const char *str = hdr.ofs_text ? (char *)&buf[hdr.ofs_text] : "";
iqmpose *poses = (iqmpose *)&buf[hdr.ofs_poses];
iqmanim *anims = (iqmanim *)&buf[hdr.ofs_anims];
ushort *frames = (ushort *)&buf[hdr.ofs_frames];
- loopi(hdr.num_anims)
- {
+ loopi(hdr.num_anims) {
iqmanim &a = anims[i];
string name;
copystring(name, filename);
sa->frame = skel->numframes;
sa->range = a.num_frames;
dualquat *animbones = new dualquat[(skel->numframes+a.num_frames)*skel->numbones];
- if(skel->bones)
- {
+ if(skel->bones) {
memcpy(animbones, skel->framebones, skel->numframes*skel->numbones*sizeof(dualquat));
delete[] skel->framebones;
}
animbones += skel->numframes*skel->numbones;
skel->numframes += a.num_frames;
ushort *animdata = &frames[a.first_frame*hdr.num_framechannels];
- loopj(a.num_frames)
- {
+ loopj(a.num_frames) {
dualquat *frame = &animbones[j*skel->numbones];
- loopk(skel->numbones)
- {
+ loopk(skel->numbones) {
iqmpose &p = poses[k];
vec pos;
quat orient;
orient.z = -p.offsetorient.z; if(p.mask&0x20) orient.z -= *animdata++ * p.scaleorient.z;
orient.w = p.offsetorient.w; if(p.mask&0x40) orient.w += *animdata++ * p.scaleorient.w;
orient.normalize();
- if(p.mask&0x380)
- {
+ if(p.mask&0x380) {
if(p.mask&0x80) animdata++;
if(p.mask&0x100) animdata++;
if(p.mask&0x200) animdata++;
}
}
}
-
return true;
}
-
- bool loadiqm(const char *filename, bool doloadmesh, bool doloadanim)
- {
+ bool loadiqm(const char *filename, bool doloadmesh, bool doloadanim) {
stream *f = openfile(filename, "rb");
if(!f) return false;
-
uchar *buf = NULL;
iqmheader hdr;
if(f->read(&hdr, sizeof(hdr)) != sizeof(hdr) || memcmp(hdr.magic, "INTERQUAKEMODEL", sizeof(hdr.magic))) goto error;
if(hdr.filesize > (16<<20)) goto error; // sanity check... don't load files bigger than 16 MB
buf = new (false) uchar[hdr.filesize];
if(!buf || f->read(buf + sizeof(hdr), hdr.filesize - sizeof(hdr)) != hdr.filesize - sizeof(hdr)) goto error;
-
if(doloadmesh && !loadiqmmeshes(filename, hdr, buf)) goto error;
if(doloadanim && !loadiqmanims(filename, hdr, buf)) goto error;
-
delete[] buf;
delete f;
return true;
-
error:
if(buf) delete[] buf;
delete f;
return false;
}
-
- bool loadmesh(const char *filename)
- {
+ bool loadmesh(const char *filename) {
name = newstring(filename);
-
return loadiqm(filename, true, false);
}
-
- skelanimspec *loadanim(const char *animname)
- {
+ skelanimspec *loadanim(const char *animname) {
const char *sep = strchr(animname, ':');
skelanimspec *sa = skel->findskelanim(animname, sep ? '\0' : ':');
- if(!sa)
- {
+ if(!sa) {
string filename;
copystring(filename, animname);
if(sep) filename[sep - animname] = '\0';
return sa;
}
};
-
- meshgroup *loadmeshes(const char *name, va_list args)
- {
+ meshgroup *loadmeshes(const char *name, va_list args) {
iqmmeshgroup *group = new iqmmeshgroup;
group->shareskeleton(va_arg(args, char *));
if(!group->loadmesh(name)) { delete group; return NULL; }
return group;
}
-
- bool loaddefaultparts()
- {
+ bool loaddefaultparts() {
skelpart &mdl = addpart();
mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
adjustments.setsize(0);
};
skelcommands<iqm> iqmcommands;
-
struct lightmapinfo;
struct lightmaptask;
-struct lightmapworker
-{
+struct lightmapworker {
uchar *buf;
int bufstart, bufused;
lightmapinfo *firstlightmap, *lastlightmap, *curlightmaps;
bool needspace, doneworking;
SDL_cond *spacecond;
SDL_Thread *thread;
-
lightmapworker();
~lightmapworker();
-
void reset();
bool setupthread();
void cleanupthread();
-
static int work(void *data);
};
-struct lightmapinfo
-{
+struct lightmapinfo {
lightmapinfo *next;
cube *c;
uchar *colorbuf;
int type, w, h, bpp, bufsize, surface, layers;
};
-struct lightmaptask
-{
+struct lightmaptask {
ivec o;
int size, usefaces, progress;
cube *c;
lightmapworker *worker;
};
-struct lightmapext
-{
+struct lightmapext {
cube *c;
cubeext *ext;
};
VARR(bumperror, 1, 3, 16);
VARR(lightlod, 0, 0, 10);
bvec ambientcolor(36, 24, 12);
-HVARFR(ambient, 1, 0x191919, 0xFFFFFF,
-{
+HVARFR(ambient, 1, 0x191919, 0xFFFFFF, {
if(ambient <= 255) ambient |= (ambient<<8) | (ambient<<16);
ambientcolor = bvec((ambient>>16)&0xFF, (ambient>>8)&0xFF, ambient&0xFF);
});
-static const surfaceinfo brightsurfaces[6] =
-{
+static const surfaceinfo brightsurfaces[6] = {
brightsurface,
brightsurface,
brightsurface,
brightsurface
};
-void brightencube(cube &c)
-{
+void brightencube(cube &c) {
if(!c.ext) newcubeext(c, 0, false);
memcpy(c.ext->surfaces, brightsurfaces, sizeof(brightsurfaces));
}
-void setsurfaces(cube &c, const surfaceinfo *surfs, const vertinfo *verts, int numverts)
-{
+void setsurfaces(cube &c, const surfaceinfo *surfs, const vertinfo *verts, int numverts) {
if(!c.ext || c.ext->maxverts < numverts) newcubeext(c, numverts, false);
memcpy(c.ext->surfaces, surfs, sizeof(c.ext->surfaces));
memcpy(c.ext->verts(), verts, numverts*sizeof(vertinfo));
}
-void setsurface(cube &c, int orient, const surfaceinfo &src, const vertinfo *srcverts, int numsrcverts)
-{
+void setsurface(cube &c, int orient, const surfaceinfo &src, const vertinfo *srcverts, int numsrcverts) {
int dstoffset = 0;
if(!c.ext) newcubeext(c, numsrcverts, true);
- else
- {
+ else {
int numbefore = 0, beforeoffset = 0;
- loopi(orient)
- {
+ loopi(orient) {
surfaceinfo &surf = c.ext->surfaces[i];
int numverts = surf.totalverts();
if(!numverts) continue;
beforeoffset = surf.verts + numverts;
}
int numafter = 0, afteroffset = c.ext->maxverts;
- for(int i = 5; i > orient; i--)
- {
+ for(int i = 5; i > orient; i--) {
surfaceinfo &surf = c.ext->surfaces[i];
int numverts = surf.totalverts();
if(!numverts) continue;
afteroffset = surf.verts;
}
if(afteroffset - beforeoffset >= numsrcverts) dstoffset = beforeoffset;
- else
- {
+ else {
cubeext *ext = c.ext;
- if(numbefore + numsrcverts + numafter > c.ext->maxverts)
- {
+ if(numbefore + numsrcverts + numafter > c.ext->maxverts) {
ext = growcubeext(c.ext, numbefore + numsrcverts + numafter);
memcpy(ext->surfaces, c.ext->surfaces, sizeof(ext->surfaces));
}
int offset = 0;
- if(numbefore == beforeoffset)
- {
+ if(numbefore == beforeoffset) {
if(numbefore && c.ext != ext) memcpy(ext->verts(), c.ext->verts(), numbefore*sizeof(vertinfo));
offset = numbefore;
}
- else loopi(orient)
- {
+ else loopi(orient) {
surfaceinfo &surf = ext->surfaces[i];
int numverts = surf.totalverts();
if(!numverts) continue;
}
dstoffset = offset;
offset += numsrcverts;
- if(numafter && offset > afteroffset)
- {
+ if(numafter && offset > afteroffset) {
offset += numafter;
- for(int i = 5; i > orient; i--)
- {
+ for(int i = 5; i > orient; i--) {
surfaceinfo &surf = ext->surfaces[i];
int numverts = surf.totalverts();
if(!numverts) continue;
bool calclight_canceled = false;
volatile bool check_calclight_progress = false;
-void check_calclight_canceled()
-{
- if(interceptkey(SDLK_ESCAPE))
- {
+void check_calclight_canceled() {
+ if(interceptkey(SDLK_ESCAPE)) {
calclight_canceled = true;
loopv(lightmapworkers) lightmapworkers[i]->doneworking = true;
}
if(!calclight_canceled) check_calclight_progress = false;
}
-void show_calclight_progress()
-{
+void show_calclight_progress() {
float bar1 = float(progress) / float(allocnodes);
defformatstring(text1, "%d%% using %d textures", int(bar1 * 100), lightmaps.length());
-
- if(LM_PACKW <= hwtexsize && !progresstex)
- {
+ if(LM_PACKW <= hwtexsize && !progresstex) {
glGenTextures(1, &progresstex);
createtexture(progresstex, LM_PACKW, LM_PACKH, NULL, 3, 1, GL_RGB);
}
-
// only update once a sec (4 * 250 ms ticks) to not kill performance
- if(progresstex && !calclight_canceled && progresslightmap >= 0 && !(progresstexticks++ % 4))
- {
+ if(progresstex && !calclight_canceled && progresslightmap >= 0 && !(progresstexticks++ % 4)) {
if(tasklock) SDL_LockMutex(tasklock);
LightMap &lm = lightmaps[progresslightmap];
uchar *data = lm.data;
#define CHECK_PROGRESS_LOCKED(exit, before, after) CHECK_CALCLIGHT_PROGRESS_LOCKED(exit, show_calclight_progress, before, after)
#define CHECK_PROGRESS(exit) CHECK_PROGRESS_LOCKED(exit, , )
-bool PackNode::insert(ushort &tx, ushort &ty, ushort tw, ushort th)
-{
+bool PackNode::insert(ushort &tx, ushort &ty, ushort tw, ushort th) {
if((available < tw && available < th) || w < tw || h < th)
return false;
- if(child1)
- {
+ if(child1) {
bool inserted = child1->insert(tx, ty, tw, th) ||
child2->insert(tx, ty, tw, th);
available = max(child1->available, child2->available);
if(!available) clear();
return inserted;
}
- if(w == tw && h == th)
- {
+ if(w == tw && h == th) {
available = 0;
tx = x;
ty = y;
return true;
}
-
- if(w - tw > h - th)
- {
+ if(w - tw > h - th) {
child1 = new PackNode(x, y, tw, h);
child2 = new PackNode(x + tw, y, w - tw, h);
}
- else
- {
+ else {
child1 = new PackNode(x, y, w, th);
child2 = new PackNode(x, y + th, w, h - th);
}
-
bool inserted = child1->insert(tx, ty, tw, th);
available = max(child1->available, child2->available);
return inserted;
}
-bool LightMap::insert(ushort &tx, ushort &ty, uchar *src, ushort tw, ushort th)
-{
+bool LightMap::insert(ushort &tx, ushort &ty, uchar *src, ushort tw, ushort th) {
if((type&LM_TYPE) != LM_BUMPMAP1 && !packroot.insert(tx, ty, tw, th))
return false;
-
copy(tx, ty, src, tw, th);
return true;
}
-void LightMap::copy(ushort tx, ushort ty, uchar *src, ushort tw, ushort th)
-{
+void LightMap::copy(ushort tx, ushort ty, uchar *src, ushort tw, ushort th) {
uchar *dst = data + bpp * tx + ty * bpp * LM_PACKW;
- loopi(th)
- {
+ loopi(th) {
memcpy(dst, src, bpp * tw);
dst += bpp * LM_PACKW;
src += bpp * tw;
lumels += tw * th;
}
-static void insertunlit(int i)
-{
+static void insertunlit(int i) {
LightMap &l = lightmaps[i];
- if((l.type&LM_TYPE) == LM_BUMPMAP1)
- {
+ if((l.type&LM_TYPE) == LM_BUMPMAP1) {
l.unlitx = l.unlity = -1;
return;
}
ushort x, y;
uchar unlit[4] = { ambientcolor[0], ambientcolor[1], ambientcolor[2], 255 };
- if(l.insert(x, y, unlit, 1, 1))
- {
- if((l.type&LM_TYPE) == LM_BUMPMAP0)
- {
+ if(l.insert(x, y, unlit, 1, 1)) {
+ if((l.type&LM_TYPE) == LM_BUMPMAP0) {
bvec front(128, 128, 255);
ASSERT(lightmaps[i+1].insert(x, y, front.v, 1, 1));
}
}
}
-struct layoutinfo
-{
+struct layoutinfo {
ushort x, y, lmid;
uchar w, h;
};
-static void insertlightmap(lightmapinfo &li, layoutinfo &si)
-{
- loopv(lightmaps)
- {
- if(lightmaps[i].type == li.type && lightmaps[i].insert(si.x, si.y, li.colorbuf, si.w, si.h))
- {
+static void insertlightmap(lightmapinfo &li, layoutinfo &si) {
+ loopv(lightmaps) {
+ if(lightmaps[i].type == li.type && lightmaps[i].insert(si.x, si.y, li.colorbuf, si.w, si.h)) {
si.lmid = i + LMID_RESERVED;
if((li.type&LM_TYPE) == LM_BUMPMAP0) ASSERT(lightmaps[i+1].insert(si.x, si.y, (uchar *)li.raybuf, si.w, si.h));
return;
}
}
-
progresslightmap = lightmaps.length();
-
si.lmid = lightmaps.length() + LMID_RESERVED;
LightMap &l = lightmaps.add();
l.type = li.type;
l.data = new uchar[li.bpp*LM_PACKW*LM_PACKH];
memset(l.data, 0, li.bpp*LM_PACKW*LM_PACKH);
ASSERT(l.insert(si.x, si.y, li.colorbuf, si.w, si.h));
- if((li.type&LM_TYPE) == LM_BUMPMAP0)
- {
+ if((li.type&LM_TYPE) == LM_BUMPMAP0) {
LightMap &r = lightmaps.add();
r.type = LM_BUMPMAP1 | (li.type&~LM_TYPE);
r.bpp = 3;
}
}
-static inline bool htcmp(const lightmapinfo &k, const layoutinfo &v)
-{
+static inline bool htcmp(const lightmapinfo &k, const layoutinfo &v) {
int kw = k.w, kh = k.h;
if(kw != v.w || kh != v.h) return false;
LightMap &vlm = lightmaps[v.lmid - LMID_RESERVED];
if(ktype != vlm.type) return false;
int kbpp = k.bpp;
const uchar *kcolor = k.colorbuf, *vcolor = vlm.data + kbpp*(v.x + v.y*LM_PACKW);
- loopi(kh)
- {
+ loopi(kh) {
if(memcmp(kcolor, vcolor, kbpp*kw)) return false;
kcolor += kbpp*kw;
vcolor += kbpp*LM_PACKW;
}
if((ktype&LM_TYPE) != LM_BUMPMAP0) return true;
const bvec *kdir = k.raybuf, *vdir = (const bvec *)lightmaps[v.lmid+1 - LMID_RESERVED].data + (v.x + v.y*LM_PACKW);
- loopi(kh)
- {
+ loopi(kh) {
if(memcmp(kdir, vdir, kw*sizeof(bvec))) return false;
kdir += kw;
vdir += LM_PACKW;
return true;
}
-static inline uint hthash(const lightmapinfo &k)
-{
+static inline uint hthash(const lightmapinfo &k) {
int kw = k.w, kh = k.h, kbpp = k.bpp;
uint hash = kw + (kh<<8);
const uchar *color = k.colorbuf;
- loopi(kw*kh)
- {
+ loopi(kw*kh) {
hash ^= color[0] + (color[1] << 4) + (color[2] << 8);
color += kbpp;
}
VAR(lightcompress, 0, 3, 6);
-static bool packlightmap(lightmapinfo &l, layoutinfo &surface)
-{
+static bool packlightmap(lightmapinfo &l, layoutinfo &surface) {
surface.w = l.w;
surface.h = l.h;
- if((int)l.w <= lightcompress && (int)l.h <= lightcompress)
- {
+ if((int)l.w <= lightcompress && (int)l.h <= lightcompress) {
layoutinfo *val = compressed.access(l);
- if(!val)
- {
+ if(!val) {
insertlightmap(l, surface);
compressed[l] = surface;
}
- else
- {
+ else {
surface.x = val->x;
surface.y = val->y;
surface.lmid = val->lmid;
return true;
}
-static uint generatelumel(lightmapworker *w, const float tolerance, uint lightmask, const vector<const extentity *> &lights, const vec &target, const vec &normal, vec &sample, int x, int y)
-{
+static uint generatelumel(lightmapworker *w, const float tolerance, uint lightmask, const vector<const extentity *> &lights, const vec &target, const vec &normal, vec &sample, int x, int y) {
vec avgray(0, 0, 0);
float r = 0, g = 0, b = 0;
uint lightused = 0;
- loopv(lights)
- {
+ loopv(lights) {
if(lightmask&(1<<i)) continue;
const extentity &light = *lights[i];
vec ray = target;
float mag = ray.magnitude();
if(!mag) continue;
float attenuation = 1;
- if(light.attr1)
- {
+ if(light.attr1) {
attenuation -= mag / float(light.attr1);
if(attenuation <= 0) continue;
}
ray.mul(1.0f / mag);
float angle = -ray.dot(normal);
if(angle <= 0) continue;
- if(light.attached && light.attached->type==ET_SPOTLIGHT)
- {
+ if(light.attached && light.attached->type==ET_SPOTLIGHT) {
vec spot = vec(light.attached->o).sub(light.o).normalize();
float maxatten = sincos360[clamp(int(light.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
if(spotatten <= 0) continue;
attenuation *= spotatten;
}
- if(lmshadows && mag)
- {
+ if(lmshadows && mag) {
float dist = shadowray(w->shadowraycache, light.o, ray, mag - tolerance, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0));
if(dist < mag - tolerance) continue;
}
lightused |= 1<<i;
float intensity;
- switch(w->type&LM_TYPE)
- {
+ switch(w->type&LM_TYPE) {
case LM_BUMPMAP0:
intensity = attenuation;
avgray.add(ray.mul(-attenuation));
g += intensity * float(light.attr3);
b += intensity * float(light.attr4);
}
- switch(w->type&LM_TYPE)
- {
+ switch(w->type&LM_TYPE) {
case LM_BUMPMAP0:
if(avgray.iszero()) break;
// transform to tangent space
return lightused;
}
-static bool lumelsample(const vec &sample, int aasample, int stride)
-{
+static bool lumelsample(const vec &sample, int aasample, int stride) {
if(sample.x >= int(ambientcolor[0])+1 || sample.y >= int(ambientcolor[1])+1 || sample.z >= int(ambientcolor[2])+1) return true;
#define NCHECK(n) \
if((n).x >= int(ambientcolor[0])+1 || (n).y >= int(ambientcolor[1])+1 || (n).z >= int(ambientcolor[2])+1) \
return false;
}
-static inline void generatealpha(lightmapworker *w, float tolerance, const vec &pos, uchar &alpha)
-{
+static inline void generatealpha(lightmapworker *w, float tolerance, const vec &pos, uchar &alpha) {
alpha = 0;
- if(w->slot->layermask)
- {
+ if(w->slot->layermask) {
static const int sdim[] = { 1, 0, 0 }, tdim[] = { 2, 2, 1 };
int dim = dimension(w->orient);
float k = 8.0f/w->vslot->scale,
if(mx < 0) mx += mask.w;
if(my < 0) my += mask.h;
uchar maskval = mask.data[mask.bpp*(mx + 1) - 1 + mask.pitch*my];
- switch(w->slot->layermaskmode)
- {
+ switch(w->slot->layermaskmode) {
case 2: alpha = min(alpha, maskval); break;
case 3: alpha = max(alpha, maskval); break;
case 4: alpha = min(alpha, uchar(0xFF - maskval)); break;
VAR(edgetolerance, 1, 4, 64);
VAR(adaptivesample, 0, 2, 2);
-enum
-{
+enum {
NO_SURFACE = 0,
SURFACE_AMBIENT_BOTTOM,
SURFACE_AMBIENT_TOP,
#define SURFACE_AMBIENT SURFACE_AMBIENT_BOTTOM
#define SURFACE_LIGHTMAP SURFACE_LIGHTMAP_BOTTOM
-static bool generatelightmap(lightmapworker *w, float lpu, const lerpvert *lv, int numv, vec origin1, const vec &xstep1, const vec &ystep1, vec origin2, const vec &xstep2, const vec &ystep2, float side0, float sidestep)
-{
- static const float aacoords[8][2] =
- {
- {0.0f, 0.0f},
- {-0.5f, -0.5f},
- {0.0f, -0.5f},
- {-0.5f, 0.0f},
-
- {0.3f, -0.6f},
- {0.6f, 0.3f},
- {-0.3f, 0.6f},
- {-0.6f, -0.3f},
+static bool generatelightmap(lightmapworker *w, float lpu, const lerpvert *lv, int numv, vec origin1, const vec &xstep1, const vec &ystep1, vec origin2, const vec &xstep2, const vec &ystep2, float side0, float sidestep) {
+ static const float aacoords[8][2] = {
+ {
+ 0.0f, 0.0f}, {
+ -0.5f, -0.5f}, {
+ 0.0f, -0.5f}, {
+ -0.5f, 0.0f},
+ {
+ 0.3f, -0.6f}, {
+ 0.6f, 0.3f}, {
+ -0.3f, 0.6f}, {
+ -0.6f, -0.3f},
};
float tolerance = 0.5 / lpu;
uint lightmask = 0, lightused = 0;
vec offsets1[8], offsets2[8];
- loopi(8)
- {
+ loopi(8) {
offsets1[i] = vec(xstep1).mul(aacoords[i][0]).add(vec(ystep1).mul(aacoords[i][1]));
offsets2[i] = vec(xstep2).mul(aacoords[i][0]).add(vec(ystep2).mul(aacoords[i][1]));
}
if((w->type&LM_TYPE) == LM_BUMPMAP0) memclear(w->raydata, (LM_MAXW + 4)*(LM_MAXH + 4));
-
origin1.sub(vec(ystep1).add(xstep1).mul(0));
origin2.sub(vec(ystep2).add(xstep2).mul(0));
-
int aasample = min(1 << lmaa, 4);
int stride = aasample*(w->w+1);
vec *sample = w->colordata;
lerpbounds start, end;
initlerpbounds(-0, -0, lv, numv, start, end);
float sidex = side0 + 0*sidestep;
- for(int y = 0; y < w->h; ++y, sidex += sidestep)
- {
+ for(int y = 0; y < w->h; ++y, sidex += sidestep) {
vec normal, nstep;
lerpnormal(-0, y - 0, lv, numv, start, end, normal, nstep);
-
- for(int x = 0; x < w->w; ++x, normal.add(nstep), amb += w->bpp)
- {
+ for(int x = 0; x < w->w; ++x, normal.add(nstep), amb += w->bpp) {
#define EDGE_TOLERANCE(x, y) \
(x < 0 \
|| x+1 > w->w - 0 \
sample = w->colordata;
initlerpbounds(-0, -0, lv, numv, start, end);
sidex = side0 + 0*sidestep;
- for(int y = 0; y < w->h; ++y, sidex += sidestep)
- {
+ for(int y = 0; y < w->h; ++y, sidex += sidestep) {
vec normal, nstep;
lerpnormal(-0, y - 0, lv, numv, start, end, normal, nstep);
-
- for(int x = 0; x < w->w; ++x, normal.add(nstep))
- {
+ for(int x = 0; x < w->w; ++x, normal.add(nstep)) {
vec ¢er = *sample++;
if(adaptivesample && x > 0 && x+1 < w->w && y > 0 && y+1 < w->h && !lumelsample(center, aasample, stride))
loopi(aasample-1) *sample++ = center;
- else
- {
+ else {
#define AA_EDGE_TOLERANCE(x, y, i) EDGE_TOLERANCE(x + aacoords[i][0], y + aacoords[i][1])
vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
const vec *offsets = x < sidex ? offsets1 : offsets2;
vec n = vec(normal).normalize();
loopi(aasample-1)
generatelumel(w, AA_EDGE_TOLERANCE(x, y, i+1) * tolerance, lightmask, w->lights, vec(u).add(offsets[i+1]), n, *sample++, x, y);
- if(lmaa == 3)
- {
- loopi(4)
- {
+ if(lmaa == 3) {
+ loopi(4) {
vec s;
generatelumel(w, AA_EDGE_TOLERANCE(x, y, i+4) * tolerance, lightmask, w->lights, vec(u).add(offsets[i+4]), n, s, x, y);
center.add(s);
}
}
}
- if(aasample > 1)
- {
+ if(aasample > 1) {
vec u = w->w < sidex ? vec(xstep1).mul(w->w).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(w->w).add(vec(ystep2).mul(y)).add(origin2);
const vec *offsets = w->w < sidex ? offsets1 : offsets2;
vec n = vec(normal).normalize();
}
sample += aasample;
}
-
- if(aasample > 1)
- {
+ if(aasample > 1) {
vec normal, nstep;
lerpnormal(-0, w->h - 0, lv, numv, start, end, normal, nstep);
-
- for(int x = 0; x <= w->w; ++x, normal.add(nstep))
- {
+ for(int x = 0; x <= w->w; ++x, normal.add(nstep)) {
vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(w->h)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(w->h)).add(origin2);
const vec *offsets = x < sidex ? offsets1 : offsets2;
vec n = vec(normal).normalize();
return true;
}
-static int finishlightmap(lightmapworker *w)
-{
+static int finishlightmap(lightmapworker *w) {
vec *sample = w->colordata;
int aasample = min(1 << lmaa, 4), stride = aasample*(w->w+1);
float weight = 1.0f / (1.0f + 4.0f*lmaa),
uchar mincolor[4] = { 255, 255, 255, 255 }, maxcolor[4] = { 0, 0, 0, 0 };
bvec *dstray = 0 && (w->w > 1 || w->h > 1) ? (bvec *)w->raydata : w->raybuf;
bvec minray(255, 255, 255), maxray(0, 0, 0);
- loop(y, w->h)
- {
- loop(x, w->w)
- {
+ loop(y, w->h) {
+ loop(x, w->w) {
vec l(0, 0, 0);
const vec ¢er = *sample++;
loopi(aasample-1) l.add(*sample++);
- if(aasample > 1)
- {
+ if(aasample > 1) {
l.add(sample[1]);
if(aasample > 2) l.add(sample[3]);
}
vec *next = sample + stride - aasample;
- if(aasample > 1)
- {
+ if(aasample > 1) {
l.add(next[1]);
if(aasample > 2) l.add(next[2]);
l.add(next[aasample+1]);
}
-
int r = int(center.x*cweight + l.x*weight),
g = int(center.y*cweight + l.y*weight),
b = int(center.z*cweight + l.z*weight),
dstcolor[0] = max(ar, r);
dstcolor[1] = max(ag, g);
dstcolor[2] = max(ab, b);
- loopk(3)
- {
+ loopk(3) {
mincolor[k] = min(mincolor[k], dstcolor[k]);
maxcolor[k] = max(maxcolor[k], dstcolor[k]);
}
- if(w->type&LM_ALPHA)
- {
+ if(w->type&LM_ALPHA) {
dstcolor[3] = 127;///TODO
mincolor[3] = min(mincolor[3], dstcolor[3]);
maxcolor[3] = max(maxcolor[3], dstcolor[3]);
}
- if((w->type&LM_TYPE) == LM_BUMPMAP0)
- {
+ if((w->type&LM_TYPE) == LM_BUMPMAP0) {
if(ray->iszero()) dstray[0] = bvec(128, 128, 255);
- else
- {
+ else {
ray->normalize();
int l = max(r, max(g, b)), a = max(ar, max(ag, ab));
ray->mul(max(l-a, 0));
ray->z += a;
dstray[0] = bvec(ray->normalize());
}
- loopk(3)
- {
+ loopk(3) {
minray[k] = min(minray[k], dstray[0][k]);
maxray[k] = max(maxray[k], dstray[0][k]);
}
if(int(maxcolor[0]) - int(mincolor[0]) <= lighterror &&
int(maxcolor[1]) - int(mincolor[1]) <= lighterror &&
int(maxcolor[2]) - int(mincolor[2]) <= lighterror &&
- mincolor[3] >= maxcolor[3])
- {
+ mincolor[3] >= maxcolor[3]) {
uchar color[3];
loopk(3) color[k] = (int(maxcolor[k]) + int(mincolor[k])) / 2;
if(color[0] <= int(ambientcolor[0]) + lighterror &&
(int(maxray.x) - int(minray.x) <= bumperror &&
int(maxray.y) - int(minray.z) <= bumperror &&
int(maxray.z) - int(minray.z) <= bumperror))
-
- {
+ {
memcpy(w->colorbuf, color, 3);
if(w->type&LM_ALPHA) w->colorbuf[3] = mincolor[3];
- if((w->type&LM_TYPE) == LM_BUMPMAP0)
- {
+ if((w->type&LM_TYPE) == LM_BUMPMAP0) {
loopk(3) w->raybuf[0][k] = uchar((int(maxray[k])+int(minray[k]))/2);
}
w->lastlightmap->w = w->w = 1;
else return SURFACE_LIGHTMAP_BLEND;
}
-static int previewlightmapalpha(lightmapworker *w, float lpu, const vec &origin1, const vec &xstep1, const vec &ystep1, const vec &origin2, const vec &xstep2, const vec &ystep2, float side0, float sidestep)
-{
+static int previewlightmapalpha(lightmapworker *w, float lpu, const vec &origin1, const vec &xstep1, const vec &ystep1, const vec &origin2, const vec &xstep2, const vec &ystep2, float side0, float sidestep) {
extern int fullbrightlevel;
float tolerance = 0.5 / lpu;
uchar *dst = w->colorbuf;
uchar minalpha = 255, maxalpha = 0;
float sidex = side0;
- for(int y = 0; y < w->h; ++y, sidex += sidestep)
- {
- for(int x = 0; x < w->w; ++x, dst += 4)
- {
+ for(int y = 0; y < w->h; ++y, sidex += sidestep) {
+ for(int x = 0; x < w->w; ++x, dst += 4) {
vec u = x < sidex ?
vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) :
vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
return SURFACE_LIGHTMAP_BLEND;
}
-static void clearsurfaces(cube *c)
-{
- loopi(8)
- {
- if(c[i].ext)
- {
- loopj(6)
- {
+static void clearsurfaces(cube *c) {
+ loopi(8) {
+ if(c[i].ext) {
+ loopj(6) {
surfaceinfo &surf = c[i].ext->surfaces[j];
if(!surf.used()) continue;
surf.clear();
int numverts = surf.numverts&MAXFACEVERTS;
- if(numverts)
- {
+ if(numverts) {
if(!(c[i].merged&(1<<j))) { surf.numverts &= ~MAXFACEVERTS; continue; }
-
vertinfo *verts = c[i].ext->verts() + surf.verts;
- loopk(numverts)
- {
+ loopk(numverts) {
vertinfo &v = verts[k];
v.u = 0;
v.v = 0;
#define LIGHTCACHESIZE 1024
-static struct lightcacheentry
-{
+static struct lightcacheentry {
int x, y;
vector<int> lights;
} lightcache[LIGHTCACHESIZE];
VARF(lightcachesize, 4, 6, 12, clearlightcache());
-void clearlightcache(int id)
-{
- if(id >= 0)
- {
+void clearlightcache(int id) {
+ if(id >= 0) {
const extentity &light = *entities::getents()[id];
int radius = light.attr1;
- if(radius)
- {
+ if(radius) {
for(int x = int(max(light.o.x-radius, 0.0f))>>lightcachesize, ex = int(min(light.o.x+radius, worldsize-1.0f))>>lightcachesize; x <= ex; x++)
- for(int y = int(max(light.o.y-radius, 0.0f))>>lightcachesize, ey = int(min(light.o.y+radius, worldsize-1.0f))>>lightcachesize; y <= ey; y++)
- {
+ for(int y = int(max(light.o.y-radius, 0.0f))>>lightcachesize, ey = int(min(light.o.y+radius, worldsize-1.0f))>>lightcachesize; y <= ey; y++) {
lightcacheentry &lce = lightcache[LIGHTCACHEHASH(x, y)];
if(lce.x != x || lce.y != y) continue;
lce.x = -1;
return;
}
}
-
- for(lightcacheentry *lce = lightcache; lce < &lightcache[LIGHTCACHESIZE]; lce++)
- {
+ for(lightcacheentry *lce = lightcache; lce < &lightcache[LIGHTCACHESIZE]; lce++) {
lce->x = -1;
lce->lights.setsize(0);
}
}
-const vector<int> &checklightcache(int x, int y)
-{
+const vector<int> &checklightcache(int x, int y) {
x >>= lightcachesize;
y >>= lightcachesize;
lightcacheentry &lce = lightcache[LIGHTCACHEHASH(x, y)];
if(lce.x == x && lce.y == y) return lce.lights;
-
lce.lights.setsize(0);
int csize = 1<<lightcachesize, cx = x<<lightcachesize, cy = y<<lightcachesize;
const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
const extentity &light = *ents[i];
- switch(light.type)
- {
- case ET_LIGHT:
- {
+ switch(light.type) {
+ case ET_LIGHT: {
int radius = light.attr1;
- if(radius > 0)
- {
+ if(radius > 0) {
if(light.o.x + radius < cx || light.o.x - radius > cx + csize ||
light.o.y + radius < cy || light.o.y - radius > cy + csize)
continue;
}
lce.lights.add(i);
}
-
lce.x = x;
lce.y = y;
return lce.lights;
}
-static inline void addlight(lightmapworker *w, const extentity &light, int cx, int cy, int cz, int size, const vec *v, const vec *n, int numv)
-{
+static inline void addlight(lightmapworker *w, const extentity &light, int cx, int cy, int cz, int size, const vec *v, const vec *n, int numv) {
int radius = light.attr1;
- if(radius > 0)
- {
+ if(radius > 0) {
if(light.o.x + radius < cx || light.o.x - radius > cx + size ||
light.o.y + radius < cy || light.o.y - radius > cy + size ||
light.o.z + radius < cz || light.o.z - radius > cz + size)
return;
}
-
- loopi(4)
- {
+ loopi(4) {
vec p(light.o);
p.sub(v[i]);
float dist = p.dot(n[i]);
- if(dist >= 0 && (!radius || dist < radius))
- {
+ if(dist >= 0 && (!radius || dist < radius)) {
w->lights.add(&light);
break;
}
}
}
-static bool findlights(lightmapworker *w, int cx, int cy, int cz, int size, const vec *v, const vec *n, int numv, const Slot &slot, const VSlot &vslot)
-{
+static bool findlights(lightmapworker *w, int cx, int cy, int cz, int size, const vec *v, const vec *n, int numv, const Slot &slot, const VSlot &vslot) {
w->lights.setsize(0);
const vector<extentity *> &ents = entities::getents();
static volatile bool usinglightcache = false;
- if(size <= 1<<lightcachesize && (!lightlock || !usinglightcache))
- {
+ if(size <= 1<<lightcachesize && (!lightlock || !usinglightcache)) {
if(lightlock) { SDL_LockMutex(lightlock); usinglightcache = true; }
const vector<int> &lights = checklightcache(cx, cy);
- loopv(lights)
- {
+ loopv(lights) {
const extentity &light = *ents[lights[i]];
- switch(light.type)
- {
+ switch(light.type) {
case ET_LIGHT: addlight(w, light, cx, cy, cz, size, v, n, numv); break;
}
}
if(lightlock) { usinglightcache = false; SDL_UnlockMutex(lightlock); }
}
- else loopv(ents)
- {
+ else loopv(ents) {
const extentity &light = *ents[i];
- switch(light.type)
- {
+ switch(light.type) {
case ET_LIGHT: addlight(w, light, cx, cy, cz, size, v, n, numv); break;
}
}
return w->lights.length();
}
-static int packlightmaps(lightmapworker *w = NULL)
-{
+static int packlightmaps(lightmapworker *w = NULL) {
int numpacked = 0;
- for(; packidx < lightmaptasks[0].length(); packidx++, numpacked++)
- {
+ for(; packidx < lightmaptasks[0].length(); packidx++, numpacked++) {
lightmaptask &t = lightmaptasks[0][packidx];
if(!t.lightmaps) break;
- if(t.ext && t.c->ext != t.ext)
- {
+ if(t.ext && t.c->ext != t.ext) {
lightmapext &e = lightmapexts.add();
e.c = t.c;
e.ext = t.ext;
lightmapinfo *l = t.lightmaps;
if(l == (lightmapinfo *)-1) continue;
int space = 0;
- for(; l && l->c == t.c; l = l->next)
- {
+ for(; l && l->c == t.c; l = l->next) {
l->packed = true;
space += l->bufsize;
if(l->surface < 0 || !t.ext) continue;
packlightmap(*l, layout);
int numverts = surf.numverts&MAXFACEVERTS;
vertinfo *verts = t.ext->verts() + surf.verts;
- if(l->layers&LAYER_DUP)
- {
+ if(l->layers&LAYER_DUP) {
if(l->type&LM_ALPHA) surf.lmid[0] = layout.lmid;
else { surf.lmid[1] = layout.lmid; verts += numverts; }
}
- else
- {
+ else {
if(l->layers&LAYER_TOP) surf.lmid[0] = layout.lmid;
if(l->layers&LAYER_BOTTOM) surf.lmid[1] = layout.lmid;
}
ushort offsetx = layout.x*((USHRT_MAX+1)/LM_PACKW), offsety = layout.y*((USHRT_MAX+1)/LM_PACKH);
- loopk(numverts)
- {
+ loopk(numverts) {
vertinfo &v = verts[k];
v.u += offsetx;
v.v += offsety;
}
}
- if(t.worker == w)
- {
+ if(t.worker == w) {
w->bufused -= space;
w->bufstart = (w->bufstart + space)%LIGHTMAPBUFSIZE;
w->firstlightmap = l;
- if(!l)
- {
+ if(!l) {
w->lastlightmap = NULL;
w->bufstart = w->bufused = 0;
}
return numpacked;
}
-static lightmapinfo *alloclightmap(lightmapworker *w)
-{
+static lightmapinfo *alloclightmap(lightmapworker *w) {
int needspace1 = sizeof(lightmapinfo) + w->w*w->h*w->bpp,
needspace2 = (w->type&LM_TYPE) == LM_BUMPMAP0 ? w->w*w->h*3 : 0,
needspace = needspace1 + needspace2,
availspace = LIGHTMAPBUFSIZE - w->bufused,
availspace1 = min(availspace, LIGHTMAPBUFSIZE - bufend),
availspace2 = min(availspace, w->bufstart);
- if(availspace < needspace || (max(availspace1, availspace2) < needspace && (availspace1 < needspace1 || availspace2 < needspace2)))
- {
+ if(availspace < needspace || (max(availspace1, availspace2) < needspace && (availspace1 < needspace1 || availspace2 < needspace2))) {
if(tasklock) SDL_LockMutex(tasklock);
- while(!w->doneworking)
- {
+ while(!w->doneworking) {
lightmapinfo *l = w->firstlightmap;
- for(; l && l->packed; l = l->next)
- {
+ for(; l && l->packed; l = l->next) {
w->bufused -= l->bufsize;
w->bufstart = (w->bufstart + l->bufsize)%LIGHTMAPBUFSIZE;
}
w->firstlightmap = l;
- if(!l)
- {
+ if(!l) {
w->lastlightmap = NULL;
w->bufstart = w->bufused = 0;
}
}
int usedspace = needspace;
lightmapinfo *l = NULL;
- if(availspace1 >= needspace1)
- {
+ if(availspace1 >= needspace1) {
l = (lightmapinfo *)&w->buf[bufend];
w->colorbuf = (uchar *)(l + 1);
if((w->type&LM_TYPE) != LM_BUMPMAP0) w->raybuf = NULL;
else if(availspace1 >= needspace) w->raybuf = (bvec *)&w->buf[bufend + needspace1];
- else
- {
+ else {
w->raybuf = (bvec *)w->buf;
usedspace += availspace1 - needspace1;
}
}
- else if(availspace2 >= needspace)
- {
+ else if(availspace2 >= needspace) {
usedspace += availspace1;
l = (lightmapinfo *)w->buf;
w->colorbuf = (uchar *)(l + 1);
return l;
}
-static void freelightmap(lightmapworker *w)
-{
+static void freelightmap(lightmapworker *w) {
lightmapinfo *l = w->lastlightmap;
if(!l || l->surface >= 0) return;
- if(w->firstlightmap == w->lastlightmap)
- {
+ if(w->firstlightmap == w->lastlightmap) {
w->firstlightmap = w->lastlightmap = w->curlightmaps = NULL;
w->bufstart = w->bufused = 0;
}
- else
- {
+ else {
w->bufused -= l->bufsize - sizeof(lightmapinfo);
l->bufsize = sizeof(lightmapinfo);
l->packed = true;
if(w->curlightmaps == l) w->curlightmaps = NULL;
}
-static int setupsurface(lightmapworker *w, plane planes[2], int numplanes, const vec *p, const vec *n, int numverts, vertinfo *litverts, bool preview = false)
-{
+static int setupsurface(lightmapworker *w, plane planes[2], int numplanes, const vec *p, const vec *n, int numverts, vertinfo *litverts, bool preview = false) {
vec u, v, t;
vec2 c[MAXFACEVERTS];
-
u = vec(p[2]).sub(p[0]).normalize();
v.cross(planes[0], u);
c[0] = vec2(0, 0);
vec r1 = vec(p[1]).sub(p[0]);
c[1] = vec2(r1.dot(u), min(r1.dot(v), 0.0f));
c[2] = vec2(vec(p[2]).sub(p[0]).dot(u), 0);
- for(int i = 3; i < numverts; i++)
- {
+ for(int i = 3; i < numverts; i++) {
vec r = vec(p[i]).sub(p[0]);
c[i] = vec2(r.dot(u), max(r.dot(t), 0.0f));
}
-
float carea = 1e16f;
vec2 cx(0, 0), cy(0, 0), co(0, 0), cmin(0, 0), cmax(0, 0);
- loopi(numverts)
- {
+ loopi(numverts) {
vec2 px = vec2(c[i+1 < numverts ? i+1 : 0]).sub(c[i]);
float len = px.squaredlen();
if(!len) continue;
px.mul(1/sqrtf(len));
vec2 py(-px.y, px.x), pmin(0, 0), pmax(0, 0);
if(numplanes >= 2 && (i == 0 || i >= 3)) px.neg();
- loopj(numverts)
- {
+ loopj(numverts) {
vec2 rj = vec2(c[j]).sub(c[i]), pj(rj.dot(px), rj.dot(py));
pmin.x = min(pmin.x, pj.x);
pmin.y = min(pmin.y, pj.y);
float area = (pmax.x-pmin.x)*(pmax.y-pmin.y);
if(area < carea) { carea = area; cx = px; cy = py; co = c[i]; cmin = pmin; cmax = pmax; }
}
-
int scale = int(min(cmax.x - cmin.x, cmax.y - cmin.y));
float lpu = 16.0f / float(lightlod && scale < (1 << lightlod) ? max(lightprecision / 2, 1) : lightprecision);
int lw = clamp(int(ceil((cmax.x - cmin.x + 1)*lpu)), LM_MINW, LM_MAXW), lh = clamp(int(ceil((cmax.y - cmin.y + 1)*lpu)), LM_MINH, LM_MAXH);
w->w = lw;
w->h = lh;
if(!alloclightmap(w)) return NO_SURFACE;
-
vec2 cscale = vec2(cmax).sub(cmin).div(vec2(lw-1, lh-1)),
comin = vec2(cx).mul(cmin.x).add(vec2(cy).mul(cmin.y)).add(co);
- loopi(numverts)
- {
+ loopi(numverts) {
vec2 ri = vec2(c[i]).sub(comin);
c[i] = vec2(ri.dot(cx)/cscale.x, ri.dot(cy)/cscale.y);
}
-
vec xstep1 = vec(v).mul(cx.y).add(vec(u).mul(cx.x)).mul(cscale.x),
ystep1 = vec(v).mul(cy.y).add(vec(u).mul(cy.x)).mul(cscale.y),
origin1 = vec(v).mul(comin.y).add(vec(u).mul(comin.x)).add(p[0]),
xstep2 = xstep1, ystep2 = ystep1, origin2 = origin1;
float side0 = LM_MAXW + 1, sidestep = 0;
- if(numplanes >= 2)
- {
+ if(numplanes >= 2) {
xstep2 = vec(t).mul(cx.y).add(vec(u).mul(cx.x)).mul(cscale.x);
ystep2 = vec(t).mul(cy.y).add(vec(u).mul(cy.x)).mul(cscale.y);
origin2 = vec(t).mul(comin.y).add(vec(u).mul(comin.x)).add(p[0]);
else if(cy.y) { side0 = ceil(comin.y/-(cy.y*cscale.y))*(LM_MAXW + 1); sidestep = -(LM_MAXW + 1); if(cy.y < 0) { side0 = (LM_MAXW + 1) - side0; sidestep = -sidestep; } }
else side0 = comin.y <= 0 ? LM_MAXW + 1 : -1;
}
-
int surftype = NO_SURFACE;
- if(preview)
- {
+ if(preview) {
surftype = previewlightmapalpha(w, lpu, origin1, xstep1, ystep1, origin2, xstep2, ystep2, side0, sidestep);
}
- else
- {
+ else {
lerpvert lv[MAXFACEVERTS];
int numv = numverts;
calclerpverts(c, n, lv, numv);
-
if(!generatelightmap(w, lpu, lv, numv, origin1, xstep1, ystep1, origin2, xstep2, ystep2, side0, sidestep)) return NO_SURFACE;
surftype = finishlightmap(w);
}
if(surftype<SURFACE_LIGHTMAP) return surftype;
-
vec2 texscale(float(USHRT_MAX+1)/LM_PACKW, float(USHRT_MAX+1)/LM_PACKH);
if(lw != w->w) texscale.x *= float(w->w - 1) / (lw - 1);
if(lh != w->h) texscale.y *= float(w->h - 1) / (lh - 1);
- loopk(numverts)
- {
+ loopk(numverts) {
litverts[k].u = ushort(floor(clamp(c[k].x*texscale.x, 0.0f, float(USHRT_MAX))));
litverts[k].v = ushort(floor(clamp(c[k].y*texscale.y, 0.0f, float(USHRT_MAX))));
}
return surftype;
}
-static void removelmalpha(lightmapworker *w)
-{
+static void removelmalpha(lightmapworker *w) {
if(!(w->type&LM_ALPHA)) return;
for(uchar *dst = w->colorbuf, *src = w->colorbuf, *end = &src[w->w*w->h*4];
src < end;
- dst += 3, src += 4)
- {
+ dst += 3, src += 4) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
w->lastlightmap->bpp = w->bpp;
}
-static lightmapinfo *setupsurfaces(lightmapworker *w, lightmaptask &task)
-{
+static lightmapinfo *setupsurfaces(lightmapworker *w, lightmaptask &task) {
cube &c = *task.c;
const ivec &co = task.o;
int size = task.size, usefacemask = task.usefaces;
-
w->curlightmaps = NULL;
w->c = &c;
-
surfaceinfo surfaces[6];
vertinfo litverts[6*2*MAXFACEVERTS];
int numlitverts = 0;
memclear(surfaces);
- loopi(6)
- {
+ loopi(6) {
int usefaces = usefacemask&0xF;
usefacemask >>= 4;
- if(!usefaces)
- {
+ if(!usefaces) {
if(!c.ext) continue;
surfaceinfo &surf = surfaces[i];
surf = c.ext->surfaces[i];
int numverts = surf.totalverts();
- if(numverts)
- {
+ if(numverts) {
memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
surf.verts = numlitverts;
numlitverts += numverts;
}
continue;
}
-
VSlot &vslot = lookupvslot(c.texture[i], false),
*layer = vslot.layer && !(c.material&MAT_ALPHA) ? &lookupvslot(vslot.layer, false) : NULL;
Shader *shader = vslot.slot->shader;
int shadertype = shader->type;
if(layer) shadertype |= layer->slot->shader->type;
-
surfaceinfo &surf = surfaces[i];
vertinfo *curlitverts = &litverts[numlitverts];
int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0;
ivec mo(co);
int msz = size, convex = 0;
- if(numverts)
- {
+ if(numverts) {
vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
loopj(numverts) curlitverts[j].set(verts[j].getxyz());
- if(c.merged&(1<<i))
- {
+ if(c.merged&(1<<i)) {
msz = 1<<calcmergedsize(i, mo, size, verts, numverts);
mo.mask(~(msz-1));
-
- if(!(surf.numverts&MAXFACEVERTS))
- {
+ if(!(surf.numverts&MAXFACEVERTS)) {
surf.verts = numlitverts;
surf.numverts |= numverts;
numlitverts += numverts;
}
else if(!flataxisface(c, i)) convex = faceconvexity(verts, numverts, size);
}
- else
- {
+ else {
ivec v[4];
genfaceverts(c, i, v);
if(!flataxisface(c, i)) convex = faceconvexity(v);
curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
if(usefaces&2) curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
}
-
vec pos[MAXFACEVERTS], n[MAXFACEVERTS], po(ivec(co).mask(~0xFFF));
loopj(numverts) pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
-
plane planes[2];
int numplanes = 0;
planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
if(numverts < 4 || !convex) loopk(numverts) findnormal(pos[k], planes[0], n[k]);
- else
- {
+ else {
planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
vec avg = vec(planes[0]).add(planes[1]).normalize();
findnormal(pos[0], avg, n[0]);
findnormal(pos[2], avg, n[2]);
for(int k = 3; k < numverts; k++) findnormal(pos[k], planes[1], n[k]);
}
-
- if(shadertype&SHADER_NORMALSLMS)
- {
+ if(shadertype&SHADER_NORMALSLMS) {
loopk(numverts) curlitverts[k].norm = encodenormal(n[k]);
- if(!(surf.numverts&MAXFACEVERTS))
- {
+ if(!(surf.numverts&MAXFACEVERTS)) {
surf.verts = numlitverts;
surf.numverts |= numverts;
numlitverts += numverts;
}
}
-
- if(!findlights(w, mo.x, mo.y, mo.z, msz, pos, n, numverts, *vslot.slot, vslot))
- {
+ if(!findlights(w, mo.x, mo.y, mo.z, msz, pos, n, numverts, *vslot.slot, vslot)) {
if(surf.numverts&MAXFACEVERTS) surf.numverts |= LAYER_TOP;
continue;
}
-
w->slot = vslot.slot;
w->vslot = &vslot;
w->type = shader->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
w->orient = i;
w->rotate = vslot.rotation;
int surftype = setupsurface(w, planes, numplanes, pos, n, numverts, curlitverts);
- switch(surftype)
- {
+ switch(surftype) {
case SURFACE_LIGHTMAP_BOTTOM:
if((shader->type^layer->slot->shader->type)&SHADER_NORMALSLMS ||
- (shader->type&SHADER_NORMALSLMS && vslot.rotation!=layer->rotation))
- {
+ (shader->type&SHADER_NORMALSLMS && vslot.rotation!=layer->rotation)) {
freelightmap(w);
break;
}
// fall through
case SURFACE_LIGHTMAP_BLEND:
- case SURFACE_LIGHTMAP_TOP:
- {
- if(!(surf.numverts&MAXFACEVERTS))
- {
+ case SURFACE_LIGHTMAP_TOP: {
+ if(!(surf.numverts&MAXFACEVERTS)) {
surf.verts = numlitverts;
surf.numverts |= numverts;
numlitverts += numverts;
}
-
w->lastlightmap->surface = i;
w->lastlightmap->layers = (surftype==SURFACE_LIGHTMAP_BOTTOM ? LAYER_BOTTOM : LAYER_TOP);
- if(surftype==SURFACE_LIGHTMAP_BLEND)
- {
+ if(surftype==SURFACE_LIGHTMAP_BLEND) {
surf.numverts |= LAYER_BLEND;
w->lastlightmap->layers = LAYER_TOP;
if((shader->type^layer->slot->shader->type)&SHADER_NORMALSLMS ||
break;
w->lastlightmap->layers |= LAYER_BOTTOM;
}
- else
- {
- if(surftype==SURFACE_LIGHTMAP_BOTTOM)
- {
+ else {
+ if(surftype==SURFACE_LIGHTMAP_BOTTOM) {
surf.numverts |= LAYER_BOTTOM;
w->lastlightmap->layers = LAYER_BOTTOM;
}
- else
- {
+ else {
surf.numverts |= LAYER_TOP;
w->lastlightmap->layers = LAYER_TOP;
}
}
continue;
}
-
case SURFACE_AMBIENT_BOTTOM:
freelightmap(w);
surf.numverts |= layer ? LAYER_BOTTOM : LAYER_TOP;
continue;
-
case SURFACE_AMBIENT_TOP:
freelightmap(w);
surf.numverts |= LAYER_TOP;
continue;
-
default:
freelightmap(w);
continue;
}
-
w->slot = layer->slot;
w->vslot = layer;
w->type = layer->slot->shader->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
w->bpp = 3;
w->rotate = layer->rotation;
vertinfo *blendverts = surf.numverts&MAXFACEVERTS ? &curlitverts[numverts] : curlitverts;
- switch(setupsurface(w, planes, numplanes, pos, n, numverts, blendverts))
- {
- case SURFACE_LIGHTMAP_TOP:
- {
- if(!(surf.numverts&MAXFACEVERTS))
- {
+ switch(setupsurface(w, planes, numplanes, pos, n, numverts, blendverts)) {
+ case SURFACE_LIGHTMAP_TOP: {
+ if(!(surf.numverts&MAXFACEVERTS)) {
surf.verts = numlitverts;
surf.numverts |= numverts;
numlitverts += numverts;
}
- else if(!(surf.numverts&LAYER_DUP))
- {
+ else if(!(surf.numverts&LAYER_DUP)) {
surf.numverts |= LAYER_DUP;
w->lastlightmap->layers |= LAYER_DUP;
- loopk(numverts)
- {
+ loopk(numverts) {
vertinfo &src = curlitverts[k];
vertinfo &dst = blendverts[k];
dst.setxyz(src.getxyz());
}
surf.numverts |= LAYER_BOTTOM;
w->lastlightmap->layers |= LAYER_BOTTOM;
-
w->lastlightmap->surface = i;
break;
}
-
- case SURFACE_AMBIENT_TOP:
- {
+ case SURFACE_AMBIENT_TOP: {
freelightmap(w);
surf.numverts |= LAYER_BOTTOM;
break;
}
-
default: freelightmap(w); break;
}
}
- loopk(6)
- {
+ loopk(6) {
surfaceinfo &surf = surfaces[k];
- if(surf.used())
- {
+ if(surf.used()) {
cubeext *ext = c.ext && c.ext->maxverts >= numlitverts ? c.ext : growcubeext(c.ext, numlitverts);
memcpy(ext->surfaces, surfaces, sizeof(ext->surfaces));
memcpy(ext->verts(), litverts, numlitverts*sizeof(vertinfo));
return w->curlightmaps ? w->curlightmaps : (lightmapinfo *)-1;
}
-int lightmapworker::work(void *data)
-{
+int lightmapworker::work(void *data) {
lightmapworker *w = (lightmapworker *)data;
SDL_LockMutex(tasklock);
- while(!w->doneworking)
- {
- if(allocidx < lightmaptasks[0].length())
- {
+ while(!w->doneworking) {
+ if(allocidx < lightmaptasks[0].length()) {
lightmaptask &t = lightmaptasks[0][allocidx++];
t.worker = w;
SDL_UnlockMutex(tasklock);
t.lightmaps = l;
packlightmaps(w);
}
- else
- {
+ else {
if(packidx >= lightmaptasks[0].length()) SDL_CondSignal(emptycond);
SDL_CondWait(fullcond, tasklock);
}
return 0;
}
-static bool processtasks(bool finish = false)
-{
+static bool processtasks(bool finish = false) {
if(tasklock) SDL_LockMutex(tasklock);
- while(finish || lightmaptasks[1].length())
- {
- if(packidx >= lightmaptasks[0].length())
- {
+ while(finish || lightmaptasks[1].length()) {
+ if(packidx >= lightmaptasks[0].length()) {
if(lightmaptasks[1].empty()) break;
lightmaptasks[0].setsize(0);
lightmaptasks[0].move(lightmaptasks[1]);
packidx = allocidx = 0;
if(fullcond) SDL_CondBroadcast(fullcond);
}
- else if(lightmapping > 1)
- {
+ else if(lightmapping > 1) {
SDL_CondWaitTimeout(emptycond, tasklock, 250);
CHECK_PROGRESS_LOCKED({ SDL_UnlockMutex(tasklock); return false; }, SDL_UnlockMutex(tasklock), SDL_LockMutex(tasklock));
}
- else
- {
- while(allocidx < lightmaptasks[0].length())
- {
+ else {
+ while(allocidx < lightmaptasks[0].length()) {
lightmaptask &t = lightmaptasks[0][allocidx++];
t.worker = lightmapworkers[0];
t.lightmaps = setupsurfaces(lightmapworkers[0], t);
return true;
}
-static void generatelightmaps(cube *c, const ivec &co, int size)
-{
+static void generatelightmaps(cube *c, const ivec &co, int size) {
CHECK_PROGRESS(return);
-
taskprogress++;
-
- loopi(8)
- {
+ loopi(8) {
ivec o(i, co, size);
if(c[i].children)
generatelightmaps(c[i].children, o, size >> 1);
- else if(!isempty(c[i]))
- {
- if(c[i].ext)
- {
- loopj(6)
- {
+ else if(!isempty(c[i])) {
+ if(c[i].ext) {
+ loopj(6) {
surfaceinfo &surf = c[i].ext->surfaces[j];
if(surf.lmid[0] >= LMID_RESERVED || surf.lmid[1] >= LMID_RESERVED) goto nextcube;
surf.clear();
}
}
int usefacemask = 0;
- loopj(6) if(!(c[i].merged&(1<<j)) || (c[i].ext && c[i].ext->surfaces[j].numverts&MAXFACEVERTS))
- {
+ loopj(6) if(!(c[i].merged&(1<<j)) || (c[i].ext && c[i].ext->surfaces[j].numverts&MAXFACEVERTS)) {
usefacemask |= visibletris(c[i], j, o, size)<<(4*j);
}
- if(usefacemask)
- {
+ if(usefacemask) {
lightmaptask &t = lightmaptasks[1].add();
t.o = o;
t.size = size;
}
}
-void cleanuplightmaps()
-{
- loopv(lightmaps)
- {
+void cleanuplightmaps() {
+ loopv(lightmaps) {
LightMap &lm = lightmaps[i];
lm.tex = lm.offsetx = lm.offsety = -1;
}
if(progresstex) { glDeleteTextures(1, &progresstex); progresstex = 0; }
}
-void resetlightmaps(bool fullclean)
-{
+void resetlightmaps(bool fullclean) {
cleanuplightmaps();
lightmaps.shrink(0);
compressed.clear();
if(fullclean) while(lightmapworkers.length()) delete lightmapworkers.pop();
}
-lightmapworker::lightmapworker()
-{
+lightmapworker::lightmapworker() {
buf = new uchar[LIGHTMAPBUFSIZE];
bufstart = bufused = 0;
firstlightmap = lastlightmap = curlightmaps = NULL;
thread = NULL;
}
-lightmapworker::~lightmapworker()
-{
+lightmapworker::~lightmapworker() {
cleanupthread();
delete[] buf;
delete[] ambient;
freeshadowraycache(shadowraycache);
}
-void lightmapworker::cleanupthread()
-{
+void lightmapworker::cleanupthread() {
if(spacecond) { SDL_DestroyCond(spacecond); spacecond = NULL; }
thread = NULL;
}
-void lightmapworker::reset()
-{
+void lightmapworker::reset() {
bufstart = bufused = 0;
firstlightmap = lastlightmap = curlightmaps = NULL;
needspace = doneworking = false;
resetshadowraycache(shadowraycache);
}
-bool lightmapworker::setupthread()
-{
+bool lightmapworker::setupthread() {
if(!spacecond) spacecond = SDL_CreateCond();
if(!spacecond) return false;
thread = SDL_CreateThread(work, "lightmap worker", this);
return thread!=NULL;
}
-static Uint32 calclighttimer(Uint32 interval, void *param)
-{
+static Uint32 calclighttimer(Uint32 interval, void *param) {
check_calclight_progress = true;
return interval;
}
-bool setlightmapquality(int quality)
-{
- switch(quality)
- {
+bool setlightmapquality(int quality) {
+ switch(quality) {
case 1: lmshadows = 2; lmaa = 3; lerptjoints = 1; break;
case 0: lmshadows = lmshadows_; lmaa = lmaa_; lerptjoints = lerptjoints_; break;
case -1: lmshadows = 1; lmaa = 0; lerptjoints = 0; break;
#define ALLOCLOCK(name, init) { if(lightmapping > 1) name = init(); if(!name) lightmapping = 1; }
#define FREELOCK(name, destroy) { if(name) { destroy(name); name = NULL; } }
-static void cleanuplocks()
-{
+static void cleanuplocks() {
FREELOCK(lightlock, SDL_DestroyMutex);
FREELOCK(tasklock, SDL_DestroyMutex);
FREELOCK(fullcond, SDL_DestroyCond);
FREELOCK(emptycond, SDL_DestroyCond);
}
-static void setupthreads(int numthreads)
-{
+static void setupthreads(int numthreads) {
loopi(2) lightmaptasks[i].setsize(0);
lightmapexts.setsize(0);
packidx = allocidx = 0;
lightmapping = numthreads;
- if(lightmapping > 1)
- {
+ if(lightmapping > 1) {
ALLOCLOCK(lightlock, SDL_CreateMutex);
ALLOCLOCK(tasklock, SDL_CreateMutex);
ALLOCLOCK(fullcond, SDL_CreateCond);
ALLOCLOCK(emptycond, SDL_CreateCond);
}
while(lightmapworkers.length() < lightmapping) lightmapworkers.add(new lightmapworker);
- loopi(lightmapping)
- {
+ loopi(lightmapping) {
lightmapworker *w = lightmapworkers[i];
w->reset();
if(lightmapping <= 1 || w->setupthread()) continue;
if(lightmapping <= 1) cleanuplocks();
}
-static void cleanupthreads()
-{
+static void cleanupthreads() {
processtasks(true);
- if(lightmapping > 1)
- {
+ if(lightmapping > 1) {
SDL_LockMutex(tasklock);
loopv(lightmapworkers) lightmapworkers[i]->doneworking = true;
SDL_CondBroadcast(fullcond);
- loopv(lightmapworkers)
- {
+ loopv(lightmapworkers) {
lightmapworker *w = lightmapworkers[i];
if(w->needspace && w->spacecond) SDL_CondSignal(w->spacecond);
}
SDL_UnlockMutex(tasklock);
- loopv(lightmapworkers)
- {
+ loopv(lightmapworkers) {
lightmapworker *w = lightmapworkers[i];
if(w->thread) SDL_WaitThread(w->thread, NULL);
}
}
- loopv(lightmapexts)
- {
+ loopv(lightmapexts) {
lightmapext &e = lightmapexts[i];
setcubeext(*e.c, e.ext);
}
lightmapping = 0;
}
-void calclight(int *quality)
-{
- if(!setlightmapquality(*quality))
- {
+void calclight(int *quality) {
+ if(!setlightmapquality(*quality)) {
conoutf(CON_ERROR, "valid range for calclight quality is -1..1");
return;
}
Uint32 end = SDL_GetTicks();
if(timer) SDL_RemoveTimer(timer);
uint total = 0, lumels = 0;
- loopv(lightmaps)
- {
+ loopv(lightmaps) {
insertunlit(i);
if(!editmode) lightmaps[i].finalize();
total += lightmaps[i].lightmaps;
COMMAND(calclight, "i");
-void clearlightmaps()
-{
+void clearlightmaps() {
if(noedit(true)) return;
renderprogress(0, "clearing lightmaps...");
resetlightmaps(false);
COMMAND(clearlightmaps, "");
-void setfullbrightlevel(int fullbrightlevel)
-{
- if(lightmaptexs.length() > LMID_BRIGHT)
- {
+void setfullbrightlevel(int fullbrightlevel) {
+ if(lightmaptexs.length() > LMID_BRIGHT) {
uchar bright[3] = { uchar(fullbrightlevel), uchar(fullbrightlevel), uchar(fullbrightlevel) };
createtexture(lightmaptexs[LMID_BRIGHT].id, 1, 1, bright, 0, 1);
}
vector<LightMapTexture> lightmaptexs;
-static void copylightmap(LightMap &lm, uchar *dst, size_t stride)
-{
+static void copylightmap(LightMap &lm, uchar *dst, size_t stride) {
const uchar *c = lm.data;
- loopi(LM_PACKH)
- {
+ loopi(LM_PACKH) {
memcpy(dst, c, lm.bpp*LM_PACKW);
c += lm.bpp*LM_PACKW;
dst += stride;
}
}
-void genreservedlightmaptexs()
-{
- while(lightmaptexs.length() < LMID_RESERVED)
- {
+void genreservedlightmaptexs() {
+ while(lightmaptexs.length() < LMID_RESERVED) {
LightMapTexture &tex = lightmaptexs.add();
tex.type = lightmaptexs.length()&1 ? LM_DIFFUSE : LM_BUMPMAP1;
glGenTextures(1, &tex.id);
createtexture(lightmaptexs[LMID_DARK1].id, 1, 1, &front, 0, 1);
}
-static void findunlit(int i)
-{
+static void findunlit(int i) {
LightMap &lm = lightmaps[i];
if(lm.unlitx>=0) return;
- else if((lm.type&LM_TYPE)==LM_BUMPMAP0)
- {
+ else if((lm.type&LM_TYPE)==LM_BUMPMAP0) {
if(i+1>=lightmaps.length() || (lightmaps[i+1].type&LM_TYPE)!=LM_BUMPMAP1) return;
}
else if((lm.type&LM_TYPE)!=LM_DIFFUSE) return;
uchar *data = lm.data;
- loop(y, 2) loop(x, LM_PACKW)
- {
- if(!data[0] && !data[1] && !data[2])
- {
+ loop(y, 2) loop(x, LM_PACKW) {
+ if(!data[0] && !data[1] && !data[2]) {
memcpy(data, ambientcolor.v, 3);
if((lm.type&LM_TYPE)==LM_BUMPMAP0) ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] = bvec(128, 128, 255);
lm.unlitx = x;
lm.unlity = y;
return;
}
- if(data[0]==ambientcolor[0] && data[1]==ambientcolor[1] && data[2]==ambientcolor[2])
- {
- if((lm.type&LM_TYPE)!=LM_BUMPMAP0 || ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] == bvec(128, 128, 255))
- {
+ if(data[0]==ambientcolor[0] && data[1]==ambientcolor[1] && data[2]==ambientcolor[2]) {
+ if((lm.type&LM_TYPE)!=LM_BUMPMAP0 || ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] == bvec(128, 128, 255)) {
lm.unlitx = x;
lm.unlity = y;
return;
VARF(roundlightmaptex, 0, 4, 16, { cleanuplightmaps(); initlights(); allchanged(); });
VARF(batchlightmaps, 0, 4, 256, { cleanuplightmaps(); initlights(); allchanged(); });
-void genlightmaptexs(int flagmask, int flagval)
-{
+void genlightmaptexs(int flagmask, int flagval) {
if(lightmaptexs.length() < LMID_RESERVED) genreservedlightmaptexs();
-
int remaining[LM_TYPE+1] = { 0 }, total = 0;
- loopv(lightmaps)
- {
+ loopv(lightmaps) {
LightMap &lm = lightmaps[i];
if(lm.tex >= 0 || (lm.type&flagmask)!=flagval) continue;
int type = lm.type&LM_TYPE;
total++;
if(lm.unlitx < 0) findunlit(i);
}
-
int sizelimit = (maxtexsize ? min(maxtexsize, hwtexsize) : hwtexsize)/max(LM_PACKW, LM_PACKH);
sizelimit = min(batchlightmaps, sizelimit*sizelimit);
- while(total)
- {
+ while(total) {
int type = LM_DIFFUSE;
LightMap *firstlm = NULL;
- loopv(lightmaps)
- {
+ loopv(lightmaps) {
LightMap &lm = lightmaps[i];
if(lm.tex >= 0 || (lm.type&flagmask) != flagval) continue;
type = lm.type&LM_TYPE;
used--;
int oldval = remaining[type];
remaining[type] -= 1<<used;
- if(remaining[type] && (2<<used) <= min(roundlightmaptex, sizelimit))
- {
+ if(remaining[type] && (2<<used) <= min(roundlightmaptex, sizelimit)) {
remaining[type] -= min(remaining[type], 1<<used);
used++;
}
int bpp = firstlm->bpp;
uchar *data = used ? new uchar[bpp*tex.w*tex.h] : NULL;
int offsetx = 0, offsety = 0;
- loopv(lightmaps)
- {
+ loopv(lightmaps) {
LightMap &lm = lightmaps[i];
if(lm.tex >= 0 || (lm.type&flagmask) != flagval || (lm.type&LM_TYPE) != type) continue;
-
lm.tex = lightmaptexs.length()-1;
lm.offsetx = offsetx;
lm.offsety = offsety;
- if(tex.unlitx < 0 && lm.unlitx >= 0)
- {
+ if(tex.unlitx < 0 && lm.unlitx >= 0) {
tex.unlitx = offsetx + lm.unlitx;
tex.unlity = offsety + lm.unlity;
}
-
if(data) copylightmap(lm, &data[bpp*(offsety*tex.w + offsetx)], bpp*tex.w);
-
offsetx += LM_PACKW;
if(offsetx >= tex.w) { offsetx = 0; offsety += LM_PACKH; }
if(offsety >= tex.h) break;
}
-
glGenTextures(1, &tex.id);
createtexture(tex.id, tex.w, tex.h, data ? data : firstlm->data, 3, 1, bpp==4 ? GL_RGBA : GL_RGB);
if(data) delete[] data;
bool brightengeom = false, shouldlightents = false;
-void clearlights()
-{
+void clearlights() {
clearlightcache();
const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
e.light.color = vec(1, 1, 1);
e.light.dir = vec(0, 0, 1);
}
shouldlightents = false;
-
genlightmaptexs(LM_ALPHA, 0);
genlightmaptexs(LM_ALPHA, LM_ALPHA);
brightengeom = true;
}
-void lightent(extentity &e, float height)
-{
+void lightent(extentity &e, float height) {
if(e.type==ET_LIGHT) return;
float ambient = 0.0f;
- if(e.type==ET_MAPMODEL)
- {
+ if(e.type==ET_MAPMODEL) {
model *m = loadmodel(NULL, e.attr2);
if(m) height = m->above()*0.75f;
}
lightreaching(target, e.light.color, e.light.dir, false, &e, ambient);
}
-void lightents(bool force)
-{
+void lightents(bool force) {
if(!force && !shouldlightents) return;
-
const vector<extentity *> &ents = entities::getents();
loopv(ents) lightent(*ents[i]);
-
shouldlightents = false;
}
-void initlights()
-{
- if((fullbright && editmode) || lightmaps.empty())
- {
+void initlights() {
+ if((fullbright && editmode) || lightmaps.empty()) {
clearlights();
return;
}
-
clearlightcache();
genlightmaptexs(LM_ALPHA, 0);
genlightmaptexs(LM_ALPHA, LM_ALPHA);
shouldlightents = true;
}
-void lightreaching(const vec &target, vec &color, vec &dir, bool fast, extentity *t, float ambient)
-{
- if((fullbright && editmode) || lightmaps.empty())
- {
+void lightreaching(const vec &target, vec &color, vec &dir, bool fast, extentity *t, float ambient) {
+ if((fullbright && editmode) || lightmaps.empty()) {
color = vec(1, 1, 1);
dir = vec(0, 0, 1);
return;
}
-
color = dir = vec(0, 0, 0);
const vector<extentity *> &ents = entities::getents();
const vector<int> &lights = checklightcache(int(target.x), int(target.y));
- loopv(lights)
- {
+ loopv(lights) {
extentity &e = *ents[lights[i]];
if(e.type != ET_LIGHT)
continue;
-
vec ray(target);
ray.sub(e.o);
float mag = ray.magnitude();
if(e.attr1 && mag >= float(e.attr1))
continue;
-
if(mag < 1e-4f) ray = vec(0, 0, -1);
- else
- {
+ else {
ray.div(mag);
if(shadowray(e.o, ray, mag, RAY_SHADOW | RAY_POLY, t) < mag)
continue;
}
-
float intensity = 1;
if(e.attr1)
intensity -= mag / float(e.attr1);
- if(e.attached && e.attached->type==ET_SPOTLIGHT)
- {
+ if(e.attached && e.attached->type==ET_SPOTLIGHT) {
vec spot = vec(e.attached->o).sub(e.o).normalize();
float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
if(spotatten <= 0) continue;
intensity *= spotatten;
}
-
vec lightcol = vec(e.attr2, e.attr3, e.attr4).mul(1.0f/255);
color.add(vec(lightcol).mul(intensity));
dir.add(vec(ray).mul(-intensity*lightcol.x*lightcol.y*lightcol.z));
else dir.normalize();
}
-entity *brightestlight(const vec &target, const vec &dir)
-{
+entity *brightestlight(const vec &target, const vec &dir) {
const vector<extentity *> &ents = entities::getents();
const vector<int> &lights = checklightcache(int(target.x), int(target.y));
extentity *brightest = NULL;
float bintensity = 0;
- loopv(lights)
- {
+ loopv(lights) {
extentity &e = *ents[lights[i]];
if(e.type != ET_LIGHT || vec(e.o).sub(target).dot(dir)<0)
continue;
-
vec ray(target);
ray.sub(e.o);
float mag = ray.magnitude();
if(e.attr1 && mag >= float(e.attr1))
continue;
-
ray.div(mag);
if(shadowray(e.o, ray, mag, RAY_SHADOW | RAY_POLY) < mag)
continue;
float intensity = 1;
if(e.attr1)
intensity -= mag / float(e.attr1);
- if(e.attached && e.attached->type==ET_SPOTLIGHT)
- {
+ if(e.attached && e.attached->type==ET_SPOTLIGHT) {
vec spot = vec(e.attached->o).sub(e.o).normalize();
float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
if(spotatten <= 0) continue;
intensity *= spotatten;
}
-
- if(!brightest || intensity > bintensity)
- {
+ if(!brightest || intensity > bintensity) {
brightest = &e;
bintensity = intensity;
}
return brightest;
}
-void dumplms()
-{
- loopv(lightmaps)
- {
+void dumplms() {
+ loopv(lightmaps) {
ImageData temp(LM_PACKW, LM_PACKH, lightmaps[i].bpp, lightmaps[i].data);
const char *map = game::getclientmap(), *name = strrchr(map, '/');
defformatstring(buf, "lightmap_%s_%d.png", name ? name+1 : map, i);
#define LM_PACKW 512
#define LM_PACKH 512
-struct PackNode
-{
+struct PackNode {
PackNode *child1, *child2;
ushort x, y, w, h;
int available;
-
PackNode() : child1(0), child2(0), x(0), y(0), w(LM_PACKW), h(LM_PACKH), available(min(LM_PACKW, LM_PACKH)) {}
PackNode(ushort x, ushort y, ushort w, ushort h) : child1(0), child2(0), x(x), y(y), w(w), h(h), available(min(w, h)) {}
-
- void clear()
- {
+ void clear() {
DELETEP(child1);
DELETEP(child2);
}
-
- ~PackNode()
- {
+ ~PackNode() {
clear();
}
-
bool insert(ushort &tx, ushort &ty, ushort tw, ushort th);
};
-enum
-{
+enum {
LM_DIFFUSE = 0,
LM_BUMPMAP0,
LM_BUMPMAP1,
LM_TYPE = 0x0F,
-
LM_ALPHA = 1<<4,
LM_FLAGS = 0xF0
};
-struct LightMap
-{
+struct LightMap {
int type, bpp, tex, offsetx, offsety;
PackNode packroot;
uint lightmaps, lumels;
int unlitx, unlity;
uchar *data;
-
LightMap()
: type(LM_DIFFUSE), bpp(3), tex(-1), offsetx(-1), offsety(-1),
lightmaps(0), lumels(0), unlitx(-1), unlity(-1),
- data(NULL)
- {
+ data(NULL) {
}
-
- ~LightMap()
- {
+ ~LightMap() {
if(data) delete[] data;
}
-
- void finalize()
- {
+ void finalize() {
packroot.clear();
packroot.available = 0;
}
-
void copy(ushort tx, ushort ty, uchar *src, ushort tw, ushort th);
bool insert(ushort &tx, ushort &ty, uchar *src, ushort tw, ushort th);
};
extern vector<LightMap> lightmaps;
-struct LightMapTexture
-{
+struct LightMapTexture {
int w, h, type;
GLuint id;
int unlitx, unlity;
-
LightMapTexture()
- : w(0), h(0), type(LM_DIFFUSE), id(0), unlitx(-1), unlity(-1)
- {}
+ : w(0), h(0), type(LM_DIFFUSE), id(0), unlitx(-1), unlity(-1) {
+ }
};
extern vector<LightMapTexture> lightmaptexs;
extern void setsurfaces(cube &c, const surfaceinfo *surfs, const vertinfo *verts, int numverts);
extern void setsurface(cube &c, int orient, const surfaceinfo &surf, const vertinfo *verts, int numverts);
-struct lerpvert
-{
+struct lerpvert {
vec normal;
vec2 tc;
-
bool operator==(const lerpvert &l) const { return tc == l.tc;; }
bool operator!=(const lerpvert &l) const { return tc != l.tc; }
};
-struct lerpbounds
-{
+struct lerpbounds {
const lerpvert *min;
const lerpvert *max;
float u, ustep;
extern void lerpnormal(float u, float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end, vec &normal, vec &nstep);
#define CHECK_CALCLIGHT_PROGRESS_LOCKED(exit, show_calclight_progress, before, after) \
- if(check_calclight_progress) \
- { \
- if(!calclight_canceled) \
- { \
+ if(check_calclight_progress) { \
+ \
+ if(!calclight_canceled) { \
+ \
before; \
show_calclight_progress(); \
check_calclight_canceled(); \
+++ /dev/null
-#define MAXLIGHTNINGSTEPS 64
-#define LIGHTNINGSTEP 8
-int lnjitterx[2][MAXLIGHTNINGSTEPS], lnjittery[2][MAXLIGHTNINGSTEPS];
-int lnjitterframe = 0, lastlnjitter = 0;
-
-VAR(lnjittermillis, 0, 100, 1000);
-VAR(lnjitterradius, 0, 4, 100);
-FVAR(lnjitterscale, 0, 0.5f, 10);
-VAR(lnscrollmillis, 1, 300, 5000);
-FVAR(lnscrollscale, 0, 0.125f, 10);
-FVAR(lnblendpower, 0, 0.25f, 1000);
-
-static void calclightningjitter(int frame)
-{
- loopi(MAXLIGHTNINGSTEPS)
- {
- lnjitterx[lnjitterframe][i] = -lnjitterradius + rnd(2*lnjitterradius + 1);
- lnjittery[lnjitterframe][i] = -lnjitterradius + rnd(2*lnjitterradius + 1);
- }
-}
-
-static void setuplightning()
-{
- if(!lastlnjitter || lastmillis-lastlnjitter > lnjittermillis)
- {
- if(!lastlnjitter) calclightningjitter(lnjitterframe);
- lastlnjitter = lastmillis - (lastmillis%lnjittermillis);
- calclightningjitter(lnjitterframe ^= 1);
- }
-}
-
-static void renderlightning(Texture *tex, const vec &o, const vec &d, float sz)
-{
- vec step(d);
- step.sub(o);
- float len = step.magnitude();
- int numsteps = clamp(int(ceil(len/LIGHTNINGSTEP)), 2, MAXLIGHTNINGSTEPS);
- step.div(numsteps+1);
- int jitteroffset = detrnd(int(d.x+d.y+d.z), MAXLIGHTNINGSTEPS);
- vec cur(o), up, right;
- up.orthogonal(step);
- up.normalize();
- right.cross(up, step);
- right.normalize();
- float scroll = -float(lastmillis%lnscrollmillis)/lnscrollmillis,
- scrollscale = lnscrollscale*(LIGHTNINGSTEP*tex->ys)/(sz*tex->xs),
- blend = pow(clamp(float(lastmillis - lastlnjitter)/lnjittermillis, 0.0f, 1.0f), lnblendpower),
- jitter0 = (1-blend)*lnjitterscale*sz/lnjitterradius, jitter1 = blend*lnjitterscale*sz/lnjitterradius;
- gle::begin(GL_TRIANGLE_STRIP);
- loopj(numsteps)
- {
- vec next(cur);
- next.add(step);
- if(j+1==numsteps) next = d;
- else
- {
- int lj = (j+jitteroffset)%MAXLIGHTNINGSTEPS;
- next.add(vec(right).mul((jitter1*lnjitterx[lnjitterframe][lj] + jitter0*lnjitterx[lnjitterframe^1][lj])));
- next.add(vec(up).mul((jitter1*lnjittery[lnjitterframe][lj] + jitter0*lnjittery[lnjitterframe^1][lj])));
- }
- vec dir1 = next, dir2 = next, across;
- dir1.sub(cur);
- dir2.sub(camera1->o);
- across.cross(dir2, dir1).normalize().mul(sz);
- gle::attribf(cur.x-across.x, cur.y-across.y, cur.z-across.z);
- gle::attribf(scroll, 1);
- gle::attribf(cur.x+across.x, cur.y+across.y, cur.z+across.z);
- gle::attribf(scroll, 0);
- scroll += scrollscale;
- if(j+1==numsteps)
- {
- gle::attribf(next.x-across.x, next.y-across.y, next.z-across.z);
- gle::attribf(scroll, 1);
- gle::attribf(next.x+across.x, next.y+across.y, next.z+across.z);
- gle::attribf(scroll, 0);
- }
- cur = next;
- }
- gle::end();
-}
-
-struct lightningrenderer : listrenderer
-{
- lightningrenderer()
- : listrenderer("packages/particles/lightning.png", 2, PT_LIGHTNING|PT_TRACK|PT_GLARE)
- {}
-
- void startrender()
- {
- glDisable(GL_CULL_FACE);
- gle::defattrib(gle::ATTRIB_VERTEX, 3, GL_FLOAT);
- gle::defattrib(gle::ATTRIB_TEXCOORD0, 2, GL_FLOAT);
- }
-
- void endrender()
- {
- glEnable(GL_CULL_FACE);
- }
-
- void update()
- {
- setuplightning();
- }
-
- void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
- {
- pe.maxfade = max(pe.maxfade, fade);
- pe.extendbb(o, size);
- pe.extendbb(d, size);
- }
-
- void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
- {
- blend = min(blend<<2, 255);
- if(type&PT_MOD) //multiply alpha into color
- gle::colorub((p->color.r*blend)>>8, (p->color.g*blend)>>8, (p->color.b*blend)>>8);
- else
- gle::color(p->color, blend);
- renderlightning(tex, o, d, p->size);
- }
-};
-static lightningrenderer lightnings;
-
extern void cleargamma();
-void cleanup()
-{
+void cleanup() {
cleanupserver();
SDL_ShowCursor(SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_FALSE);
extern void writeinitcfg();
-void quit() // normal exit
-{
+void quit() { // normal exit {
writeinitcfg();
writeservercfg();
abortconnect();
exit(EXIT_SUCCESS);
}
-void fatal(const char *s, ...) // failure exit
-{
+void fatal(const char *s, ...) { // failure exit {
static int errors = 0;
errors++;
-
- if(errors <= 2) // print up to one extra recursive error
- {
+ if(errors <= 2) { // print up to one extra recursive error {
defvformatstring(msg,s,s);
logoutf("%s", msg);
-
- if(errors <= 1) // avoid recursion
- {
- if(SDL_WasInit(SDL_INIT_VIDEO))
- {
+ if(errors <= 1) { // avoid recursion {
+ if(SDL_WasInit(SDL_INIT_VIDEO)) {
SDL_ShowCursor(SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_FALSE);
if(screen) SDL_SetWindowGrab(screen, SDL_FALSE);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Cube 2: Sauerbraten fatal error", msg, NULL);
}
}
-
exit(EXIT_FAILURE);
}
int initing = NOT_INITING;
-bool initwarning(const char *desc, int level, int type)
-{
- if(initing < level)
- {
+bool initwarning(const char *desc, int level, int type) {
+ if(initing < level) {
addchange(desc, type);
return true;
}
VARF(depthbits, 0, 0, 32, initwarning("depth-buffer precision"));
VARF(fsaa, -1, -1, 16, initwarning("anti-aliasing"));
-void writeinitcfg()
-{
+void writeinitcfg() {
stream *f = openutf8file("init.cfg", "w");
if(!f) return;
f->printf("// automatically written on exit, DO NOT MODIFY\n// modify settings in game\n");
COMMAND(quit, "");
-static void getbackgroundres(int &w, int &h)
-{
+static void getbackgroundres(int &w, int &h) {
float wk = 1, hk = 1;
if(w < 1024) wk = 1024.0f/w;
if(h < 768) hk = 768.0f/h;
string backgroundmapname = "";
char *backgroundmapinfo = NULL;
-void setbackgroundinfo(const char *caption = NULL, Texture *mapshot = NULL, const char *mapname = NULL, const char *mapinfo = NULL)
-{
+void setbackgroundinfo(const char *caption = NULL, Texture *mapshot = NULL, const char *mapname = NULL, const char *mapinfo = NULL) {
renderedframe = false;
copystring(backgroundcaption, caption ? caption : "");
backgroundmapshot = mapshot;
copystring(backgroundmapname, mapname ? mapname : "");
- if(mapinfo != backgroundmapinfo)
- {
+ if(mapinfo != backgroundmapinfo) {
DELETEA(backgroundmapinfo);
if(mapinfo) backgroundmapinfo = newstring(mapinfo);
}
}
-void restorebackground(bool force = false)
-{
- if(renderedframe)
- {
+void restorebackground(bool force = false) {
+ if(renderedframe) {
if(!force) return;
setbackgroundinfo();
}
renderbackground(backgroundcaption[0] ? backgroundcaption : NULL, backgroundmapshot, backgroundmapname[0] ? backgroundmapname : NULL, backgroundmapinfo, true);
}
-void bgquad(float x, float y, float w, float h, float tx = 0, float ty = 0, float tw = 1, float th = 1)
-{
+void bgquad(float x, float y, float w, float h, float tx = 0, float ty = 0, float tw = 1, float th = 1) {
gle::begin(GL_TRIANGLE_STRIP);
gle::attribf(x, y); gle::attribf(tx, ty);
gle::attribf(x+w, y); gle::attribf(tx + tw, ty);
gle::end();
}
-void renderbackground(const char *caption, Texture *mapshot, const char *mapname, const char *mapinfo, bool restore, bool force)
-{
+void renderbackground(const char *caption, Texture *mapshot, const char *mapname, const char *mapinfo, bool restore, bool force) {
if(!inbetweenframes && !force) return;
-
if(!restore || force) stopsounds(); // stop sounds while loading
-
int w = screenw, h = screenh;
if(forceaspect) w = int(ceil(h*forceaspect));
getbackgroundres(w, h);
gettextres(w, h);
-
static int lastupdate = -1, lastw = -1, lasth = -1;
static int numdecals = 0;
static struct decal { float x, y, size; int side; } decals[12];
- if((renderedframe && !mainmenu && lastupdate != lastmillis) || lastw != w || lasth != h)
- {
+ if((renderedframe && !mainmenu && lastupdate != lastmillis) || lastw != w || lasth != h) {
lastupdate = lastmillis;
lastw = w;
lasth = h;
-
numdecals = sizeof(decals)/sizeof(decals[0]);
numdecals = numdecals/3 + rnd((numdecals*2)/3 + 1);
float maxsize = min(w, h)/16.0f;
- loopi(numdecals)
- {
+ loopi(numdecals) {
decal d = { rndscale(w), rndscale(h), maxsize/2 + rndscale(maxsize/2), rnd(2) };
decals[i] = d;
}
}
else if(lastupdate != lastmillis) lastupdate = lastmillis;
-
- loopi(restore ? 1 : 3)
- {
+ loopi(restore ? 1 : 3) {
hudmatrix.ortho(0, w, h, 0, -1, 1);
resethudmatrix();
-
hudshader->set();
gle::colorf(1, 1, 1);
-
gle::defvertex(2);
gle::deftexcoord0();
-
settexture("background/daemex.png", 0);
bgquad(0, 0, screenw, screenh, 0, 0, 1, 1);
glEnable(GL_BLEND);
lx = 0.5f*(w - lw), ly = 0.5f*(h*0.5f - lh);
settexture((maxtexsize ? min(maxtexsize, hwtexsize) : hwtexsize) >= 1024 && (screenw > 1280 || screenh > 800) ? "data/logo_1024.png" : "data/logo.png", 3);
bgquad(lx, ly, lw, lh);
- if(caption)
- {
+ if(caption) {
int tw = text_width(caption);
float tsz = 0.04f*min(w, h)/FONTH,
tx = 0.5f*(w - tw*tsz), ty = h - 0.075f*1.5f*min(w, h) - 1.25f*FONTH*tsz;
draw_text(caption, 0, 0);
pophudmatrix();
}
- if(mapshot || mapname)
- {
+ if(mapshot || mapname) {
int infowidth = 12*FONTH;
float sz = 0.35f*min(w, h), msz = (0.75f*min(w, h) - sz)/(infowidth + FONTH), x = 0.5f*(w-sz), y = ly+lh - sz/15;
- if(mapinfo)
- {
+ if(mapinfo) {
int mw, mh;
text_bounds(mapinfo, mw, mh, infowidth);
x -= 0.5f*(mw*msz + FONTH*msz);
}
- if(mapshot && mapshot!=notexture)
- {
+ if(mapshot && mapshot!=notexture) {
glBindTexture(GL_TEXTURE_2D, mapshot->id);
bgquad(x, y, sz, sz);
}
- else
- {
+ else {
int qw, qh;
text_bounds("?", qw, qh);
float qsz = sz*0.5f/max(qw, qh);
}
settexture("data/mapshot_frame.png", 3);
bgquad(x, y, sz, sz);
- if(mapname)
- {
+ if(mapname) {
int tw = text_width(mapname);
float tsz = sz/(8*FONTH),
tx = 0.9f*sz - tw*tsz, ty = 0.9f*sz - FONTH*tsz;
draw_text(mapname, 0, 0);
pophudmatrix();
}
- if(mapinfo)
- {
+ if(mapinfo) {
pushhudmatrix();
hudmatrix.translate(x+sz+FONTH*msz, y, 0);
hudmatrix.scale(msz, msz, 1);
glDisable(GL_BLEND);
if(!restore) swapbuffers(false);
}
-
if(!restore) setbackgroundinfo(caption, mapshot, mapname, mapinfo);
}
float loadprogress = 0;
-void renderprogress(float bar, const char *text, GLuint tex, bool background) // also used during loading
-{
+void renderprogress(float bar, const char *text, GLuint tex, bool background) { // also used during loading {
if(!inbetweenframes || drawtex) return;
-
extern int menufps, maxfps;
int fps = menufps ? (maxfps ? min(maxfps, menufps) : menufps) : maxfps;
- if(fps)
- {
+ if(fps) {
static int lastprogress = 0;
int ticks = SDL_GetTicks(), diff = ticks - lastprogress;
if(bar > 0 && diff >= 0 && diff < (1000 + fps-1)/fps) return;
lastprogress = ticks;
}
-
clientkeepalive(); // make sure our connection doesn't time out while loading maps etc.
-
SDL_PumpEvents(); // keep the event queue awake to avoid 'beachball' cursor
-
extern int mesa_swap_bug, curvsync;
bool forcebackground = progressbackground || (mesa_swap_bug && (curvsync || totalmillis==1));
if(background || forcebackground) restorebackground(forcebackground);
-
int w = screenw, h = screenh;
if(forceaspect) w = int(ceil(h*forceaspect));
getbackgroundres(w, h);
gettextres(w, h);
-
hudmatrix.ortho(0, w, h, 0, -1, 1);
resethudmatrix();
-
hudshader->set();
gle::colorf(1, 1, 1);
-
gle::defvertex(2);
gle::deftexcoord0();
-
float fh = 0.075f*min(w, h), fw = fh*10,
fx = renderedframe ? w - fw - fh/4 : 0.5f*(w - fw),
fy = renderedframe ? fh/4 : h - fh*1.5f,
fv1 = 0/64.0f, fv2 = 52/64.0f;
settexture("data/loading_frame.png", 3);
bgquad(fx, fy, fw, fh, fu1, fv1, fu2-fu1, fv2-fv1);
-
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
float bw = fw*(511 - 2*17)/511.0f, bh = fh*20/52.0f,
bx = fx + fw*17/511.0f, by = fy + fh*16/52.0f,
bv1 = 0/32.0f, bv2 = 20/32.0f,
eu1 = 23/32.0f, eu2 = 30/32.0f, ew = fw*7/511.0f,
mw = bw - sw - ew,
ex = bx+sw + max(mw*bar, fw*7/511.0f);
- if(bar > 0)
- {
+ if(bar > 0) {
settexture("data/loading_bar.png", 3);
gle::begin(GL_QUADS);
gle::attribf(bx, by); gle::attribf(su1, bv1);
gle::attribf(bx+sw, by); gle::attribf(su2, bv1);
gle::attribf(bx+sw, by+bh); gle::attribf(su2, bv2);
gle::attribf(bx, by+bh); gle::attribf(su1, bv2);
-
gle::attribf(bx+sw, by); gle::attribf(su2, bv1);
gle::attribf(ex, by); gle::attribf(eu1, bv1);
gle::attribf(ex, by+bh); gle::attribf(eu1, bv2);
gle::attribf(bx+sw, by+bh); gle::attribf(su2, bv2);
-
gle::attribf(ex, by); gle::attribf(eu1, bv1);
gle::attribf(ex+ew, by); gle::attribf(eu2, bv1);
gle::attribf(ex+ew, by+bh); gle::attribf(eu2, bv2);
gle::attribf(ex, by+bh); gle::attribf(eu1, bv2);
gle::end();
}
-
- if(text)
- {
+ if(text) {
int tw = text_width(text);
float tsz = bh*0.8f/FONTH;
if(tw*tsz > mw) tsz = mw/tw;
draw_text(text, 0, 0);
pophudmatrix();
}
-
glDisable(GL_BLEND);
-
- if(tex)
- {
+ if(tex) {
glBindTexture(GL_TEXTURE_2D, tex);
float sz = 0.35f*min(w, h), x = 0.5f*(w-sz), y = 0.5f*min(w, h) - sz/15;
bgquad(x, y, sz, sz);
-
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
settexture("data/mapshot_frame.png", 3);
bgquad(x, y, sz, sz);
glDisable(GL_BLEND);
}
-
swapbuffers(false);
}
Uint32 textinputtime = 0;
VAR(textinputfilter, 0, 5, 1000);
-void keyrepeat(bool on, int mask)
-{
+void keyrepeat(bool on, int mask) {
if(on) keyrepeatmask |= mask;
else keyrepeatmask &= ~mask;
}
-void textinput(bool on, int mask)
-{
- if(on)
- {
- if(!textinputmask)
- {
+void textinput(bool on, int mask) {
+ if(on) {
+ if(!textinputmask) {
SDL_StartTextInput();
textinputtime = SDL_GetTicks();
}
textinputmask |= mask;
}
- else if(textinputmask)
- {
+ else if(textinputmask) {
textinputmask &= ~mask;
if(!textinputmask) SDL_StopTextInput();
}
VAR(sdl_xgrab_bug, 0, 0, 1);
#endif
-void inputgrab(bool on, bool delay = false)
-{
+void inputgrab(bool on, bool delay = false) {
#ifdef SDL_VIDEO_DRIVER_X11
bool wasrelativemouse = relativemouse;
#endif
- if(on)
- {
+ if(on) {
SDL_ShowCursor(SDL_FALSE);
- if(canrelativemouse && userelativemouse)
- {
- if(SDL_SetRelativeMouseMode(SDL_TRUE) >= 0)
- {
+ if(canrelativemouse && userelativemouse) {
+ if(SDL_SetRelativeMouseMode(SDL_TRUE) >= 0) {
SDL_SetWindowGrab(screen, SDL_TRUE);
relativemouse = true;
}
- else
- {
+ else {
SDL_SetWindowGrab(screen, SDL_FALSE);
canrelativemouse = false;
relativemouse = false;
}
}
}
- else
- {
+ else {
SDL_ShowCursor(SDL_TRUE);
- if(relativemouse)
- {
+ if(relativemouse) {
SDL_SetWindowGrab(screen, SDL_FALSE);
SDL_SetRelativeMouseMode(SDL_FALSE);
relativemouse = false;
shouldgrab = delay;
#ifdef SDL_VIDEO_DRIVER_X11
- if((relativemouse || wasrelativemouse) && sdl_xgrab_bug)
- {
+ if((relativemouse || wasrelativemouse) && sdl_xgrab_bug) {
// Workaround for buggy SDL X11 pointer grabbing
union { SDL_SysWMinfo info; uchar buf[sizeof(SDL_SysWMinfo) + 128]; };
SDL_GetVersion(&info.version);
- if(SDL_GetWindowWMInfo(screen, &info) && info.subsystem == SDL_SYSWM_X11)
- {
- if(relativemouse)
- {
+ if(SDL_GetWindowWMInfo(screen, &info) && info.subsystem == SDL_SYSWM_X11) {
+ if(relativemouse) {
uint mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
XGrabPointer(info.info.x11.display, info.info.x11.window, True, mask, GrabModeAsync, GrabModeAsync, info.info.x11.window, None, CurrentTime);
}
bool initwindowpos = false;
-void setfullscreen(bool enable)
-{
+void setfullscreen(bool enable) {
if(!screen) return;
//initwarning(enable ? "fullscreen" : "windowed");
extern int fullscreendesktop;
SDL_SetWindowFullscreen(screen, enable ? (fullscreendesktop ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN) : 0);
- if(!enable)
- {
+ if(!enable) {
SDL_SetWindowSize(screen, scr_w, scr_h);
- if(initwindowpos)
- {
+ if(initwindowpos) {
int winx = SDL_WINDOWPOS_CENTERED, winy = SDL_WINDOWPOS_CENTERED;
SDL_SetWindowPosition(screen, winx, winy);
initwindowpos = false;
VARF(fullscreen, 0, 1, 1, setfullscreen(fullscreen!=0));
#endif
-void resetfullscreen()
-{
+void resetfullscreen() {
setfullscreen(false);
setfullscreen(true);
}
VARF(fullscreendesktop, 0, 0, 1, if(fullscreen) resetfullscreen());
-void screenres(int w, int h)
-{
+void screenres(int w, int h) {
scr_w = clamp(w, SCR_MINW, SCR_MAXW);
scr_h = clamp(h, SCR_MINH, SCR_MAXH);
- if(screen)
- {
- if(fullscreendesktop)
- {
+ if(screen) {
+ if(fullscreendesktop) {
scr_w = min(scr_w, desktopw);
scr_h = min(scr_h, desktoph);
}
- if(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN)
- {
+ if(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN) {
if(fullscreendesktop) gl_resize();
else resetfullscreen();
initwindowpos = true;
}
- else
- {
+ else {
SDL_SetWindowSize(screen, scr_w, scr_h);
SDL_SetWindowPosition(screen, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
initwindowpos = false;
}
}
- else
- {
+ else {
initwarning("screen resolution");
}
}
ICOMMAND(screenres, "ii", (int *w, int *h), screenres(*w, *h));
-static void setgamma(int val)
-{
+static void setgamma(int val) {
if(screen && SDL_SetWindowBrightness(screen, val/100.0f) < 0) conoutf(CON_ERROR, "Could not set gamma: %s", SDL_GetError());
}
static int curgamma = 100;
-VARFNP(gamma, reqgamma, 30, 100, 300,
-{
+VARFNP(gamma, reqgamma, 30, 100, 300, {
if(initing || reqgamma == curgamma) return;
curgamma = reqgamma;
setgamma(curgamma);
});
-void restoregamma()
-{
+void restoregamma() {
if(initing || reqgamma == 100) return;
curgamma = reqgamma;
setgamma(curgamma);
}
-void cleargamma()
-{
+void cleargamma() {
if(curgamma != 100 && screen) SDL_SetWindowBrightness(screen, 1.0f);
}
int curvsync = -1;
-void restorevsync()
-{
+void restorevsync() {
if(initing || !glcontext) return;
extern int vsync, vsynctear;
if(!SDL_GL_SetSwapInterval(vsync ? (vsynctear ? -1 : 1) : 0))
VARFP(vsync, 0, 0, 1, restorevsync());
VARFP(vsynctear, 0, 0, 1, { if(vsync) restorevsync(); });
-void setupscreen()
-{
- if(glcontext)
- {
+void setupscreen() {
+ if(glcontext) {
SDL_GL_DeleteContext(glcontext);
glcontext = NULL;
}
- if(screen)
- {
+ if(screen) {
SDL_DestroyWindow(screen);
screen = NULL;
}
curvsync = -1;
-
SDL_Rect desktop;
if(SDL_GetDisplayBounds(0, &desktop) < 0) fatal("failed querying desktop bounds: %s", SDL_GetError());
desktopw = desktop.w;
desktoph = desktop.h;
-
if(scr_h < 0) scr_h = fullscreen ? desktoph : SCR_DEFAULTH;
if(scr_w < 0) scr_w = (scr_h*desktopw)/desktoph;
scr_w = clamp(scr_w, SCR_MINW, SCR_MAXW);
scr_h = clamp(scr_h, SCR_MINH, SCR_MAXH);
- if(fullscreendesktop)
- {
+ if(fullscreendesktop) {
scr_w = min(scr_w, desktopw);
scr_h = min(scr_h, desktoph);
}
-
int winx = SDL_WINDOWPOS_UNDEFINED, winy = SDL_WINDOWPOS_UNDEFINED, winw = scr_w, winh = scr_h, flags = SDL_WINDOW_RESIZABLE;
- if(fullscreen)
- {
- if(fullscreendesktop)
- {
+ if(fullscreen) {
+ if(fullscreendesktop) {
winw = desktopw;
winh = desktoph;
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
else flags |= SDL_WINDOW_FULLSCREEN;
initwindowpos = true;
}
-
SDL_GL_ResetAttributes();
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- static const int configs[] =
- {
+ static const int configs[] = {
0x3, /* try everything */
0x2, 0x1, /* try disabling one at a time */
0 /* try disabling everything */
};
int config = 0;
if(!depthbits) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
- if(!fsaa)
- {
+ if(!fsaa) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
}
- loopi(sizeof(configs)/sizeof(configs[0]))
- {
+ loopi(sizeof(configs)/sizeof(configs[0])) {
config = configs[i];
if(!depthbits && config&1) continue;
if(fsaa<=0 && config&2) continue;
if(depthbits) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config&1 ? depthbits : 24);
- if(fsaa>0)
- {
+ if(fsaa>0) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, config&2 ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config&2 ? fsaa : 0);
}
screen = SDL_CreateWindow("Cube 2: Sauerbraten", winx, winy, winw, winh, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS | flags);
if(!screen) continue;
-
static const int glversions[] = { 33, 32, 31, 30, 20 };
- loopj(sizeof(glversions)/sizeof(glversions[0]))
- {
+ loopj(sizeof(glversions)/sizeof(glversions[0])) {
glcompat = glversions[j] <= 30 ? 1 : 0;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glversions[j] / 10);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glversions[j] % 10);
}
if(!screen) fatal("failed to create OpenGL window: %s", SDL_GetError());
else if(!glcontext) fatal("failed to create OpenGL context: %s", SDL_GetError());
- else
- {
+ else {
if(depthbits && (config&1)==0) conoutf(CON_WARN, "%d bit z-buffer not supported - disabling", depthbits);
if(fsaa>0 && (config&2)==0) conoutf(CON_WARN, "%dx anti-aliasing not supported - disabling", fsaa);
}
-
SDL_SetWindowMinimumSize(screen, SCR_MINW, SCR_MINH);
SDL_SetWindowMaximumSize(screen, SCR_MAXW, SCR_MAXH);
-
SDL_GetWindowSize(screen, &screenw, &screenh);
}
-void resetgl()
-{
+void resetgl() {
clearchanges(CHANGE_GFX);
-
renderbackground("resetting OpenGL");
-
extern void cleanupva();
extern void cleanupparticles();
extern void cleanupdecals();
cleanshadowmap();
cleanupshaders();
cleanupgl();
-
setupscreen();
inputgrab(grabinput);
gl_init();
-
inbetweenframes = false;
if(!reloadtexture(*notexture) ||
!reloadtexture("data/logo.png") ||
static queue<SDL_Event, 32> events;
-static inline bool filterevent(const SDL_Event &event)
-{
- switch(event.type)
- {
+static inline bool filterevent(const SDL_Event &event) {
+ switch(event.type) {
case SDL_MOUSEMOTION:
- if(grabinput && !relativemouse && !(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN))
- {
+ if(grabinput && !relativemouse && !(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN)) {
if(event.motion.x == screenw / 2 && event.motion.y == screenh / 2)
return false; // ignore any motion events generated by SDL_WarpMouse
}
return true;
}
-template <int SIZE> static inline bool pumpevents(queue<SDL_Event, SIZE> &events)
-{
- while(events.empty())
- {
+template <int SIZE> static inline bool pumpevents(queue<SDL_Event, SIZE> &events) {
+ while(events.empty()) {
SDL_PumpEvents();
databuf<SDL_Event> buf = events.reserve(events.capacity());
int n = SDL_PeepEvents(buf.getbuf(), buf.remaining(), SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
static int interceptkeysym = 0;
-static int interceptevents(void *data, SDL_Event *event)
-{
- switch(event->type)
- {
+static int interceptevents(void *data, SDL_Event *event) {
+ switch(event->type) {
case SDL_MOUSEMOTION: return 0;
case SDL_KEYDOWN:
- if(event->key.keysym.sym == interceptkeysym)
- {
+ if(event->key.keysym.sym == interceptkeysym) {
interceptkeysym = -interceptkeysym;
return 0;
}
return 1;
}
-static void clearinterceptkey()
-{
+static void clearinterceptkey() {
SDL_DelEventWatch(interceptevents, NULL);
interceptkeysym = 0;
}
-bool interceptkey(int sym)
-{
- if(!interceptkeysym)
- {
+bool interceptkey(int sym) {
+ if(!interceptkeysym) {
interceptkeysym = sym;
SDL_FilterEvents(interceptevents, NULL);
- if(interceptkeysym < 0)
- {
+ if(interceptkeysym < 0) {
interceptkeysym = 0;
return true;
}
}
else if(abs(interceptkeysym) != sym) interceptkeysym = sym;
SDL_PumpEvents();
- if(interceptkeysym < 0)
- {
+ if(interceptkeysym < 0) {
clearinterceptkey();
interceptkeysym = sym;
SDL_FilterEvents(interceptevents, NULL);
return false;
}
-static void ignoremousemotion()
-{
+static void ignoremousemotion() {
SDL_PumpEvents();
SDL_FlushEvent(SDL_MOUSEMOTION);
}
-static void resetmousemotion()
-{
- if(grabinput && !relativemouse && !(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN))
- {
+static void resetmousemotion() {
+ if(grabinput && !relativemouse && !(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN)) {
SDL_WarpMouseInWindow(screen, screenw / 2, screenh / 2);
}
}
-static void checkmousemotion(int &dx, int &dy)
-{
- while(pumpevents(events))
- {
+static void checkmousemotion(int &dx, int &dy) {
+ while(pumpevents(events)) {
SDL_Event &event = events.removing();
if(event.type != SDL_MOUSEMOTION) return;
dx += event.motion.xrel;
}
}
-void checkinput()
-{
+void checkinput() {
if(interceptkeysym) clearinterceptkey();
//int lasttype = 0, lastbut = 0;
bool mousemoved = false;
int focused = 0;
- while(pumpevents(events))
- {
+ while(pumpevents(events)) {
SDL_Event &event = events.remove();
-
if(focused && event.type!=SDL_WINDOWEVENT) { if(grabinput != (focused>0)) inputgrab(grabinput = focused>0, shouldgrab); focused = 0; }
-
- switch(event.type)
- {
+ switch(event.type) {
case SDL_QUIT:
quit();
return;
-
case SDL_TEXTINPUT:
- if(textinputmask && int(event.text.timestamp-textinputtime) >= textinputfilter)
- {
+ if(textinputmask && int(event.text.timestamp-textinputtime) >= textinputfilter) {
uchar buf[SDL_TEXTINPUTEVENT_TEXT_SIZE+1];
size_t len = decodeutf8(buf, sizeof(buf)-1, (const uchar *)event.text.text, strlen(event.text.text));
if(len > 0) { buf[len] = '\0'; processtextinput((const char *)buf, len); }
}
break;
-
case SDL_KEYDOWN:
case SDL_KEYUP:
if(keyrepeatmask || !event.key.repeat)
processkey(event.key.keysym.sym, event.key.state==SDL_PRESSED, event.key.keysym.mod | SDL_GetModState());
break;
-
case SDL_WINDOWEVENT:
- switch(event.window.event)
- {
+ switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE:
quit();
break;
-
case SDL_WINDOWEVENT_FOCUS_GAINED:
shouldgrab = true;
break;
shouldgrab = false;
focused = 1;
break;
-
case SDL_WINDOWEVENT_LEAVE:
case SDL_WINDOWEVENT_FOCUS_LOST:
shouldgrab = false;
focused = -1;
break;
-
case SDL_WINDOWEVENT_MINIMIZED:
minimized = true;
break;
-
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
minimized = false;
break;
-
case SDL_WINDOWEVENT_RESIZED:
break;
-
- case SDL_WINDOWEVENT_SIZE_CHANGED:
- {
+ case SDL_WINDOWEVENT_SIZE_CHANGED: {
SDL_GetWindowSize(screen, &screenw, &screenh);
- if(!fullscreendesktop || !(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN))
- {
+ if(!fullscreendesktop || !(SDL_GetWindowFlags(screen) & SDL_WINDOW_FULLSCREEN)) {
scr_w = clamp(screenw, SCR_MINW, SCR_MAXW);
scr_h = clamp(screenh, SCR_MINH, SCR_MAXH);
}
}
}
break;
-
case SDL_MOUSEMOTION:
- if(grabinput)
- {
+ if(grabinput) {
int dx = event.motion.xrel, dy = event.motion.yrel;
checkmousemotion(dx, dy);
if(!g3d_movecursor(dx, dy)) mousemove(dx, dy);
}
else if(shouldgrab) inputgrab(grabinput = true);
break;
-
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
//if(lasttype==event.type && lastbut==event.button.button) break; // why?? get event twice without it
- switch(event.button.button)
- {
+ switch(event.button.button) {
case SDL_BUTTON_LEFT: processkey(-1, event.button.state==SDL_PRESSED); break;
case SDL_BUTTON_MIDDLE: processkey(-2, event.button.state==SDL_PRESSED); break;
case SDL_BUTTON_RIGHT: processkey(-3, event.button.state==SDL_PRESSED); break;
//lasttype = event.type;
//lastbut = event.button.button;
break;
-
case SDL_MOUSEWHEEL:
if(event.wheel.y > 0) { processkey(-4, true); processkey(-4, false); }
else if(event.wheel.y < 0) { processkey(-5, true); processkey(-5, false); }
if(mousemoved) resetmousemotion();
}
-void swapbuffers(bool overlay)
-{
+void swapbuffers(bool overlay) {
gle::disable();
SDL_GL_SwapWindow(screen);
}
VAR(menufps, 0, 60, 1000);
VARP(maxfps, 0, 200, 1000);
-void limitfps(int &millis, int curmillis)
-{
+void limitfps(int &millis, int curmillis) {
int limit = (mainmenu || minimized) && menufps ? (maxfps ? min(maxfps, menufps) : menufps) : maxfps;
if(!limit) return;
static int fpserror = 0;
int delay = 1000/limit - (millis-curmillis);
if(delay < 0) fpserror = 0;
- else
- {
+ else {
fpserror += 1000%limit;
- if(fpserror >= limit)
- {
+ if(fpserror >= limit) {
++delay;
fpserror -= limit;
}
- if(delay > 0)
- {
+ if(delay > 0) {
SDL_Delay(delay);
millis += delay;
}
int fpspos = 0, fpshistory[MAXFPSHISTORY];
-void resetfpshistory()
-{
+void resetfpshistory() {
loopi(MAXFPSHISTORY) fpshistory[i] = 1;
fpspos = 0;
}
-void updatefpshistory(int millis)
-{
+void updatefpshistory(int millis) {
fpshistory[fpspos++] = max(1, min(1000, millis));
if(fpspos>=MAXFPSHISTORY) fpspos = 0;
}
-void getfps(int &fps, int &bestdiff, int &worstdiff)
-{
+void getfps(int &fps, int &bestdiff, int &worstdiff) {
int total = fpshistory[MAXFPSHISTORY-1], best = total, worst = total;
- loopi(MAXFPSHISTORY-1)
- {
+ loopi(MAXFPSHISTORY-1) {
int millis = fpshistory[i];
total += millis;
if(millis < best) best = millis;
if(millis > worst) worst = millis;
}
-
fps = (1000*MAXFPSHISTORY)/total;
bestdiff = 1000/best-fps;
worstdiff = fps-1000/worst;
}
-void getfps_(int *raw)
-{
+void getfps_(int *raw) {
int fps, bestdiff, worstdiff;
if(*raw) fps = 1000/fpshistory[(fpspos+MAXFPSHISTORY-1)%MAXFPSHISTORY];
else getfps(fps, bestdiff, worstdiff);
bool inbetweenframes = false, renderedframe = true;
-static bool findarg(int argc, char **argv, const char *str)
-{
+static bool findarg(int argc, char **argv, const char *str) {
for(int i = 1; i<argc; i++) if(strstr(argv[i], str)==argv[i]) return true;
return false;
}
VARFP(clockerror, 990000, 1000000, 1010000, clockreset());
VARFP(clockfix, 0, 0, 1, clockreset());
-int getclockmillis()
-{
+int getclockmillis() {
int millis = SDL_GetTicks() - clockrealbase;
if(clockfix) millis = int(millis*(double(clockerror)/1000000));
millis += clockvirtbase;
VAR(numcpus, 1, 1, 16);
-int main(int argc, char **argv)
-{
+int main(int argc, char **argv) {
setlogfile(NULL);
-
int dedicated = 0;
char *load = NULL, *initscript = NULL;
-
initing = INIT_RESET;
// set home dir first
for(int i = 1; i<argc; i++) if(argv[i][0]=='-' && argv[i][1] == 'q') { sethomedir(&argv[i][2]); break; }
// set log after home dir, but before anything else
- for(int i = 1; i<argc; i++) if(argv[i][0]=='-' && argv[i][1] == 'g')
- {
+ for(int i = 1; i<argc; i++) if(argv[i][0]=='-' && argv[i][1] == 'g') {
const char *file = argv[i][2] ? &argv[i][2] : "log.txt";
setlogfile(file);
logoutf("Setting log file: %s", file);
break;
}
execfile("init.cfg", false);
- for(int i = 1; i<argc; i++)
- {
- if(argv[i][0]=='-') switch(argv[i][1])
- {
+ for(int i = 1; i<argc; i++) {
+ if(argv[i][0]=='-') switch(argv[i][1]) {
case 'q': if(homedir[0]) logoutf("Using home directory: %s", homedir); break;
case 'r': /* compat, ignore */ break;
- case 'k':
- {
+ case 'k': {
const char *dir = addpackagedir(&argv[i][2]);
if(dir) logoutf("Adding package directory: %s", dir);
break;
case 't': fullscreen = atoi(&argv[i][2]); break;
case 's': /* compat, ignore */ break;
case 'f': /* compat, ignore */ break;
- case 'l':
- {
+ case 'l': {
char pkgdir[] = "packages/";
load = strstr(path(&argv[i][2]), path(pkgdir));
if(load) load += sizeof(pkgdir)-1;
else gameargs.add(argv[i]);
}
initing = NOT_INITING;
-
numcpus = clamp(SDL_GetCPUCount(), 1, 16);
-
- if(dedicated <= 1)
- {
+ if(dedicated <= 1) {
logoutf("init: sdl");
-
if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0) fatal("Unable to initialize SDL: %s", SDL_GetError());
#ifdef SDL_VIDEO_DRIVER_X11
sdl_xgrab_bug = 1;
#endif
}
-
logoutf("init: net");
if(enet_initialize()<0) fatal("Unable to initialise network module");
atexit(enet_deinitialize);
enet_time_set(0);
-
logoutf("init: game");
game::parseoptions(gameargs);
initserver(dedicated>0, dedicated>1); // never returns if dedicated
ASSERT(dedicated <= 1);
game::initclient();
-
logoutf("init: video");
SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "0");
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
setupscreen();
SDL_ShowCursor(SDL_FALSE);
SDL_StopTextInput(); // workaround for spurious text-input events getting sent on first text input toggle?
-
logoutf("init: gl");
gl_checkextensions();
gl_init();
notexture = textureload("packages/textures/texture_error.png");
if(!notexture) fatal("could not find core textures");
-
logoutf("init: console");
if(!execfile("data/stdlib.cfg", false)) fatal("cannot find data files (you are running from the wrong folder, try .bat file in the main folder)"); // this is the first file we load.
if(!execfile("packages/fonts/default.cfg", false)) fatal("cannot find font definitions");
if(!setfont("default")) fatal("no default font specified");
-
inbetweenframes = true;
renderbackground("initializing...");
-
logoutf("init: world");
camera1 = player = game::iterdynents(0);
emptymap(0, true, NULL, false);
-
logoutf("init: sound");
initsound();
-
logoutf("init: cfg");
initing = INIT_LOAD;
execfile("data/keymap.cfg");
execfile("data/game.cfg");
execfile("data/custom_maps_menu.cfg");
if(game::savedservers()) execfile(game::savedservers(), false);
-
identflags |= IDF_PERSIST;
-
- if(!execfile(game::savedconfig(), false))
- {
+ if(!execfile(game::savedconfig(), false)) {
execfile(game::defaultconfig());
writecfg(game::restoreconfig());
}
execfile(game::autoexec(), false);
-
identflags &= ~IDF_PERSIST;
-
initing = INIT_GAME;
game::loadconfigs();
-
initing = NOT_INITING;
-
logoutf("init: render");
restoregamma();
restorevsync();
loadshaders();
initparticles();
initdecals();
-
identflags |= IDF_PERSIST;
-
logoutf("init: mainloop");
-
if(execfile("once.cfg", false)) remove(findfile("once.cfg", "rb"));
-
- if(load)
- {
+ if(load) {
logoutf("init: localconnect");
//localconnect();
game::changemap(load);
}
-
if(initscript) execute(initscript);
-
resetfpshistory();
-
inputgrab(grabinput = true);
ignoremousemotion();
-
- for(;;)
- {
+ for(;;) {
static int frames = 0;
int millis = getclockmillis();
limitfps(millis, totalmillis);
lastmillis += curtime;
totalmillis = millis;
updatetime();
-
checkinput();
menuprocess();
tryedit();
-
if(lastmillis) game::updateworld();
-
checksleep(lastmillis);
-
serverslice(false, 0);
-
if(frames) updatefpshistory(elapsedtime);
frames++;
-
// miscellaneous general game effects
recomputecamera();
updateparticles();
updatesounds();
-
if(minimized) continue;
-
inbetweenframes = false;
-
glClearColor(0,0,0,1);///TODO
-
if(mainmenu) gl_drawmainmenu();
else gl_drawframe();
swapbuffers();
renderedframe = inbetweenframes = true;
}
-
ASSERT(0);
return EXIT_FAILURE;
}
FILE *logfile = NULL;
-struct userinfo
-{
+struct userinfo {
char *name;
void *pubkey;
};
hashnameset<userinfo> users;
-void adduser(char *name, char *pubkey)
-{
+void adduser(char *name, char *pubkey) {
name = newstring(name);
userinfo &u = users[name];
u.name = name;
}
COMMAND(adduser, "ss");
-void clearusers()
-{
+void clearusers() {
enumerate(users, userinfo, u, { delete[] u.name; freepubkey(u.pubkey); });
users.clear();
}
vector<ipmask> bans, servbans, gbans;
-void clearbans()
-{
+void clearbans() {
bans.shrink(0);
servbans.shrink(0);
gbans.shrink(0);
}
COMMAND(clearbans, "");
-void addban(vector<ipmask> &bans, const char *name)
-{
+void addban(vector<ipmask> &bans, const char *name) {
ipmask ban;
ban.parse(name);
bans.add(ban);
ICOMMAND(servban, "s", (char *name), addban(servbans, name));
ICOMMAND(gban, "s", (char *name), addban(gbans, name));
-bool checkban(vector<ipmask> &bans, enet_uint32 host)
-{
+bool checkban(vector<ipmask> &bans, enet_uint32 host) {
loopv(bans) if(bans[i].check(host)) return true;
return false;
}
-struct authreq
-{
+struct authreq {
enet_uint32 reqtime;
uint id;
void *answer;
};
-struct gameserver
-{
+struct gameserver {
ENetAddress address;
string ip;
int port, numpings;
};
vector<gameserver *> gameservers;
-struct messagebuf
-{
+struct messagebuf {
vector<messagebuf *> &owner;
vector<char> buf;
int refs;
-
messagebuf(vector<messagebuf *> &owner) : owner(owner), refs(0) {}
-
const char *getbuf() { return buf.getbuf(); }
int length() { return buf.length(); }
void purge();
-
- bool equals(const messagebuf &m) const
- {
+ bool equals(const messagebuf &m) const {
return buf.length() == m.buf.length() && !memcmp(buf.getbuf(), m.buf.getbuf(), buf.length());
}
-
- bool endswith(const messagebuf &m) const
- {
+ bool endswith(const messagebuf &m) const {
return buf.length() >= m.buf.length() && !memcmp(&buf[buf.length() - m.buf.length()], m.buf.getbuf(), m.buf.length());
}
-
- void concat(const messagebuf &m)
- {
+ void concat(const messagebuf &m) {
if(buf.length() && buf.last() == '\0') buf.pop();
buf.put(m.buf.getbuf(), m.buf.length());
}
vector<messagebuf *> gameserverlists, gbanlists;
bool updateserverlist = true;
-struct client
-{
+struct client {
ENetAddress address;
ENetSocket socket;
char input[INPUT_LIMIT];
vector<authreq> authreqs;
bool shouldpurge;
bool registeredserver;
-
client() : message(NULL), inputpos(0), outputpos(0), servport(-1), lastauth(0), shouldpurge(false), registeredserver(false) {}
};
vector<client *> clients;
time_t starttime;
enet_uint32 servtime = 0;
-void fatal(const char *fmt, ...)
-{
+void fatal(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(logfile, fmt, args);
exit(EXIT_FAILURE);
}
-void conoutfv(int type, const char *fmt, va_list args)
-{
+void conoutfv(int type, const char *fmt, va_list args) {
vfprintf(logfile, fmt, args);
fputc('\n', logfile);
}
-void purgeclient(int n)
-{
+void purgeclient(int n) {
client &c = *clients[n];
if(c.message) c.message->purge();
enet_socket_destroy(c.socket);
clients.remove(n);
}
-void output(client &c, const char *msg, int len = 0)
-{
+void output(client &c, const char *msg, int len = 0) {
if(!len) len = strlen(msg);
c.output.put(msg, len);
}
-void outputf(client &c, const char *fmt, ...)
-{
+void outputf(client &c, const char *fmt, ...) {
string msg;
va_list args;
va_start(args, fmt);
vformatstring(msg, fmt, args);
va_end(args);
-
output(c, msg);
}
ENetSocket pingsocket = ENET_SOCKET_NULL;
-bool setuppingsocket(ENetAddress *address)
-{
+bool setuppingsocket(ENetAddress *address) {
if(pingsocket != ENET_SOCKET_NULL) return true;
pingsocket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
if(pingsocket == ENET_SOCKET_NULL) return false;
return true;
}
-void setupserver(int port, const char *ip = NULL)
-{
+void setupserver(int port, const char *ip = NULL) {
ENetAddress address;
address.host = ENET_HOST_ANY;
address.port = port;
-
- if(ip)
- {
+ if(ip) {
if(enet_address_set_host(&address, ip)<0)
fatal("failed to resolve server address: %s", ip);
}
fatal("failed to make server socket non-blocking");
if(!setuppingsocket(&address))
fatal("failed to create ping socket");
-
enet_time_set(0);
-
starttime = time(NULL);
char *ct = ctime(&starttime);
if(strchr(ct, '\n')) *strchr(ct, '\n') = '\0';
conoutf("*** Starting master server on %s %d at %s ***", ip ? ip : "localhost", port, ct);
}
-void genserverlist()
-{
+void genserverlist() {
if(!updateserverlist) return;
while(gameserverlists.length() && gameserverlists.last()->refs<=0)
delete gameserverlists.pop();
messagebuf *l = new messagebuf(gameserverlists);
- loopv(gameservers)
- {
+ loopv(gameservers) {
gameserver &s = *gameservers[i];
if(!s.lastpong) continue;
defformatstring(cmd, "addserver %s %d\n", s.ip, s.port);
updateserverlist = false;
}
-void gengbanlist()
-{
+void gengbanlist() {
messagebuf *l = new messagebuf(gbanlists);
const char *header = "cleargbans\n";
l->buf.put(header, strlen(header));
string cmd = "addgban ";
int cmdlen = strlen(cmd);
- loopv(gbans)
- {
+ loopv(gbans) {
ipmask &b = gbans[i];
l->buf.put(cmd, cmdlen + b.print(&cmd[cmdlen]));
l->buf.add('\n');
}
- if(gbanlists.length() && gbanlists.last()->equals(*l))
- {
+ if(gbanlists.length() && gbanlists.last()->equals(*l)) {
delete l;
return;
}
while(gbanlists.length() && gbanlists.last()->refs<=0)
delete gbanlists.pop();
- loopv(gbanlists)
- {
+ loopv(gbanlists) {
messagebuf *m = gbanlists[i];
if(m->refs > 0 && !m->endswith(*l)) m->concat(*l);
}
gbanlists.add(l);
- loopv(clients)
- {
+ loopv(clients) {
client &c = *clients[i];
- if(c.servport >= 0 && !c.message)
- {
+ if(c.servport >= 0 && !c.message) {
c.message = l;
c.message->refs++;
}
}
}
-void addgameserver(client &c)
-{
+void addgameserver(client &c) {
if(gameservers.length() >= SERVER_LIMIT) return;
int dups = 0;
- loopv(gameservers)
- {
+ loopv(gameservers) {
gameserver &s = *gameservers[i];
if(s.address.host != c.address.host) continue;
++dups;
- if(s.port == c.servport)
- {
+ if(s.port == c.servport) {
s.lastping = 0;
s.numpings = 0;
return;
}
}
- if(dups >= SERVER_DUP_LIMIT)
- {
+ if(dups >= SERVER_DUP_LIMIT) {
outputf(c, "failreg too many servers on ip\n");
return;
}
string hostname;
- if(enet_address_get_host_ip(&c.address, hostname, sizeof(hostname)) < 0)
- {
+ if(enet_address_get_host_ip(&c.address, hostname, sizeof(hostname)) < 0) {
outputf(c, "failreg failed resolving ip\n");
return;
}
s.lastping = s.lastpong = 0;
}
-client *findclient(gameserver &s)
-{
- loopv(clients)
- {
+client *findclient(gameserver &s) {
+ loopv(clients) {
client &c = *clients[i];
if(s.address.host == c.address.host && s.port == c.servport)
return &c;
return NULL;
}
-void servermessage(gameserver &s, const char *msg)
-{
+void servermessage(gameserver &s, const char *msg) {
client *c = findclient(s);
if(c) outputf(*c, msg);
}
-void checkserverpongs()
-{
+void checkserverpongs() {
ENetBuffer buf;
ENetAddress addr;
static uchar pong[MAXTRANS];
- for(;;)
- {
+ for(;;) {
buf.data = pong;
buf.dataLength = sizeof(pong);
int len = enet_socket_receive(pingsocket, &addr, &buf, 1);
if(len <= 0) break;
- loopv(gameservers)
- {
+ loopv(gameservers) {
gameserver &s = *gameservers[i];
- if(s.address.host == addr.host && s.address.port == addr.port)
- {
- if(s.lastping && (!s.lastpong || ENET_TIME_GREATER(s.lastping, s.lastpong)))
- {
+ if(s.address.host == addr.host && s.address.port == addr.port) {
+ if(s.lastping && (!s.lastpong || ENET_TIME_GREATER(s.lastping, s.lastpong))) {
client *c = findclient(s);
- if(c)
- {
+ if(c) {
c->registeredserver = true;
outputf(*c, "succreg\n");
- if(!c->message && gbanlists.length())
- {
+ if(!c->message && gbanlists.length()) {
c->message = gbanlists.last();
c->message->refs++;
}
}
}
-void bangameservers()
-{
- loopvrev(gameservers) if(checkban(servbans, gameservers[i]->address.host))
- {
+void bangameservers() {
+ loopvrev(gameservers) if(checkban(servbans, gameservers[i]->address.host)) {
delete gameservers.remove(i);
updateserverlist = true;
}
}
-void checkgameservers()
-{
+void checkgameservers() {
ENetBuffer buf;
- loopv(gameservers)
- {
+ loopv(gameservers) {
gameserver &s = *gameservers[i];
- if(s.lastping && s.lastpong && ENET_TIME_LESS_EQUAL(s.lastping, s.lastpong))
- {
- if(ENET_TIME_DIFFERENCE(servtime, s.lastpong) > KEEPALIVE_TIME)
- {
+ if(s.lastping && s.lastpong && ENET_TIME_LESS_EQUAL(s.lastping, s.lastpong)) {
+ if(ENET_TIME_DIFFERENCE(servtime, s.lastpong) > KEEPALIVE_TIME) {
delete gameservers.remove(i--);
updateserverlist = true;
}
}
- else if(!s.lastping || ENET_TIME_DIFFERENCE(servtime, s.lastping) > PING_TIME)
- {
- if(s.numpings >= PING_RETRY)
- {
+ else if(!s.lastping || ENET_TIME_DIFFERENCE(servtime, s.lastping) > PING_TIME) {
+ if(s.numpings >= PING_RETRY) {
servermessage(s, "failreg failed pinging server\n");
delete gameservers.remove(i--);
updateserverlist = true;
}
- else
- {
+ else {
static const uchar ping[] = { 1 };
buf.data = (void *)ping;
buf.dataLength = sizeof(ping);
}
}
-void messagebuf::purge()
-{
+void messagebuf::purge() {
refs = max(refs - 1, 0);
- if(refs<=0 && owner.last()!=this)
- {
+ if(refs<=0 && owner.last()!=this) {
owner.removeobj(this);
delete this;
}
}
-void purgeauths(client &c)
-{
+void purgeauths(client &c) {
int expired = 0;
- loopv(c.authreqs)
- {
- if(ENET_TIME_DIFFERENCE(servtime, c.authreqs[i].reqtime) >= AUTH_TIME)
- {
+ loopv(c.authreqs) {
+ if(ENET_TIME_DIFFERENCE(servtime, c.authreqs[i].reqtime) >= AUTH_TIME) {
outputf(c, "failauth %u\n", c.authreqs[i].id);
freechallenge(c.authreqs[i].answer);
expired = i + 1;
if(expired > 0) c.authreqs.remove(0, expired);
}
-void reqauth(client &c, uint id, char *name)
-{
+void reqauth(client &c, uint id, char *name) {
if(ENET_TIME_DIFFERENCE(servtime, c.lastauth) < AUTH_THROTTLE)
return;
-
c.lastauth = servtime;
-
purgeauths(c);
-
time_t t = time(NULL);
char *ct = ctime(&t);
- if(ct)
- {
+ if(ct) {
char *newline = strchr(ct, '\n');
if(newline) *newline = '\0';
}
string ip;
if(enet_address_get_host_ip(&c.address, ip, sizeof(ip)) < 0) copystring(ip, "-");
conoutf("%s: attempting \"%s\" as %u from %s", ct ? ct : "-", name, id, ip);
-
userinfo *u = users.access(name);
- if(!u)
- {
+ if(!u) {
outputf(c, "failauth %u\n", id);
return;
}
-
- if(c.authreqs.length() >= AUTH_LIMIT)
- {
+ if(c.authreqs.length() >= AUTH_LIMIT) {
outputf(c, "failauth %u\n", c.authreqs[0].id);
freechallenge(c.authreqs[0].answer);
c.authreqs.remove(0);
}
-
authreq &a = c.authreqs.add();
a.reqtime = servtime;
a.id = id;
static vector<char> buf;
buf.setsize(0);
a.answer = genchallenge(u->pubkey, seed, sizeof(seed), buf);
-
outputf(c, "chalauth %u %s\n", id, buf.getbuf());
}
-void confauth(client &c, uint id, const char *val)
-{
+void confauth(client &c, uint id, const char *val) {
purgeauths(c);
-
- loopv(c.authreqs) if(c.authreqs[i].id == id)
- {
+ loopv(c.authreqs) if(c.authreqs[i].id == id) {
string ip;
if(enet_address_get_host_ip(&c.address, ip, sizeof(ip)) < 0) copystring(ip, "-");
- if(checkchallenge(val, c.authreqs[i].answer))
- {
+ if(checkchallenge(val, c.authreqs[i].answer)) {
outputf(c, "succauth %u\n", id);
conoutf("succeeded %u from %s", id, ip);
}
- else
- {
+ else {
outputf(c, "failauth %u\n", id);
conoutf("failed %u from %s", id, ip);
}
outputf(c, "failauth %u\n", id);
}
-bool checkclientinput(client &c)
-{
+bool checkclientinput(client &c) {
if(c.inputpos<0) return true;
char *end = (char *)memchr(c.input, '\n', c.inputpos);
- while(end)
- {
+ while(end) {
*end++ = '\0';
c.lastinput = servtime;
-
int port;
uint id;
string user, val;
- if(!strncmp(c.input, "list", 4) && (!c.input[4] || c.input[4] == '\n' || c.input[4] == '\r'))
- {
+ if(!strncmp(c.input, "list", 4) && (!c.input[4] || c.input[4] == '\n' || c.input[4] == '\r')) {
genserverlist();
if(gameserverlists.empty() || c.message) return false;
c.message = gameserverlists.last();
c.shouldpurge = true;
return true;
}
- else if(sscanf(c.input, "regserv %d", &port) == 1)
- {
+ else if(sscanf(c.input, "regserv %d", &port) == 1) {
if(checkban(servbans, c.address.host)) return false;
if(port < 0 || port > 0xFFFF-1 || (c.servport >= 0 && port != c.servport)) outputf(c, "failreg invalid port\n");
- else
- {
+ else {
c.servport = port;
addgameserver(c);
}
}
- else if(sscanf(c.input, "reqauth %u %100s", &id, user) == 2)
- {
+ else if(sscanf(c.input, "reqauth %u %100s", &id, user) == 2) {
reqauth(c, id, user);
}
- else if(sscanf(c.input, "confauth %u %100s", &id, val) == 2)
- {
+ else if(sscanf(c.input, "confauth %u %100s", &id, val) == 2) {
confauth(c, id, val);
}
c.inputpos = &c.input[c.inputpos] - end;
memmove(c.input, end, c.inputpos);
-
end = (char *)memchr(c.input, '\n', c.inputpos);
}
return c.inputpos<(int)sizeof(c.input);
ENetSocketSet readset, writeset;
-void checkclients()
-{
+void checkclients() {
ENetSocketSet readset, writeset;
ENetSocket maxsock = max(serversocket, pingsocket);
ENET_SOCKETSET_EMPTY(readset);
ENET_SOCKETSET_EMPTY(writeset);
ENET_SOCKETSET_ADD(readset, serversocket);
ENET_SOCKETSET_ADD(readset, pingsocket);
- loopv(clients)
- {
+ loopv(clients) {
client &c = *clients[i];
if(c.authreqs.length()) purgeauths(c);
if(c.message || c.output.length()) ENET_SOCKETSET_ADD(writeset, c.socket);
maxsock = max(maxsock, c.socket);
}
if(enet_socketset_select(maxsock, &readset, &writeset, 1000)<=0) return;
-
if(ENET_SOCKETSET_CHECK(readset, pingsocket)) checkserverpongs();
- if(ENET_SOCKETSET_CHECK(readset, serversocket))
- {
+ if(ENET_SOCKETSET_CHECK(readset, serversocket)) {
ENetAddress address;
ENetSocket clientsocket = enet_socket_accept(serversocket, &address);
if(clients.length()>=CLIENT_LIMIT || checkban(bans, address.host)) enet_socket_destroy(clientsocket);
- else if(clientsocket!=ENET_SOCKET_NULL)
- {
+ else if(clientsocket!=ENET_SOCKET_NULL) {
int dups = 0, oldest = -1;
- loopv(clients) if(clients[i]->address.host == address.host)
- {
+ loopv(clients) if(clients[i]->address.host == address.host) {
dups++;
if(oldest<0 || clients[i]->connecttime < clients[oldest]->connecttime) oldest = i;
}
if(dups >= DUP_LIMIT) purgeclient(oldest);
-
client *c = new client;
c->address = address;
c->socket = clientsocket;
clients.add(c);
}
}
-
- loopv(clients)
- {
+ loopv(clients) {
client &c = *clients[i];
- if((c.message || c.output.length()) && ENET_SOCKETSET_CHECK(writeset, c.socket))
- {
+ if((c.message || c.output.length()) && ENET_SOCKETSET_CHECK(writeset, c.socket)) {
const char *data = c.output.length() ? c.output.getbuf() : c.message->getbuf();
int len = c.output.length() ? c.output.length() : c.message->length();
ENetBuffer buf;
buf.data = (void *)&data[c.outputpos];
buf.dataLength = len-c.outputpos;
int res = enet_socket_send(c.socket, NULL, &buf, 1);
- if(res>=0)
- {
+ if(res>=0) {
c.outputpos += res;
- if(c.outputpos>=len)
- {
+ if(c.outputpos>=len) {
if(c.output.length()) c.output.setsize(0);
- else
- {
+ else {
c.message->purge();
c.message = NULL;
}
c.outputpos = 0;
- if(!c.message && c.output.empty() && c.shouldpurge)
- {
+ if(!c.message && c.output.empty() && c.shouldpurge) {
purgeclient(i--);
continue;
}
}
else { purgeclient(i--); continue; }
}
- if(ENET_SOCKETSET_CHECK(readset, c.socket))
- {
+ if(ENET_SOCKETSET_CHECK(readset, c.socket)) {
ENetBuffer buf;
buf.data = &c.input[c.inputpos];
buf.dataLength = sizeof(c.input) - c.inputpos;
int res = enet_socket_receive(c.socket, NULL, &buf, 1);
- if(res>0)
- {
+ if(res>0) {
c.inputpos += res;
c.input[min(c.inputpos, (int)sizeof(c.input)-1)] = '\0';
if(!checkclientinput(c)) { purgeclient(i--); continue; }
}
}
-void banclients()
-{
+void banclients() {
loopvrev(clients) if(checkban(bans, clients[i]->address.host)) purgeclient(i);
}
volatile int reloadcfg = 1;
-void reloadsignal(int signum)
-{
+void reloadsignal(int signum) {
reloadcfg = 1;
}
-int main(int argc, char **argv)
-{
+int main(int argc, char **argv) {
if(enet_initialize()<0) fatal("Unable to initialise network module");
atexit(enet_deinitialize);
-
const char *dir = "", *ip = NULL;
int port = 28787;
if(argc>=2) dir = argv[1];
setvbuf(logfile, NULL, _IOLBF, BUFSIZ);
signal(SIGUSR1, reloadsignal);
setupserver(port, ip);
- for(;;)
- {
- if(reloadcfg)
- {
+ for(;;) {
+ if(reloadcfg) {
conoutf("reloading master.cfg");
execfile(cfgname);
bangameservers();
gengbanlist();
reloadcfg = 0;
}
-
servtime = enet_time_get();
checkclients();
checkgameservers();
}
-
return EXIT_SUCCESS;
}
int x, y, size;
uint filled;
QuadNode *child[4];
-
QuadNode(int x, int y, int size) : x(x), y(y), size(size), filled(0) { loopi(4) child[i] = 0; }
-
void clear() { loopi(4) DELETEP(child[i]); }
-
~QuadNode() { clear(); }
-
void insert(int mx, int my, int msize) {
if(size == msize) {
filled = 0xF;
}
if(!child[i]) child[i] = new QuadNode(i&1 ? x+csize : x, i&2 ? y+csize : y, csize);
child[i]->insert(mx, my, msize);
- loopj(4) if(child[j])
- {
+ loopj(4) if(child[j]) {
if(child[j]->filled == 0xF) {
DELETEP(child[j]);
filled |= (1 << j);
}
}
}
-
void genmatsurf(ushort mat, uchar orient, uchar visible, int x, int y, int z, int size, materialsurface *&matbuf) {
materialsurface &m = *matbuf++;
m.material = mat;
m.o[R[dim]] = y;
m.o[dim] = z;
}
-
void genmatsurfs(ushort mat, uchar orient, uchar flags, int z, materialsurface *&matbuf) {
if(filled == 0xF) genmatsurf(mat, orient, flags, x, y, z, size, matbuf);
- else if(filled)
- {
+ else if(filled) {
int csize = size>>1;
loopi(4) if(filled & (1 << i))
genmatsurf(mat, orient, flags, i&1 ? x+csize : x, i&2 ? y+csize : y, z, csize, matbuf);
bvec4(0, 0, 0x7F)
};
-static void drawmaterial(const materialsurface &m, float offset, const bvec4 &color)
-{
- if(gle::attribbuf.empty())
- {
+static void drawmaterial(const materialsurface &m, float offset, const bvec4 &color) {
+ if(gle::attribbuf.empty()) {
gle::defvertex();
gle::defcolor(4, GL_UNSIGNED_BYTE);
gle::begin(GL_QUADS);
}
float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize, rsize = m.rsize;
- switch(m.orient)
- {
+ switch(m.orient) {
#define GENFACEORIENT(orient, v0, v1, v2, v3) \
case orient: v0 v1 v2 v3 break;
- #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \
- { \
+ #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) { \
+ \
gle::attribf(mx sx, my sy, mz sz); \
gle::attrib(color); \
}
}
}
-const struct material
-{
+const struct material {
const char *name;
ushort id;
-} materials[] =
-{
- {"air", MAT_AIR},
- {"clip", MAT_CLIP},
- {"noclip", MAT_NOCLIP},
- {"gameclip", MAT_GAMECLIP},
- {"death", MAT_DEATH},
- {"alpha", MAT_ALPHA}
+} materials[] = {
+ {
+ "air", MAT_AIR}, {
+ "clip", MAT_CLIP}, {
+ "noclip", MAT_NOCLIP}, {
+ "gameclip", MAT_GAMECLIP}, {
+ "death", MAT_DEATH}, {
+ "alpha", MAT_ALPHA}
};
-int findmaterial(const char *name)
-{
- loopi(sizeof(materials)/sizeof(material))
- {
+int findmaterial(const char *name) {
+ loopi(sizeof(materials)/sizeof(material)) {
if(!strcmp(materials[i].name, name)) return materials[i].id;
}
return -1;
}
-const char *findmaterialname(int mat)
-{
+const char *findmaterialname(int mat) {
loopi(sizeof(materials)/sizeof(materials[0])) if(materials[i].id == mat) return materials[i].name;
return NULL;
}
-const char *getmaterialdesc(int mat, const char *prefix)
-{
+const char *getmaterialdesc(int mat, const char *prefix) {
static const ushort matmasks[] = { MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_ALPHA };
static string desc;
desc[0] = '\0';
- loopi(sizeof(matmasks)/sizeof(matmasks[0])) if(mat&matmasks[i])
- {
+ loopi(sizeof(matmasks)/sizeof(matmasks[0])) if(mat&matmasks[i]) {
const char *matname = findmaterialname(mat&matmasks[i]);
- if(matname)
- {
+ if(matname) {
concatstring(desc, desc[0] ? ", " : prefix);
concatstring(desc, matname);
}
return desc;
}
-int visiblematerial(const cube &c, int orient, const ivec &co, int size, ushort matmask)
-{
+int visiblematerial(const cube &c, int orient, const ivec &co, int size, ushort matmask) {
ushort mat = c.material&matmask;
- switch(mat)
- {
+ switch(mat) {
case MAT_AIR:
break;
-
default:
if(visibleface(c, orient, co, size, mat, MAT_AIR, matmask))
return MATSURF_EDIT_ONLY;
return MATSURF_NOT_VISIBLE;
}
-void genmatsurfs(const cube &c, const ivec &co, int size, vector<materialsurface> &matsurfs)
-{
- loopi(6)
- {
+void genmatsurfs(const cube &c, const ivec &co, int size, vector<materialsurface> &matsurfs) {
+ loopi(6) {
static const ushort matmasks[] = { MATF_INDEX, MATF_CLIP, MAT_DEATH, MAT_ALPHA };
- loopj(sizeof(matmasks)/sizeof(matmasks[0]))
- {
+ loopj(sizeof(matmasks)/sizeof(matmasks[0])) {
int matmask = matmasks[j];
int vis = visiblematerial(c, i, co, size, matmask&~MATF_INDEX);
- if(vis != MATSURF_NOT_VISIBLE)
- {
+ if(vis != MATSURF_NOT_VISIBLE) {
materialsurface m;
m.material = c.material&matmask;
m.orient = i;
}
}
-static inline bool mergematcmp(const materialsurface &x, const materialsurface &y)
-{
+static inline bool mergematcmp(const materialsurface &x, const materialsurface &y) {
int dim = dimension(x.orient), c = C[dim], r = R[dim];
if(x.o[r] + x.rsize < y.o[r] + y.rsize) return true;
if(x.o[r] + x.rsize > y.o[r] + y.rsize) return false;
return x.o[c] < y.o[c];
}
-static int mergematr(materialsurface *m, int sz, materialsurface &n)
-{
+static int mergematr(materialsurface *m, int sz, materialsurface &n) {
int dim = dimension(n.orient), c = C[dim], r = R[dim];
- for(int i = sz-1; i >= 0; --i)
- {
+ for(int i = sz-1; i >= 0; --i) {
if(m[i].o[r] + m[i].rsize < n.o[r]) break;
- if(m[i].o[r] + m[i].rsize == n.o[r] && m[i].o[c] == n.o[c] && m[i].csize == n.csize)
- {
+ if(m[i].o[r] + m[i].rsize == n.o[r] && m[i].o[c] == n.o[c] && m[i].csize == n.csize) {
n.o[r] = m[i].o[r];
n.rsize += m[i].rsize;
memmove(&m[i], &m[i+1], (sz - (i+1)) * sizeof(materialsurface));
return 0;
}
-static int mergematc(materialsurface &m, materialsurface &n)
-{
+static int mergematc(materialsurface &m, materialsurface &n) {
int dim = dimension(n.orient), c = C[dim], r = R[dim];
- if(m.o[r] == n.o[r] && m.rsize == n.rsize && m.o[c] + m.csize == n.o[c])
- {
+ if(m.o[r] == n.o[r] && m.rsize == n.rsize && m.o[c] + m.csize == n.o[c]) {
n.o[c] = m.o[c];
n.csize += m.csize;
return 1;
return 0;
}
-static int mergemat(materialsurface *m, int sz, materialsurface &n)
-{
- for(bool merged = false; sz; merged = true)
- {
+static int mergemat(materialsurface *m, int sz, materialsurface &n) {
+ for(bool merged = false; sz; merged = true) {
int rmerged = mergematr(m, sz, n);
sz -= rmerged;
if(!rmerged && merged) break;
return sz;
}
-static int mergemats(materialsurface *m, int sz)
-{
+static int mergemats(materialsurface *m, int sz) {
quicksort(m, sz, mergematcmp);
-
int nsz = 0;
loopi(sz) nsz = mergemat(m, nsz, m[i]);
return nsz;
}
-static inline bool optmatcmp(const materialsurface &x, const materialsurface &y)
-{
+static inline bool optmatcmp(const materialsurface &x, const materialsurface &y) {
if(x.material < y.material) return true;
if(x.material > y.material) return false;
if(x.orient > y.orient) return true;
VARF(optmats, 0, 1, 1, allchanged());
-int optimizematsurfs(materialsurface *matbuf, int matsurfs)
-{
+int optimizematsurfs(materialsurface *matbuf, int matsurfs) {
quicksort(matbuf, matsurfs, optmatcmp);
if(!optmats) return matsurfs;
materialsurface *cur = matbuf, *end = matbuf+matsurfs;
- while(cur < end)
- {
+ while(cur < end) {
materialsurface *start = cur++;
int dim = dimension(start->orient);
while(cur < end &&
return matsurfs - (end-matbuf);
}
-void setupmaterials(int start, int len)
-{
+void setupmaterials(int start, int len) {
int hasmat = 0;
unionfind uf;
if(!len) len = valist.length();
- for(int i = start; i < len; i++)
- {
+ for(int i = start; i < len; i++) {
vtxarray *va = valist[i];
materialsurface *skip = NULL;
- loopj(va->matsurfs)
- {
+ loopj(va->matsurfs) {
materialsurface &m = va->matbuf[j];
int matvol = 0;
if(matvol) hasmat |= 1<<m.material;
static ivec sortorigin;
static bool sortedit;
-static inline bool vismatcmp(const materialsurface *xm, const materialsurface *ym)
-{
+static inline bool vismatcmp(const materialsurface *xm, const materialsurface *ym) {
const materialsurface &x = *xm, &y = *ym;
int xdim = dimension(x.orient), ydim = dimension(y.orient);
- loopi(3)
- {
+ loopi(3) {
int dim = sortdim[i], xmin, xmax, ymin, ymax;
xmin = xmax = x.o[dim];
if(dim==C[xdim]) xmax += x.csize;
return false;
}
-void sortmaterials(vector<materialsurface *> &vismats)
-{
+void sortmaterials(vector<materialsurface *> &vismats) {
sortorigin = ivec(camera1->o);
vec dir;
vecfromyawpitch(camera1->yaw, camera1->pitch, 1, 0, dir);
if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]);
if(dir[sortdim[1]] > dir[sortdim[0]]) swap(sortdim[1], sortdim[0]);
if(dir[sortdim[2]] > dir[sortdim[1]]) swap(sortdim[2], sortdim[1]);
-
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->matsurfs || va->occluded >= OCCLUDE_BB) continue;
- loopi(va->matsurfs)
- {
+ loopi(va->matsurfs) {
materialsurface &m = va->matbuf[i];
- if(!editmode || !showmat || drawtex)
- {
+ if(!editmode || !showmat || drawtex) {
if(m.visible == MATSURF_EDIT_ONLY) { i += m.skip; continue; }
}
vismats.add(&m);
vismats.sort(vismatcmp);
}
-void rendermatgrid(vector<materialsurface *> &vismats)
-{
+void rendermatgrid(vector<materialsurface *> &vismats) {
enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
int lastmat = -1;
bvec4 color(0, 0, 0, 0);
- loopvrev(vismats)
- {
+ loopvrev(vismats) {
materialsurface &m = *vismats[i];
- if(m.material != lastmat)
- {
- switch(m.material&~MATF_INDEX)
- {
+ if(m.material != lastmat) {
+ switch(m.material&~MATF_INDEX) {
case MAT_CLIP: color = bvec4(85, 0, 0, 255); break; // red
case MAT_NOCLIP: color = bvec4( 0, 85, 0, 255); break; // green
case MAT_GAMECLIP: color = bvec4(85, 85, 0, 255); break; // yellow
disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
}
-void rendermaterials()
-{
+void rendermaterials() {
vector<materialsurface *> vismats;
sortmaterials(vismats);
if(vismats.empty()) return;
-
glDisable(GL_CULL_FACE);
-
int lastorient = -1, lastmat = -1;
bool depth = true, blended = false;
-
GLOBALPARAM(camera, camera1->o);
-
- if(editmode && showmat && !drawtex)
- {
+ if(editmode && showmat && !drawtex) {
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
glEnable(GL_BLEND); blended = true;
bvec4 color(0, 0, 0, 0);
- loopv(vismats)
- {
+ loopv(vismats) {
const materialsurface &m = *vismats[i];
- if(lastmat!=m.material)
- {
- switch(m.material&~MATF_INDEX)
- {
+ if(lastmat!=m.material) {
+ switch(m.material&~MATF_INDEX) {
case MAT_CLIP: color = bvec4( 0, 255, 255, 255); break; // red
case MAT_NOCLIP: color = bvec4(255, 0, 255, 255); break; // green
case MAT_GAMECLIP: color = bvec4( 0, 0, 255, 255); break; // yellow
}
xtraverts += gle::end();
}
-
if(lastorient >= 0)
if(lastmat&~MATF_INDEX)
xtraverts += gle::end();
-
if(!depth) glDepthMask(GL_TRUE);
if(blended) glDisable(GL_BLEND);
extern int wireframe;
if(editmode && showmat && !drawtex && !wireframe)
rendermatgrid(vismats);
-
glEnable(GL_CULL_FACE);
}
+++ /dev/null
-struct md3;
-
-struct md3frame
-{
- vec bbmin, bbmax, origin;
- float radius;
- uchar name[16];
-};
-
-struct md3tag
-{
- char name[64];
- float translation[3];
- float rotation[3][3];
-};
-
-struct md3vertex
-{
- short vertex[3];
- short normal;
-};
-
-struct md3triangle
-{
- int vertexindices[3];
-};
-
-struct md3header
-{
- char id[4];
- int version;
- char name[64];
- int flags;
- int numframes, numtags, nummeshes, numskins;
- int ofs_frames, ofs_tags, ofs_meshes, ofs_eof; // offsets
-};
-
-struct md3meshheader
-{
- char id[4];
- char name[64];
- int flags;
- int numframes, numshaders, numvertices, numtriangles;
- int ofs_triangles, ofs_shaders, ofs_uv, ofs_vertices, meshsize; // offsets
-};
-
-struct md3 : vertloader<md3>
-{
- md3(const char *name) : vertloader(name) {}
-
- static const char *formatname() { return "md3"; }
- bool flipy() const { return true; }
- int type() const { return MDL_MD3; }
-
- struct md3meshgroup : vertmeshgroup
- {
- bool load(const char *path)
- {
- stream *f = openfile(path, "rb");
- if(!f) return false;
- md3header header;
- f->read(&header, sizeof(md3header));
- lilswap(&header.version, 1);
- lilswap(&header.flags, 9);
- if(strncmp(header.id, "IDP3", 4) != 0 || header.version != 15) // header check
- {
- delete f;
- conoutf(CON_ERROR, "md3: corrupted header");
- return false;
- }
-
- name = newstring(path);
-
- numframes = header.numframes;
-
- int mesh_offset = header.ofs_meshes;
- loopi(header.nummeshes)
- {
- vertmesh &m = *new vertmesh;
- m.group = this;
- meshes.add(&m);
-
- md3meshheader mheader;
- f->seek(mesh_offset, SEEK_SET);
- f->read(&mheader, sizeof(md3meshheader));
- lilswap(&mheader.flags, 10);
-
- m.name = newstring(mheader.name);
-
- m.numtris = mheader.numtriangles;
- m.tris = new tri[m.numtris];
- f->seek(mesh_offset + mheader.ofs_triangles, SEEK_SET);
- loopj(m.numtris)
- {
- md3triangle tri = { 0 };
- f->read(&tri, sizeof(md3triangle)); // read the triangles
- lilswap(tri.vertexindices, 3);
- loopk(3) m.tris[j].vert[k] = (ushort)tri.vertexindices[k];
- }
-
- m.numverts = mheader.numvertices;
- m.tcverts = new tcvert[m.numverts];
- f->seek(mesh_offset + mheader.ofs_uv , SEEK_SET);
- f->read(m.tcverts, m.numverts*2*sizeof(float)); // read the UV data
- lilswap(&m.tcverts[0].tc.x, 2*m.numverts);
-
- m.verts = new vert[numframes*m.numverts];
- f->seek(mesh_offset + mheader.ofs_vertices, SEEK_SET);
- loopj(numframes*m.numverts)
- {
- md3vertex v = { {0}, 0 };
- f->read(&v, sizeof(md3vertex)); // read the vertices
- lilswap(v.vertex, 4);
-
- m.verts[j].pos = vec(v.vertex[0]/64.0f, -v.vertex[1]/64.0f, v.vertex[2]/64.0f);
-
- float lng = (v.normal&0xFF)*2*M_PI/255.0f; // decode vertex normals
- float lat = ((v.normal>>8)&0xFF)*2*M_PI/255.0f;
- m.verts[j].norm = vec(cosf(lat)*sinf(lng), -sinf(lat)*sinf(lng), cosf(lng));
- }
-
- mesh_offset += mheader.meshsize;
- }
-
- numtags = header.numtags;
- if(numtags)
- {
- tags = new tag[numframes*numtags];
- f->seek(header.ofs_tags, SEEK_SET);
- md3tag tag;
-
- loopi(header.numframes*header.numtags)
- {
- f->read(&tag, sizeof(md3tag));
- lilswap(tag.translation, 12);
- if(tag.name[0] && i<header.numtags) tags[i].name = newstring(tag.name);
- matrix4x3 &m = tags[i].transform;
- tag.translation[1] *= -1;
- // undo the -y
- loopj(3) tag.rotation[1][j] *= -1;
- // then restore it
- loopj(3) tag.rotation[j][1] *= -1;
- m.a = vec(tag.rotation[0]);
- m.b = vec(tag.rotation[1]);
- m.c = vec(tag.rotation[2]);
- m.d = vec(tag.translation);
- }
- }
-
- delete f;
- return true;
- }
- };
-
- meshgroup *loadmeshes(const char *name, va_list args)
- {
- md3meshgroup *group = new md3meshgroup;
- if(!group->load(name)) { delete group; return NULL; }
- return group;
- }
-
- bool loaddefaultparts()
- {
- const char *pname = parentdir(name);
- part &mdl = addpart();
- defformatstring(name1, "packages/models/%s/tris.md3", name);
- mdl.meshes = sharemeshes(path(name1));
- if(!mdl.meshes)
- {
- defformatstring(name2, "packages/models/%s/tris.md3", pname); // try md3 in parent folder (vert sharing)
- mdl.meshes = sharemeshes(path(name2));
- if(!mdl.meshes) return false;
- }
- Texture *tex, *masks;
- loadskin(name, pname, tex, masks);
- mdl.initskins(tex, masks);
- if(tex==notexture) conoutf(CON_ERROR, "could not load model skin for %s", name1);
- return true;
- }
-};
-
-vertcommands<md3> md3commands;
-
struct md5;
-struct md5joint
-{
+struct md5joint {
vec pos;
quat orient;
};
-struct md5weight
-{
+struct md5weight {
int joint;
float bias;
vec pos;
};
-struct md5vert
-{
+struct md5vert {
vec2 tc;
ushort start, count;
};
-struct md5hierarchy
-{
+struct md5hierarchy {
string name;
int parent, flags, start;
};
-struct md5 : skelloader<md5>
-{
+struct md5 : skelloader<md5> {
md5(const char *name) : skelloader(name) {}
-
static const char *formatname() { return "md5"; }
int type() const { return MDL_MD5; }
-
- struct md5mesh : skelmesh
- {
+ struct md5mesh : skelmesh {
md5weight *weightinfo;
int numweights;
md5vert *vertinfo;
-
- md5mesh() : weightinfo(NULL), numweights(0), vertinfo(NULL)
- {
+ md5mesh() : weightinfo(NULL), numweights(0), vertinfo(NULL) {
}
-
- ~md5mesh()
- {
+ ~md5mesh() {
cleanup();
}
-
- void cleanup()
- {
+ void cleanup() {
DELETEA(weightinfo);
DELETEA(vertinfo);
}
-
- void buildverts(vector<md5joint> &joints)
- {
- loopi(numverts)
- {
+ void buildverts(vector<md5joint> &joints) {
+ loopi(numverts) {
md5vert &v = vertinfo[i];
vec pos(0, 0, 0);
- loopk(v.count)
- {
+ loopk(v.count) {
md5weight &w = weightinfo[v.start+k];
md5joint &j = joints[w.joint];
vec wpos = j.orient.rotate(w.pos);
vert &vv = verts[i];
vv.pos = pos;
vv.tc = v.tc;
-
blendcombo c;
int sorted = 0;
- loopj(v.count)
- {
+ loopj(v.count) {
md5weight &w = weightinfo[v.start+j];
sorted = c.addweight(sorted, w.bias, w.joint);
}
vv.blend = addblendcombo(c);
}
}
-
- void load(stream *f, char *buf, size_t bufsize)
- {
+ void load(stream *f, char *buf, size_t bufsize) {
md5weight w;
md5vert v;
tri t;
int index;
-
- while(f->getline(buf, bufsize) && buf[0]!='}')
- {
- if(strstr(buf, "// meshes:"))
- {
+ while(f->getline(buf, bufsize) && buf[0]!='}') {
+ if(strstr(buf, "// meshes:")) {
char *start = strchr(buf, ':')+1;
if(*start==' ') start++;
char *end = start + strlen(start)-1;
while(end >= start && isspace(*end)) end--;
name = newstring(start, end+1-start);
}
- else if(strstr(buf, "shader"))
- {
+ else if(strstr(buf, "shader")) {
char *start = strchr(buf, '"'), *end = start ? strchr(start+1, '"') : NULL;
- if(start && end)
- {
+ if(start && end) {
char *texname = newstring(start+1, end-(start+1));
part *p = loading->parts.last();
p->initskins(notexture, notexture, group->meshes.length());
delete[] texname;
}
}
- else if(sscanf(buf, " numverts %d", &numverts)==1)
- {
+ else if(sscanf(buf, " numverts %d", &numverts)==1) {
numverts = max(numverts, 0);
- if(numverts)
- {
+ if(numverts) {
vertinfo = new md5vert[numverts];
verts = new vert[numverts];
}
}
- else if(sscanf(buf, " numtris %d", &numtris)==1)
- {
+ else if(sscanf(buf, " numtris %d", &numtris)==1) {
numtris = max(numtris, 0);
if(numtris) tris = new tri[numtris];
}
- else if(sscanf(buf, " numweights %d", &numweights)==1)
- {
+ else if(sscanf(buf, " numweights %d", &numweights)==1) {
numweights = max(numweights, 0);
if(numweights) weightinfo = new md5weight[numweights];
}
- else if(sscanf(buf, " vert %d ( %f %f ) %hu %hu", &index, &v.tc.x, &v.tc.y, &v.start, &v.count)==5)
- {
+ else if(sscanf(buf, " vert %d ( %f %f ) %hu %hu", &index, &v.tc.x, &v.tc.y, &v.start, &v.count)==5) {
if(index>=0 && index<numverts) vertinfo[index] = v;
}
- else if(sscanf(buf, " tri %d %hu %hu %hu", &index, &t.vert[0], &t.vert[1], &t.vert[2])==4)
- {
+ else if(sscanf(buf, " tri %d %hu %hu %hu", &index, &t.vert[0], &t.vert[1], &t.vert[2])==4) {
if(index>=0 && index<numtris) tris[index] = t;
}
- else if(sscanf(buf, " weight %d %d %f ( %f %f %f ) ", &index, &w.joint, &w.bias, &w.pos.x, &w.pos.y, &w.pos.z)==6)
- {
+ else if(sscanf(buf, " weight %d %d %f ( %f %f %f ) ", &index, &w.joint, &w.bias, &w.pos.x, &w.pos.y, &w.pos.z)==6) {
w.pos.y = -w.pos.y;
if(index>=0 && index<numweights) weightinfo[index] = w;
}
}
}
};
-
- struct md5meshgroup : skelmeshgroup
- {
- md5meshgroup()
- {
+ struct md5meshgroup : skelmeshgroup {
+ md5meshgroup() {
}
-
- bool loadmesh(const char *filename, float smooth)
- {
+ bool loadmesh(const char *filename, float smooth) {
stream *f = openfile(filename, "r");
if(!f) return false;
-
char buf[512];
vector<md5joint> basejoints;
- while(f->getline(buf, sizeof(buf)))
- {
+ while(f->getline(buf, sizeof(buf))) {
int tmp;
- if(sscanf(buf, " MD5Version %d", &tmp)==1)
- {
+ if(sscanf(buf, " MD5Version %d", &tmp)==1) {
if(tmp!=10) { delete f; return false; }
}
- else if(sscanf(buf, " numJoints %d", &tmp)==1)
- {
+ else if(sscanf(buf, " numJoints %d", &tmp)==1) {
if(tmp<1) { delete f; return false; }
if(skel->numbones>0) continue;
skel->numbones = tmp;
skel->bones = new boneinfo[skel->numbones];
}
- else if(sscanf(buf, " numMeshes %d", &tmp)==1)
- {
+ else if(sscanf(buf, " numMeshes %d", &tmp)==1) {
if(tmp<1) { delete f; return false; }
}
- else if(strstr(buf, "joints {"))
- {
+ else if(strstr(buf, "joints {")) {
string name;
int parent;
md5joint j;
- while(f->getline(buf, sizeof(buf)) && buf[0]!='}')
- {
+ while(f->getline(buf, sizeof(buf)) && buf[0]!='}') {
char *curbuf = buf, *curname = name;
bool allowspace = false;
while(*curbuf && isspace(*curbuf)) curbuf++;
if(*curbuf == '"') { curbuf++; allowspace = true; }
- while(*curbuf && curname < &name[sizeof(name)-1])
- {
+ while(*curbuf && curname < &name[sizeof(name)-1]) {
char c = *curbuf++;
if(c == '"') break;
if(isspace(c) && !allowspace) break;
*curname = '\0';
if(sscanf(curbuf, " %d ( %f %f %f ) ( %f %f %f )",
&parent, &j.pos.x, &j.pos.y, &j.pos.z,
- &j.orient.x, &j.orient.y, &j.orient.z)==7)
- {
+ &j.orient.x, &j.orient.y, &j.orient.z)==7) {
j.pos.y = -j.pos.y;
j.orient.x = -j.orient.x;
j.orient.z = -j.orient.z;
}
if(basejoints.length()!=skel->numbones) { delete f; return false; }
}
- else if(strstr(buf, "mesh {"))
- {
+ else if(strstr(buf, "mesh {")) {
md5mesh *m = new md5mesh;
m->group = this;
meshes.add(m);
m->load(f, buf, sizeof(buf));
- if(!m->numtris || !m->numverts)
- {
+ if(!m->numtris || !m->numverts) {
conoutf(CON_WARN, "empty mesh in %s", filename);
meshes.removeobj(m);
delete m;
}
}
}
-
- if(skel->shared <= 1)
- {
+ if(skel->shared <= 1) {
skel->linkchildren();
- loopv(basejoints)
- {
+ loopv(basejoints) {
boneinfo &b = skel->bones[i];
b.base = dualquat(basejoints[i].orient, basejoints[i].pos);
(b.invbase = b.base).invert();
}
}
-
- loopv(meshes)
- {
+ loopv(meshes) {
md5mesh &m = *(md5mesh *)meshes[i];
m.buildverts(basejoints);
if(smooth <= 1) m.smoothnorms(smooth);
else m.buildnorms();
m.cleanup();
}
-
sortblendcombos();
-
delete f;
return true;
}
-
- skelanimspec *loadanim(const char *filename)
- {
+ skelanimspec *loadanim(const char *filename) {
skelanimspec *sa = skel->findskelanim(filename);
if(sa) return sa;
-
stream *f = openfile(filename, "r");
if(!f) return NULL;
-
vector<md5hierarchy> hierarchy;
vector<md5joint> basejoints;
int animdatalen = 0, animframes = 0;
float *animdata = NULL;
dualquat *animbones = NULL;
char buf[512];
- while(f->getline(buf, sizeof(buf)))
- {
+ while(f->getline(buf, sizeof(buf))) {
int tmp;
- if(sscanf(buf, " MD5Version %d", &tmp)==1)
- {
+ if(sscanf(buf, " MD5Version %d", &tmp)==1) {
if(tmp!=10) { delete f; return NULL; }
}
- else if(sscanf(buf, " numJoints %d", &tmp)==1)
- {
+ else if(sscanf(buf, " numJoints %d", &tmp)==1) {
if(tmp!=skel->numbones) { delete f; return NULL; }
}
- else if(sscanf(buf, " numFrames %d", &animframes)==1)
- {
+ else if(sscanf(buf, " numFrames %d", &animframes)==1) {
if(animframes<1) { delete f; return NULL; }
}
else if(sscanf(buf, " frameRate %d", &tmp)==1);
- else if(sscanf(buf, " numAnimatedComponents %d", &animdatalen)==1)
- {
+ else if(sscanf(buf, " numAnimatedComponents %d", &animdatalen)==1) {
if(animdatalen>0) animdata = new float[animdatalen];
}
- else if(strstr(buf, "bounds {"))
- {
+ else if(strstr(buf, "bounds {")) {
while(f->getline(buf, sizeof(buf)) && buf[0]!='}');
}
- else if(strstr(buf, "hierarchy {"))
- {
- while(f->getline(buf, sizeof(buf)) && buf[0]!='}')
- {
+ else if(strstr(buf, "hierarchy {")) {
+ while(f->getline(buf, sizeof(buf)) && buf[0]!='}') {
md5hierarchy h;
if(sscanf(buf, " %100s %d %d %d", h.name, &h.parent, &h.flags, &h.start)==4)
hierarchy.add(h);
}
}
- else if(strstr(buf, "baseframe {"))
- {
- while(f->getline(buf, sizeof(buf)) && buf[0]!='}')
- {
+ else if(strstr(buf, "baseframe {")) {
+ while(f->getline(buf, sizeof(buf)) && buf[0]!='}') {
md5joint j;
- if(sscanf(buf, " ( %f %f %f ) ( %f %f %f )", &j.pos.x, &j.pos.y, &j.pos.z, &j.orient.x, &j.orient.y, &j.orient.z)==6)
- {
+ if(sscanf(buf, " ( %f %f %f ) ( %f %f %f )", &j.pos.x, &j.pos.y, &j.pos.z, &j.orient.x, &j.orient.y, &j.orient.z)==6) {
j.pos.y = -j.pos.y;
j.orient.x = -j.orient.x;
j.orient.z = -j.orient.z;
}
if(basejoints.length()!=skel->numbones) { delete f; if(animdata) delete[] animdata; return NULL; }
animbones = new dualquat[(skel->numframes+animframes)*skel->numbones];
- if(skel->framebones)
- {
+ if(skel->framebones) {
memcpy(animbones, skel->framebones, skel->numframes*skel->numbones*sizeof(dualquat));
delete[] skel->framebones;
}
skel->framebones = animbones;
animbones += skel->numframes*skel->numbones;
-
sa = &skel->addskelanim(filename);
sa->frame = skel->numframes;
sa->range = animframes;
-
skel->numframes += animframes;
}
- else if(sscanf(buf, " frame %d", &tmp)==1)
- {
- for(int numdata = 0; f->getline(buf, sizeof(buf)) && buf[0]!='}';)
- {
- for(char *src = buf, *next = src; numdata < animdatalen; numdata++, src = next)
- {
+ else if(sscanf(buf, " frame %d", &tmp)==1) {
+ for(int numdata = 0; f->getline(buf, sizeof(buf)) && buf[0]!='}';) {
+ for(char *src = buf, *next = src; numdata < animdatalen; numdata++, src = next) {
animdata[numdata] = strtod(src, &next);
if(next <= src) break;
}
}
dualquat *frame = &animbones[tmp*skel->numbones];
- loopv(basejoints)
- {
+ loopv(basejoints) {
md5hierarchy &h = hierarchy[i];
md5joint j = basejoints[i];
- if(h.start < animdatalen && h.flags)
- {
+ if(h.start < animdatalen && h.flags) {
float *jdata = &animdata[h.start];
if(h.flags&1) j.pos.x = *jdata++;
if(h.flags&2) j.pos.y = -*jdata++;
}
}
}
-
if(animdata) delete[] animdata;
delete f;
-
return sa;
}
-
- bool load(const char *meshfile, float smooth)
- {
+ bool load(const char *meshfile, float smooth) {
name = newstring(meshfile);
-
if(!loadmesh(meshfile, smooth)) return false;
-
return true;
}
};
-
- meshgroup *loadmeshes(const char *name, va_list args)
- {
+ meshgroup *loadmeshes(const char *name, va_list args) {
md5meshgroup *group = new md5meshgroup;
group->shareskeleton(va_arg(args, char *));
if(!group->load(name, va_arg(args, double))) { delete group; return NULL; }
return group;
}
-
- bool loaddefaultparts()
- {
+ bool loaddefaultparts() {
skelpart &mdl = addpart();
mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
adjustments.setsize(0);
VAR(guitabnum, 1, 0, 0);
-struct menu : g3d_callback
-{
+struct menu : g3d_callback {
char *name, *header;
uint *contents, *init, *onclear;
bool showtab, keeptab;
int menutab;
-
menu() : name(NULL), header(NULL), contents(NULL), init(NULL), onclear(NULL), showtab(true), keeptab(false), menutab(1) {}
-
- void gui(g3d_gui &g, bool firstpass)
- {
+ void gui(g3d_gui &g, bool firstpass) {
cgui = &g;
guitabnum = menutab;
cgui->start(menustart, 0.03f, showtab ? &menutab : NULL);
cgui = NULL;
guitabnum = 0;
}
-
- virtual void clear()
- {
+ virtual void clear() {
if(onclear) { freecode(onclear); onclear = NULL; }
}
};
-struct delayedupdate
-{
- enum
- {
+struct delayedupdate {
+ enum {
INT,
FLOAT,
STRING,
ACTION
} type;
ident *id;
- union
- {
+ union {
int i;
float f;
char *s;
} val;
delayedupdate() : type(ACTION), id(NULL) { val.s = NULL; }
~delayedupdate() { if(type == STRING || type == ACTION) DELETEA(val.s); }
-
void schedule(const char *s) { type = ACTION; val.s = newstring(s); }
void schedule(ident *var, int i) { type = INT; id = var; val.i = i; }
void schedule(ident *var, float f) { type = FLOAT; id = var; val.f = f; }
void schedule(ident *var, char *s) { type = STRING; id = var; val.s = newstring(s); }
-
- int getint() const
- {
- switch(type)
- {
+ int getint() const {
+ switch(type) {
case INT: return val.i;
case FLOAT: return int(val.f);
case STRING: return int(strtol(val.s, NULL, 0));
default: return 0;
}
}
-
- float getfloat() const
- {
- switch(type)
- {
+ float getfloat() const {
+ switch(type) {
case INT: return float(val.i);
case FLOAT: return val.f;
case STRING: return float(parsefloat(val.s));
default: return 0;
}
}
-
- const char *getstring() const
- {
- switch(type)
- {
+ const char *getstring() const {
+ switch(type) {
case INT: return intstr(val.i);
case FLOAT: return intstr(int(floor(val.f)));
case STRING: return val.s;
default: return "";
}
}
-
- void run()
- {
+ void run() {
if(type == ACTION) { if(val.s) execute(val.s); }
- else if(id) switch(id->type)
- {
+ else if(id) switch(id->type) {
case ID_VAR: setvarchecked(id, getint()); break;
case ID_FVAR: setfvarchecked(id, getfloat()); break;
case ID_SVAR: setsvarchecked(id, getstring()); break;
VARP(menudistance, 16, 40, 256);
VARP(menuautoclose, 32, 120, 4096);
-vec menuinfrontofplayer()
-{
+vec menuinfrontofplayer() {
vec dir;
vecfromyawpitch(camera1->yaw, 0, 1, 0, dir);
dir.mul(menudistance).add(camera1->o);
return dir;
}
-void popgui()
-{
+void popgui() {
menu *m = guistack.pop();
m->clear();
}
-void removegui(menu *m)
-{
- loopv(guistack) if(guistack[i]==m)
- {
+void removegui(menu *m) {
+ loopv(guistack) if(guistack[i]==m) {
guistack.remove(i);
m->clear();
return;
}
}
-void pushgui(menu *m, int pos = -1)
-{
- if(guistack.empty())
- {
+void pushgui(menu *m, int pos = -1) {
+ if(guistack.empty()) {
menupos = menuinfrontofplayer();
g3d_resetcursor();
}
if(pos < 0) guistack.add(m);
else guistack.insert(pos, m);
- if(pos < 0 || pos==guistack.length()-1)
- {
+ if(pos < 0 || pos==guistack.length()-1) {
if(!m->keeptab) m->menutab = 1;
menustart = totalmillis;
}
if(m->init) execute(m->init);
}
-void restoregui(int pos)
-{
+void restoregui(int pos) {
int clear = guistack.length()-pos-1;
loopi(clear) popgui();
menustart = totalmillis;
}
-void showgui(const char *name)
-{
+void showgui(const char *name) {
menu *m = guis.access(name);
if(!m) return;
int pos = guistack.find(m);
else restoregui(pos);
}
-void hidegui(const char *name)
-{
+void hidegui(const char *name) {
menu *m = guis.access(name);
if(m) removegui(m);
}
-int cleargui(int n)
-{
+int cleargui(int n) {
int clear = guistack.length();
- if(mainmenu && !isconnected(true) && clear > 0 && guistack[0]->name && !strcmp(guistack[0]->name, "main"))
- {
+ if(mainmenu && !isconnected(true) && clear > 0 && guistack[0]->name && !strcmp(guistack[0]->name, "main")) {
clear--;
if(!clear) return 1;
}
return clear;
}
-void clearguis(int level = -1)
-{
+void clearguis(int level = -1) {
if(level < 0) level = guistack.length();
- loopvrev(guistack)
- {
+ loopvrev(guistack) {
menu *m = guistack[i];
if(m->onclear)
- {
+ {
uint *action = m->onclear;
m->onclear = NULL;
execute(action);
cleargui(level);
}
-void guionclear(char *action)
-{
+void guionclear(char *action) {
if(guistack.empty()) return;
menu *m = guistack.last();
if(m->onclear) { freecode(m->onclear); m->onclear = NULL; }
if(action[0]) m->onclear = compilecode(action);
}
-void guistayopen(uint *contents)
-{
+void guistayopen(uint *contents) {
bool oldclearmenu = shouldclearmenu;
shouldclearmenu = false;
execute(contents);
shouldclearmenu = oldclearmenu;
}
-void guinoautotab(uint *contents)
-{
+void guinoautotab(uint *contents) {
if(!cgui) return;
bool oldval = cgui->allowautotab(false);
execute(contents);
cgui->allowautotab(oldval);
}
-void guimerge(uint *contents)
-{
+void guimerge(uint *contents) {
if(!cgui) return;
bool oldval = cgui->mergehits(true);
execute(contents);
}
//@DOC name and icon are optional
-void guibutton(char *name, char *action, char *icon)
-{
+void guibutton(char *name, char *action, char *icon) {
if(!cgui) return;
bool hideicon = !strcmp(icon, "0");
int ret = cgui->button(name, GUI_BUTTON_COLOR, hideicon ? NULL : (icon[0] ? icon : (strstr(action, "showgui") ? "menu" : "action")));
- if(ret&G3D_UP)
- {
+ if(ret&G3D_UP) {
updatelater.add().schedule(action[0] ? action : name);
if(shouldclearmenu) clearlater = true;
}
- else if(ret&G3D_ROLLOVER)
- {
+ else if(ret&G3D_ROLLOVER) {
alias("guirollovername", name);
alias("guirolloveraction", action);
}
}
-void guiimage(char *path, char *action, float *scale, int *overlaid, char *alt, char *title)
-{
+void guiimage(char *path, char *action, float *scale, int *overlaid, char *alt, char *title) {
if(!cgui) return;
Texture *t = textureload(path, 0, true, false);
- if(t==notexture)
- {
+ if(t==notexture) {
if(alt[0]) t = textureload(alt, 0, true, false);
if(t==notexture) return;
}
int ret = cgui->image(t, *scale, *overlaid!=0 ? title : NULL);
- if(ret&G3D_UP)
- {
- if(*action)
- {
+ if(ret&G3D_UP) {
+ if(*action) {
updatelater.add().schedule(action);
if(shouldclearmenu) clearlater = true;
}
}
- else if(ret&G3D_ROLLOVER)
- {
+ else if(ret&G3D_ROLLOVER) {
alias("guirolloverimgpath", path);
alias("guirolloverimgaction", action);
}
}
-void guicolor(int *color)
-{
- if(cgui)
- {
+void guicolor(int *color) {
+ if(cgui) {
defformatstring(desc, "0x%06X", *color);
cgui->text(desc, *color, NULL);
}
}
-void guitextbox(char *text, int *width, int *height, int *color)
-{
+void guitextbox(char *text, int *width, int *height, int *color) {
if(cgui && text[0]) cgui->textbox(text, *width ? *width : 12, *height ? *height : 1, *color ? *color : 0xFFFFFF);
}
-void guitext(char *name, char *icon)
-{
+void guitext(char *name, char *icon) {
bool hideicon = !strcmp(icon, "0");
if(cgui) cgui->text(name, !hideicon && icon[0] ? GUI_BUTTON_COLOR : GUI_TEXT_COLOR, hideicon ? NULL : (icon[0] ? icon : "info"));
}
-void guititle(char *name)
-{
+void guititle(char *name) {
if(cgui) cgui->title(name, GUI_TITLE_COLOR);
}
-void guitab(char *name)
-{
+void guitab(char *name) {
if(cgui) cgui->tab(name, GUI_TITLE_COLOR);
}
-void guibar()
-{
+void guibar() {
if(cgui) cgui->separator();
}
-void guistrut(float *strut, int *alt)
-{
- if(cgui)
- {
+void guistrut(float *strut, int *alt) {
+ if(cgui) {
if(*alt) cgui->strut(*strut); else cgui->space(*strut);
}
}
-void guispring(int *weight)
-{
+void guispring(int *weight) {
if(cgui) cgui->spring(max(*weight, 1));
}
-void guicolumn(int *col)
-{
+void guicolumn(int *col) {
if(cgui) cgui->column(*col);
}
-template<class T> static void updateval(char *var, T val, char *onchange)
-{
+template<class T> static void updateval(char *var, T val, char *onchange) {
ident *id = writeident(var);
updatelater.add().schedule(id, val);
if(onchange[0]) updatelater.add().schedule(onchange);
}
-static int getval(char *var)
-{
+static int getval(char *var) {
ident *id = readident(var);
if(!id) return 0;
- switch(id->type)
- {
+ switch(id->type) {
case ID_VAR: return *id->storage.i;
case ID_FVAR: return int(*id->storage.f);
case ID_SVAR: return parseint(*id->storage.s);
}
}
-static float getfval(char *var)
-{
+static float getfval(char *var) {
ident *id = readident(var);
if(!id) return 0;
- switch(id->type)
- {
+ switch(id->type) {
case ID_VAR: return *id->storage.i;
case ID_FVAR: return *id->storage.f;
case ID_SVAR: return parsefloat(*id->storage.s);
}
}
-static const char *getsval(char *var)
-{
+static const char *getsval(char *var) {
ident *id = readident(var);
if(!id) return "";
- switch(id->type)
- {
+ switch(id->type) {
case ID_VAR: return intstr(*id->storage.i);
case ID_FVAR: return floatstr(*id->storage.f);
case ID_SVAR: return *id->storage.s;
}
}
-void guislider(char *var, int *min, int *max, char *onchange)
-{
+void guislider(char *var, int *min, int *max, char *onchange) {
if(!cgui) return;
int oldval = getval(var), val = oldval, vmin = *max > INT_MIN ? *min : getvarmin(var), vmax = *max > INT_MIN ? *max : getvarmax(var);
cgui->slider(val, vmin, vmax, GUI_TITLE_COLOR);
if(val != oldval) updateval(var, val, onchange);
}
-void guilistslider(char *var, char *list, char *onchange)
-{
+void guilistslider(char *var, char *list, char *onchange) {
if(!cgui) return;
vector<int> vals;
list += strspn(list, "\n\t ");
- while(*list)
- {
+ while(*list) {
vals.add(parseint(list));
list += strcspn(list, "\n\t \0");
list += strspn(list, "\n\t ");
if(offset != oldoffset) updateval(var, vals[offset], onchange);
}
-void guinameslider(char *var, char *names, char *list, char *onchange)
-{
+void guinameslider(char *var, char *names, char *list, char *onchange) {
if(!cgui) return;
vector<int> vals;
list += strspn(list, "\n\t ");
- while(*list)
- {
+ while(*list) {
vals.add(parseint(list));
list += strcspn(list, "\n\t \0");
list += strspn(list, "\n\t ");
delete[] label;
}
-void guicheckbox(char *name, char *var, float *on, float *off, char *onchange)
-{
+void guicheckbox(char *name, char *var, float *on, float *off, char *onchange) {
bool enabled = getfval(var)!=*off;
- if(cgui && cgui->button(name, GUI_BUTTON_COLOR, enabled ? "checkbox_on" : "checkbox_off")&G3D_UP)
- {
+ if(cgui && cgui->button(name, GUI_BUTTON_COLOR, enabled ? "checkbox_on" : "checkbox_off")&G3D_UP) {
updateval(var, enabled ? *off : (*on || *off ? *on : 1.0f), onchange);
}
}
-void guiradio(char *name, char *var, float *n, char *onchange)
-{
+void guiradio(char *name, char *var, float *n, char *onchange) {
bool enabled = getfval(var)==*n;
- if(cgui && cgui->button(name, GUI_BUTTON_COLOR, enabled ? "radio_on" : "radio_off")&G3D_UP)
- {
+ if(cgui && cgui->button(name, GUI_BUTTON_COLOR, enabled ? "radio_on" : "radio_off")&G3D_UP) {
if(!enabled) updateval(var, *n, onchange);
}
}
-void guibitfield(char *name, char *var, int *mask, char *onchange)
-{
+void guibitfield(char *name, char *var, int *mask, char *onchange) {
int val = getval(var);
bool enabled = (val & *mask) != 0;
- if(cgui && cgui->button(name, GUI_BUTTON_COLOR, enabled ? "checkbox_on" : "checkbox_off")&G3D_UP)
- {
+ if(cgui && cgui->button(name, GUI_BUTTON_COLOR, enabled ? "checkbox_on" : "checkbox_off")&G3D_UP) {
updateval(var, enabled ? val & ~*mask : val | *mask, onchange);
}
}
//-ve length indicates a wrapped text field of any (approx 260 chars) length, |length| is the field width
-void guifield(char *var, int *maxlength, char *onchange)
-{
+void guifield(char *var, int *maxlength, char *onchange) {
if(!cgui) return;
const char *initval = getsval(var);
char *result = cgui->field(var, GUI_BUTTON_COLOR, *maxlength ? *maxlength : 12, 0, initval);
}
//-ve maxlength indicates a wrapped text field of any (approx 260 chars) length, |maxlength| is the field width
-void guieditor(char *name, int *maxlength, int *height, int *mode)
-{
+void guieditor(char *name, int *maxlength, int *height, int *mode) {
if(!cgui) return;
cgui->field(name, GUI_BUTTON_COLOR, *maxlength ? *maxlength : 12, *height, NULL, *mode<=0 ? EDITORFOREVER : *mode);
//returns a non-NULL pointer (the currentline) when the user commits, could then manipulate via text* commands
}
//-ve length indicates a wrapped text field of any (approx 260 chars) length, |length| is the field width
-void guikeyfield(char *var, int *maxlength, char *onchange)
-{
+void guikeyfield(char *var, int *maxlength, char *onchange) {
if(!cgui) return;
const char *initval = getsval(var);
char *result = cgui->keyfield(var, GUI_BUTTON_COLOR, *maxlength ? *maxlength : -8, 0, initval);
//use text<action> to do more...
-void guilist(uint *contents)
-{
+void guilist(uint *contents) {
if(!cgui) return;
cgui->pushlist();
execute(contents);
cgui->poplist();
}
-void guialign(int *align, uint *contents)
-{
+void guialign(int *align, uint *contents) {
if(!cgui) return;
cgui->pushlist();
if(*align >= 0) cgui->spring();
cgui->poplist();
}
-void newgui(char *name, char *contents, char *header, char *init)
-{
+void newgui(char *name, char *contents, char *header, char *init) {
menu *m = guis.access(name);
- if(!m)
- {
+ if(!m) {
name = newstring(name);
m = &guis[name];
m->name = name;
}
- else
- {
+ else {
DELETEA(m->header);
freecode(m->contents);
freecode(m->init);
}
- if(header && header[0])
- {
+ if(header && header[0]) {
char *end = NULL;
int val = strtol(header, &end, 0);
- if(end && !*end)
- {
+ if(end && !*end) {
m->header = NULL;
m->showtab = val != 0;
}
- else
- {
+ else {
m->header = newstring(header);
m->showtab = true;
}
}
- else
- {
+ else {
m->header = NULL;
m->showtab = true;
}
menu *guiserversmenu = NULL;
-void guiservers(uint *header, int *pagemin, int *pagemax)
-{
+void guiservers(uint *header, int *pagemin, int *pagemax) {
extern const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax);
- if(cgui)
- {
+ if(cgui) {
const char *command = showservers(cgui, header, *pagemin, *pagemax > 0 ? *pagemax : INT_MAX);
- if(command)
- {
+ if(command) {
updatelater.add().schedule(command);
if(shouldclearmenu) clearlater = true;
guiserversmenu = clearlater || guistack.empty() ? NULL : guistack.last();
}
}
-void notifywelcome()
-{
- if(guiserversmenu)
- {
+void notifywelcome() {
+ if(guiserversmenu) {
if(guistack.length() && guistack.last() == guiserversmenu) clearguis();
guiserversmenu = NULL;
}
COMMAND(guicolor, "i");
COMMAND(guitextbox, "siii");
-void guiplayerpreview(int *model, int *team, int *weap, char *action, float *scale, int *overlaid, char *title)
-{
+void guiplayerpreview(int *model, int *team, int *weap, char *action, float *scale, int *overlaid, char *title) {
if(!cgui) return;
int ret = cgui->playerpreview(*model, *team, *weap, *scale, *overlaid!=0 ? title : NULL);
- if(ret&G3D_UP)
- {
- if(*action)
- {
+ if(ret&G3D_UP) {
+ if(*action) {
updatelater.add().schedule(action);
if(shouldclearmenu) clearlater = true;
}
}
COMMAND(guiplayerpreview, "iiisfis");
-void guimodelpreview(char *model, char *animspec, char *action, float *scale, int *overlaid, char *title, int *throttle)
-{
+void guimodelpreview(char *model, char *animspec, char *action, float *scale, int *overlaid, char *title, int *throttle) {
if(!cgui) return;
int anim = ANIM_ALL;
- if(animspec[0])
- {
- if(isdigit(animspec[0]))
- {
+ if(animspec[0]) {
+ if(isdigit(animspec[0])) {
anim = parseint(animspec);
if(anim >= 0) anim %= ANIM_INDEX;
else anim = ANIM_ALL;
}
- else
- {
+ else {
vector<int> anims;
findanims(animspec, anims);
if(anims.length()) anim = anims[0];
}
}
int ret = cgui->modelpreview(model, anim|ANIM_LOOP, *scale, *overlaid!=0 ? title : NULL, *throttle!=0);
- if(ret&G3D_UP)
- {
- if(*action)
- {
+ if(ret&G3D_UP) {
+ if(*action) {
updatelater.add().schedule(action);
if(shouldclearmenu) clearlater = true;
}
}
- else if(ret&G3D_ROLLOVER)
- {
+ else if(ret&G3D_ROLLOVER) {
alias("guirolloverpreviewname", model);
alias("guirolloverpreviewaction", action);
}
}
COMMAND(guimodelpreview, "sssfisi");
-void guiprefabpreview(char *prefab, int *color, char *action, float *scale, int *overlaid, char *title, int *throttle)
-{
+void guiprefabpreview(char *prefab, int *color, char *action, float *scale, int *overlaid, char *title, int *throttle) {
if(!cgui) return;
int ret = cgui->prefabpreview(prefab, vec::hexcolor(*color), *scale, *overlaid!=0 ? title : NULL, *throttle!=0);
- if(ret&G3D_UP)
- {
- if(*action)
- {
+ if(ret&G3D_UP) {
+ if(*action) {
updatelater.add().schedule(action);
if(shouldclearmenu) clearlater = true;
}
}
- else if(ret&G3D_ROLLOVER)
- {
+ else if(ret&G3D_ROLLOVER) {
alias("guirolloverpreviewname", prefab);
alias("guirolloverpreviewaction", action);
}
}
COMMAND(guiprefabpreview, "sisfisi");
-struct change
-{
+struct change {
int type;
const char *desc;
-
change() {}
change(int type, const char *desc) : type(type), desc(desc) {}
};
static vector<change> needsapply;
-static struct applymenu : menu
-{
- void gui(g3d_gui &g, bool firstpass)
- {
+static struct applymenu : menu {
+ void gui(g3d_gui &g, bool firstpass) {
if(guistack.empty()) return;
g.start(menustart, 0.03f);
g.text("the following settings have changed:", GUI_TEXT_COLOR, "info");
loopv(needsapply) g.text(needsapply[i].desc, GUI_TEXT_COLOR, "info");
g.separator();
g.text("apply changes now?", GUI_TEXT_COLOR, "info");
- if(g.button("yes", GUI_BUTTON_COLOR, "action")&G3D_UP)
- {
+ if(g.button("yes", GUI_BUTTON_COLOR, "action")&G3D_UP) {
int changetypes = 0;
loopv(needsapply) changetypes |= needsapply[i].type;
if(changetypes&CHANGE_GFX) updatelater.add().schedule("resetgl");
clearlater = true;
g.end();
}
-
- void clear()
- {
+ void clear() {
menu::clear();
needsapply.shrink(0);
}
static bool processingmenu = false;
-void addchange(const char *desc, int type)
-{
+void addchange(const char *desc, int type) {
if(!applydialog) return;
loopv(needsapply) if(!strcmp(needsapply[i].desc, desc)) return;
needsapply.add(change(type, desc));
pushgui(&applymenu, processingmenu ? max(guistack.length()-1, 0) : -1);
}
-void clearchanges(int type)
-{
- loopv(needsapply)
- {
- if(needsapply[i].type&type)
- {
+void clearchanges(int type) {
+ loopv(needsapply) {
+ if(needsapply[i].type&type) {
needsapply[i].type &= ~type;
if(!needsapply[i].type) needsapply.remove(i--);
}
if(needsapply.empty()) removegui(&applymenu);
}
-void menuprocess()
-{
+void menuprocess() {
processingmenu = true;
int wasmain = mainmenu, level = guistack.length();
loopv(updatelater) updatelater[i].run();
updatelater.shrink(0);
- if(wasmain > mainmenu || clearlater)
- {
+ if(wasmain > mainmenu || clearlater) {
if(wasmain > mainmenu || level==guistack.length()) clearguis(level);
clearlater = false;
}
VAR(mainmenu, 1, 1, 0);
-void clearmainmenu()
-{
- if(mainmenu && isconnected())
- {
+void clearmainmenu() {
+ if(mainmenu && isconnected()) {
mainmenu = 0;
if(!processingmenu) cleargui();
}
}
-void g3d_mainmenu()
-{
- if(!guistack.empty())
- {
+void g3d_mainmenu() {
+ if(!guistack.empty()) {
extern int usegui2d;
if(!mainmenu && !usegui2d && camera1->o.dist(menupos) > menuautoclose) cleargui();
else g3d_addgui(guistack.last(), menupos, GUI_2D | GUI_FOLLOW);
-enum { MDL_MD3, MDL_MD5, MDL_IQM, NUMMODELTYPES };
+enum { MDL_MD5, MDL_IQM, NUMMODELTYPES };
-struct model
-{
+struct model {
char *name;
float spinyaw, spinpitch, offsetyaw, offsetpitch;
bool collide, ellipsecollide, shadow, alphadepth, depthoffset;
vec bbcenter, bbradius, bbextend, collidecenter, collideradius;
float rejectradius, eyeheight, collidexyradius, collideheight;
int batch;
-
model(const char *name) : name(name ? newstring(name) : NULL), spinyaw(0), spinpitch(0), offsetyaw(0), offsetpitch(0), collide(true), ellipsecollide(false), shadow(true), alphadepth(true), depthoffset(false), scale(1.0f), translate(0, 0, 0), bih(0), bbcenter(0, 0, 0), bbradius(-1, -1, -1), bbextend(0, 0, 0), collidecenter(0, 0, 0), collideradius(-1, -1, -1), rejectradius(-1), eyeheight(0.9f), collidexyradius(0), collideheight(0), batch(-1) {}
virtual ~model() { DELETEA(name); DELETEP(bih); }
virtual void calcbb(vec ¢er, vec &radius) = 0;
virtual int type() const = 0;
virtual BIH *setBIH() { return 0; }
virtual bool skeletal() const { return false; }
-
- virtual void setshader(Shader *shader) {}
- virtual void setspec(float spec) {}
- virtual void setambient(float ambient) {}
- virtual void setalphatest(float alpha) {}
- virtual void setalphablend(bool blend) {}
- virtual void setfullbright(float fullbright) {}
- virtual void setcullface(bool cullface) {}
-
+ virtual void setshader(Shader *) {}
+ virtual void setspec(float) {}
+ virtual void setambient(float) {}
+ virtual void setalphatest(float) {}
+ virtual void setalphablend(bool) {}
+ virtual void setfullbright(float) {}
+ virtual void setcullface(bool) {}
virtual void preloadBIH() { if(!bih) setBIH(); }
- virtual void preloadshaders(bool force = false) {}
+ virtual void preloadshaders() {}
virtual void preloadmeshes() {}
virtual void cleanup() {}
-
virtual void startrender() {}
virtual void endrender() {}
-
- void boundbox(vec ¢er, vec &radius)
- {
- if(bbradius.x < 0)
- {
+ void boundbox(vec ¢er, vec &radius) {
+ if(bbradius.x < 0) {
calcbb(bbcenter, bbradius);
bbradius.add(bbextend);
}
center = bbcenter;
radius = bbradius;
}
-
- float collisionbox(vec ¢er, vec &radius)
- {
- if(collideradius.x < 0)
- {
+ float collisionbox(vec ¢er, vec &radius) {
+ if(collideradius.x < 0) {
boundbox(collidecenter, collideradius);
- if(collidexyradius)
- {
+ if(collidexyradius) {
collidecenter.x = collidecenter.y = 0;
collideradius.x = collideradius.y = collidexyradius;
}
- if(collideheight)
- {
+ if(collideheight) {
collidecenter.z = collideradius.z = collideheight/2;
}
rejectradius = vec(collidecenter).abs().add(collideradius).magnitude();
radius = collideradius;
return rejectradius;
}
-
- float boundsphere(vec ¢er)
- {
+ float boundsphere(vec ¢er) {
vec radius;
boundbox(center, radius);
return radius.magnitude();
}
-
- float above()
- {
+ float above() {
vec center, radius;
boundbox(center, radius);
return center.z+radius.z;
// This code is based off the Minkowski Portal Refinement algorithm by Gary Snethen in XenoCollide & Game Programming Gems 7.
-namespace mpr
-{
- struct CubePlanes
- {
+namespace mpr {
+ struct CubePlanes {
const clipplanes &p;
-
CubePlanes(const clipplanes &p) : p(p) {}
-
vec center() const { return p.o; }
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
int besti = 7;
float bestd = n.dot(p.v[7]);
- loopi(7)
- {
+ loopi(7) {
float d = n.dot(p.v[i]);
if(d > bestd) { besti = i; bestd = d; }
}
return p.v[besti];
}
};
-
- struct SolidCube
- {
+ struct SolidCube {
vec o;
int size;
-
SolidCube(float x, float y, float z, int size) : o(x, y, z), size(size) {}
SolidCube(const vec &o, int size) : o(o), size(size) {}
SolidCube(const ivec &o, int size) : o(o), size(size) {}
-
vec center() const { return vec(o).add(size/2); }
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
vec p(o);
if(n.x > 0) p.x += size;
if(n.y > 0) p.y += size;
return p;
}
};
-
- struct Ent
- {
+ struct Ent {
physent *ent;
-
Ent(physent *ent) : ent(ent) {}
-
vec center() const { return vec(ent->o.x, ent->o.y, ent->o.z + (ent->aboveeye - ent->eyeheight)/2); }
};
-
- struct EntOBB : Ent
- {
+ struct EntOBB : Ent {
matrix3 orient;
float zmargin;
-
- EntOBB(physent *ent, float zmargin = 0) : Ent(ent), zmargin(zmargin)
- {
+ EntOBB(physent *ent, float zmargin = 0) : Ent(ent), zmargin(zmargin) {
orient.setyaw(ent->yaw*RAD);
}
-
vec center() const { return vec(ent->o.x, ent->o.y, ent->o.z + (ent->aboveeye - ent->eyeheight - zmargin)/2); }
-
- vec contactface(const vec &wn, const vec &wdir) const
- {
+ vec contactface(const vec &wn, const vec &wdir) const {
vec n = orient.transform(wn).div(vec(ent->xradius, ent->yradius, (ent->aboveeye + ent->eyeheight + zmargin)/2)),
dir = orient.transform(wdir),
an(fabs(n.x), fabs(n.y), dir.z ? fabs(n.z) : 0),
fn(0, 0, 0);
- if(an.x > an.y)
- {
+ if(an.x > an.y) {
if(an.x > an.z) fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
else if(an.z > 0) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
}
else if(an.z > 0) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
return orient.transposedtransform(fn);
}
-
- vec localsupportpoint(const vec &ln) const
- {
+ vec localsupportpoint(const vec &ln) const {
return vec(ln.x > 0 ? ent->xradius : -ent->xradius,
ln.y > 0 ? ent->yradius : -ent->yradius,
ln.z > 0 ? ent->aboveeye : -ent->eyeheight - zmargin);
}
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
return orient.transposedtransform(localsupportpoint(orient.transform(n))).add(ent->o);
}
-
- float supportcoordneg(float a, float b, float c) const
- {
+ float supportcoordneg(float a, float b, float c) const {
return localsupportpoint(vec(-a, -b, -c)).dot(vec(a, b, c));
}
- float supportcoord(float a, float b, float c) const
- {
+ float supportcoord(float a, float b, float c) const {
return localsupportpoint(vec(a, b, c)).dot(vec(a, b, c));
}
-
float left() const { return supportcoordneg(orient.a.x, orient.b.x, orient.c.x) + ent->o.x; }
float right() const { return supportcoord(orient.a.x, orient.b.x, orient.c.x) + ent->o.x; }
float back() const { return supportcoordneg(orient.a.y, orient.b.y, orient.c.y) + ent->o.y; }
float bottom() const { return ent->o.z - ent->eyeheight - zmargin; }
float top() const { return ent->o.z + ent->aboveeye; }
};
-
- struct EntFuzzy : Ent
- {
+ struct EntFuzzy : Ent {
EntFuzzy(physent *ent) : Ent(ent) {}
-
float left() const { return ent->o.x - ent->radius; }
float right() const { return ent->o.x + ent->radius; }
float back() const { return ent->o.y - ent->radius; }
float bottom() const { return ent->o.z - ent->eyeheight; }
float top() const { return ent->o.z + ent->aboveeye; }
};
-
- struct EntCylinder : EntFuzzy
- {
+ struct EntCylinder : EntFuzzy {
float zmargin;
-
EntCylinder(physent *ent, float zmargin = 0) : EntFuzzy(ent), zmargin(zmargin) {}
-
vec center() const { return vec(ent->o.x, ent->o.y, ent->o.z + (ent->aboveeye - ent->eyeheight - zmargin)/2); }
-
float bottom() const { return ent->o.z - ent->eyeheight - zmargin; }
-
- vec contactface(const vec &n, const vec &dir) const
- {
+ vec contactface(const vec &n, const vec &dir) const {
float dxy = n.dot2(n)/(ent->radius*ent->radius), dz = n.z*n.z*4/(ent->aboveeye + ent->eyeheight + zmargin);
vec fn(0, 0, 0);
if(dz > dxy && dir.z) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
- else if(n.dot2(dir) < 0)
- {
+ else if(n.dot2(dir) < 0) {
fn.x = n.x;
fn.y = n.y;
fn.normalize();
}
return fn;
}
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
vec p(ent->o);
if(n.z > 0) p.z += ent->aboveeye;
else p.z -= ent->eyeheight + zmargin;
- if(n.x || n.y)
- {
+ if(n.x || n.y) {
float r = ent->radius / n.magnitude2();
p.x += n.x*r;
p.y += n.y*r;
return p;
}
};
-
- struct EntCapsule : EntFuzzy
- {
+ struct EntCapsule : EntFuzzy {
EntCapsule(physent *ent) : EntFuzzy(ent) {}
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
vec p(ent->o);
if(n.z > 0) p.z += ent->aboveeye - ent->radius;
else p.z -= ent->eyeheight - ent->radius;
return p;
}
};
-
- struct EntEllipsoid : EntFuzzy
- {
+ struct EntEllipsoid : EntFuzzy {
EntEllipsoid(physent *ent) : EntFuzzy(ent) {}
-
- vec supportpoint(const vec &dir) const
- {
+ vec supportpoint(const vec &dir) const {
vec p(ent->o), n = vec(dir).normalize();
p.x += ent->radius*n.x;
p.y += ent->radius*n.y;
return p;
}
};
-
- struct Model
- {
+ struct Model {
vec o, radius;
matrix3 orient;
-
- Model(const vec &ent, const vec ¢er, const vec &radius, int yaw) : o(ent), radius(radius)
- {
+ Model(const vec &ent, const vec ¢er, const vec &radius, int yaw) : o(ent), radius(radius) {
orient.setyaw(yaw*RAD);
o.add(orient.transposedtransform(center));
}
-
vec center() const { return o; }
};
-
- struct ModelOBB : Model
- {
+ struct ModelOBB : Model {
ModelOBB(const vec &ent, const vec ¢er, const vec &radius, int yaw) :
- Model(ent, center, radius, yaw)
- {}
-
- vec contactface(const vec &wn, const vec &wdir) const
- {
+ Model(ent, center, radius, yaw) {
+ }
+ vec contactface(const vec &wn, const vec &wdir) const {
vec n = orient.transform(wn).div(radius), dir = orient.transform(wdir),
an(fabs(n.x), fabs(n.y), dir.z ? fabs(n.z) : 0),
fn(0, 0, 0);
- if(an.x > an.y)
- {
+ if(an.x > an.y) {
if(an.x > an.z) fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
else if(an.z > 0) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
}
else if(an.z > 0) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
return orient.transposedtransform(fn);
}
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
vec ln = orient.transform(n), p(0, 0, 0);
if(ln.x > 0) p.x += radius.x;
else p.x -= radius.x;
return orient.transposedtransform(p).add(o);
}
};
-
- struct ModelEllipse : Model
- {
+ struct ModelEllipse : Model {
ModelEllipse(const vec &ent, const vec ¢er, const vec &radius, int yaw) :
- Model(ent, center, radius, yaw)
- {}
-
- vec contactface(const vec &wn, const vec &wdir) const
- {
+ Model(ent, center, radius, yaw) {
+ }
+ vec contactface(const vec &wn, const vec &wdir) const {
vec n = orient.transform(wn).div(radius), dir = orient.transform(wdir);
float dxy = n.dot2(n), dz = n.z*n.z;
vec fn(0, 0, 0);
if(dz > dxy && dir.z) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
- else if(n.dot2(dir) < 0)
- {
+ else if(n.dot2(dir) < 0) {
fn.x = n.x*radius.y;
fn.y = n.y*radius.x;
fn.normalize();
}
return orient.transposedtransform(fn);
}
-
- vec supportpoint(const vec &n) const
- {
+ vec supportpoint(const vec &n) const {
vec ln = orient.transform(n), p(0, 0, 0);
if(ln.z > 0) p.z += radius.z;
else p.z -= radius.z;
- if(ln.x || ln.y)
- {
+ if(ln.x || ln.y) {
float r = ln.magnitude2();
p.x += ln.x*radius.x/r;
p.y += ln.y*radius.y/r;
return orient.transposedtransform(p).add(o);
}
};
-
const float boundarytolerance = 1e-3f;
-
template<class T, class U>
- bool collide(const T &p1, const U &p2)
- {
+ bool collide(const T &p1, const U &p2) {
// v0 = center of Minkowski difference
vec v0 = p2.center().sub(p1.center());
if(v0.iszero()) return true; // v0 and origin overlap ==> hit
-
// v1 = support in direction of origin
vec n = vec(v0).neg();
vec v1 = p2.supportpoint(n).sub(p1.supportpoint(vec(n).neg()));
if(v1.dot(n) <= 0) return false; // origin outside v1 support plane ==> miss
-
// v2 = support perpendicular to plane containing origin, v0 and v1
n.cross(v1, v0);
if(n.iszero()) return true; // v0, v1 and origin colinear (and origin inside v1 support plane) == > hit
vec v2 = p2.supportpoint(n).sub(p1.supportpoint(vec(n).neg()));
if(v2.dot(n) <= 0) return false; // origin outside v2 support plane ==> miss
-
// v3 = support perpendicular to plane containing v0, v1 and v2
n.cross(v0, v1, v2);
-
// If the origin is on the - side of the plane, reverse the direction of the plane
- if(n.dot(v0) > 0)
- {
+ if(n.dot(v0) > 0) {
swap(v1, v2);
n.neg();
}
-
///
// Phase One: Find a valid portal
-
- loopi(100)
- {
+ loopi(100) {
// Obtain the next support point
vec v3 = p2.supportpoint(n).sub(p1.supportpoint(vec(n).neg()));
if(v3.dot(n) <= 0) return false; // origin outside v3 support plane ==> miss
-
// If origin is outside (v1,v0,v3), then portal is invalid -- eliminate v2 and find new support outside face
vec v3xv0;
v3xv0.cross(v3, v0);
- if(v1.dot(v3xv0) < 0)
- {
+ if(v1.dot(v3xv0) < 0) {
v2 = v3;
n.cross(v0, v1, v3);
continue;
}
-
// If origin is outside (v3,v0,v2), then portal is invalid -- eliminate v1 and find new support outside face
- if(v2.dot(v3xv0) > 0)
- {
+ if(v2.dot(v3xv0) > 0) {
v1 = v3;
n.cross(v0, v3, v2);
continue;
}
-
///
// Phase Two: Refine the portal
-
- for(int j = 0;; j++)
- {
+ for(int j = 0;; j++) {
// Compute outward facing normal of the portal
n.cross(v1, v2, v3);
-
// If the origin is inside the portal, we have a hit
if(n.dot(v1) >= 0) return true;
-
n.normalize();
-
// Find the support point in the direction of the portal's normal
vec v4 = p2.supportpoint(n).sub(p1.supportpoint(vec(n).neg()));
-
// If the origin is outside the support plane or the boundary is thin enough, we have a miss
if(v4.dot(n) <= 0 || vec(v4).sub(v3).dot(n) <= boundarytolerance || j > 100) return false;
-
// Test origin against the three planes that separate the new portal candidates: (v1,v4,v0) (v2,v4,v0) (v3,v4,v0)
// Note: We're taking advantage of the triple product identities here as an optimization
// (v1 % v4) * v0 == v1 * (v4 % v0) > 0 if origin inside (v1, v4, v0)
// (v3 % v4) * v0 == v3 * (v4 % v0) > 0 if origin inside (v3, v4, v0)
vec v4xv0;
v4xv0.cross(v4, v0);
- if(v1.dot(v4xv0) > 0)
- {
+ if(v1.dot(v4xv0) > 0) {
if(v2.dot(v4xv0) > 0) v1 = v4; // Inside v1 & inside v2 ==> eliminate v1
else v3 = v4; // Inside v1 & outside v2 ==> eliminate v3
}
- else
- {
+ else {
if(v3.dot(v4xv0) > 0) v2 = v4; // Outside v1 & inside v3 ==> eliminate v2
else v1 = v4; // Outside v1 & outside v3 ==> eliminate v1
}
}
return false;
}
-
template<class T, class U>
- bool collide(const T &p1, const U &p2, vec *contactnormal, vec *contactpoint1, vec *contactpoint2)
- {
+ bool collide(const T &p1, const U &p2, vec *contactnormal, vec *contactpoint1, vec *contactpoint2) {
// v0 = center of Minkowski sum
vec v01 = p1.center();
vec v02 = p2.center();
vec v0 = vec(v02).sub(v01);
-
// Avoid case where centers overlap -- any direction is fine in this case
if(v0.iszero()) v0 = vec(0, 0, 1e-5f);
-
// v1 = support in direction of origin
vec n = vec(v0).neg();
vec v11 = p1.supportpoint(vec(n).neg());
vec v12 = p2.supportpoint(n);
vec v1 = vec(v12).sub(v11);
- if(v1.dot(n) <= 0)
- {
+ if(v1.dot(n) <= 0) {
if(contactnormal) *contactnormal = n;
return false;
}
-
// v2 - support perpendicular to v1,v0
n.cross(v1, v0);
- if(n.iszero())
- {
+ if(n.iszero()) {
n = vec(v1).sub(v0);
n.normalize();
if(contactnormal) *contactnormal = n;
vec v21 = p1.supportpoint(vec(n).neg());
vec v22 = p2.supportpoint(n);
vec v2 = vec(v22).sub(v21);
- if(v2.dot(n) <= 0)
- {
+ if(v2.dot(n) <= 0) {
if(contactnormal) *contactnormal = n;
return false;
}
-
// Determine whether origin is on + or - side of plane (v1,v0,v2)
n.cross(v0, v1, v2);
ASSERT( !n.iszero() );
// If the origin is on the - side of the plane, reverse the direction of the plane
- if(n.dot(v0) > 0)
- {
+ if(n.dot(v0) > 0) {
swap(v1, v2);
swap(v11, v21);
swap(v12, v22);
n.neg();
}
-
///
// Phase One: Identify a portal
-
- loopi(100)
- {
+ loopi(100) {
// Obtain the support point in a direction perpendicular to the existing plane
// Note: This point is guaranteed to lie off the plane
vec v31 = p1.supportpoint(vec(n).neg());
vec v32 = p2.supportpoint(n);
vec v3 = vec(v32).sub(v31);
- if(v3.dot(n) <= 0)
- {
+ if(v3.dot(n) <= 0) {
if(contactnormal) *contactnormal = n;
return false;
}
-
// If origin is outside (v1,v0,v3), then eliminate v2 and loop
vec v3xv0;
v3xv0.cross(v3, v0);
- if(v1.dot(v3xv0) < 0)
- {
+ if(v1.dot(v3xv0) < 0) {
v2 = v3;
v21 = v31;
v22 = v32;
n.cross(v0, v1, v3);
continue;
}
-
// If origin is outside (v3,v0,v2), then eliminate v1 and loop
- if(v2.dot(v3xv0) > 0)
- {
+ if(v2.dot(v3xv0) > 0) {
v1 = v3;
v11 = v31;
v12 = v32;
n.cross(v0, v3, v2);
continue;
}
-
bool hit = false;
-
///
// Phase Two: Refine the portal
-
// We are now inside of a wedge...
- for(int j = 0;; j++)
- {
+ for(int j = 0;; j++) {
// Compute normal of the wedge face
n.cross(v1, v2, v3);
-
// Can this happen??? Can it be handled more cleanly?
- if(n.iszero())
- {
+ if(n.iszero()) {
ASSERT(0);
return true;
}
-
n.normalize();
-
// If the origin is inside the wedge, we have a hit
- if(n.dot(v1) >= 0 && !hit)
- {
+ if(n.dot(v1) >= 0 && !hit) {
if(contactnormal) *contactnormal = n;
-
// Compute the barycentric coordinates of the origin
- if(contactpoint1 || contactpoint2)
- {
+ if(contactpoint1 || contactpoint2) {
float b0 = v3.scalartriple(v1, v2),
b1 = v0.scalartriple(v3, v2),
b2 = v3.scalartriple(v0, v1),
b3 = v0.scalartriple(v2, v1),
sum = b0 + b1 + b2 + b3;
- if(sum <= 0)
- {
+ if(sum <= 0) {
b0 = 0;
b1 = n.scalartriple(v2, v3);
b2 = n.scalartriple(v3, v1);
if(contactpoint2)
*contactpoint2 = (vec(v02).mul(b0).add(vec(v12).mul(b1)).add(vec(v22).mul(b2)).add(vec(v32).mul(b3))).mul(1.0f/sum);
}
-
// HIT!!!
hit = true;
}
-
// Find the support point in the direction of the wedge face
vec v41 = p1.supportpoint(vec(n).neg());
vec v42 = p2.supportpoint(n);
vec v4 = vec(v42).sub(v41);
-
// If the boundary is thin enough or the origin is outside the support plane for the newly discovered vertex, then we can terminate
- if(v4.dot(n) <= 0 || vec(v4).sub(v3).dot(n) <= boundarytolerance || j > 100)
- {
+ if(v4.dot(n) <= 0 || vec(v4).sub(v3).dot(n) <= boundarytolerance || j > 100) {
if(contactnormal) *contactnormal = n;
return hit;
}
-
// Test origin against the three planes that separate the new portal candidates: (v1,v4,v0) (v2,v4,v0) (v3,v4,v0)
// Note: We're taking advantage of the triple product identities here as an optimization
// (v1 % v4) * v0 == v1 * (v4 % v0) > 0 if origin inside (v1, v4, v0)
// (v3 % v4) * v0 == v3 * (v4 % v0) > 0 if origin inside (v3, v4, v0)
vec v4xv0;
v4xv0.cross(v4, v0);
- if(v1.dot(v4xv0) > 0) // Compute the tetrahedron dividing face d1 = (v4,v0,v1)
- {
- if(v2.dot(v4xv0) > 0) // Compute the tetrahedron dividing face d2 = (v4,v0,v2)
- {
+ if(v1.dot(v4xv0) > 0) { // Compute the tetrahedron dividing face d1 = (v4,v0,v1) {
+ if(v2.dot(v4xv0) > 0) { // Compute the tetrahedron dividing face d2 = (v4,v0,v2) {
// Inside d1 & inside d2 ==> eliminate v1
v1 = v4;
v11 = v41;
v12 = v42;
}
- else
- {
+ else {
// Inside d1 & outside d2 ==> eliminate v3
v3 = v4;
v31 = v41;
v32 = v42;
}
}
- else
- {
- if(v3.dot(v4xv0) > 0) // Compute the tetrahedron dividing face d3 = (v4,v0,v3)
- {
+ else {
+ if(v3.dot(v4xv0) > 0) { // Compute the tetrahedron dividing face d3 = (v4,v0,v3) {
// Outside d1 & inside d3 ==> eliminate v2
v2 = v4;
v21 = v41;
v22 = v42;
}
- else
- {
+ else {
// Outside d1 & outside d3 ==> eliminate v1
v1 = v4;
v11 = v41;
return false;
}
}
-
#include "engine.h"
-struct normalgroup
-{
+struct normalgroup {
vec pos;
int flat, normals, tnormals;
-
normalgroup() : flat(0), normals(-1), tnormals(-1) {}
normalgroup(const vec &pos) : pos(pos), flat(0), normals(-1), tnormals(-1) {}
};
static inline bool htcmp(const vec &v, const normalgroup &n) { return v == n.pos; }
-struct normal
-{
+struct normal {
int next;
vec surface;
};
-struct tnormal
-{
+struct tnormal {
int next;
float offset;
int normals[2];
static float lerpthreshold = 0;
static bool usetnormals = true;
-static int addnormal(const vec &key, const vec &surface)
-{
+static int addnormal(const vec &key, const vec &surface) {
normalgroup &g = normalgroups.access(key, key);
normal &n = normals.add();
n.next = g.normals;
return g.normals = normals.length()-1;
}
-static void addtnormal(const vec &key, float offset, int normal1, int normal2, normalgroup *group1, normalgroup *group2)
-{
+static void addtnormal(const vec &key, float offset, int normal1, int normal2, normalgroup *group1, normalgroup *group2) {
normalgroup &g = normalgroups.access(key, key);
tnormal &n = tnormals.add();
n.next = g.tnormals;
g.tnormals = tnormals.length()-1;
}
-static int addnormal(const vec &key, int axis)
-{
+static int addnormal(const vec &key, int axis) {
normalgroup &g = normalgroups.access(key, key);
g.flat += 1<<(4*axis);
return axis - 6;
}
-static inline void findnormal(const normalgroup &g, const vec &surface, vec &v)
-{
+static inline void findnormal(const normalgroup &g, const vec &surface, vec &v) {
v = vec(0, 0, 0);
int total = 0;
if(surface.x >= lerpthreshold) { int n = (g.flat>>4)&0xF; v.x += n; total += n; }
else if(surface.y <= -lerpthreshold) { int n = (g.flat>>8)&0xF; v.y -= n; total += n; }
if(surface.z >= lerpthreshold) { int n = (g.flat>>20)&0xF; v.z += n; total += n; }
else if(surface.z <= -lerpthreshold) { int n = (g.flat>>16)&0xF; v.z -= n; total += n; }
- for(int cur = g.normals; cur >= 0;)
- {
+ for(int cur = g.normals; cur >= 0;) {
normal &o = normals[cur];
- if(o.surface.dot(surface) >= lerpthreshold)
- {
+ if(o.surface.dot(surface) >= lerpthreshold) {
v.add(o.surface);
total++;
}
else if(!total) v = surface;
}
-static inline bool findtnormal(const normalgroup &g, const vec &surface, vec &v)
-{
+static inline bool findtnormal(const normalgroup &g, const vec &surface, vec &v) {
float bestangle = lerpthreshold;
tnormal *bestnorm = NULL;
- for(int cur = g.tnormals; cur >= 0;)
- {
+ for(int cur = g.tnormals; cur >= 0;) {
tnormal &o = tnormals[cur];
static const vec flats[6] = { vec(-1, 0, 0), vec(1, 0, 0), vec(0, -1, 0), vec(0, 1, 0), vec(0, 0, -1), vec(0, 0, 1) };
vec n1 = o.normals[0] < 0 ? flats[o.normals[0]+6] : normals[o.normals[0]].surface,
nt;
nt.lerp(n1, n2, o.offset).normalize();
float tangle = nt.dot(surface);
- if(tangle >= bestangle)
- {
+ if(tangle >= bestangle) {
bestangle = tangle;
bestnorm = &o;
}
return true;
}
-void findnormal(const vec &key, const vec &surface, vec &v)
-{
+void findnormal(const vec &key, const vec &surface, vec &v) {
const normalgroup *g = normalgroups.access(key);
if(!g) v = surface;
else if(g->tnormals < 0 || !findtnormal(*g, surface, v))
static uint progress = 0;
-void show_addnormals_progress()
-{
+void show_addnormals_progress() {
float bar1 = float(progress) / float(allocnodes);
renderprogress(bar1, "computing normals...");
}
-void addnormals(cube &c, const ivec &o, int size)
-{
+void addnormals(cube &c, const ivec &o, int size) {
CHECK_CALCLIGHT_PROGRESS(return, show_addnormals_progress);
-
- if(c.children)
- {
+ if(c.children) {
progress++;
size >>= 1;
loopi(8) addnormals(c.children[i], ivec(i, o, size), size);
return;
}
else if(isempty(c)) return;
-
vec pos[MAXFACEVERTS];
int norms[MAXFACEVERTS];
int tj = usetnormals && c.ext ? c.ext->tjoints : -1, vis;
- loopi(6) if((vis = visibletris(c, i, o, size)))
- {
+ loopi(6) if((vis = visibletris(c, i, o, size))) {
CHECK_CALCLIGHT_PROGRESS(return, show_addnormals_progress);
-
vec planes[2];
int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0, convex = 0, numplanes = 0;
- if(numverts)
- {
+ if(numverts) {
vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
vec vo(ivec(o).mask(~0xFFF));
- loopj(numverts)
- {
+ loopj(numverts) {
vertinfo &v = verts[j];
pos[j] = vec(v.x, v.y, v.z).mul(1.0f/8).add(vo);
}
if(!(c.merged&(1<<i)) && !flataxisface(c, i)) convex = faceconvexity(verts, numverts, size);
}
else if(c.merged&(1<<i)) continue;
- else
- {
+ else {
ivec v[4];
genfaceverts(c, i, v);
if(!flataxisface(c, i)) convex = faceconvexity(v);
pos[numverts++] = vec(v[order+2]).mul(size/8.0f).add(vo);
if(vis&2) pos[numverts++] = vec(v[(order+3)&3]).mul(size/8.0f).add(vo);
}
-
- if(!flataxisface(c, i))
- {
+ if(!flataxisface(c, i)) {
planes[numplanes++].cross(pos[0], pos[1], pos[2]).normalize();
if(convex) planes[numplanes++].cross(pos[0], pos[2], pos[3]).normalize();
}
-
if(!numplanes) loopk(numverts) norms[k] = addnormal(pos[k], i);
else if(numplanes==1) loopk(numverts) norms[k] = addnormal(pos[k], planes[0]);
- else
- {
+ else {
vec avg = vec(planes[0]).add(planes[1]).normalize();
norms[0] = addnormal(pos[0], avg);
norms[1] = addnormal(pos[1], planes[0]);
norms[2] = addnormal(pos[2], avg);
for(int k = 3; k < numverts; k++) norms[k] = addnormal(pos[k], planes[1]);
}
-
while(tj >= 0 && tjoints[tj].edge < i*(MAXFACEVERTS+1)) tj = tjoints[tj].next;
- while(tj >= 0 && tjoints[tj].edge < (i+1)*(MAXFACEVERTS+1))
- {
+ while(tj >= 0 && tjoints[tj].edge < (i+1)*(MAXFACEVERTS+1)) {
int edge = tjoints[tj].edge, e1 = edge%(MAXFACEVERTS+1), e2 = (e1+1)%numverts;
const vec &v1 = pos[e1], &v2 = pos[e2];
ivec d(vec(v2).sub(v1).mul(8));
offset2 = (int(v2[axis]*8) - origin) / d[axis];
vec o = vec(v1).sub(vec(d).mul(offset1/8.0f)), n1, n2;
float doffset = 1.0f / (offset2 - offset1);
-
- while(tj >= 0)
- {
+ while(tj >= 0) {
tjoint &t = tjoints[tj];
if(t.edge != edge) break;
float offset = (t.offset - offset1) * doffset;
}
}
-void calcnormals(bool lerptjoints)
-{
+void calcnormals(bool lerptjoints) {
if(!lerpangle) return;
usetnormals = lerptjoints;
if(usetnormals) findtjoints();
loopi(8) addnormals(worldroot[i], ivec(i, ivec(0, 0, 0), worldsize/2), worldsize/2);
}
-void clearnormals()
-{
+void clearnormals() {
normalgroups.clear();
normals.setsize(0);
tnormals.setsize(0);
}
-void calclerpverts(const vec2 *c, const vec *n, lerpvert *lv, int &numv)
-{
+void calclerpverts(const vec2 *c, const vec *n, lerpvert *lv, int &numv) {
int i = 0;
- loopj(numv)
- {
- if(j)
- {
+ loopj(numv) {
+ if(j) {
if(c[j] == c[j-1] && n[j] == n[j-1]) continue;
if(j == numv-1 && c[j] == c[0] && n[j] == n[0]) continue;
}
numv = i;
}
-void setlerpstep(float v, lerpbounds &bounds)
-{
- if(bounds.min->tc.y + 1 > bounds.max->tc.y)
- {
+void setlerpstep(float v, lerpbounds &bounds) {
+ if(bounds.min->tc.y + 1 > bounds.max->tc.y) {
bounds.nstep = vec(0, 0, 0);
bounds.normal = bounds.min->normal;
- if(bounds.min->normal != bounds.max->normal)
- {
+ if(bounds.min->normal != bounds.max->normal) {
bounds.normal.add(bounds.max->normal);
bounds.normal.normalize();
}
bounds.u = bounds.min->tc.x;
return;
}
-
bounds.nstep = bounds.max->normal;
bounds.nstep.sub(bounds.min->normal);
bounds.nstep.div(bounds.max->tc.y-bounds.min->tc.y);
-
bounds.normal = bounds.nstep;
bounds.normal.mul(v - bounds.min->tc.y);
bounds.normal.add(bounds.min->normal);
-
bounds.ustep = (bounds.max->tc.x-bounds.min->tc.x) / (bounds.max->tc.y-bounds.min->tc.y);
bounds.u = bounds.ustep * (v-bounds.min->tc.y) + bounds.min->tc.x;
}
-void initlerpbounds(float u, float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end)
-{
+void initlerpbounds(float u, float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end) {
const lerpvert *first = &lv[0], *second = NULL;
- loopi(numv-1)
- {
+ loopi(numv-1) {
if(lv[i+1].tc.y < first->tc.y) { second = first; first = &lv[i+1]; }
else if(!second || lv[i+1].tc.y < second->tc.y) second = &lv[i+1];
}
-
if(int(first->tc.y) < int(second->tc.y)) { start.min = end.min = first; }
else if(first->tc.x > second->tc.x) { start.min = second; end.min = first; }
else { start.min = first; end.min = second; }
-
- if((lv[1].tc.x - lv->tc.x)*(lv[2].tc.y - lv->tc.y) > (lv[1].tc.y - lv->tc.y)*(lv[2].tc.x - lv->tc.x))
- {
+ if((lv[1].tc.x - lv->tc.x)*(lv[2].tc.y - lv->tc.y) > (lv[1].tc.y - lv->tc.y)*(lv[2].tc.x - lv->tc.x)) {
start.winding = end.winding = 1;
start.max = (start.min == lv ? &lv[numv-1] : start.min-1);
end.max = (end.min == &lv[numv-1] ? lv : end.min+1);
}
- else
- {
+ else {
start.winding = end.winding = -1;
start.max = (start.min == &lv[numv-1] ? lv : start.min+1);
end.max = (end.min == lv ? &lv[numv-1] : end.min-1);
}
-
setlerpstep(v, start);
setlerpstep(v, end);
}
-void updatelerpbounds(float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end)
-{
- if(v >= start.max->tc.y)
- {
+void updatelerpbounds(float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end) {
+ if(v >= start.max->tc.y) {
const lerpvert *next = start.winding > 0 ?
(start.max == lv ? &lv[numv-1] : start.max-1) :
(start.max == &lv[numv-1] ? lv : start.max+1);
- if(next->tc.y > start.max->tc.y)
- {
+ if(next->tc.y > start.max->tc.y) {
start.min = start.max;
start.max = next;
setlerpstep(v, start);
}
}
- if(v >= end.max->tc.y)
- {
+ if(v >= end.max->tc.y) {
const lerpvert *next = end.winding > 0 ?
(end.max == &lv[numv-1] ? lv : end.max+1) :
(end.max == lv ? &lv[numv-1] : end.max-1);
- if(next->tc.y > end.max->tc.y)
- {
+ if(next->tc.y > end.max->tc.y) {
end.min = end.max;
end.max = next;
setlerpstep(v, end);
}
}
-void lerpnormal(float u, float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end, vec &normal, vec &nstep)
-{
+void lerpnormal(float u, float v, const lerpvert *lv, int numv, lerpbounds &start, lerpbounds &end, vec &normal, vec &nstep) {
updatelerpbounds(v, lv, numv, start, end);
-
- if(start.u + 1 > end.u)
- {
+ if(start.u + 1 > end.u) {
nstep = vec(0, 0, 0);
normal = start.normal;
normal.add(end.normal);
normal.normalize();
}
- else
- {
+ else {
vec nstart(start.normal), nend(end.normal);
nstart.normalize();
nend.normalize();
-
nstep = nend;
nstep.sub(nstart);
nstep.div(end.u-start.u);
-
normal = nstep;
normal.mul(u-start.u);
normal.add(nstart);
normal.normalize();
}
-
start.normal.add(start.nstep);
start.u += start.ustep;
-
end.normal.add(end.nstep);
end.u += end.ustep;
}
cube *worldroot = newcubes(F_SOLID);
int allocnodes = 0;
-cubeext *growcubeext(cubeext *old, int maxverts)
-{
+cubeext *growcubeext(cubeext *old, int maxverts) {
cubeext *ext = (cubeext *)new uchar[sizeof(cubeext) + maxverts*sizeof(vertinfo)];
- if(old)
- {
+ if(old) {
ext->va = old->va;
ext->ents = old->ents;
ext->tjoints = old->tjoints;
}
- else
- {
+ else {
ext->va = NULL;
ext->ents = NULL;
ext->tjoints = -1;
return ext;
}
-void setcubeext(cube &c, cubeext *ext)
-{
+void setcubeext(cube &c, cubeext *ext) {
cubeext *old = c.ext;
if(old == ext) return;
c.ext = ext;
if(old) delete[] (uchar *)old;
}
-cubeext *newcubeext(cube &c, int maxverts, bool init)
-{
+cubeext *newcubeext(cube &c, int maxverts, bool init) {
if(c.ext && c.ext->maxverts >= maxverts) return c.ext;
cubeext *ext = growcubeext(c.ext, maxverts);
- if(init)
- {
- if(c.ext)
- {
+ if(init) {
+ if(c.ext) {
memcpy(ext->surfaces, c.ext->surfaces, sizeof(ext->surfaces));
memcpy(ext->verts(), c.ext->verts(), c.ext->maxverts*sizeof(vertinfo));
}
return ext;
}
-cube *newcubes(uint face, int mat)
-{
+cube *newcubes(uint face, int mat) {
cube *c = new cube[8];
- loopi(8)
- {
+ loopi(8) {
c->children = NULL;
c->ext = NULL;
c->visible = 0;
return c-8;
}
-int familysize(const cube &c)
-{
+int familysize(const cube &c) {
int size = 1;
if(c.children) loopi(8) size += familysize(c.children[i]);
return size;
}
-void freeocta(cube *c)
-{
+void freeocta(cube *c) {
if(!c) return;
loopi(8) discardchildren(c[i]);
delete[] c;
allocnodes--;
}
-void freecubeext(cube &c)
-{
- if(c.ext)
- {
+void freecubeext(cube &c) {
+ if(c.ext) {
delete[] (uchar *)c.ext;
c.ext = NULL;
}
}
-void discardchildren(cube &c, bool fixtex, int depth)
-{
+void discardchildren(cube &c, bool fixtex, int depth) {
c.material = MAT_AIR;
c.visible = 0;
c.merged = 0;
- if(c.ext)
- {
+ if(c.ext) {
if(c.ext->va) destroyva(c.ext->va);
c.ext->va = NULL;
c.ext->tjoints = -1;
freeoctaentities(c);
freecubeext(c);
}
- if(c.children)
- {
+ if(c.children) {
uint filled = F_EMPTY;
- loopi(8)
- {
+ loopi(8) {
discardchildren(c.children[i], fixtex, depth+1);
filled |= c.children[i].faces[0];
}
- if(fixtex)
- {
+ if(fixtex) {
loopi(6) c.texture[i] = getmippedtexture(c, i);
if(depth > 0 && filled != F_EMPTY) c.faces[0] = F_SOLID;
}
}
}
-void getcubevector(cube &c, int d, int x, int y, int z, ivec &p)
-{
+void getcubevector(cube &c, int d, int x, int y, int z, ivec &p) {
ivec v(d, x, y, z);
-
loopi(3)
p[i] = edgeget(cubeedge(c, i, v[R[i]], v[C[i]]), v[D[i]]);
}
-void setcubevector(cube &c, int d, int x, int y, int z, const ivec &p)
-{
+void setcubevector(cube &c, int d, int x, int y, int z, const ivec &p) {
ivec v(d, x, y, z);
-
loopi(3)
edgeset(cubeedge(c, i, v[R[i]], v[C[i]]), v[D[i]], p[i]);
}
-static inline void getcubevector(cube &c, int i, ivec &p)
-{
+static inline void getcubevector(cube &c, int i, ivec &p) {
p.x = edgeget(cubeedge(c, 0, (i>>R[0])&1, (i>>C[0])&1), (i>>D[0])&1);
p.y = edgeget(cubeedge(c, 1, (i>>R[1])&1, (i>>C[1])&1), (i>>D[1])&1);
p.z = edgeget(cubeedge(c, 2, (i>>R[2])&1, (i>>C[2])&1), (i>>D[2])&1);
}
-static inline void setcubevector(cube &c, int i, const ivec &p)
-{
+static inline void setcubevector(cube &c, int i, const ivec &p) {
edgeset(cubeedge(c, 0, (i>>R[0])&1, (i>>C[0])&1), (i>>D[0])&1, p.x);
edgeset(cubeedge(c, 1, (i>>R[1])&1, (i>>C[1])&1), (i>>D[1])&1, p.y);
edgeset(cubeedge(c, 2, (i>>R[2])&1, (i>>C[2])&1), (i>>D[2])&1, p.z);
}
-void optiface(uchar *p, cube &c)
-{
+void optiface(uchar *p, cube &c) {
uint f = *(uint *)p;
if(((f>>4)&0x0F0F0F0FU) == (f&0x0F0F0F0FU)) emptyfaces(c);
}
-void printcube()
-{
+void printcube() {
cube &c = lookupcube(lu); // assume this is cube being pointed at
conoutf(CON_DEBUG, "= %p = (%d, %d, %d) @ %d", (void *)&c, lu.x, lu.y, lu.z, lusize);
conoutf(CON_DEBUG, " x %.8x", c.faces[0]);
COMMAND(printcube, "");
-bool isvalidcube(const cube &c)
-{
+bool isvalidcube(const cube &c) {
clipplanes p;
genclipplanes(c, ivec(0, 0, 0), 256, p);
- loopi(8) // test that cube is convex
- {
+ loopi(8) { // test that cube is convex {
vec v = p.v[i];
loopj(p.size) if(p.p[j].dist(v)>1e-3f) return false;
}
return true;
}
-void validatec(cube *c, int size)
-{
- loopi(8)
- {
- if(c[i].children)
- {
- if(size<=1)
- {
+void validatec(cube *c, int size) {
+ loopi(8) {
+ if(c[i].children) {
+ if(size<=1) {
solidfaces(c[i]);
discardchildren(c[i], true);
}
else validatec(c[i].children, size>>1);
}
- else if(size > 0x1000)
- {
+ else if(size > 0x1000) {
subdividecube(c[i], true, false);
validatec(c[i].children, size>>1);
}
- else
- {
- loopj(3)
- {
+ else {
+ loopj(3) {
uint f = c[i].faces[j], e0 = f&0x0F0F0F0FU, e1 = (f>>4)&0x0F0F0F0FU;
- if(e0 == e1 || ((e1+0x07070707U)|(e1-e0))&0xF0F0F0F0U)
- {
+ if(e0 == e1 || ((e1+0x07070707U)|(e1-e0))&0xF0F0F0F0U) {
emptyfaces(c[i]);
break;
}
ivec lu;
int lusize;
-cube &lookupcube(const ivec &to, int tsize, ivec &ro, int &rsize)
-{
+cube &lookupcube(const ivec &to, int tsize, ivec &ro, int &rsize) {
int tx = clamp(to.x, 0, worldsize-1),
ty = clamp(to.y, 0, worldsize-1),
tz = clamp(to.z, 0, worldsize-1);
int scale = worldscale-1, csize = abs(tsize);
cube *c = &worldroot[octastep(tx, ty, tz, scale)];
- if(!(csize>>scale)) do
- {
- if(!c->children)
- {
- if(tsize > 0) do
- {
+ if(!(csize>>scale)) do {
+ if(!c->children) {
+ if(tsize > 0) do {
subdividecube(*c);
scale--;
c = &c->children[octastep(tx, ty, tz, scale)];
return *c;
}
-int lookupmaterial(const vec &v)
-{
+int lookupmaterial(const vec &v) {
ivec o(v);
if(!insideworld(o)) return MAT_AIR;
int scale = worldscale-1;
cube *c = &worldroot[octastep(o.x, o.y, o.z, scale)];
- while(c->children)
- {
+ while(c->children) {
scale--;
c = &c->children[octastep(o.x, o.y, o.z, scale)];
}
const cube *neighbourstack[32];
int neighbourdepth = -1;
-const cube &neighbourcube(const cube &c, int orient, const ivec &co, int size, ivec &ro, int &rsize)
-{
+const cube &neighbourcube(const cube &c, int orient, const ivec &co, int size, ivec &ro, int &rsize) {
ivec n = co;
int dim = dimension(orient);
uint diff = n[dim];
if(diff >= uint(worldsize)) { ro = n; rsize = size; return c; }
int scale = worldscale;
const cube *nc = worldroot;
- if(neighbourdepth >= 0)
- {
+ if(neighbourdepth >= 0) {
scale -= neighbourdepth + 1;
diff >>= scale;
do { scale++; diff >>= 1; } while(diff);
}
scale--;
nc = &nc[octastep(n.x, n.y, n.z, scale)];
- if(!(size>>scale) && nc->children) do
- {
+ if(!(size>>scale) && nc->children) do {
scale--;
nc = &nc->children[octastep(n.x, n.y, n.z, scale)];
} while(!(size>>scale) && nc->children);
////////// (re)mip //////////
-int getmippedtexture(const cube &p, int orient)
-{
+int getmippedtexture(const cube &p, int orient) {
cube *c = p.children;
int d = dimension(orient), dc = dimcoord(orient), texs[4] = { -1, -1, -1, -1 }, numtexs = 0;
- loop(x, 2) loop(y, 2)
- {
+ loop(x, 2) loop(y, 2) {
int n = octaindex(d, x, y, dc);
- if(isempty(c[n]))
- {
+ if(isempty(c[n])) {
n = oppositeocta(d, n);
if(isempty(c[n]))
continue;
return DEFAULT_GEOM;
}
-void forcemip(cube &c, bool fixtex)
-{
+void forcemip(cube &c, bool fixtex) {
cube *ch = c.children;
emptyfaces(c);
-
- loopi(8) loopj(8)
- {
+ loopi(8) loopj(8) {
int n = i^(j==3 ? 4 : (j==4 ? 3 : j));
- if(!isempty(ch[n])) // breadth first search for cube near vert
- {
+ if(!isempty(ch[n])) { // breadth first search for cube near vert {
ivec v;
getcubevector(ch[n], i, v);
// adjust vert to parent size
break;
}
}
-
if(fixtex) loopj(6)
c.texture[j] = getmippedtexture(c, j);
}
-static int midedge(const ivec &a, const ivec &b, int xd, int yd, bool &perfect)
-{
+static int midedge(const ivec &a, const ivec &b, int xd, int yd, bool &perfect) {
int ax = a[xd], ay = a[yd], bx = b[xd], by = b[yd];
if(ay==by) return ay;
if(ax==bx) { perfect = false; return ay; }
return crossy ? 8 : min(max(y, 0), 16);
}
-static inline bool crosscenter(const ivec &a, const ivec &b, int xd, int yd)
-{
+static inline bool crosscenter(const ivec &a, const ivec &b, int xd, int yd) {
int ax = a[xd], ay = a[yd], bx = b[xd], by = b[yd];
return (((ax <= 8 && bx <= 8) || (ax >= 8 && bx >= 8)) &&
((ay <= 8 && by <= 8) || (ay >= 8 && by >= 8))) ||
(ax + bx == 16 && ay + by == 16);
}
-bool subdividecube(cube &c, bool fullcheck, bool brighten)
-{
+bool subdividecube(cube &c, bool fullcheck, bool brighten) {
if(c.children) return true;
if(c.ext) memset(c.ext->surfaces, 0, sizeof(c.ext->surfaces));
- if(isempty(c) || isentirelysolid(c))
- {
+ if(isempty(c) || isentirelysolid(c)) {
c.children = newcubes(isempty(c) ? F_EMPTY : F_SOLID, c.material);
- loopi(8)
- {
+ loopi(8) {
loopl(6) c.children[i].texture[l] = c.texture[l];
if(brighten && !isempty(c)) brightencube(c.children[i]);
}
cube *ch = c.children = newcubes(F_SOLID, c.material);
bool perfect = true;
ivec v[8];
- loopi(8)
- {
+ loopi(8) {
getcubevector(c, i, v[i]);
v[i].mul(2);
}
-
- loopj(6)
- {
+ loopj(6) {
int d = dimension(j), z = dimcoord(j);
const ivec &v00 = v[octaindex(d, 0, 0, z)],
&v10 = v[octaindex(d, 1, 0, z)],
bool p1 = perfect, p2 = perfect;
int c1 = midedge(v00, v11, R[d], d, p1);
int c2 = midedge(v01, v10, R[d], d, p2);
- if(z ? c1 > c2 : c1 < c2)
- {
+ if(z ? c1 > c2 : c1 < c2) {
e[1][1] = c1;
perfect = p1 && (c1 == c2 || crosscenter(v00, v11, C[d], R[d]));
}
- else
- {
+ else {
e[1][1] = c2;
perfect = p2 && (c1 == c2 || crosscenter(v01, v10, C[d], R[d]));
}
-
- loopi(8)
- {
+ loopi(8) {
ch[i].texture[j] = c.texture[j];
int rd = (i>>R[d])&1, cd = (i>>C[d])&1, dd = (i>>D[d])&1;
edgeset(cubeedge(ch[i], d, 0, 0), z, clamp(e[rd][cd] - dd*8, 0, 8));
edgeset(cubeedge(ch[i], d, 1, 1), z, clamp(e[1+rd][1+cd] - dd*8, 0, 8));
}
}
-
validatec(ch);
- if(fullcheck) loopi(8) if(!isvalidcube(ch[i])) // not so good...
- {
+ if(fullcheck) loopi(8) if(!isvalidcube(ch[i])) { // not so good... {
emptyfaces(ch[i]);
perfect=false;
}
bool crushededge(uchar e, int dc) { return dc ? e==0 : e==0x88; }
-int visibleorient(const cube &c, int orient)
-{
- loopi(2)
- {
+int visibleorient(const cube &c, int orient) {
+ loopi(2) {
int a = faceedgesidx[orient][i*2 + 0];
int b = faceedgesidx[orient][i*2 + 1];
- loopj(2)
- {
+ loopj(2) {
if(crushededge(c.edges[a],j) &&
crushededge(c.edges[b],j) &&
touchingface(c, orient)) return ((a>>2)<<1) + j;
static int remipprogress = 0, remiptotal = 0;
-bool remip(cube &c, const ivec &co, int size)
-{
+bool remip(cube &c, const ivec &co, int size) {
cube *ch = c.children;
- if(!ch)
- {
+ if(!ch) {
if(size<<1 <= 0x1000) return true;
subdividecube(c);
ch = c.children;
}
else if((remipprogress++&0xFFF)==1) renderprogress(float(remipprogress)/remiptotal, "remipping...");
-
bool perfect = true;
- loopi(8)
- {
+ loopi(8) {
ivec o(i, co, size);
if(!remip(ch[i], o, size>>1)) perfect = false;
}
-
solidfaces(c); // so texmip is more consistent
loopj(6)
c.texture[j] = getmippedtexture(c, j); // parents get child texs regardless
-
if(!perfect) return false;
if(size<<1 > 0x1000) return false;
-
ushort mat = MAT_AIR;
- loopi(8)
- {
+ loopi(8) {
mat = ch[i].material;
- if((mat&MATF_CLIP) == MAT_NOCLIP || mat&MAT_ALPHA)
- {
+ if((mat&MATF_CLIP) == MAT_NOCLIP || mat&MAT_ALPHA) {
if(i > 0) return false;
while(++i < 8) if(ch[i].material != mat) return false;
break;
}
- else if(!isentirelysolid(ch[i]))
- {
- while(++i < 8)
- {
+ else if(!isentirelysolid(ch[i])) {
+ while(++i < 8) {
int omat = ch[i].material;
if(isentirelysolid(ch[i]) ? (omat&MATF_CLIP) == MAT_NOCLIP || omat&MAT_ALPHA : mat != omat) return false;
}
break;
}
}
-
cube n = c;
n.ext = NULL;
forcemip(n);
n.children = NULL;
- if(!subdividecube(n, false, false))
- { freeocta(n.children); return false; }
-
+ if(!subdividecube(n, false, false)) {
+ freeocta(n.children); return false; }
cube *nh = n.children;
uchar vis[6] = {0, 0, 0, 0, 0, 0};
- loopi(8)
- {
+ loopi(8) {
if(ch[i].faces[0] != nh[i].faces[0] ||
ch[i].faces[1] != nh[i].faces[1] ||
- ch[i].faces[2] != nh[i].faces[2])
- { freeocta(nh); return false; }
-
+ ch[i].faces[2] != nh[i].faces[2]) {
+ freeocta(nh); return false; }
if(isempty(ch[i]) && isempty(nh[i])) continue;
-
ivec o(i, co, size);
loop(orient, 6)
- if(visibleface(ch[i], orient, o, size, MAT_AIR, (mat&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA))
- {
+ if(visibleface(ch[i], orient, o, size, MAT_AIR, (mat&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA)) {
if(ch[i].texture[orient] != n.texture[orient]) { freeocta(nh); return false; }
vis[orient] |= 1<<i;
}
}
- if(mipvis) loop(orient, 6)
- {
+ if(mipvis) loop(orient, 6) {
int mask = 0;
loop(x, 2) loop(y, 2) mask |= 1<<octaindex(dimension(orient), x, y, dimcoord(orient));
if(vis[orient]&mask && (vis[orient]&mask)!=mask) { freeocta(nh); return false; }
}
-
freeocta(nh);
discardchildren(c);
loopi(3) c.faces[i] = n.faces[i];
return true;
}
-void mpremip(bool local)
-{
+void mpremip(bool local) {
extern selinfo sel;
if(local) game::edittrigger(sel, EDIT_REMIP);
remipprogress = 1;
remiptotal = allocnodes;
- loopi(8)
- {
+ loopi(8) {
ivec o(i, ivec(0, 0, 0), worldsize>>1);
remip(worldroot[i], o, worldsize>>2);
}
if(!local) allchanged();
}
-void remip_()
-{
+void remip_() {
mpremip(true);
allchanged();
}
COMMANDN(remip, remip_, "");
-static inline int edgeval(cube &c, const ivec &p, int dim, int coord)
-{
+static inline int edgeval(cube &c, const ivec &p, int dim, int coord) {
return edgeget(cubeedge(c, dim, p[R[dim]]>>3, p[C[dim]]>>3), coord);
}
-void genvertp(cube &c, ivec &p1, ivec &p2, ivec &p3, plane &pl, bool solid = false)
-{
+void genvertp(cube &c, ivec &p1, ivec &p2, ivec &p3, plane &pl, bool solid = false) {
int dim = 0;
if(p1.y==p2.y && p2.y==p3.y) dim = 1;
else if(p1.z==p2.z && p2.z==p3.z) dim = 2;
-
int coord = p1[dim];
ivec v1(p1), v2(p2), v3(p3);
v1[dim] = solid ? coord*8 : edgeval(c, p1, dim, coord);
v2[dim] = solid ? coord*8 : edgeval(c, p2, dim, coord);
v3[dim] = solid ? coord*8 : edgeval(c, p3, dim, coord);
-
pl.toplane(vec(v1), vec(v2), vec(v3));
}
-static bool threeplaneintersect(plane &pl1, plane &pl2, plane &pl3, vec &dest)
-{
+static bool threeplaneintersect(plane &pl1, plane &pl2, plane &pl3, vec &dest) {
vec &t1 = dest, t2, t3, t4;
t1.cross(pl1, pl2); t4 = t1; t1.mul(pl3.offset);
t2.cross(pl3, pl1); t2.mul(pl2.offset);
return true;
}
-static void genedgespanvert(ivec &p, cube &c, vec &v)
-{
+static void genedgespanvert(ivec &p, cube &c, vec &v) {
ivec p1(8-p.x, p.y, p.z);
ivec p2(p.x, 8-p.y, p.z);
ivec p3(p.x, p.y, 8-p.z);
-
plane plane1, plane2, plane3;
genvertp(c, p, p1, p2, plane1);
genvertp(c, p, p2, p3, plane2);
if(plane1==plane2) genvertp(c, p, p1, p2, plane1, true);
if(plane1==plane3) genvertp(c, p, p1, p2, plane1, true);
if(plane2==plane3) genvertp(c, p, p2, p3, plane2, true);
-
ASSERT(threeplaneintersect(plane1, plane2, plane3, v));
//ASSERT(v.x>=0 && v.x<=8);
//ASSERT(v.y>=0 && v.y<=8);
v.z = max(0.0f, min(8.0f, v.z));
}
-void edgespan2vectorcube(cube &c)
-{
+void edgespan2vectorcube(cube &c) {
if(isentirelysolid(c) || isempty(c)) return;
cube o = c;
- loop(x, 2) loop(y, 2) loop(z, 2)
- {
+ loop(x, 2) loop(y, 2) loop(z, 2) {
ivec p(8*x, 8*y, 8*z);
vec v;
genedgespanvert(p, o, v);
-
edgeset(cubeedge(c, 0, y, z), x, int(v.x+0.49f));
edgeset(cubeedge(c, 1, z, x), y, int(v.y+0.49f));
edgeset(cubeedge(c, 2, x, y), z, int(v.z+0.49f));
}
}
-const ivec cubecoords[8] = // verts of bounding cube
-{
+const ivec cubecoords[8] = {// verts of bounding cube {
#define GENCUBEVERT(n, x, y, z) ivec(x, y, z),
GENCUBEVERTS(0, 8, 0, 8, 0, 8)
#undef GENCUBEVERT
};
template<class T>
-static inline void gencubevert(const cube &c, int i, T &v)
-{
- switch(i)
- {
+static inline void gencubevert(const cube &c, int i, T &v) {
+ switch(i) {
default:
#define GENCUBEVERT(n, x, y, z) \
case n: \
}
}
-void genfaceverts(const cube &c, int orient, ivec v[4])
-{
- switch(orient)
- {
+void genfaceverts(const cube &c, int orient, ivec v[4]) {
+ switch(orient) {
default:
#define GENFACEORIENT(o, v0, v1, v2, v3) \
case o: v0 v1 v2 v3 break;
}
}
-const ivec facecoords[6][4] =
-{
-#define GENFACEORIENT(o, v0, v1, v2, v3) \
- { v0, v1, v2, v3 },
+const ivec facecoords[6][4] = {
+#define GENFACEORIENT(o, v0, v1, v2, v3) { \
+ v0, v1, v2, v3 },
#define GENFACEVERT(o, n, x,y,z, xv,yv,zv) \
ivec(x,y,z)
GENFACEVERTS(0, 8, 0, 8, 0, 8, , , , , , )
#undef GENFACEVERT
};
-const uchar fv[6][4] = // indexes for cubecoords, per each vert of a face orientation
-{
+const uchar fv[6][4] = { // indexes for cubecoords, per each vert of a face orientation {
{ 2, 1, 6, 5 },
{ 3, 4, 7, 0 },
{ 4, 5, 6, 7 },
{ 5, 4, 3, 2 },
};
-const uchar fvmasks[64] = // mask of verts used given a mask of visible face orientations
-{
+const uchar fvmasks[64] = { // mask of verts used given a mask of visible face orientations {
0x00, 0x66, 0x99, 0xFF, 0xF0, 0xF6, 0xF9, 0xFF,
0x0F, 0x6F, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC3, 0xE7, 0xDB, 0xFF, 0xF3, 0xF7, 0xFB, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
-const uchar faceedgesidx[6][4] = // ordered edges surrounding each orient
-{//0..1 = row edges, 2..3 = column edges
+const uchar faceedgesidx[6][4] = { // ordered edges surrounding each orient {
+//0..1 = row edges, 2..3 = column edges {
{ 4, 5, 8, 10 },
{ 6, 7, 9, 11 },
{ 8, 9, 0, 2 },
{ 2, 3, 5, 7 },
};
-bool flataxisface(const cube &c, int orient)
-{
+bool flataxisface(const cube &c, int orient) {
uint face = c.faces[dimension(orient)];
if(dimcoord(orient)) face >>= 4;
return (face&0x0F0F0F0F) == 0x01010101*(face&0x0F);
}
-bool collideface(const cube &c, int orient)
-{
- if(flataxisface(c, orient))
- {
+bool collideface(const cube &c, int orient) {
+ if(flataxisface(c, orient)) {
uchar r1 = c.edges[faceedgesidx[orient][0]], r2 = c.edges[faceedgesidx[orient][1]];
if(uchar((r1>>4)|(r2&0xF0)) == uchar((r1&0x0F)|(r2<<4))) return false;
uchar c1 = c.edges[faceedgesidx[orient][2]], c2 = c.edges[faceedgesidx[orient][3]];
return true;
}
-bool touchingface(const cube &c, int orient)
-{
+bool touchingface(const cube &c, int orient) {
uint face = c.faces[dimension(orient)];
return dimcoord(orient) ? (face&0xF0F0F0F0)==0x80808080 : (face&0x0F0F0F0F)==0;
}
-bool notouchingface(const cube &c, int orient)
-{
+bool notouchingface(const cube &c, int orient) {
uint face = c.faces[dimension(orient)];
return dimcoord(orient) ? (face&0x80808080)==0 : ((0x88888888-face)&0x08080808) == 0;
}
-int faceconvexity(const ivec v[4])
-{
+int faceconvexity(const ivec v[4]) {
ivec n;
n.cross(ivec(v[1]).sub(v[0]), ivec(v[2]).sub(v[0]));
return ivec(v[0]).sub(v[3]).dot(n);
// 1 if convex, -1 if concave, 0 if flat
}
-int faceconvexity(const vertinfo *verts, int numverts, int size)
-{
+int faceconvexity(const vertinfo *verts, int numverts, int size) {
if(numverts < 4) return 0;
ivec v0 = verts[0].getxyz(),
e1 = verts[1].getxyz().sub(v0),
e2 = verts[2].getxyz().sub(v0),
n;
- if(size >= (8<<5))
- {
+ if(size >= (8<<5)) {
if(size >= (8<<10)) n.cross(e1.shr(10), e2.shr(10));
else n.cross(e1, e2).shr(10);
}
return verts[3].getxyz().sub(v0).dot(n);
}
-int faceconvexity(const ivec v[4], int &vis)
-{
+int faceconvexity(const ivec v[4], int &vis) {
ivec e1, e2, e3, n;
n.cross((e1 = v[1]).sub(v[0]), (e2 = v[2]).sub(v[0]));
int convex = (e3 = v[0]).sub(v[3]).dot(n);
- if(!convex)
- {
+ if(!convex) {
if(ivec().cross(e3, e2).iszero()) { if(!n.iszero()) vis = 1; }
else if(n.iszero()) { vis = 2; }
return 0;
return convex;
}
-int faceconvexity(const cube &c, int orient)
-{
+int faceconvexity(const cube &c, int orient) {
if(flataxisface(c, orient)) return 0;
ivec v[4];
genfaceverts(c, orient, v);
return faceconvexity(v);
}
-int faceorder(const cube &c, int orient) // gets above 'fv' so that each face is convex
-{
+int faceorder(const cube &c, int orient) { // gets above 'fv' so that each face is convex {
return faceconvexity(c, orient)<0 ? 1 : 0;
}
-static inline void faceedges(const cube &c, int orient, uchar edges[4])
-{
+static inline void faceedges(const cube &c, int orient, uchar edges[4]) {
loopk(4) edges[k] = c.edges[faceedgesidx[orient][k]];
}
-uint faceedges(const cube &c, int orient)
-{
+uint faceedges(const cube &c, int orient) {
union { uchar edges[4]; uint face; } u;
faceedges(c, orient, u.edges);
return u.face;
}
-static inline int genfacevecs(const cube &cu, int orient, const ivec &pos, int size, bool solid, ivec2 *fvecs, const ivec *v = NULL)
-{
+static inline int genfacevecs(const cube &cu, int orient, const ivec &pos, int size, bool solid, ivec2 *fvecs, const ivec *v = NULL) {
int i = 0;
- if(solid)
- {
- switch(orient)
- {
+ if(solid) {
+ switch(orient) {
#define GENFACEORIENT(orient, v0, v1, v2, v3) \
- case orient: \
- { \
+ case orient: { \
+ \
if(dimcoord(orient)) { v0 v1 v2 v3 } else { v3 v2 v1 v0 } \
break; \
}
- #define GENFACEVERT(orient, vert, xv,yv,zv, x,y,z) \
- { ivec2 &f = fvecs[i]; x ((xv)<<3); y ((yv)<<3); z ((zv)<<3); i++; }
+ #define GENFACEVERT(orient, vert, xv,yv,zv, x,y,z) { \
+ ivec2 &f = fvecs[i]; x ((xv)<<3); y ((yv)<<3); z ((zv)<<3); i++; }
GENFACEVERTS(pos.x, pos.x+size, pos.y, pos.y+size, pos.z, pos.z+size, f.x = , f.x = , f.y = , f.y = , (void), (void))
#undef GENFACEVERT
}
ivec buf[4];
if(!v) { genfaceverts(cu, orient, buf); v = buf; }
ivec2 prev(INT_MAX, INT_MAX);
- switch(orient)
- {
- #define GENFACEVERT(orient, vert, sx,sy,sz, dx,dy,dz) \
- { \
+ switch(orient) {
+ #define GENFACEVERT(orient, vert, sx,sy,sz, dx,dy,dz) { \
+ \
const ivec &e = v[vert]; \
ivec ef; \
ef.dx = e.sx; ef.dy = e.sy; ef.dz = e.sz; \
- if(ef.z == dimcoord(orient)*8) \
- { \
+ if(ef.z == dimcoord(orient)*8) { \
+ \
ivec2 &f = fvecs[i]; \
ivec pf; \
pf.dx = pos.sx; pf.dy = pos.sy; pf.dz = pos.sz; \
return i;
}
-static inline int clipfacevecy(const ivec2 &o, const ivec2 &dir, int cx, int cy, int size, ivec2 &r)
-{
- if(dir.x >= 0)
- {
+static inline int clipfacevecy(const ivec2 &o, const ivec2 &dir, int cx, int cy, int size, ivec2 &r) {
+ if(dir.x >= 0) {
if(cx <= o.x || cx >= o.x+dir.x) return 0;
}
else if(cx <= o.x+dir.x || cx >= o.x) return 0;
-
int t = (o.y-cy) + (cx-o.x)*dir.y/dir.x;
if(t <= 0 || t >= size) return 0;
-
r.x = cx;
r.y = cy + t;
return 1;
}
-static inline int clipfacevecx(const ivec2 &o, const ivec2 &dir, int cx, int cy, int size, ivec2 &r)
-{
- if(dir.y >= 0)
- {
+static inline int clipfacevecx(const ivec2 &o, const ivec2 &dir, int cx, int cy, int size, ivec2 &r) {
+ if(dir.y >= 0) {
if(cy <= o.y || cy >= o.y+dir.y) return 0;
}
else if(cy <= o.y+dir.y || cy >= o.y) return 0;
-
int t = (o.x-cx) + (cy-o.y)*dir.x/dir.y;
if(t <= 0 || t >= size) return 0;
-
r.x = cx + t;
r.y = cy;
return 1;
}
-static inline int clipfacevec(const ivec2 &o, const ivec2 &dir, int cx, int cy, int size, ivec2 *rvecs)
-{
+static inline int clipfacevec(const ivec2 &o, const ivec2 &dir, int cx, int cy, int size, ivec2 *rvecs) {
int r = 0;
-
if(o.x >= cx && o.x <= cx+size &&
o.y >= cy && o.y <= cy+size &&
- ((o.x != cx && o.x != cx+size) || (o.y != cy && o.y != cy+size)))
- {
+ ((o.x != cx && o.x != cx+size) || (o.y != cy && o.y != cy+size))) {
rvecs[0].x = o.x;
rvecs[0].y = o.y;
r++;
}
-
r += clipfacevecx(o, dir, cx, cy, size, rvecs[r]);
r += clipfacevecx(o, dir, cx, cy+size, size, rvecs[r]);
r += clipfacevecy(o, dir, cx, cy, size, rvecs[r]);
r += clipfacevecy(o, dir, cx+size, cy, size, rvecs[r]);
-
ASSERT(r <= 2);
return r;
}
-static inline bool insideface(const ivec2 *p, int nump, const ivec2 *o, int numo)
-{
+static inline bool insideface(const ivec2 *p, int nump, const ivec2 *o, int numo) {
int bounds = 0;
ivec2 prev = o[numo-1];
- loopi(numo)
- {
+ loopi(numo) {
const ivec2 &cur = o[i];
ivec2 dir(cur.x-prev.x, cur.y-prev.y);
int offset = dir.x*prev.y - dir.y*prev.x;
return bounds>=3;
}
-static inline int clipfacevecs(const ivec2 *o, int numo, int cx, int cy, int size, ivec2 *rvecs)
-{
+static inline int clipfacevecs(const ivec2 *o, int numo, int cx, int cy, int size, ivec2 *rvecs) {
cx <<= 3;
cy <<= 3;
size <<= 3;
-
int r = 0;
ivec2 prev = o[numo-1];
- loopi(numo)
- {
+ loopi(numo) {
const ivec2 &cur = o[i];
r += clipfacevec(prev, ivec2(cur.x-prev.x, cur.y-prev.y), cx, cy, size, &rvecs[r]);
prev = cur;
return r;
}
-bool collapsedface(const cube &c, int orient)
-{
+bool collapsedface(const cube &c, int orient) {
int e0 = c.edges[faceedgesidx[orient][0]], e1 = c.edges[faceedgesidx[orient][1]],
e2 = c.edges[faceedgesidx[orient][2]], e3 = c.edges[faceedgesidx[orient][3]],
face = dimension(orient)*4,
ivec().cross(v2, v3.sub(v0)).iszero();
}
-static inline bool occludesface(const cube &c, int orient, const ivec &o, int size, const ivec &vo, int vsize, ushort vmat, ushort nmat, ushort matmask, const ivec2 *vf, int numv)
-{
+static inline bool occludesface(const cube &c, int orient, const ivec &o, int size, const ivec &vo, int vsize, ushort vmat, ushort nmat, ushort matmask, const ivec2 *vf, int numv) {
int dim = dimension(orient);
- if(!c.children)
- {
+ if(!c.children) {
if(nmat != MAT_AIR && (c.material&matmask) == nmat)
{
ivec2 nf[8];
int numo = genfacevecs(c, orient, o, size, false, of);
return numo >= 3 && insideface(cf, numc, of, numo);
}
-
size >>= 1;
int coord = dimcoord(orient);
- loopi(8) if(octacoord(dim, i) == coord)
- {
+ loopi(8) if(octacoord(dim, i) == coord) {
if(!occludesface(c.children[i], orient, ivec(i, o, size), size, vo, vsize, vmat, nmat, matmask, vf, numv)) return false;
}
-
return true;
}
-bool visibleface(const cube &c, int orient, const ivec &co, int size, ushort mat, ushort nmat, ushort matmask)
-{
- if(mat != MAT_AIR)
- {
+bool visibleface(const cube &c, int orient, const ivec &co, int size, ushort mat, ushort nmat, ushort matmask) {
+ if(mat != MAT_AIR) {
if(faceedges(c, orient)==F_SOLID && touchingface(c, orient)) return false;
}
- else
- {
+ else {
if(collapsedface(c, orient)) return false;
if(!touchingface(c, orient)) return true;
}
-
ivec no;
int nsize;
const cube &o = neighbourcube(c, orient, co, size, no, nsize);
if(&o==&c) return false;
-
int opp = opposite(orient);
- if(nsize > size || (nsize == size && !o.children))
- {
+ if(nsize > size || (nsize == size && !o.children)) {
if(nmat != MAT_AIR && (o.material&matmask) == nmat) return true;
if(isentirelysolid(o)) return false;
if(isempty(o) || notouchingface(o, opp)) return true;
if(touchingface(o, opp) && faceedges(o, opp) == F_SOLID) return false;
-
ivec vo = ivec(co).mask(0xFFF);
no.mask(0xFFF);
ivec2 cf[4], of[4];
return numo < 3 || !insideface(cf, numc, of, numo);
}
-
ivec vo = ivec(co).mask(0xFFF);
no.mask(0xFFF);
ivec2 cf[4];
return !occludesface(o, opp, no, nsize, vo, size, mat, nmat, matmask, cf, numc);
}
-int classifyface(const cube &c, int orient, const ivec &co, int size)
-{
+int classifyface(const cube &c, int orient, const ivec &co, int size) {
if(collapsedface(c, orient)) return 0;
int vismask = (c.material&MATF_CLIP) == MAT_NOCLIP ? 1 : 3;
if(!touchingface(c, orient)) return vismask;
-
ivec no;
int nsize;
const cube &o = neighbourcube(c, orient, co, size, no, nsize);
if(&o==&c) return 0;
-
int vis = 0, opp = opposite(orient);
- if(nsize > size || (nsize == size && !o.children))
- {
+ if(nsize > size || (nsize == size && !o.children)) {
if((~c.material & o.material) & MAT_ALPHA) vis |= 1;
if((o.material&MATF_CLIP) == MAT_NOCLIP) vis |= vismask&2;
if(vis == vismask || isentirelysolid(o)) return vis;
if(isempty(o) || notouchingface(o, opp)) return vismask;
if(touchingface(o, opp) && faceedges(o, opp) == F_SOLID) return vis;
-
ivec vo = ivec(co).mask(0xFFF);
no.mask(0xFFF);
ivec2 cf[4], of[4];
if(numo < 3 || !insideface(cf, numc, of, numo)) return vismask;
return vis;
}
-
ivec vo = ivec(co).mask(0xFFF);
no.mask(0xFFF);
ivec2 cf[4];
}
// more expensive version that checks both triangles of a face independently
-int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat, ushort matmask)
-{
+int visibletris(const cube &c, int orient, const ivec &co, int size, ushort nmat, ushort matmask) {
int vis = 3, touching = 0xF;
ivec v[4], e1, e2, e3, n;
genfaceverts(c, orient, v);
n.cross((e1 = v[1]).sub(v[0]), (e2 = v[2]).sub(v[0]));
int convex = (e3 = v[0]).sub(v[3]).dot(n);
- if(!convex)
- {
+ if(!convex) {
if(ivec().cross(e3, e2).iszero() || v[1] == v[3]) { if(n.iszero()) return 0; vis = 1; touching = 0xF&~(1<<3); }
else if(n.iszero()) { vis = 2; touching = 0xF&~(1<<1); }
}
-
int dim = dimension(orient), coord = dimcoord(orient);
if(v[0][dim] != coord*8) touching &= ~(1<<0);
if(v[1][dim] != coord*8) touching &= ~(1<<1);
if(v[2][dim] != coord*8) touching &= ~(1<<2);
if(v[3][dim] != coord*8) touching &= ~(1<<3);
- static const int notouchmasks[2][16] = // mask of triangles not touching
- { // order 0: flat or convex
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- { 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 1, 3, 0 },
- // order 1: concave
- { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 0 },
+ static const int notouchmasks[2][16] = { // mask of triangles not touching {
+ // order 0: flat or convex
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 {
+ { 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 1, 3, 0 },
+ // order 1: concave {
+ { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 0 },
};
int order = convex < 0 ? 1 : 0, notouch = notouchmasks[order][touching];
if((vis¬ouch)==vis) return vis;
-
ivec no;
int nsize;
const cube &o = neighbourcube(c, orient, co, size, no, nsize);
if(&o==&c) return 0;
-
if((c.material&matmask) == nmat) nmat = MAT_AIR;
-
ivec vo = ivec(co).mask(0xFFF);
no.mask(0xFFF);
ivec2 cf[4], of[4];
int opp = opposite(orient), numo = 0, numc;
- if(nsize > size || (nsize == size && !o.children))
- {
+ if(nsize > size || (nsize == size && !o.children)) {
if(isempty(o) || notouchingface(o, opp)) return vis;
if(nmat != MAT_AIR && (o.material&matmask) == nmat) return vis;
if(isentirelysolid(o) || (touchingface(o, opp) && faceedges(o, opp) == F_SOLID)) return vis¬ouch;
-
numc = genfacevecs(c, orient, vo, size, false, cf, v);
numo = genfacevecs(o, opp, no, nsize, false, of);
if(numo < 3) return vis;
if(insideface(cf, numc, of, numo)) return vis¬ouch;
}
- else
- {
+ else {
numc = genfacevecs(c, orient, vo, size, false, cf, v);
if(occludesface(o, opp, no, nsize, vo, size, MAT_AIR, nmat, matmask, cf, numc)) return vis¬ouch;
}
if(vis != 3 || notouch) return vis;
-
- static const int triverts[2][2][2][3] =
- { // order
- { // coord
- { { 1, 2, 3 }, { 0, 1, 3 } }, // verts
- { { 0, 1, 2 }, { 0, 2, 3 } }
- },
- { // coord
- { { 0, 1, 2 }, { 3, 0, 2 } }, // verts
- { { 1, 2, 3 }, { 1, 3, 0 } }
+ static const int triverts[2][2][2][3] = {
+ // order {
+ // coord {
+ {
+ { { 1, 2, 3 }, { 0, 1, 3 } }, // verts {
+ { { 0, 1, 2 }, { 0, 2, 3 } }
+ }, {
+ // coord {
+ { { 0, 1, 2 }, { 3, 0, 2 } }, // verts {
+ { { 1, 2, 3 }, { 1, 3, 0 } }
}
};
-
- do
- {
- loopi(2)
- {
+ do {
+ loopi(2) {
const int *verts = triverts[order][coord][i];
ivec2 tf[3] = { cf[verts[0]], cf[verts[1]], cf[verts[2]] };
if(numo > 0) { if(!insideface(tf, 3, of, numo)) continue; }
}
vis |= 4;
} while(++order <= 1);
-
return 3;
}
-void calcvert(const cube &c, const ivec &co, int size, ivec &v, int i, bool solid)
-{
+void calcvert(const cube &c, const ivec &co, int size, ivec &v, int i, bool solid) {
if(solid) v = cubecoords[i]; else gencubevert(c, i, v);
// avoid overflow
if(size>=8) v.mul(size/8);
v.add(ivec(co).shl(3));
}
-void calcvert(const cube &c, const ivec &co, int size, vec &v, int i, bool solid)
-{
+void calcvert(const cube &c, const ivec &co, int size, vec &v, int i, bool solid) {
if(solid) v = vec(cubecoords[i]); else gencubevert(c, i, v);
v.mul(size/8.0f).add(vec(co));
}
-int genclipplane(const cube &c, int orient, vec *v, plane *clip)
-{
+int genclipplane(const cube &c, int orient, vec *v, plane *clip) {
int planes = 0, convex = faceconvexity(c, orient), order = convex < 0 ? 1 : 0;
const vec &v0 = v[fv[orient][order]], &v1 = v[fv[orient][order+1]], &v2 = v[fv[orient][order+2]], &v3 = v[fv[orient][(order+3)&3]];
if(v0==v2) return 0;
return planes;
}
-void genclipplanes(const cube &c, const ivec &co, int size, clipplanes &p, bool collide)
-{
+void genclipplanes(const cube &c, const ivec &co, int size, clipplanes &p, bool collide) {
// generate tight bounding box
calcvert(c, co, size, p.v[0], 0);
vec mx = p.v[0], mn = p.v[0];
- for(int i = 1; i < 8; i++)
- {
+ for(int i = 1; i < 8; i++) {
calcvert(c, co, size, p.v[i], i);
mx.max(p.v[i]);
mn.min(p.v[i]);
}
-
p.r = mx.sub(mn).mul(0.5f);
p.o = mn.add(p.r);
-
p.size = 0;
p.visible = 0;
- if(collide || (c.visible&0xC0) == 0x40)
- {
- loopi(6) if(c.visible&(1<<i))
- {
+ if(collide || (c.visible&0xC0) == 0x40) {
+ loopi(6) if(c.visible&(1<<i)) {
int vis;
if(flataxisface(c, i)) p.visible |= 1<<i;
- else if((vis = visibletris(c, i, co, size, MAT_NOCLIP, MATF_CLIP)))
- {
+ else if((vis = visibletris(c, i, co, size, MAT_NOCLIP, MATF_CLIP))) {
int convex = faceconvexity(c, i), order = vis&4 || convex < 0 ? 1 : 0;
const vec &v0 = p.v[fv[i][order]], &v1 = p.v[fv[i][order+1]], &v2 = p.v[fv[i][order+2]], &v3 = p.v[fv[i][(order+3)&3]];
if(vis&1) { p.side[p.size] = i; p.p[p.size++].toplane(v0, v1, v2); }
}
}
}
- else if(c.visible&0x80)
- {
+ else if(c.visible&0x80) {
int vis;
- loopi(6) if((vis = visibletris(c, i, co, size)))
- {
+ loopi(6) if((vis = visibletris(c, i, co, size))) {
if(flataxisface(c, i)) p.visible |= 1<<i;
- else
- {
+ else {
int convex = faceconvexity(c, i), order = vis&4 || convex < 0 ? 1 : 0;
const vec &v0 = p.v[fv[i][order]], &v1 = p.v[fv[i][order+1]], &v2 = p.v[fv[i][order+2]], &v3 = p.v[fv[i][(order+3)&3]];
if(vis&1) { p.side[p.size] = i; p.p[p.size++].toplane(v0, v1, v2); }
}
}
-static inline bool mergefacecmp(const facebounds &x, const facebounds &y)
-{
+static inline bool mergefacecmp(const facebounds &x, const facebounds &y) {
if(x.v2 < y.v2) return true;
if(x.v2 > y.v2) return false;
if(x.u1 < y.u1) return true;
return false;
}
-static int mergefacev(int orient, facebounds *m, int sz, facebounds &n)
-{
- for(int i = sz-1; i >= 0; --i)
- {
+static int mergefacev(int orient, facebounds *m, int sz, facebounds &n) {
+ for(int i = sz-1; i >= 0; --i) {
if(m[i].v2 < n.v1) break;
- if(m[i].v2 == n.v1 && m[i].u1 == n.u1 && m[i].u2 == n.u2)
- {
+ if(m[i].v2 == n.v1 && m[i].u1 == n.u1 && m[i].u2 == n.u2) {
n.v1 = m[i].v1;
memmove(&m[i], &m[i+1], (sz - (i+1)) * sizeof(facebounds));
return 1;
return 0;
}
-static int mergefaceu(int orient, facebounds &m, facebounds &n)
-{
- if(m.v1 == n.v1 && m.v2 == n.v2 && m.u2 == n.u1)
- {
+static int mergefaceu(int orient, facebounds &m, facebounds &n) {
+ if(m.v1 == n.v1 && m.v2 == n.v2 && m.u2 == n.u1) {
n.u1 = m.u1;
return 1;
}
return 0;
}
-static int mergeface(int orient, facebounds *m, int sz, facebounds &n)
-{
- for(bool merged = false; sz; merged = true)
- {
+static int mergeface(int orient, facebounds *m, int sz, facebounds &n) {
+ for(bool merged = false; sz; merged = true) {
int vmerged = mergefacev(orient, m, sz, n);
sz -= vmerged;
if(!vmerged && merged) break;
return sz;
}
-int mergefaces(int orient, facebounds *m, int sz)
-{
+int mergefaces(int orient, facebounds *m, int sz) {
quicksort(m, sz, mergefacecmp);
-
int nsz = 0;
loopi(sz) nsz = mergeface(orient, m, nsz, m[i]);
return nsz;
}
-struct cfkey
-{
+struct cfkey {
uchar orient;
ushort material, tex;
ivec n;
int offset;
};
-static inline bool htcmp(const cfkey &x, const cfkey &y)
-{
+static inline bool htcmp(const cfkey &x, const cfkey &y) {
return x.orient == y.orient && x.tex == y.tex && x.n == y.n && x.offset == y.offset && x.material==y.material;
}
-static inline uint hthash(const cfkey &k)
-{
+static inline uint hthash(const cfkey &k) {
return hthash(k.n)^k.offset^k.tex^k.orient^k.material;
}
-void mincubeface(const cube &cu, int orient, const ivec &o, int size, const facebounds &orig, facebounds &cf, ushort nmat, ushort matmask)
-{
+void mincubeface(const cube &cu, int orient, const ivec &o, int size, const facebounds &orig, facebounds &cf, ushort nmat, ushort matmask) {
int dim = dimension(orient);
- if(cu.children)
- {
+ if(cu.children) {
size >>= 1;
int coord = dimcoord(orient);
loopi(8) if(octacoord(dim, i) == coord)
uc2 = min(uc2, orig.u2);
vc1 = max(vc1, orig.v1);
vc2 = min(vc2, orig.v2);
- if(!isempty(cu) && touchingface(cu, orient) && !(nmat!=MAT_AIR && (cu.material&matmask)==nmat))
- {
+ if(!isempty(cu) && touchingface(cu, orient) && !(nmat!=MAT_AIR && (cu.material&matmask)==nmat)) {
uchar r1 = cu.edges[faceedgesidx[orient][0]], r2 = cu.edges[faceedgesidx[orient][1]],
c1 = cu.edges[faceedgesidx[orient][2]], c2 = cu.edges[faceedgesidx[orient][3]];
ushort u1 = max(c1&0xF, c2&0xF)*size+uco, u2 = min(c1>>4, c2>>4)*size+uco,
u2 = min(u2, orig.u2);
v1 = max(v1, orig.v1);
v2 = min(v2, orig.v2);
- if(v2-v1==vc2-vc1)
- {
+ if(v2-v1==vc2-vc1) {
if(u2-u1==uc2-uc1) return;
if(u1==uc1) uc1 = u2;
if(u2==uc2) uc2 = u1;
}
- else if(u2-u1==uc2-uc1)
- {
+ else if(u2-u1==uc2-uc1) {
if(v1==vc1) vc1 = v2;
if(v2==vc2) vc2 = v1;
}
cf.v2 = max(cf.v2, vc2);
}
-bool mincubeface(const cube &cu, int orient, const ivec &co, int size, facebounds &orig)
-{
+bool mincubeface(const cube &cu, int orient, const ivec &co, int size, facebounds &orig) {
ivec no;
int nsize;
const cube &nc = neighbourcube(cu, orient, co, size, no, nsize);
VAR(maxmerge, 0, 6, 12);
VAR(minface, 0, 4, 12);
-struct pvert
-{
+struct pvert {
ushort x, y;
-
pvert() {}
pvert(ushort x, ushort y) : x(x), y(y) {}
-
bool operator==(const pvert &o) const { return x == o.x && y == o.y; }
bool operator!=(const pvert &o) const { return x != o.x || y != o.y; }
};
-struct pedge
-{
+struct pedge {
pvert from, to;
-
pedge() {}
pedge(const pvert &from, const pvert &to) : from(from), to(to) {}
-
bool operator==(const pedge &o) const { return from == o.from && to == o.to; }
bool operator!=(const pedge &o) const { return from != o.from || to != o.to; }
};
static inline uint hthash(const pedge &x) { return uint(x.from.x)^(uint(x.from.y)<<8); }
static inline bool htcmp(const pedge &x, const pedge &y) { return x == y; }
-struct poly
-{
+struct poly {
cube *c;
int numverts;
bool merged;
pvert verts[MAXFACEVERTS];
};
-bool clippoly(poly &p, const facebounds &b)
-{
+bool clippoly(poly &p, const facebounds &b) {
pvert verts1[MAXFACEVERTS+4], verts2[MAXFACEVERTS+4];
int numverts1 = 0, numverts2 = 0, px = p.verts[p.numverts-1].x, py = p.verts[p.numverts-1].y;
- loopi(p.numverts)
- {
+ loopi(p.numverts) {
int x = p.verts[i].x, y = p.verts[i].y;
- if(x < b.u1)
- {
+ if(x < b.u1) {
if(px > b.u2) verts1[numverts1++] = pvert(b.u2, y + ((y - py)*(b.u2 - x))/(x - px));
if(px > b.u1) verts1[numverts1++] = pvert(b.u1, y + ((y - py)*(b.u1 - x))/(x - px));
}
- else if(x > b.u2)
- {
+ else if(x > b.u2) {
if(px < b.u1) verts1[numverts1++] = pvert(b.u1, y + ((y - py)*(b.u1 - x))/(x - px));
if(px < b.u2) verts1[numverts1++] = pvert(b.u2, y + ((y - py)*(b.u2 - x))/(x - px));
}
- else
- {
- if(px < b.u1)
- {
+ else {
+ if(px < b.u1) {
if(x > b.u1) verts1[numverts1++] = pvert(b.u1, y + ((y - py)*(b.u1 - x))/(x - px));
}
else if(px > b.u2 && x < b.u2) verts1[numverts1++] = pvert(b.u2, y + ((y - py)*(b.u2 - x))/(x - px));
if(numverts1 < 3) return false;
px = verts1[numverts1-1].x;
py = verts1[numverts1-1].y;
- loopi(numverts1)
- {
+ loopi(numverts1) {
int x = verts1[i].x, y = verts1[i].y;
- if(y < b.v1)
- {
+ if(y < b.v1) {
if(py > b.v2) verts2[numverts2++] = pvert(x + ((x - px)*(b.v2 - y))/(y - py), b.v2);
if(py > b.v1) verts2[numverts2++] = pvert(x + ((x - px)*(b.v1 - y))/(y - py), b.v1);
}
- else if(y > b.v2)
- {
+ else if(y > b.v2) {
if(py < b.v1) verts2[numverts2++] = pvert(x + ((x - px)*(b.v1 - y))/(y - py), b.v1);
if(py < b.v2) verts2[numverts2++] = pvert(x + ((x - px)*(b.v2 - y))/(y - py), b.v2);
}
- else
- {
- if(py < b.v1)
- {
+ else {
+ if(py < b.v1) {
if(y > b.v1) verts2[numverts2++] = pvert(x + ((x - px)*(b.v1 - y))/(y - py), b.v1);
}
else if(py > b.v2 && y < b.v2) verts2[numverts2++] = pvert(x + ((x - px)*(b.v2 - y))/(y - py), b.v2);
return true;
}
-bool genpoly(cube &cu, int orient, const ivec &o, int size, int vis, ivec &n, int &offset, poly &p)
-{
+bool genpoly(cube &cu, int orient, const ivec &o, int size, int vis, ivec &n, int &offset, poly &p) {
int dim = dimension(orient), coord = dimcoord(orient);
ivec v[4];
genfaceverts(cu, orient, v);
- if(flataxisface(cu, orient))
- {
+ if(flataxisface(cu, orient)) {
n = ivec(0, 0, 0);
n[dim] = coord ? 1 : -1;
}
- else
- {
+ else {
if(faceconvexity(v)) return false;
n.cross(ivec(v[1]).sub(v[0]), ivec(v[2]).sub(v[0]));
if(n.iszero()) n.cross(ivec(v[2]).sub(v[0]), ivec(v[3]).sub(v[0]));
reduceslope(n);
}
-
ivec po = ivec(o).mask(0xFFF).shl(3);
loopk(4) v[k].mul(size).add(po);
offset = -n.dot(v[3]);
-
int r = R[dim], c = C[dim], order = vis&4 ? 1 : 0;
p.numverts = 0;
- if(coord)
- {
+ if(coord) {
const ivec &v0 = v[order]; p.verts[p.numverts++] = pvert(v0[c], v0[r]);
if(vis&1) { const ivec &v1 = v[order+1]; p.verts[p.numverts++] = pvert(v1[c], v1[r]); }
const ivec &v2 = v[order+2]; p.verts[p.numverts++] = pvert(v2[c], v2[r]);
if(vis&2) { const ivec &v3 = v[(order+3)&3]; p.verts[p.numverts++] = pvert(v3[c], v3[r]); }
}
- else
- {
+ else {
if(vis&2) { const ivec &v3 = v[(order+3)&3]; p.verts[p.numverts++] = pvert(v3[c], v3[r]); }
const ivec &v2 = v[order+2]; p.verts[p.numverts++] = pvert(v2[c], v2[r]);
if(vis&1) { const ivec &v1 = v[order+1]; p.verts[p.numverts++] = pvert(v1[c], v1[r]); }
const ivec &v0 = v[order]; p.verts[p.numverts++] = pvert(v0[c], v0[r]);
}
-
- if(faceedges(cu, orient)!=F_SOLID)
- {
+ if(faceedges(cu, orient)!=F_SOLID) {
int px = int(p.verts[p.numverts-2].x) - int(p.verts[p.numverts-3].x), py = int(p.verts[p.numverts-2].y) - int(p.verts[p.numverts-3].y),
cx = int(p.verts[p.numverts-1].x) - int(p.verts[p.numverts-2].x), cy = int(p.verts[p.numverts-1].y) - int(p.verts[p.numverts-2].y),
dir = px*cy - py*cx;
if(dir > 0) return false;
if(!dir) { if(p.numverts < 4) return false; p.verts[1] = p.verts[2]; p.verts[2] = p.verts[3]; p.numverts--; }
}
-
p.c = &cu;
p.merged = false;
-
- if(minface && size >= 1<<minface && touchingface(cu, orient))
- {
+ if(minface && size >= 1<<minface && touchingface(cu, orient)) {
facebounds b;
b.u1 = b.u2 = p.verts[0].x;
b.v1 = b.v2 = p.verts[0].y;
- for(int i = 1; i < p.numverts; i++)
- {
+ for(int i = 1; i < p.numverts; i++) {
const pvert &v = p.verts[i];
b.u1 = min(b.u1, v.x);
b.u2 = max(b.u2, v.x);
if(mincubeface(cu, orient, o, size, b) && clippoly(p, b))
p.merged = true;
}
-
return true;
}
-struct plink : pedge
-{
+struct plink : pedge {
int polys[2];
-
plink() { clear(); }
plink(const pedge &p) : pedge(p) { clear(); }
-
void clear() { polys[0] = polys[1] = -1; }
};
-bool mergepolys(int orient, hashset<plink> &links, vector<plink *> &queue, int owner, poly &p, poly &q, const pedge &e)
-{
+bool mergepolys(int orient, hashset<plink> &links, vector<plink *> &queue, int owner, poly &p, poly &q, const pedge &e) {
int pe = -1, qe = -1;
loopi(p.numverts) if(p.verts[i] == e.from) { pe = i; break; }
loopi(q.numverts) if(q.verts[i] == e.to) { qe = i; break; }
*/
pvert verts[2*MAXFACEVERTS];
int numverts = 0, index = pe+2; // starts at A = T+1, ends at F = T+p.numverts
- loopi(p.numverts-1)
- {
+ loopi(p.numverts-1) {
if(index >= p.numverts) index -= p.numverts;
verts[numverts++] = p.verts[index++];
}
index = qe+2; // starts at C = T+2 = F+1, ends at T = T+q.numverts
int px = int(verts[numverts-1].x) - int(verts[numverts-2].x), py = int(verts[numverts-1].y) - int(verts[numverts-2].y);
- loopi(q.numverts-1)
- {
+ loopi(q.numverts-1) {
if(index >= q.numverts) index -= q.numverts;
pvert &src = q.verts[index++];
int cx = int(src.x) - int(verts[numverts-1].x), cy = int(src.y) - int(verts[numverts-1].y),
dir = px*cy - py*cx;
if(dir > 0) return false;
if(!dir) numverts--;
-
if(numverts > MAXFACEVERTS) return false;
-
q.merged = true;
q.numverts = 0;
-
p.merged = true;
p.numverts = numverts;
memcpy(p.verts, verts, numverts*sizeof(pvert));
-
int prev = p.numverts-1;
- loopj(p.numverts)
- {
+ loopj(p.numverts) {
pedge e(p.verts[prev], p.verts[j]);
int order = e.from.x > e.to.x || (e.from.x == e.to.x && e.from.y > e.to.y) ? 1 : 0;
if(order) swap(e.from, e.to);
if(shouldqueue) queue.add(&l);
prev = j;
}
-
return true;
}
-void addmerge(cube &cu, int orient, const ivec &co, const ivec &n, int offset, poly &p)
-{
+void addmerge(cube &cu, int orient, const ivec &co, const ivec &n, int offset, poly &p) {
cu.merged |= 1<<orient;
- if(!p.numverts)
- {
+ if(!p.numverts) {
if(cu.ext) cu.ext->surfaces[orient] = ambientsurface;
return;
}
vertinfo verts[MAXFACEVERTS];
surf.numverts |= p.numverts;
int dim = dimension(orient), coord = dimcoord(orient), c = C[dim], r = R[dim];
- loopk(p.numverts)
- {
+ loopk(p.numverts) {
pvert &src = p.verts[coord ? k : p.numverts-1-k];
vertinfo &dst = verts[k];
ivec v;
v[dim] = -(offset + n[c]*src.x + n[r]*src.y)/n[dim];
dst.set(v);
}
- if(cu.ext)
- {
+ if(cu.ext) {
const surfaceinfo &oldsurf = cu.ext->surfaces[orient];
int numverts = oldsurf.numverts&MAXFACEVERTS;
- if(numverts == p.numverts)
- {
+ if(numverts == p.numverts) {
ivec v0 = verts[0].getxyz();
const vertinfo *oldverts = cu.ext->verts() + oldsurf.verts;
- loopj(numverts) if(v0 == oldverts[j].getxyz())
- {
- for(int k = 1; k < numverts; k++)
- {
+ loopj(numverts) if(v0 == oldverts[j].getxyz()) {
+ for(int k = 1; k < numverts; k++) {
if(++j >= numverts) j = 0;
if(verts[k].getxyz() != oldverts[j].getxyz()) goto nomatch;
}
setsurface(cu, orient, surf, verts, p.numverts);
}
-static inline void clearmerge(cube &c, int orient)
-{
- if(c.merged&(1<<orient))
- {
+static inline void clearmerge(cube &c, int orient) {
+ if(c.merged&(1<<orient)) {
c.merged &= ~(1<<orient);
if(c.ext) c.ext->surfaces[orient] = brightsurface;
}
}
-void addmerges(int orient, const ivec &co, const ivec &n, int offset, vector<poly> &polys)
-{
- loopv(polys)
- {
+void addmerges(int orient, const ivec &co, const ivec &n, int offset, vector<poly> &polys) {
+ loopv(polys) {
poly &p = polys[i];
if(p.merged) addmerge(*p.c, orient, co, n, offset, p);
else clearmerge(*p.c, orient);
}
}
-void mergepolys(int orient, const ivec &co, const ivec &n, int offset, vector<poly> &polys)
-{
+void mergepolys(int orient, const ivec &co, const ivec &n, int offset, vector<poly> &polys) {
if(polys.length() <= 1) { addmerges(orient, co, n, offset, polys); return; }
hashset<plink> links(polys.length() <= 32 ? 128 : 1024);
vector<plink *> queue;
- loopv(polys)
- {
+ loopv(polys) {
poly &p = polys[i];
int prev = p.numverts-1;
- loopj(p.numverts)
- {
+ loopj(p.numverts) {
pedge e(p.verts[prev], p.verts[j]);
int order = e.from.x > e.to.x || (e.from.x == e.to.x && e.from.y > e.to.y) ? 1 : 0;
if(order) swap(e.from, e.to);
}
}
vector<plink *> nextqueue;
- while(queue.length())
- {
- loopv(queue)
- {
+ while(queue.length()) {
+ loopv(queue) {
plink &l = *queue[i];
if(l.polys[0] >= 0 && l.polys[1] >= 0)
mergepolys(orient, links, nextqueue, l.polys[0], polys[l.polys[0]], polys[l.polys[1]], l);
static int genmergeprogress = 0;
-struct cfpolys
-{
+struct cfpolys {
vector<poly> polys;
};
static hashtable<cfkey, cfpolys> cpolys;
-void genmerges(cube *c = worldroot, const ivec &o = ivec(0, 0, 0), int size = worldsize>>1)
-{
+void genmerges(cube *c = worldroot, const ivec &o = ivec(0, 0, 0), int size = worldsize>>1) {
if((genmergeprogress++&0xFFF)==0) renderprogress(float(genmergeprogress)/allocnodes, "merging faces...");
neighbourstack[++neighbourdepth] = c;
- loopi(8)
- {
+ loopi(8) {
ivec co(i, o, size);
int vis;
if(c[i].children) genmerges(c[i].children, co, size>>1);
- else if(!isempty(c[i])) loopj(6) if((vis = visibletris(c[i], j, co, size)))
- {
+ else if(!isempty(c[i])) loopj(6) if((vis = visibletris(c[i], j, co, size))) {
cfkey k;
poly p;
- if(size < 1<<maxmerge && c != worldroot)
- {
- if(genpoly(c[i], j, co, size, vis, k.n, k.offset, p))
- {
+ if(size < 1<<maxmerge && c != worldroot) {
+ if(genpoly(c[i], j, co, size, vis, k.n, k.offset, p)) {
k.orient = j;
k.tex = c[i].texture[j];
k.material = c[i].material&MAT_ALPHA;
continue;
}
}
- else if(minface && size >= 1<<minface && touchingface(c[i], j))
- {
- if(genpoly(c[i], j, co, size, vis, k.n, k.offset, p) && p.merged)
- {
+ else if(minface && size >= 1<<minface && touchingface(c[i], j)) {
+ if(genpoly(c[i], j, co, size, vis, k.n, k.offset, p) && p.merged) {
addmerge(c[i], j, co, k.n, k.offset, p);
continue;
}
}
clearmerge(c[i], j);
}
- if((size == 1<<maxmerge || c == worldroot) && cpolys.numelems)
- {
- enumeratekt(cpolys, cfkey, key, cfpolys, val,
- {
+ if((size == 1<<maxmerge || c == worldroot) && cpolys.numelems) {
+ enumeratekt(cpolys, cfkey, key, cfpolys, val, {
mergepolys(key.orient, co, key.n, key.offset, val.polys);
});
cpolys.clear();
--neighbourdepth;
}
-int calcmergedsize(int orient, const ivec &co, int size, const vertinfo *verts, int numverts)
-{
+int calcmergedsize(int orient, const ivec &co, int size, const vertinfo *verts, int numverts) {
ushort x1 = verts[0].x, y1 = verts[0].y, z1 = verts[0].z,
x2 = x1, y2 = y1, z2 = z1;
- for(int i = 1; i < numverts; i++)
- {
+ for(int i = 1; i < numverts; i++) {
const vertinfo &v = verts[i];
x1 = min(x1, v.x);
x2 = max(x2, v.x);
ivec mo(co);
mo.mask(0xFFF);
mo.shl(3);
- while(bits<15)
- {
+ while(bits<15) {
mo.mask(~((1<<bits)-1));
if(mo.x <= x1 && mo.x + (1<<bits) >= x2 &&
mo.y <= y1 && mo.y + (1<<bits) >= y2 &&
return bits-3;
}
-static void invalidatemerges(cube &c)
-{
- if(c.merged)
- {
+static void invalidatemerges(cube &c) {
+ if(c.merged) {
brightencube(c);
c.merged = 0;
}
- if(c.ext)
- {
- if(c.ext->va)
- {
+ if(c.ext) {
+ if(c.ext->va) {
if(!(c.ext->va->hasmerges&(MERGE_PART | MERGE_ORIGIN))) return;
destroyva(c.ext->va);
c.ext->va = NULL;
static int invalidatedmerges = 0;
-void invalidatemerges(cube &c, const ivec &co, int size, bool msg)
-{
- if(msg && invalidatedmerges!=totalmillis)
- {
+void invalidatemerges(cube &c, const ivec &co, int size, bool msg) {
+ if(msg && invalidatedmerges!=totalmillis) {
renderprogress(0, "invalidating merged surfaces...");
invalidatedmerges = totalmillis;
}
invalidatemerges(c);
}
-void calcmerges()
-{
+void calcmerges() {
genmergeprogress = 0;
genmerges();
}
// 6-directional octree heightfield map format
-struct elementset
-{
+struct elementset {
ushort texture, lmid;
uchar dim, layer;
ushort length[2], minvert[2], maxvert[2];
};
-struct materialsurface
-{
+struct materialsurface {
ivec o;
ushort csize, rsize;
ushort material, skip;
uchar orient, visible;
- union
- {
+ union {
short index;
short depth;
};
- union
- {
+ union {
entity *light;
uchar ends;
};
};
-struct vertinfo
-{
+struct vertinfo {
ushort x, y, z, u, v, norm;
-
void setxyz(ushort a, ushort b, ushort c) { x = a; y = b; z = c; }
void setxyz(const ivec &v) { setxyz(v.x, v.y, v.z); }
void set(ushort a, ushort b, ushort c, ushort s = 0, ushort t = 0, ushort n = 0) { setxyz(a, b, c); u = s; v = t; norm = n; }
ivec getxyz() const { return ivec(x, y, z); }
};
-enum
-{
+enum {
LAYER_TOP = (1<<5),
LAYER_BOTTOM = (1<<6),
LAYER_DUP = (1<<7),
-
LAYER_BLEND = LAYER_TOP|LAYER_BOTTOM,
-
MAXFACEVERTS = 15
};
enum { LMID_AMBIENT = 0, LMID_AMBIENT1, LMID_BRIGHT, LMID_BRIGHT1, LMID_DARK, LMID_DARK1, LMID_RESERVED };
-struct surfaceinfo
-{
+struct surfaceinfo {
uchar lmid[2];
uchar verts, numverts;
-
int totalverts() const { return numverts&LAYER_DUP ? (numverts&MAXFACEVERTS)*2 : numverts&MAXFACEVERTS; }
bool used() const { return lmid[0] != LMID_AMBIENT || lmid[1] != LMID_AMBIENT || numverts&~LAYER_TOP; }
void clear() { lmid[0] = LMID_AMBIENT; lmid[1] = LMID_AMBIENT; numverts = (numverts&MAXFACEVERTS) | LAYER_TOP; }
static const surfaceinfo brightsurface = {{LMID_BRIGHT, LMID_AMBIENT}, 0, LAYER_TOP};
static const surfaceinfo brightbottomsurface = {{LMID_AMBIENT, LMID_BRIGHT}, 0, LAYER_BOTTOM};
-struct occludequery
-{
+struct occludequery {
void *owner;
GLuint id;
int fragments;
struct vtxarray;
-struct octaentities
-{
+struct octaentities {
vector<int> mapmodels;
vector<int> other;
occludequery *query;
ivec o;
int size;
ivec bbmin, bbmax;
-
- octaentities(const ivec &o, int size) : query(0), o(o), size(size), bbmin(o), bbmax(o)
- {
+ octaentities(const ivec &o, int size) : query(0), o(o), size(size), bbmin(o), bbmax(o) {
bbmin.add(size);
}
};
-enum
-{
+enum {
OCCLUDE_NOTHING = 0,
OCCLUDE_GEOM,
OCCLUDE_BB,
OCCLUDE_PARENT
};
-enum
-{
+enum {
MERGE_ORIGIN = 1<<0,
MERGE_PART = 1<<1,
MERGE_USE = 1<<2
};
-struct vtxarray
-{
+struct vtxarray {
vtxarray *parent;
vector<vtxarray *> children;
vtxarray *next, *rnext; // linked list of visible VOBs
struct cube;
-struct clipplanes
-{
+struct clipplanes {
vec o, r, v[8];
plane p[12];
uchar side[12];
int version;
};
-struct facebounds
-{
+struct facebounds {
ushort u1, u2, v1, v2;
-
bool empty() const { return u1 >= u2 || v1 >= v2; }
};
-struct tjoint
-{
+struct tjoint {
int next;
ushort offset;
uchar edge;
};
-struct cubeext
-{
+struct cubeext {
vtxarray *va; // vertex array for children, or NULL
octaentities *ents; // map entities inside cube
surfaceinfo surfaces[6]; // render info for each surface
int tjoints; // linked list of t-joints
uchar maxverts; // allocated space for verts
-
vertinfo *verts() { return (vertinfo *)(this+1); }
};
-struct cube
-{
+struct cube {
cube *children; // points to 8 cube structures which are its children, or NULL. -Z first, then -Y, -X
cubeext *ext; // extended info for the cube
- union
- {
+ union {
uchar edges[12]; // edges of the cube, each uchar is 2 4bit values denoting the range.
// see documentation jpgs for more info.
uint faces[3]; // 4 edges of each dimension together representing 2 perpendicular faces
ushort texture[6]; // one for each face. same order as orient.
ushort material; // empty-space material
uchar merged; // merged faces of the cube
- union
- {
+ union {
uchar escaped; // mask of which children have escaped merges
uchar visible; // visibility info for faces
};
};
-struct block3
-{
+struct block3 {
ivec o, s;
int grid, orient;
block3() {}
block3(const selinfo &sel) : o(sel.o), s(sel.s), grid(sel.grid), orient(sel.orient) {}
- cube *c() { return (cube *)(this+1); }
+ cube *c() { return (cube *)(this+1); }
int size() const { return s.x*s.y*s.z; }
};
-struct editinfo
-{
+struct editinfo {
block3 *copy;
editinfo() : copy(NULL) {}
};
-struct undoent { int i; entity e; };
-struct undoblock // undo header, all data sits in payload
-{
+struct undoent { int i; entity e; };
+struct undoblock { // undo header, all data sits in payload {
undoblock *prev, *next;
int size, timestamp, numents; // if numents is 0, is a cube undo record, otherwise an entity undo record
-
block3 *block() { return (block3 *)(this + 1); }
- uchar *gridmap()
- {
+ uchar *gridmap() {
block3 *ub = block();
return (uchar *)(ub->c() + ub->size());
}
#define octaindex(d,x,y,z) (((z)<<D[d])+((y)<<C[d])+((x)<<R[d]))
#define octastep(x, y, z, scale) (((((z)>>(scale))&1)<<2) | ((((y)>>(scale))&1)<<1) | (((x)>>(scale))&1))
-static inline uchar octaboxoverlap(const ivec &o, int size, const ivec &bbmin, const ivec &bbmax)
-{
+static inline uchar octaboxoverlap(const ivec &o, int size, const ivec &bbmin, const ivec &bbmax) {
uchar p = 0xFF; // bitmask of possible collisions with octants. 0 bit = 0 octant, etc
ivec mid = ivec(o).add(size);
if(mid.z <= bbmin.z) p &= 0xF0; // not in a -ve Z octant
#define loopoctabox(o, size, bbmin, bbmax) uchar possible = octaboxoverlap(o, size, bbmin, bbmax); loopi(8) if(possible&(1<<i))
#define loopoctaboxsize(o, size, bborigin, bbsize) uchar possible = octaboxoverlap(o, size, bborigin, ivec(bborigin).add(bbsize)); loopi(8) if(possible&(1<<i))
-enum
-{
+enum {
O_LEFT = 0,
O_RIGHT,
O_BACK,
#define dimcoord(orient) ((orient)&1)
#define opposite(orient) ((orient)^1)
-enum
-{
+enum {
VFC_FULL_VISIBLE = 0,
VFC_PART_VISIBLE,
VFC_NOT_VISIBLE,
bool boxoutline = false;
-void boxs(int orient, vec o, const vec &s, float size)
-{
+void boxs(int orient, vec o, const vec &s, float size) {
int d = dimension(orient), dc = dimcoord(orient);
float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0;
o[D[d]] += dc * s[D[d]] + f;
-
vec r(0, 0, 0), c(0, 0, 0);
r[R[d]] = s[R[d]];
c[C[d]] = s[C[d]];
-
vec v1 = o, v2 = vec(o).add(r), v3 = vec(o).add(r).add(c), v4 = vec(o).add(c);
-
r[R[d]] = 0.5f*size;
c[C[d]] = 0.5f*size;
-
gle::defvertex();
gle::begin(GL_TRIANGLE_STRIP);
gle::attrib(vec(v1).sub(r).sub(c));
xtraverts += gle::end();
}
-void boxs(int orient, vec o, const vec &s)
-{
+void boxs(int orient, vec o, const vec &s) {
int d = dimension(orient), dc = dimcoord(orient);
float f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0;
o[D[d]] += dc * s[D[d]] + f;
-
gle::defvertex();
gle::begin(GL_LINE_LOOP);
-
gle::attrib(o); o[R[d]] += s[R[d]];
gle::attrib(o); o[C[d]] += s[C[d]];
gle::attrib(o); o[R[d]] -= s[R[d]];
gle::attrib(o);
-
xtraverts += gle::end();
}
-void boxs3D(const vec &o, vec s, int g)
-{
+void boxs3D(const vec &o, vec s, int g) {
s.mul(g);
loopi(6)
boxs(i, o, s);
}
-void boxsgrid(int orient, vec o, vec s, int g)
-{
+void boxsgrid(int orient, vec o, vec s, int g) {
int d = dimension(orient), dc = dimcoord(orient);
float ox = o[R[d]],
oy = o[C[d]],
xs = s[R[d]],
ys = s[C[d]],
f = boxoutline ? (dc>0 ? 0.2f : -0.2f) : 0;
-
o[D[d]] += dc * s[D[d]]*g + f;
-
gle::defvertex();
gle::begin(GL_LINES);
- loop(x, xs)
- {
+ loop(x, xs) {
o[R[d]] += g;
gle::attrib(o);
o[C[d]] += ys*g;
gle::attrib(o);
o[C[d]] = oy;
}
- loop(y, ys)
- {
+ loop(y, ys) {
o[C[d]] += g;
o[R[d]] = ox;
gle::attrib(o);
);
int moving = 0;
-ICOMMAND(moving, "b", (int *n),
-{
- if(*n >= 0)
- {
+ICOMMAND(moving, "b", (int *n), {
+ if(*n >= 0) {
if(!*n || (moving<=1 && !pointinsel(sel, vec(cur).add(1)))) moving = 0;
else if(!moving) moving = 1;
}
intret(moving);
});
-VARF(gridpower, 0, 3, 12,
-{
+VARF(gridpower, 0, 3, 12, {
if(dragging) return;
gridsize = 1<<gridpower;
if(gridsize>=worldsize) gridsize = worldsize/2;
void forcenextundo() { lastsel.orient = -1; }
-void cubecancel()
-{
+void cubecancel() {
havesel = false;
moving = dragging = passthroughsel = 0;
forcenextundo();
}
-void cancelsel()
-{
+void cancelsel() {
cubecancel();
entcancel();
}
-void toggleedit(bool force)
-{
- if(!force)
- {
+void toggleedit(bool force) {
+ if(!force) {
if(!isconnected()) return;
if(player->state!=CS_ALIVE && player->state!=CS_DEAD && player->state!=CS_EDITING) return; // do not allow dead players to edit to avoid state confusion
if(!game::allowedittoggle()) return; // not in most multiplayer modes
}
- if(!(editmode = !editmode))
- {
+ if(!(editmode = !editmode)) {
player->state = player->editstate;
player->o.z -= player->eyeheight; // entinmap wants feet pos
entinmap(player); // find spawn closest to current floating pos
}
- else
- {
+ else {
game::resetgamestate();
player->editstate = player->state;
player->state = CS_EDITING;
VARP(editinview, 0, 1, 1);
-bool noedit(bool view, bool msg)
-{
+bool noedit(bool view, bool msg) {
if(!editmode) { if(msg) conoutf(CON_ERROR, "operation only allowed in edit mode"); return true; }
if(view || haveselent()) return false;
float r = 1.0f;
return true;
}
-void reorient()
-{
+void reorient() {
sel.cx = 0;
sel.cy = 0;
sel.cxs = sel.s[R[dimension(orient)]]*2;
sel.orient = orient;
}
-void selextend()
-{
+void selextend() {
if(noedit(true)) return;
- loopi(3)
- {
- if(cur[i]<sel.o[i])
- {
+ loopi(3) {
+ if(cur[i]<sel.o[i]) {
sel.s[i] += (sel.o[i]-cur[i])/sel.grid;
sel.o[i] = cur[i];
}
- else if(cur[i]>=sel.o[i]+sel.s[i]*sel.grid)
- {
+ else if(cur[i]>=sel.o[i]+sel.s[i]*sel.grid) {
sel.s[i] = (cur[i]-sel.o[i])/sel.grid+1;
}
}
ICOMMAND(selrestore, "", (), { if(noedit(true)) return; sel = savedsel; });
ICOMMAND(selswap, "", (), { if(noedit(true)) return; swap(sel, savedsel); });
-ICOMMAND(getselpos, "", (),
-{
+ICOMMAND(getselpos, "", (), {
if(noedit(true)) return;
defformatstring(pos, "%s %s %s", floatstr(sel.o.x), floatstr(sel.o.y), floatstr(sel.o.z));
result(pos);
});
-void setselpos(int *x, int *y, int *z)
-{
+void setselpos(int *x, int *y, int *z) {
if(noedit(moving!=0)) return;
havesel = true;
sel.o = ivec(*x, *y, *z).mask(~(gridsize-1));
}
COMMAND(setselpos, "iii");
-void movesel(int *dir, int *dim)
-{
+void movesel(int *dir, int *dim) {
if(noedit(moving!=0)) return;
if(*dim < 0 || *dim > 2) return;
sel.o[*dim] += *dir * sel.grid;
///////// selection support /////////////
-cube &blockcube(int x, int y, int z, const block3 &b, int rgrid) // looks up a world cube, based on coordinates mapped by the block
-{
+cube &blockcube(int x, int y, int z, const block3 &b, int rgrid) { // looks up a world cube, based on coordinates mapped by the block {
int dim = dimension(b.orient), dc = dimcoord(b.orient);
ivec s(dim, x*b.grid, y*b.grid, dc*(b.s[dim]-1)*b.grid);
s.add(b.o);
ICOMMAND(havesel, "", (), intret(havesel ? selchildcount : 0));
-void countselchild(cube *c, const ivec &cor, int size)
-{
+void countselchild(cube *c, const ivec &cor, int size) {
ivec ss = ivec(sel.s).mul(sel.grid);
- loopoctaboxsize(cor, size, sel.o, ss)
- {
+ loopoctaboxsize(cor, size, sel.o, ss) {
ivec o(i, cor, size);
if(c[i].children) countselchild(c[i].children, o, size/2);
- else
- {
+ else {
selchildcount++;
- if(c[i].material != MAT_AIR && selchildmat != MAT_AIR)
- {
+ if(c[i].material != MAT_AIR && selchildmat != MAT_AIR) {
if(selchildmat < 0) selchildmat = c[i].material;
else if(selchildmat != c[i].material) selchildmat = MAT_AIR;
}
}
}
-void normalizelookupcube(const ivec &o)
-{
- if(lusize>gridsize)
- {
+void normalizelookupcube(const ivec &o) {
+ if(lusize>gridsize) {
lu.x += (o.x-lu.x)/gridsize*gridsize;
lu.y += (o.y-lu.y)/gridsize*gridsize;
lu.z += (o.z-lu.z)/gridsize*gridsize;
}
- else if(gridsize>lusize)
- {
+ else if(gridsize>lusize) {
lu.x &= ~(gridsize-1);
lu.y &= ~(gridsize-1);
lu.z &= ~(gridsize-1);
lusize = gridsize;
}
-void updateselection()
-{
+void updateselection() {
sel.o.x = min(lastcur.x, cur.x);
sel.o.y = min(lastcur.y, cur.y);
sel.o.z = min(lastcur.z, cur.z);
sel.s.z = abs(lastcur.z-cur.z)/sel.grid+1;
}
-bool editmoveplane(const vec &o, const vec &ray, int d, float off, vec &handle, vec &dest, bool first)
-{
+bool editmoveplane(const vec &o, const vec &ray, int d, float off, vec &handle, vec &dest, bool first) {
plane pl(d, off);
float dist = 0.0f;
if(!pl.rayintersect(player->o, ray, dist))
return false;
-
dest = vec(ray).mul(dist).add(player->o);
if(first) handle = vec(dest).sub(o);
dest.sub(handle);
extern void entdrag(const vec &ray);
extern bool hoveringonent(int ent, int orient);
-extern void renderentselection(const vec &o, const vec &ray, bool entmoving);
+extern void renderentselection(const vec &o, bool entmoving);
extern float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent);
VAR(gridlookup, 0, 0, 1);
VAR(passthroughent, 0, 1, 1);
VARF(passthrough, 0, 0, 1, { passthroughsel = passthrough; entcancel(); });
-void rendereditcursor()
-{
+void rendereditcursor() {
int d = dimension(sel.orient),
od = dimension(orient),
odc = dimcoord(orient);
-
bool hidecursor = g3d_windowhit(true, false), hovering = false;
-
- if(moving)
- {
+ if(moving) {
static vec dest, handle;
- if(editmoveplane(vec(sel.o), camdir, od, sel.o[D[od]]+odc*sel.grid*sel.s[D[od]], handle, dest, moving==1))
- {
- if(moving==1)
- {
+ if(editmoveplane(vec(sel.o), camdir, od, sel.o[D[od]]+odc*sel.grid*sel.s[D[od]], handle, dest, moving==1)) {
+ if(moving==1) {
dest.add(handle);
handle = vec(ivec(handle).mask(~(sel.grid-1)));
dest.sub(handle);
}
}
else
- if(entmoving)
- {
+ if(entmoving) {
entdrag(camdir);
}
- else
- {
+ else {
ivec w;
float sdist = 0, wdist = 0, t;
int entorient = 0, ent = -1;
-
wdist = rayent(player->o, camdir, 1e16f,
(editmode && showmat ? RAY_EDITMAT : 0) // select cubes first
| (!dragging && entediting && (!passthrough || !passthroughent) ? RAY_ENTS : 0)
| RAY_SKIPFIRST
| (passthroughcube || passthrough ? RAY_PASS : 0), gridsize, entorient, ent);
-
if((havesel || dragging) && !passthroughsel) // now try selecting the selection
- if(rayboxintersect(vec(sel.o), vec(sel.s).mul(sel.grid), player->o, camdir, sdist, orient))
- { // and choose the nearest of the two
- if(sdist < wdist)
- {
+ if(rayboxintersect(vec(sel.o), vec(sel.s).mul(sel.grid), player->o, camdir, sdist, orient)) {
+ // and choose the nearest of the two
+ if(sdist < wdist) {
wdist = sdist;
ent = -1;
}
}
-
- if((hovering = hoveringonent(hidecursor ? -1 : ent, entorient)))
- {
+ if((hovering = hoveringonent(hidecursor ? -1 : ent, entorient))) {
if(!havesel)
- {
+ {
selchildcount = 0;
selchildmat = -1;
sel.s = ivec(0, 0, 0);
}
}
- else
- {
+ else {
vec w = vec(camdir).mul(wdist+0.05f).add(player->o);
- if(!insideworld(w))
- {
+ if(!insideworld(w)) {
loopi(3) wdist = min(wdist, ((camdir[i] > 0 ? worldsize : 0) - player->o[i]) / camdir[i]);
w = vec(camdir).mul(wdist-0.05f).add(player->o);
- if(!insideworld(w))
- {
+ if(!insideworld(w)) {
wdist = 0;
loopi(3) w[i] = clamp(player->o[i], 0.0f, float(worldsize));
}
cor = ivec(vec(w).mul(2).div(gridsize));
od = dimension(orient);
d = dimension(sel.orient);
-
- if(dragging)
- {
+ if(dragging) {
updateselection();
sel.cx = min(cor[R[d]], lastcor[R[d]]);
sel.cy = min(cor[C[d]], lastcor[C[d]]);
sel.cxs = max(cor[R[d]], lastcor[R[d]]);
sel.cys = max(cor[C[d]], lastcor[C[d]]);
-
- if(!selectcorners)
- {
+ if(!selectcorners) {
sel.cx &= ~1;
sel.cy &= ~1;
sel.cxs &= ~1;
sel.cxs -= sel.cx-2;
sel.cys -= sel.cy-2;
}
- else
- {
+ else {
sel.cxs -= sel.cx-1;
sel.cys -= sel.cy-1;
}
-
sel.cx &= 1;
sel.cy &= 1;
havesel = true;
}
- else if(!havesel)
- {
+ else if(!havesel) {
sel.o = lu;
sel.s.x = sel.s.y = sel.s.z = 1;
sel.cx = sel.cy = 0;
sel.orient = orient;
d = od;
}
-
sel.corner = (cor[R[d]]-(lu[R[d]]*2)/gridsize)+(cor[C[d]]-(lu[C[d]]*2)/gridsize)*2;
selchildcount = 0;
selchildmat = -1;
countselchild(worldroot, ivec(0, 0, 0), worldsize/2);
- if(mag>=1 && selchildcount==1)
- {
+ if(mag>=1 && selchildcount==1) {
selchildmat = c->material;
if(mag>1) selchildcount = -mag;
}
}
}
-
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
-
// cursors
-
notextureshader->set();
-
- renderentselection(player->o, camdir, entmoving!=0);
-
+ renderentselection(player->o, entmoving!=0);
boxoutline = outline!=0;
-
enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
-
- if(!moving && !hovering && !hidecursor)
- {
+ if(!moving && !hovering && !hidecursor) {
gle::colorub(120,120,120);
boxs(orient, vec(lu), vec(lusize));
}
-
// selections
- if(havesel || moving)
- {
+ if(havesel || moving) {
d = dimension(sel.orient);
gle::colorub(50,50,50); // grid
boxsgrid(sel.orient, vec(sel.o), vec(sel.s), sel.grid);
gle::colorub(0,0,120);
boxs3D(vec(sel.o), vec(sel.s), sel.grid);
}
-
disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
-
boxoutline = false;
-
glDisable(GL_BLEND);
}
-void tryedit()
-{
+void tryedit() {
extern int hidehud;
if(!editmode || hidehud || mainmenu) return;
}
static bool haschanged = false;
-void readychanges(const ivec &bbmin, const ivec &bbmax, cube *c, const ivec &cor, int size)
-{
- loopoctabox(cor, size, bbmin, bbmax)
- {
+void readychanges(const ivec &bbmin, const ivec &bbmax, cube *c, const ivec &cor, int size) {
+ loopoctabox(cor, size, bbmin, bbmax) {
ivec o(i, cor, size);
- if(c[i].ext)
- {
- if(c[i].ext->va) // removes va s so that octarender will recreate
- {
+ if(c[i].ext) {
+ if(c[i].ext->va) { // removes va s so that octarender will recreate {
int hasmerges = c[i].ext->va->hasmerges;
destroyva(c[i].ext->va);
c[i].ext->va = NULL;
freeoctaentities(c[i]);
c[i].ext->tjoints = -1;
}
- if(c[i].children)
- {
- if(size<=1)
- {
+ if(c[i].children) {
+ if(size<=1) {
solidfaces(c[i]);
discardchildren(c[i], true);
brightencube(c[i]);
}
}
-void commitchanges(bool force)
-{
+void commitchanges(bool force) {
if(!force && !haschanged) return;
haschanged = false;
-
int oldlen = valist.length();
resetclipplanes();
entitiesinoctanodes();
updatevabbs();
}
-void changed(const block3 &sel, bool commit = true)
-{
+void changed(const block3 &sel, bool commit = true) {
if(sel.s.iszero()) return;
readychanges(ivec(sel.o).sub(1), ivec(sel.s).mul(sel.grid).add(sel.o).add(1), worldroot, ivec(0, 0, 0), worldsize/2);
haschanged = true;
-
if(commit) commitchanges();
}
//////////// copy and undo /////////////
-static inline void copycube(const cube &src, cube &dst)
-{
+static inline void copycube(const cube &src, cube &dst) {
dst = src;
dst.visible = 0;
dst.merged = 0;
dst.ext = NULL; // src cube is responsible for va destruction
- if(src.children)
- {
+ if(src.children) {
dst.children = newcubes(F_EMPTY);
loopi(8) copycube(src.children[i], dst.children[i]);
}
}
-static inline void pastecube(const cube &src, cube &dst)
-{
+static inline void pastecube(const cube &src, cube &dst) {
discardchildren(dst);
copycube(src, dst);
}
-void blockcopy(const block3 &s, int rgrid, block3 *b)
-{
+void blockcopy(const block3 &s, int rgrid, block3 *b) {
*b = s;
cube *q = b->c();
loopxyz(s, rgrid, copycube(c, *q++));
}
-block3 *blockcopy(const block3 &s, int rgrid)
-{
+block3 *blockcopy(const block3 &s, int rgrid) {
int bsize = sizeof(block3)+sizeof(cube)*s.size();
if(bsize <= 0 || bsize > (100<<20)) return NULL;
block3 *b = (block3 *)new (false) uchar[bsize];
return b;
}
-void freeblock(block3 *b, bool alloced = true)
-{
+void freeblock(block3 *b, bool alloced = true) {
cube *q = b->c();
loopi(b->size()) discardchildren(*q++);
if(alloced) delete[] b;
}
-void selgridmap(selinfo &sel, uchar *g) // generates a map of the cube sizes at each grid point
-{
+void selgridmap(selinfo &sel, uchar *g) { // generates a map of the cube sizes at each grid point {
loopxyz(sel, -sel.grid, (*g++ = bitscan(lusize), (void)c));
}
-void freeundo(undoblock *u)
-{
+void freeundo(undoblock *u) {
if(!u->numents) freeblock(u->block(), false);
delete[] (uchar *)u;
}
-void pasteundoblock(block3 *b, uchar *g)
-{
+void pasteundoblock(block3 *b, uchar *g) {
cube *s = b->c();
loopxyz(*b, 1<<min(int(*g++), worldscale-1), pastecube(*s++, c));
}
-void pasteundo(undoblock *u)
-{
+void pasteundo(undoblock *u) {
if(u->numents) pasteundoents(u);
else pasteundoblock(u->block(), u->gridmap());
}
-static inline int undosize(undoblock *u)
-{
+static inline int undosize(undoblock *u) {
if(u->numents) return u->numents*sizeof(undoent);
- else
- {
+ else {
block3 *b = u->block();
cube *q = b->c();
int size = b->size(), total = size;
}
}
-struct undolist
-{
+struct undolist {
undoblock *first, *last;
-
undolist() : first(NULL), last(NULL) {}
-
bool empty() { return !first; }
-
- void add(undoblock *u)
- {
+ void add(undoblock *u) {
u->next = NULL;
u->prev = last;
if(!first) first = last = u;
- else
- {
+ else {
last->next = u;
last = u;
}
}
-
- undoblock *popfirst()
- {
+ undoblock *popfirst() {
undoblock *u = first;
first = first->next;
if(first) first->prev = NULL;
else last = NULL;
return u;
}
-
- undoblock *poplast()
- {
+ undoblock *poplast() {
undoblock *u = last;
last = last->prev;
if(last) last->next = NULL;
VARP(undomegs, 0, 8, 100); // bounded by n megs
int totalundos = 0;
-void pruneundos(int maxremain) // bound memory
-{
- while(totalundos > maxremain && !undos.empty())
- {
+void pruneundos(int maxremain) { // bound memory {
+ while(totalundos > maxremain && !undos.empty()) {
undoblock *u = undos.popfirst();
totalundos -= u->size;
freeundo(u);
}
//conoutf(CON_DEBUG, "undo: %d of %d(%%%d)", totalundos, undomegs<<20, totalundos*100/(undomegs<<20));
- while(!redos.empty())
- {
+ while(!redos.empty()) {
undoblock *u = redos.popfirst();
totalundos -= u->size;
freeundo(u);
COMMAND(clearundos, "");
-undoblock *newundocube(selinfo &s)
-{
+undoblock *newundocube(selinfo &s) {
int ssize = s.size(),
selgridsize = ssize,
blocksize = sizeof(block3)+ssize*sizeof(cube);
return u;
}
-void addundo(undoblock *u)
-{
+void addundo(undoblock *u) {
u->size = undosize(u);
u->timestamp = totalmillis;
undos.add(u);
VARP(nompedit, 0, 1, 1);
-void makeundo(selinfo &s)
-{
+void makeundo(selinfo &s) {
undoblock *u = newundocube(s);
if(u) addundo(u);
}
-void makeundo() // stores state of selected cubes before editing
-{
+void makeundo() { // stores state of selected cubes before editing {
if(lastsel==sel || sel.s.iszero()) return;
lastsel=sel;
makeundo(sel);
}
-static inline int countblock(cube *c, int n = 8)
-{
+static inline int countblock(cube *c, int n = 8) {
int r = 0;
loopi(n) if(c[i].children) r += countblock(c[i].children); else ++r;
return r;
static int countblock(block3 *b) { return countblock(b->c(), b->size()); }
-void swapundo(undolist &a, undolist &b, int op)
-{
+void swapundo(undolist &a, undolist &b, int op) {
if(noedit()) return;
if(a.empty()) { conoutf(CON_WARN, "nothing more to %s", op == EDIT_REDO ? "redo" : "undo"); return; }
int ts = a.last->timestamp;
- if(multiplayer(false))
- {
+ if(multiplayer(false)) {
int n = 0, ops = 0;
- for(undoblock *u = a.last; u && ts==u->timestamp; u = u->prev)
- {
+ for(undoblock *u = a.last; u && ts==u->timestamp; u = u->prev) {
++ops;
n += u->numents ? u->numents : countblock(u->block());
- if(ops > 10 || n > 2500)
- {
+ if(ops > 10 || n > 2500) {
conoutf(CON_WARN, "undo too big for multiplayer");
if(nompedit) { multiplayer(); return; }
op = -1;
}
}
selinfo l = sel;
- while(!a.empty() && ts==a.last->timestamp)
- {
+ while(!a.empty() && ts==a.last->timestamp) {
if(op >= 0) game::edittrigger(sel, op);
undoblock *u = a.poplast(), *r;
if(u->numents) r = copyundoents(u);
- else
- {
+ else {
block3 *ub = u->block();
l.o = ub->o;
l.s = ub->s;
l.orient = ub->orient;
r = newundocube(l);
}
- if(r)
- {
+ if(r) {
r->size = u->size;
r->timestamp = totalmillis;
b.add(r);
editinfo *localedit = NULL;
template<class B>
-static void packcube(cube &c, B &buf)
-{
- if(c.children)
- {
+static void packcube(cube &c, B &buf) {
+ if(c.children) {
buf.put(0xFF);
loopi(8) packcube(c.children[i], buf);
}
- else
- {
+ else {
cube data = c;
lilswap(data.texture, 6);
buf.put(c.material&0xFF);
}
template<class B>
-static bool packblock(block3 &b, B &buf)
-{
+static bool packblock(block3 &b, B &buf) {
if(b.size() <= 0 || b.size() > (1<<20)) return false;
block3 hdr = b;
lilswap(hdr.o.v, 3);
return true;
}
-struct vslothdr
-{
+struct vslothdr {
ushort index;
ushort slot;
};
-static void packvslots(cube &c, vector<uchar> &buf, vector<ushort> &used)
-{
- if(c.children)
- {
+static void packvslots(cube &c, vector<uchar> &buf, vector<ushort> &used) {
+ if(c.children) {
loopi(8) packvslots(c.children[i], buf, used);
}
- else loopi(6)
- {
+ else loopi(6) {
ushort index = c.texture[i];
- if(vslots.inrange(index) && vslots[index]->changed && used.find(index) < 0)
- {
+ if(vslots.inrange(index) && vslots[index]->changed && used.find(index) < 0) {
used.add(index);
VSlot &vs = *vslots[index];
vslothdr &hdr = *(vslothdr *)buf.pad(sizeof(vslothdr));
}
}
-static void packvslots(block3 &b, vector<uchar> &buf)
-{
+static void packvslots(block3 &b, vector<uchar> &buf) {
vector<ushort> used;
cube *c = b.c();
loopi(b.size()) packvslots(c[i], buf, used);
}
template<class B>
-static void unpackcube(cube &c, B &buf)
-{
+static void unpackcube(cube &c, B &buf) {
int mat = buf.get();
- if(mat == 0xFF)
- {
+ if(mat == 0xFF) {
c.children = newcubes(F_EMPTY);
loopi(8) unpackcube(c.children[i], buf);
}
- else
- {
+ else {
c.material = mat | (buf.get()<<8);
buf.get(c.edges, sizeof(c.edges));
buf.get((uchar *)c.texture, sizeof(c.texture));
}
template<class B>
-static bool unpackblock(block3 *&b, B &buf)
-{
+static bool unpackblock(block3 *&b, B &buf) {
if(b) { freeblock(b); b = NULL; }
block3 hdr;
if(buf.get((uchar *)&hdr, sizeof(hdr)) < int(sizeof(hdr))) return false;
return true;
}
-struct vslotmap
-{
+struct vslotmap {
int index;
VSlot *vslot;
-
vslotmap() {}
vslotmap(int index, VSlot *vslot) : index(index), vslot(vslot) {}
};
static vector<vslotmap> unpackingvslots;
-static void unpackvslots(cube &c, ucharbuf &buf)
-{
- if(c.children)
- {
+static void unpackvslots(cube &c, ucharbuf &buf) {
+ if(c.children) {
loopi(8) unpackvslots(c.children[i], buf);
}
- else loopi(6)
- {
+ else loopi(6) {
ushort tex = c.texture[i];
loopvj(unpackingvslots) if(unpackingvslots[j].index == tex) { c.texture[i] = unpackingvslots[j].vslot->index; break; }
}
}
-static void unpackvslots(block3 &b, ucharbuf &buf)
-{
- while(buf.remaining() >= int(sizeof(vslothdr)))
- {
+static void unpackvslots(block3 &b, ucharbuf &buf) {
+ while(buf.remaining() >= int(sizeof(vslothdr))) {
vslothdr &hdr = *(vslothdr *)buf.pad(sizeof(vslothdr));
lilswap(&hdr.index, 2);
if(!hdr.index) break;
VSlot *edit = editvslot(vs, ds);
unpackingvslots.add(vslotmap(hdr.index, edit ? edit : &vs));
}
-
cube *c = b.c();
loopi(b.size()) unpackvslots(c[i], buf);
-
unpackingvslots.setsize(0);
}
-static bool compresseditinfo(const uchar *inbuf, int inlen, uchar *&outbuf, int &outlen)
-{
+static bool compresseditinfo(const uchar *inbuf, int inlen, uchar *&outbuf, int &outlen) {
uLongf len = compressBound(inlen);
if(len > (1<<20)) return false;
outbuf = new (false) uchar[len];
- if(!outbuf || compress2((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen, Z_BEST_COMPRESSION) != Z_OK || len > (1<<16))
- {
+ if(!outbuf || compress2((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen, Z_BEST_COMPRESSION) != Z_OK || len > (1<<16)) {
delete[] outbuf;
outbuf = NULL;
return false;
return true;
}
-static bool uncompresseditinfo(const uchar *inbuf, int inlen, uchar *&outbuf, int &outlen)
-{
+static bool uncompresseditinfo(const uchar *inbuf, int inlen, uchar *&outbuf, int &outlen) {
if(compressBound(outlen) > (1<<20)) return false;
uLongf len = outlen;
outbuf = new (false) uchar[len];
- if(!outbuf || uncompress((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen) != Z_OK)
- {
+ if(!outbuf || uncompress((Bytef *)outbuf, &len, (const Bytef *)inbuf, inlen) != Z_OK) {
delete[] outbuf;
outbuf = NULL;
return false;
return true;
}
-bool packeditinfo(editinfo *e, int &inlen, uchar *&outbuf, int &outlen)
-{
+bool packeditinfo(editinfo *e, int &inlen, uchar *&outbuf, int &outlen) {
vector<uchar> buf;
if(!e || !e->copy || !packblock(*e->copy, buf)) return false;
packvslots(*e->copy, buf);
return compresseditinfo(buf.getbuf(), buf.length(), outbuf, outlen);
}
-bool unpackeditinfo(editinfo *&e, const uchar *inbuf, int inlen, int outlen)
-{
+bool unpackeditinfo(editinfo *&e, const uchar *inbuf, int inlen, int outlen) {
if(e && e->copy) { freeblock(e->copy); e->copy = NULL; }
uchar *outbuf = NULL;
if(!uncompresseditinfo(inbuf, inlen, outbuf, outlen)) return false;
ucharbuf buf(outbuf, outlen);
if(!e) e = editinfos.add(new editinfo);
- if(!unpackblock(e->copy, buf))
- {
+ if(!unpackblock(e->copy, buf)) {
delete[] outbuf;
return false;
}
return true;
}
-void freeeditinfo(editinfo *&e)
-{
+void freeeditinfo(editinfo *&e) {
if(!e) return;
editinfos.removeobj(e);
if(e->copy) freeblock(e->copy);
e = NULL;
}
-bool packundo(undoblock *u, int &inlen, uchar *&outbuf, int &outlen)
-{
+bool packundo(undoblock *u, int &inlen, uchar *&outbuf, int &outlen) {
vector<uchar> buf;
buf.reserve(512);
*(ushort *)buf.pad(2) = lilswap(ushort(u->numents));
- if(u->numents)
- {
+ if(u->numents) {
undoent *ue = u->ents();
- loopi(u->numents)
- {
+ loopi(u->numents) {
*(ushort *)buf.pad(2) = lilswap(ushort(ue[i].i));
entity &e = *(entity *)buf.pad(sizeof(entity));
e = ue[i].e;
lilswap(&e.attr1, 5);
}
}
- else
- {
+ else {
block3 &b = *u->block();
if(!packblock(b, buf)) return false;
buf.put(u->gridmap(), b.size());
return compresseditinfo(buf.getbuf(), buf.length(), outbuf, outlen);
}
-bool unpackundo(const uchar *inbuf, int inlen, int outlen)
-{
+bool unpackundo(const uchar *inbuf, int inlen, int outlen) {
uchar *outbuf = NULL;
if(!uncompresseditinfo(inbuf, inlen, outbuf, outlen)) return false;
ucharbuf buf(outbuf, outlen);
- if(buf.remaining() < 2)
- {
+ if(buf.remaining() < 2) {
delete[] outbuf;
return false;
}
int numents = lilswap(*(const ushort *)buf.pad(2));
- if(numents)
- {
- if(buf.remaining() < numents*int(2 + sizeof(entity)))
- {
+ if(numents) {
+ if(buf.remaining() < numents*int(2 + sizeof(entity))) {
delete[] outbuf;
return false;
}
- loopi(numents)
- {
+ loopi(numents) {
int idx = lilswap(*(const ushort *)buf.pad(2));
entity &e = *(entity *)buf.pad(sizeof(entity));
lilswap(&e.o.x, 3);
pasteundoent(idx, e);
}
}
- else
- {
+ else {
block3 *b = NULL;
- if(!unpackblock(b, buf) || b->grid >= worldsize || buf.remaining() < b->size())
- {
+ if(!unpackblock(b, buf) || b->grid >= worldsize || buf.remaining() < b->size()) {
freeblock(b);
delete[] outbuf;
return false;
return true;
}
-bool packundo(int op, int &inlen, uchar *&outbuf, int &outlen)
-{
- switch(op)
- {
+bool packundo(int op, int &inlen, uchar *&outbuf, int &outlen) {
+ switch(op) {
case EDIT_UNDO: return !undos.empty() && packundo(undos.last, inlen, outbuf, outlen);
case EDIT_REDO: return !redos.empty() && packundo(redos.last, inlen, outbuf, outlen);
default: return false;
}
}
-struct prefabheader
-{
+struct prefabheader {
char magic[4];
int version;
};
-struct prefab : editinfo
-{
+struct prefab : editinfo {
char *name;
GLuint ebo, vbo;
int numtris, numverts;
-
prefab() : name(NULL), ebo(0), vbo(0), numtris(0), numverts(0) {}
~prefab() { DELETEA(name); if(copy) freeblock(copy); }
-
- void cleanup()
- {
+ void cleanup() {
if(ebo) { glDeleteBuffers_(1, &ebo); ebo = 0; }
if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; }
numtris = numverts = 0;
static hashnameset<prefab> prefabs;
-void cleanupprefabs()
-{
+void cleanupprefabs() {
enumerate(prefabs, prefab, p, p.cleanup());
}
-void delprefab(char *name)
-{
+void delprefab(char *name) {
prefab *p = prefabs.access(name);
- if(p)
- {
+ if(p) {
p->cleanup();
prefabs.remove(name);
conoutf("deleted prefab %s", name);
}
COMMAND(delprefab, "s");
-void saveprefab(char *name)
-{
+void saveprefab(char *name) {
if(!name[0] || noedit(true) || (nompedit && multiplayer())) return;
prefab *b = prefabs.access(name);
- if(!b)
- {
+ if(!b) {
b = &prefabs[name];
b->name = newstring(name);
}
}
COMMAND(saveprefab, "s");
-void pasteblock(block3 &b, selinfo &sel, bool local)
-{
+void pasteblock(block3 &b, selinfo &sel, bool local) {
sel.s = b.s;
int o = sel.orient;
sel.orient = b.orient;
sel.orient = o;
}
-bool prefabloaded(const char *name)
-{
+bool prefabloaded(const char *name) {
return prefabs.access(name) != NULL;
}
-prefab *loadprefab(const char *name, bool msg = true)
-{
+prefab *loadprefab(const char *name, bool msg = true) {
prefab *b = prefabs.access(name);
if(b) return b;
return b;
}
-void pasteprefab(char *name)
-{
+void pasteprefab(char *name) {
if(!name[0] || noedit() || (nompedit && multiplayer())) return;
prefab *b = loadprefab(name, true);
if(b) pasteblock(*b->copy, sel, true);
}
COMMAND(pasteprefab, "s");
-struct prefabmesh
-{
+struct prefabmesh {
struct vertex { vec pos; bvec4 norm; };
-
static const int SIZE = 1<<9;
int table[SIZE];
vector<vertex> verts;
vector<int> chain;
vector<ushort> tris;
-
prefabmesh() { memset(table, -1, sizeof(table)); }
-
- int addvert(const vertex &v)
- {
+ int addvert(const vertex &v) {
uint h = hthash(v.pos)&(SIZE-1);
- for(int i = table[h]; i>=0; i = chain[i])
- {
+ for(int i = table[h]; i>=0; i = chain[i]) {
const vertex &c = verts[i];
if(c.pos==v.pos && c.norm==v.norm) return i;
}
chain.add(table[h]);
return table[h] = verts.length()-1;
}
-
- int addvert(const vec &pos, const bvec &norm)
- {
+ int addvert(const vec &pos, const bvec &norm) {
vertex vtx;
vtx.pos = pos;
vtx.norm = norm;
return addvert(vtx);
}
-
- void setup(prefab &p)
- {
+ void setup(prefab &p) {
if(tris.empty()) return;
-
p.cleanup();
-
loopv(verts) verts[i].norm.flip();
if(!p.vbo) glGenBuffers_(1, &p.vbo);
gle::bindvbo(p.vbo);
glBufferData_(GL_ARRAY_BUFFER, verts.length()*sizeof(vertex), verts.getbuf(), GL_STATIC_DRAW);
gle::clearvbo();
p.numverts = verts.length();
-
if(!p.ebo) glGenBuffers_(1, &p.ebo);
gle::bindebo(p.ebo);
glBufferData_(GL_ELEMENT_ARRAY_BUFFER, tris.length()*sizeof(ushort), tris.getbuf(), GL_STATIC_DRAW);
};
-static void genprefabmesh(prefabmesh &r, cube &c, const ivec &co, int size)
-{
- if(c.children)
- {
+static void genprefabmesh(prefabmesh &r, cube &c, const ivec &co, int size) {
+ if(c.children) {
neighbourstack[++neighbourdepth] = c.children;
- loopi(8)
- {
+ loopi(8) {
ivec o(i, co, size/2);
genprefabmesh(r, c.children[i], o, size/2);
}
--neighbourdepth;
}
- else if(!isempty(c))
- {
+ else if(!isempty(c)) {
int vis;
- loopi(6) if((vis = visibletris(c, i, co, size)))
- {
+ loopi(6) if((vis = visibletris(c, i, co, size))) {
ivec v[4];
genfaceverts(c, i, v);
int convex = 0;
guessnormals(pos, numverts, norm);
int index[4];
loopj(numverts) index[j] = r.addvert(pos[j], bvec(norm[j]));
- loopj(numverts-2) if(index[0]!=index[j+1] && index[j+1]!=index[j+2] && index[j+2]!=index[0])
- {
+ loopj(numverts-2) if(index[0]!=index[j+1] && index[j+1]!=index[j+2] && index[j+2]!=index[0]) {
r.tris.add(index[0]);
r.tris.add(index[j+1]);
r.tris.add(index[j+2]);
}
}
-void genprefabmesh(prefab &p)
-{
+void genprefabmesh(prefab &p) {
block3 b = *p.copy;
b.o = ivec(0, 0, 0);
-
cube *oldworldroot = worldroot;
int oldworldscale = worldscale, oldworldsize = worldsize;
-
worldroot = newcubes();
worldscale = 1;
worldsize = 2;
- while(worldsize < max(max(b.s.x, b.s.y), b.s.z)*b.grid)
- {
+ while(worldsize < max(max(b.s.x, b.s.y), b.s.z)*b.grid) {
worldscale++;
worldsize *= 2;
}
-
cube *s = p.copy->c();
loopxyz(b, b.grid, if(!isempty(*s) || s->children) pastecube(*s, c); s++);
-
prefabmesh r;
neighbourstack[++neighbourdepth] = worldroot;
loopi(8) genprefabmesh(r, worldroot[i], ivec(i, ivec(0, 0, 0), worldsize/2), worldsize/2);
--neighbourdepth;
r.setup(p);
-
freeocta(worldroot);
-
worldroot = oldworldroot;
worldscale = oldworldscale;
worldsize = oldworldsize;
-
useshaderbyname("prefab");
}
extern int outlinecolour;
-static void renderprefab(prefab &p, const vec &o, float yaw, float pitch, float roll, float size, const vec &color)
-{
- if(!p.numtris)
- {
+static void renderprefab(prefab &p, const vec &o, float yaw, float pitch, float roll, float size, const vec &color) {
+ if(!p.numtris) {
genprefabmesh(p);
if(!p.numtris) return;
}
-
block3 &b = *p.copy;
-
matrix4 m;
m.identity();
m.settranslation(o);
matrix3 w(m);
if(size > 0 && size != 1) m.scale(size);
m.translate(vec(b.s).mul(-b.grid*0.5f));
-
gle::bindvbo(p.vbo);
gle::bindebo(p.ebo);
gle::enablevertex();
prefabmesh::vertex *v = (prefabmesh::vertex *)0;
gle::vertexpointer(sizeof(prefabmesh::vertex), v->pos.v);
gle::normalpointer(sizeof(prefabmesh::vertex), v->norm.v, GL_BYTE);
-
matrix4 pm;
pm.mul(camprojmatrix, m);
GLOBALPARAM(prefabmatrix, pm);
SETSHADER(prefab);
gle::color(color);
glDrawRangeElements_(GL_TRIANGLES, 0, p.numverts-1, p.numtris*3, GL_UNSIGNED_SHORT, (ushort *)0);
-
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
-
pm.mul(camprojmatrix, m);
GLOBALPARAM(prefabmatrix, pm);
SETSHADER(prefab);
gle::color(vec::hexcolor(outlinecolour));
glDrawRangeElements_(GL_TRIANGLES, 0, p.numverts-1, p.numtris*3, GL_UNSIGNED_SHORT, (ushort *)0);
-
disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
gle::disablevertex();
gle::disablenormal();
gle::clearebo();
gle::clearvbo();
}
-void renderprefab(const char *name, const vec &o, float yaw, float pitch, float roll, float size, const vec &color)
-{
+void renderprefab(const char *name, const vec &o, float yaw, float pitch, float roll, float size, const vec &color) {
prefab *p = loadprefab(name, false);
if(p) renderprefab(*p, o, yaw, pitch, roll, size, color);
}
-void previewprefab(const char *name, const vec &color)
-{
+void previewprefab(const char *name, const vec &color) {
prefab *p = loadprefab(name, false);
- if(p)
- {
+ if(p) {
block3 &b = *p->copy;
float yaw;
vec o = calcmodelpreviewpos(vec(b.s).mul(b.grid*0.5f), yaw);
}
}
-void mpcopy(editinfo *&e, selinfo &sel, bool local)
-{
+void mpcopy(editinfo *&e, selinfo &sel, bool local) {
if(local) game::edittrigger(sel, EDIT_COPY);
if(e==NULL) e = editinfos.add(new editinfo);
if(e->copy) freeblock(e->copy);
changed(sel);
}
-void mppaste(editinfo *&e, selinfo &sel, bool local)
-{
+void mppaste(editinfo *&e, selinfo &sel, bool local) {
if(e==NULL) return;
if(local) game::edittrigger(sel, EDIT_PASTE);
if(e->copy) pasteblock(*e->copy, sel, local);
}
-void copy()
-{
+void copy() {
if(noedit(true)) return;
mpcopy(localedit, sel, true);
}
-void pastehilite()
-{
+void pastehilite() {
if(!localedit) return;
sel.s = localedit->copy->s;
reorient();
havesel = true;
}
-void paste()
-{
+void paste() {
if(noedit(true)) return;
mppaste(localedit, sel, true);
}
COMMANDN(redo, editredo, "");
static vector<int *> editingvslots;
-struct vslotref
-{
+struct vslotref {
vslotref(int &index) { editingvslots.add(&index); }
~vslotref() { editingvslots.pop(); }
};
#define editingvslot(...) vslotref vslotrefs[] = { __VA_ARGS__ }; (void)vslotrefs;
-void compacteditvslots()
-{
+void compacteditvslots() {
loopv(editingvslots) if(*editingvslots[i]) compactvslot(*editingvslots[i]);
loopv(unpackingvslots) compactvslot(*unpackingvslots[i].vslot);
- loopv(editinfos)
- {
+ loopv(editinfos) {
editinfo *e = editinfos[i];
compactvslots(e->copy->c(), e->copy->size());
}
int bounded(int n) { return n<0 ? 0 : (n>8 ? 8 : n); }
-void pushedge(uchar &edge, int dir, int dc)
-{
+void pushedge(uchar &edge, int dir, int dc) {
int ne = bounded(edgeget(edge, dc)+dir);
edgeset(edge, dc, ne);
int oe = edgeget(edge, 1-dc);
if((dir<0 && dc && oe>ne) || (dir>0 && dc==0 && oe<ne)) edgeset(edge, 1-dc, ne);
}
-void linkedpush(cube &c, int d, int x, int y, int dc, int dir)
-{
+void linkedpush(cube &c, int d, int x, int y, int dc, int dir) {
ivec v, p;
getcubevector(c, d, x, y, dc, v);
-
- loopi(2) loopj(2)
- {
+ loopi(2) loopj(2) {
getcubevector(c, d, i, j, dc, p);
if(v==p)
pushedge(cubeedge(c, d, i, j), dir, dc);
}
}
-static ushort getmaterial(cube &c)
-{
- if(c.children)
- {
+static ushort getmaterial(cube &c) {
+ if(c.children) {
ushort mat = getmaterial(c.children[7]);
loopi(7) if(mat != getmaterial(c.children[i])) return MAT_AIR;
return mat;
VAR(invalidcubeguard, 0, 1, 1);
-void mpeditface(int dir, int mode, selinfo &sel, bool local)
-{
+void mpeditface(int dir, int mode, selinfo &sel, bool local) {
if(mode==1 && (sel.cx || sel.cy || sel.cxs&1 || sel.cys&1)) mode = 0;
int d = dimension(sel.orient);
int dc = dimcoord(sel.orient);
int seldir = dc ? -dir : dir;
-
if(local)
game::edittrigger(sel, EDIT_FACE, dir, mode);
-
- if(mode==1)
- {
+ if(mode==1) {
int h = sel.o[d]+dc*sel.grid;
if(((dir>0) == dc && h<=0) || ((dir<0) == dc && h>=worldsize)) return;
if(dir<0) sel.o[d] += sel.grid * seldir;
}
-
if(dc) sel.o[d] += sel.us(d)-sel.grid;
sel.s[d] = 1;
-
loopselxyz(
if(c.children) solidfaces(c);
ushort mat = getmaterial(c);
discardchildren(c, true);
c.material = mat;
- if(mode==1) // fill command
- {
- if(dir<0)
- {
+ if(mode==1) { // fill command {
+ if(dir<0) {
solidfaces(c);
cube &o = blockcube(x, y, 1, sel, -sel.grid);
loopi(6)
else
emptyfaces(c);
}
- else
- {
+ else {
uint bak = c.faces[d];
uchar *p = (uchar *)&c.faces[d];
-
if(mode==2)
linkedpush(c, d, sel.corner&1, sel.corner>>1, dc, seldir); // corner command
- else
- {
- loop(mx,2) loop(my,2) // pull/push edges command
- {
+ else {
+ loop(mx,2) loop(my,2) { // pull/push edges command {
if(x==0 && mx==0 && sel.cx) continue;
if(y==0 && my==0 && sel.cy) continue;
if(x==sel.s[R[d]]-1 && mx==1 && (sel.cx+sel.cxs)&1) continue;
if(y==sel.s[C[d]]-1 && my==1 && (sel.cy+sel.cys)&1) continue;
if(p[mx+my*2] != ((uchar *)&bak)[mx+my*2]) continue;
-
linkedpush(c, d, mx, my, dc, seldir);
}
}
-
optiface(p, c);
- if(invalidcubeguard==1 && !isvalidcube(c))
- {
+ if(invalidcubeguard==1 && !isvalidcube(c)) {
uint newbak = c.faces[d];
uchar *m = (uchar *)&bak;
uchar *n = (uchar *)&newbak;
- loopk(4) if(n[k] != m[k]) // tries to find partial edit that is valid
- {
+ loopk(4) if(n[k] != m[k]) { // tries to find partial edit that is valid {
c.faces[d] = bak;
c.edges[d*4+k] = n[k];
if(isvalidcube(c))
sel.o[d] += sel.grid * seldir;
}
-void editface(int *dir, int *mode)
-{
+void editface(int *dir, int *mode) {
if(noedit(moving!=0)) return;
mpeditface(*dir, *mode, sel, true);
}
VAR(selectionsurf, 0, 0, 1);
-void pushsel(int *dir)
-{
+void pushsel(int *dir) {
if(noedit(moving!=0)) return;
int d = dimension(orient);
int s = dimcoord(orient) ? -*dir : *dir;
sel.o[d] += s*sel.grid;
- if(selectionsurf==1)
- {
+ if(selectionsurf==1) {
player->o[d] += s*sel.grid;
player->resetinterp();
}
}
-void mpdelcube(selinfo &sel, bool local)
-{
+void mpdelcube(selinfo &sel, bool local) {
if(local) game::edittrigger(sel, EDIT_DELCUBE);
loopselxyz(discardchildren(c, true); emptyfaces(c));
}
-void delcube()
-{
+void delcube() {
if(noedit(true)) return;
mpdelcube(sel, true);
}
int texpaneltimer = 0;
vector<ushort> texmru;
-void tofronttex() // maintain most recently used of the texture lists when applying texture
-{
+void tofronttex() { // maintain most recently used of the texture lists when applying texture {
int c = curtexindex;
- if(texmru.inrange(c))
- {
+ if(texmru.inrange(c)) {
texmru.insert(0, texmru.remove(c));
curtexindex = -1;
}
VAR(usevdelta, 1, 0, 0);
-static VSlot *remapvslot(int index, bool delta, const VSlot &ds)
-{
+static VSlot *remapvslot(int index, bool delta, const VSlot &ds) {
loopv(remappedvslots) if(remappedvslots[i].index == index) return remappedvslots[i].vslot;
VSlot &vs = lookupvslot(index, false);
if(vs.index < 0) return NULL;
VSlot *edit = NULL;
- if(delta)
- {
+ if(delta) {
VSlot ms;
mergevslot(ms, vs, ds);
edit = ms.changed ? editvslot(vs, ms) : vs.slot->variants;
return edit;
}
-static void remapvslots(cube &c, bool delta, const VSlot &ds, int orient, bool &findrep, VSlot *&findedit)
-{
- if(c.children)
- {
+static void remapvslots(cube &c, bool delta, const VSlot &ds, int orient, bool &findrep, VSlot *&findedit) {
+ if(c.children) {
loopi(8) remapvslots(c.children[i], delta, ds, orient, findrep, findedit);
return;
}
static VSlot ms;
- if(orient<0) loopi(6)
- {
+ if(orient<0) loopi(6) {
VSlot *edit = remapvslot(c.texture[i], delta, ds);
- if(edit)
- {
+ if(edit) {
c.texture[i] = edit->index;
if(!findedit) findedit = edit;
}
}
- else
- {
+ else {
int i = visibleorient(c, orient);
VSlot *edit = remapvslot(c.texture[i], delta, ds);
- if(edit)
- {
- if(findrep)
- {
+ if(edit) {
+ if(findrep) {
if(reptex < 0) reptex = c.texture[i];
else if(reptex != c.texture[i]) findrep = false;
}
}
}
-void edittexcube(cube &c, int tex, int orient, bool &findrep)
-{
+void edittexcube(cube &c, int tex, int orient, bool &findrep) {
if(orient<0) loopi(6) c.texture[i] = tex;
- else
- {
+ else {
int i = visibleorient(c, orient);
- if(findrep)
- {
+ if(findrep) {
if(reptex < 0) reptex = c.texture[i];
else if(reptex != c.texture[i]) findrep = false;
}
VAR(allfaces, 0, 0, 1);
-void mpeditvslot(int delta, VSlot &ds, int allfaces, selinfo &sel, bool local)
-{
- if(local)
- {
+void mpeditvslot(int delta, VSlot &ds, int allfaces, selinfo &sel, bool local) {
+ if(local) {
game::edittrigger(sel, EDIT_VSLOT, delta, allfaces, 0, &ds);
if(!(lastsel==sel)) tofronttex();
if(allfaces || !(repsel == sel)) reptex = -1;
VSlot *findedit = NULL;
loopselxyz(remapvslots(c, delta != 0, ds, allfaces ? -1 : sel.orient, findrep, findedit));
remappedvslots.setsize(0);
- if(local && findedit)
- {
+ if(local && findedit) {
lasttex = findedit->index;
lasttexmillis = totalmillis;
curtexindex = texmru.find(lasttex);
- if(curtexindex < 0)
- {
+ if(curtexindex < 0) {
curtexindex = texmru.length();
texmru.add(lasttex);
}
}
}
-bool mpeditvslot(int delta, int allfaces, selinfo &sel, ucharbuf &buf)
-{
+bool mpeditvslot(int delta, int allfaces, selinfo &sel, ucharbuf &buf) {
VSlot ds;
if(!unpackvslot(buf, ds, delta != 0)) return false;
editingvslot(ds.layer);
return true;
}
-void vdelta(char *body)
-{
+void vdelta(char *body) {
if(noedit()) return;
usevdelta++;
execute(body);
}
COMMAND(vdelta, "s");
-void vrotate(int *n)
-{
+void vrotate(int *n) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_ROTATION;
COMMAND(vrotate, "i");
ICOMMAND(getvrotate, "i", (int *tex), intret(lookupvslot(*tex, false).rotation));
-void voffset(int *x, int *y)
-{
+void voffset(int *x, int *y) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_OFFSET;
mpeditvslot(usevdelta, ds, allfaces, sel, true);
}
COMMAND(voffset, "ii");
-ICOMMAND(getvoffset, "i", (int *tex),
-{
+ICOMMAND(getvoffset, "i", (int *tex), {
VSlot &vslot = lookupvslot(*tex, false);
defformatstring(str, "%d %d", vslot.offset.x, vslot.offset.y);
result(str);
});
-void vscroll(float *s, float *t)
-{
+void vscroll(float *s, float *t) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_SCROLL;
mpeditvslot(usevdelta, ds, allfaces, sel, true);
}
COMMAND(vscroll, "ff");
-ICOMMAND(getvscroll, "i", (int *tex),
-{
+ICOMMAND(getvscroll, "i", (int *tex), {
VSlot &vslot = lookupvslot(*tex, false);
defformatstring(str, "%s %s", floatstr(vslot.scroll.x), floatstr(vslot.scroll.y));
result(str);
});
-void vscale(float *scale)
-{
+void vscale(float *scale) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_SCALE;
COMMAND(vscale, "f");
ICOMMAND(getvscale, "i", (int *tex), floatret(lookupvslot(*tex, false).scale));
-void vlayer(int *n)
-{
+void vlayer(int *n) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_LAYER;
- if(vslots.inrange(*n))
- {
+ if(vslots.inrange(*n)) {
ds.layer = *n;
if(vslots[ds.layer]->changed && nompedit && multiplayer()) return;
}
COMMAND(vlayer, "i");
ICOMMAND(getvlayer, "i", (int *tex), intret(lookupvslot(*tex, false).layer));
-void valpha(float *front, float *back)
-{
+void valpha(float *front, float *back) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_ALPHA;
mpeditvslot(usevdelta, ds, allfaces, sel, true);
}
COMMAND(valpha, "ff");
-ICOMMAND(getvalpha, "i", (int *tex),
-{
+ICOMMAND(getvalpha, "i", (int *tex), {
VSlot &vslot = lookupvslot(*tex, false);
defformatstring(str, "%s %s", floatstr(vslot.alphafront), floatstr(vslot.alphaback));
result(str);
});
-void vcolor(float *r, float *g, float *b)
-{
+void vcolor(float *r, float *g, float *b) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_COLOR;
mpeditvslot(usevdelta, ds, allfaces, sel, true);
}
COMMAND(vcolor, "fff");
-ICOMMAND(getvcolor, "i", (int *tex),
-{
+ICOMMAND(getvcolor, "i", (int *tex), {
VSlot &vslot = lookupvslot(*tex, false);
defformatstring(str, "%s %s %s", floatstr(vslot.colorscale.r), floatstr(vslot.colorscale.g), floatstr(vslot.colorscale.b));
result(str);
});
-void vreset()
-{
+void vreset() {
if(noedit()) return;
VSlot ds;
mpeditvslot(usevdelta, ds, allfaces, sel, true);
}
COMMAND(vreset, "");
-void vshaderparam(const char *name, float *x, float *y, float *z, float *w)
-{
+void vshaderparam(const char *name, float *x, float *y, float *z, float *w) {
if(noedit()) return;
VSlot ds;
ds.changed = 1<<VSLOT_SHPARAM;
- if(name[0])
- {
+ if(name[0]) {
SlotShaderParam p = { getshaderparamname(name), -1, {*x, *y, *z, *w} };
ds.params.add(p);
}
mpeditvslot(usevdelta, ds, allfaces, sel, true);
}
COMMAND(vshaderparam, "sffff");
-ICOMMAND(getvshaderparam, "is", (int *tex, const char *name),
-{
+ICOMMAND(getvshaderparam, "is", (int *tex, const char *name), {
VSlot &vslot = lookupvslot(*tex, false);
- loopv(vslot.params)
- {
+ loopv(vslot.params) {
SlotShaderParam &p = vslot.params[i];
- if(!strcmp(p.name, name))
- {
+ if(!strcmp(p.name, name)) {
defformatstring(str, "%s %s %s %s", floatstr(p.val[0]), floatstr(p.val[1]), floatstr(p.val[2]), floatstr(p.val[3]));
result(str);
return;
}
}
});
-ICOMMAND(getvshaderparamnames, "i", (int *tex),
-{
+ICOMMAND(getvshaderparamnames, "i", (int *tex), {
VSlot &vslot = lookupvslot(*tex, false);
vector<char> str;
- loopv(vslot.params)
- {
+ loopv(vslot.params) {
SlotShaderParam &p = vslot.params[i];
if(i) str.put(' ');
str.put(p.name, strlen(p.name));
stringret(newstring(str.getbuf(), str.length()-1));
});
-void mpedittex(int tex, int allfaces, selinfo &sel, bool local)
-{
- if(local)
- {
+void mpedittex(int tex, int allfaces, selinfo &sel, bool local) {
+ if(local) {
game::edittrigger(sel, EDIT_TEX, tex, allfaces);
if(allfaces || !(repsel == sel)) reptex = -1;
repsel = sel;
loopselxyz(edittexcube(c, tex, allfaces ? -1 : sel.orient, findrep));
}
-static int unpacktex(int &tex, ucharbuf &buf, bool insert = true)
-{
+static int unpacktex(int &tex, ucharbuf &buf, bool insert = true) {
if(tex < 0x10000) return true;
VSlot ds;
if(!unpackvslot(buf, ds, false)) return false;
return true;
}
-int shouldpacktex(int index)
-{
- if(vslots.inrange(index))
- {
+int shouldpacktex(int index) {
+ if(vslots.inrange(index)) {
VSlot &vs = *vslots[index];
if(vs.changed) return 0x10000 + vs.slot->index;
}
}
-bool mpedittex(int tex, int allfaces, selinfo &sel, ucharbuf &buf)
-{
+bool mpedittex(int tex, int allfaces, selinfo &sel, ucharbuf &buf) {
if(!unpacktex(tex, buf)) return false;
mpedittex(tex, allfaces, sel, false);
return true;
}
-void filltexlist()
-{
- if(texmru.length()!=vslots.length())
- {
- loopvrev(texmru) if(texmru[i]>=vslots.length())
- {
+void filltexlist() {
+ if(texmru.length()!=vslots.length()) {
+ loopvrev(texmru) if(texmru[i]>=vslots.length()) {
if(curtexindex > i) curtexindex--;
else if(curtexindex == i) curtexindex = -1;
texmru.remove(i);
}
}
-void compactmruvslots()
-{
+void compactmruvslots() {
remappedvslots.setsize(0);
- loopvrev(texmru)
- {
- if(vslots.inrange(texmru[i]))
- {
+ loopvrev(texmru) {
+ if(vslots.inrange(texmru[i])) {
VSlot &vs = *vslots[texmru[i]];
- if(vs.index >= 0)
- {
+ if(vs.index >= 0) {
texmru[i] = vs.index;
continue;
}
else if(curtexindex == i) curtexindex = -1;
texmru.remove(i);
}
- if(vslots.inrange(lasttex))
- {
+ if(vslots.inrange(lasttex)) {
VSlot &vs = *vslots[lasttex];
lasttex = vs.index >= 0 ? vs.index : 0;
}
reptex = vslots.inrange(reptex) ? vslots[reptex]->index : -1;
}
-void edittex(int i, bool save = true)
-{
+void edittex(int i, bool save = true) {
lasttex = i;
lasttexmillis = totalmillis;
- if(save)
- {
+ if(save) {
loopvj(texmru) if(texmru[j]==lasttex) { curtexindex = j; break; }
}
mpedittex(i, allfaces, sel, true);
}
-void edittex_(int *dir)
-{
+void edittex_(int *dir) {
if(noedit()) return;
filltexlist();
if(texmru.empty()) return;
edittex(texmru[curtexindex], false);
}
-void gettex()
-{
+void gettex() {
if(noedit(true)) return;
filltexlist();
int tex = -1;
loopxyz(sel, sel.grid, tex = c.texture[sel.orient]);
- loopv(texmru) if(texmru[i]==tex)
- {
+ loopv(texmru) if(texmru[i]==tex) {
curtexindex = i;
tofronttex();
return;
}
}
-void getcurtex()
-{
+void getcurtex() {
if(noedit(true)) return;
filltexlist();
int index = curtexindex < 0 ? 0 : curtexindex;
intret(texmru[index]);
}
-void getseltex()
-{
+void getseltex() {
if(noedit(true)) return;
cube &c = lookupcube(sel.o, -sel.grid);
if(c.children || isempty(c)) return;
intret(c.texture[sel.orient]);
}
-void gettexname(int *tex, int *subslot)
-{
+void gettexname(int *tex, int *subslot) {
if(noedit(true) || *tex<0) return;
VSlot &vslot = lookupvslot(*tex, false);
Slot &slot = *vslot.slot;
result(slot.sts[*subslot].name);
}
-void getslottex(int *idx)
-{
+void getslottex(int *idx) {
if(*idx < 0 || !slots.inrange(*idx)) { intret(-1); return; }
Slot &slot = lookupslot(*idx, false);
intret(slot.variants->index);
COMMAND(getslottex, "i");
ICOMMAND(texloaded, "i", (int *tex), intret(slots.inrange(*tex) && slots[*tex]->loaded ? 1 : 0));
-void replacetexcube(cube &c, int oldtex, int newtex)
-{
+void replacetexcube(cube &c, int oldtex, int newtex) {
loopi(6) if(c.texture[i] == oldtex) c.texture[i] = newtex;
if(c.children) loopi(8) replacetexcube(c.children[i], oldtex, newtex);
}
-void mpreplacetex(int oldtex, int newtex, bool insel, selinfo &sel, bool local)
-{
+void mpreplacetex(int oldtex, int newtex, bool insel, selinfo &sel, bool local) {
if(local) game::edittrigger(sel, EDIT_REPLACE, oldtex, newtex, insel ? 1 : 0);
- if(insel)
- {
+ if(insel) {
loopselxyz(replacetexcube(c, oldtex, newtex));
}
- else
- {
+ else {
loopi(8) replacetexcube(worldroot[i], oldtex, newtex);
}
allchanged();
}
-bool mpreplacetex(int oldtex, int newtex, bool insel, selinfo &sel, ucharbuf &buf)
-{
+bool mpreplacetex(int oldtex, int newtex, bool insel, selinfo &sel, ucharbuf &buf) {
if(!unpacktex(oldtex, buf, false)) return false;
editingvslot(oldtex);
if(!unpacktex(newtex, buf)) return false;
return true;
}
-void replace(bool insel)
-{
+void replace(bool insel) {
if(noedit()) return;
if(reptex < 0) { conoutf(CON_ERROR, "can only replace after a texture edit"); return; }
mpreplacetex(reptex, lasttex, insel, sel, true);
uint rflip(uint face) { return ((face&0xFFFF0000)>>16)| ((face&0x0000FFFF)<<16); }
uint mflip(uint face) { return (face&0xFF0000FF) | ((face&0x00FF0000)>>8) | ((face&0x0000FF00)<<8); }
-void flipcube(cube &c, int d)
-{
+void flipcube(cube &c, int d) {
swap(c.texture[d*2], c.texture[d*2+1]);
c.faces[D[d]] = dflip(c.faces[D[d]]);
c.faces[C[d]] = cflip(c.faces[C[d]]);
c.faces[R[d]] = rflip(c.faces[R[d]]);
- if(c.children)
- {
+ if(c.children) {
loopi(8) if(i&octadim(d)) swap(c.children[i], c.children[i-octadim(d)]);
loopi(8) flipcube(c.children[i], d);
}
}
-void rotatequad(cube &a, cube &b, cube &c, cube &d)
-{
+void rotatequad(cube &a, cube &b, cube &c, cube &d) {
cube t = a; a = b; b = c; c = d; d = t;
}
-void rotatecube(cube &c, int d) // rotates cube clockwise. see pics in cvs for help.
-{
+void rotatecube(cube &c, int d) { // rotates cube clockwise. see pics in cvs for help. {
c.faces[D[d]] = cflip (mflip(c.faces[D[d]]));
c.faces[C[d]] = dflip (mflip(c.faces[C[d]]));
c.faces[R[d]] = rflip (mflip(c.faces[R[d]]));
swap(c.faces[R[d]], c.faces[C[d]]);
-
swap(c.texture[2*R[d]], c.texture[2*C[d]+1]);
swap(c.texture[2*C[d]], c.texture[2*R[d]+1]);
swap(c.texture[2*C[d]], c.texture[2*C[d]+1]);
-
- if(c.children)
- {
+ if(c.children) {
int row = octadim(R[d]);
int col = octadim(C[d]);
for(int i=0; i<=octadim(d); i+=octadim(d)) rotatequad
}
}
-void mpflip(selinfo &sel, bool local)
-{
- if(local)
- {
+void mpflip(selinfo &sel, bool local) {
+ if(local) {
game::edittrigger(sel, EDIT_FLIP);
makeundo();
}
int zs = sel.s[dimension(sel.orient)];
- loopxy(sel)
- {
+ loopxy(sel) {
loop(z,zs) flipcube(selcube(x, y, z), dimension(sel.orient));
- loop(z,zs/2)
- {
+ loop(z,zs/2) {
cube &a = selcube(x, y, z);
cube &b = selcube(x, y, zs-z-1);
swap(a, b);
changed(sel);
}
-void flip()
-{
+void flip() {
if(noedit()) return;
mpflip(sel, true);
}
-void mprotate(int cw, selinfo &sel, bool local)
-{
+void mprotate(int cw, selinfo &sel, bool local) {
if(local) game::edittrigger(sel, EDIT_ROTATE, cw);
int d = dimension(sel.orient);
if(!dimcoord(sel.orient)) cw = -cw;
int m = sel.s[C[d]] < sel.s[R[d]] ? C[d] : R[d];
int ss = sel.s[m] = max(sel.s[R[d]], sel.s[C[d]]);
if(local) makeundo();
- loop(z,sel.s[D[d]]) loopi(cw>0 ? 1 : 3)
- {
+ loop(z,sel.s[D[d]]) loopi(cw>0 ? 1 : 3) {
loopxy(sel) rotatecube(selcube(x,y,z), d);
loop(y,ss/2) loop(x,ss-1-y*2) rotatequad
(
changed(sel);
}
-void rotate(int *cw)
-{
+void rotate(int *cw) {
if(noedit()) return;
mprotate(*cw, sel, true);
}
COMMAND(rotate, "i");
enum { EDITMATF_EMPTY = 0x10000, EDITMATF_NOTEMPTY = 0x20000, EDITMATF_SOLID = 0x30000, EDITMATF_NOTSOLID = 0x40000 };
-static const struct { const char *name; int filter; } editmatfilters[] =
-{
- { "empty", EDITMATF_EMPTY },
- { "notempty", EDITMATF_NOTEMPTY },
- { "solid", EDITMATF_SOLID },
- { "notsolid", EDITMATF_NOTSOLID }
+static const struct { const char *name; int filter; } editmatfilters[] = {
+ {
+ "empty", EDITMATF_EMPTY }, {
+ "notempty", EDITMATF_NOTEMPTY }, {
+ "solid", EDITMATF_SOLID }, {
+ "notsolid", EDITMATF_NOTSOLID }
};
-void setmat(cube &c, ushort mat, ushort matmask, ushort filtermat, ushort filtermask, int filtergeom)
-{
+void setmat(cube &c, ushort mat, ushort matmask, ushort filtermat, ushort filtermask, int filtergeom) {
if(c.children)
loopi(8) setmat(c.children[i], mat, matmask, filtermat, filtermask, filtergeom);
- else if((c.material&filtermask) == filtermat)
- {
- switch(filtergeom)
- {
+ else if((c.material&filtermask) == filtermat) {
+ switch(filtergeom) {
case EDITMATF_EMPTY: if(isempty(c)) break; return;
case EDITMATF_NOTEMPTY: if(!isempty(c)) break; return;
case EDITMATF_SOLID: if(isentirelysolid(c)) break; return;
case EDITMATF_NOTSOLID: if(!isentirelysolid(c)) break; return;
}
- if(mat!=MAT_AIR)
- {
+ if(mat!=MAT_AIR) {
c.material &= matmask;
c.material |= mat;
}
}
}
-void mpeditmat(int matid, int filter, selinfo &sel, bool local)
-{
+void mpeditmat(int matid, int filter, selinfo &sel, bool local) {
if(local) game::edittrigger(sel, EDIT_MAT, matid, filter);
-
ushort filtermat = 0, filtermask = 0, matmask;
int filtergeom = 0;
- if(filter >= 0)
- {
+ if(filter >= 0) {
filtermat = filter&0xFFFF;
filtermask = filtermat&(MATF_INDEX) ? (int) MATF_INDEX : (filtermat&MATF_CLIP ? (int) MATF_CLIP : (int) filtermat);
filtergeom = filter&~0xFFFF;
}
- if(matid < 0)
- {
+ if(matid < 0) {
matid = 0;
matmask = filtermask;
}
- else
- {
+ else {
matmask = matid&MATF_INDEX ? 0 : (matid&MATF_CLIP ? ~MATF_CLIP : ~matid);
}
loopselxyz(setmat(c, matid, matmask, filtermat, filtermask, filtergeom));
}
-void editmat(char *name, char *filtername)
-{
+void editmat(char *name, char *filtername) {
if(noedit()) return;
int filter = -1;
- if(filtername[0])
- {
+ if(filtername[0]) {
loopi(sizeof(editmatfilters)/sizeof(editmatfilters[0])) if(!strcmp(editmatfilters[i].name, filtername)) { filter = editmatfilters[i].filter; break; }
if(filter < 0) filter = findmaterial(filtername);
- if(filter < 0)
- {
+ if(filter < 0) {
conoutf(CON_ERROR, "unknown material \"%s\"", filtername);
return;
}
}
int id = -1;
- if(name[0] || filter < 0)
- {
+ if(name[0] || filter < 0) {
id = findmaterial(name);
if(id<0) { conoutf(CON_ERROR, "unknown material \"%s\"", name); return; }
}
VARP(texgui2d, 0, 1, 1);
VAR(texguinum, 1, -1, 0);
-struct texturegui : g3d_callback
-{
+struct texturegui : g3d_callback {
bool menuon;
vec menupos;
int menustart, menutab;
-
texturegui() : menustart(-1) {}
-
- void gui(g3d_gui &g, bool firstpass)
- {
+ void gui(g3d_gui &g, bool firstpass) {
int origtab = menutab, numtabs = max((slots.length() + texguiwidth*texguiheight - 1)/(texguiwidth*texguiheight), 1);
if(!firstpass) texguinum = -1;
g.start(menustart, 0.04f, &menutab);
bool oldautotab = g.allowautotab(false);
- loopi(numtabs)
- {
+ loopi(numtabs) {
g.tab(!i ? "Textures" : NULL, 0xFFDD88);
if(i+1 != origtab) continue; //don't load textures on non-visible tabs!
Slot *rollover = NULL;
- loop(h, texguiheight)
- {
+ loop(h, texguiheight) {
g.pushlist();
- loop(w, texguiwidth)
- {
+ loop(w, texguiwidth) {
extern VSlot dummyvslot;
int ti = (i*texguiheight+h)*texguiwidth+w;
- if(ti<slots.length())
- {
+ if(ti<slots.length()) {
Slot &slot = lookupslot(ti, false);
VSlot &vslot = *slot.variants;
if(slot.sts.empty()) continue;
- else if(!slot.loaded && !slot.thumbnail)
- {
+ else if(!slot.loaded && !slot.thumbnail) {
if(totalmillis-lastthumbnail<texguitime)
{
g.texture(dummyvslot, texguiscale, false); //create an empty space
}
int ret = g.texture(vslot, texguiscale, true);
if(ret&G3D_ROLLOVER) { rollover = &slot; texguinum = ti; }
- if(ret&G3D_UP && (slot.loaded || slot.thumbnail!=notexture))
- {
+ if(ret&G3D_UP && (slot.loaded || slot.thumbnail!=notexture)) {
edittex(vslot.index);
hudshader->set();
}
}
- else
- {
+ else {
g.texture(dummyvslot, texguiscale, false); //create an empty space
}
}
g.poplist();
}
- if(texguiname)
- {
- if(rollover)
- {
+ if(texguiname) {
+ if(rollover) {
defformatstring(name, "%d \f7:\fc %s", texguinum, rollover->sts[0].name);
g.title(name, 0xFFDD88);
}
g.allowautotab(oldautotab);
g.end();
}
-
- void showtextures(bool on)
- {
+ void showtextures(bool on) {
if(on == menuon) return;
- if((menuon = on))
- {
+ if((menuon = on)) {
if(menustart <= lasttexmillis)
menutab = 1+clamp(lookupvslot(lasttex, false).slot->index, 0, slots.length()-1)/(texguiwidth*texguiheight);
menupos = menuinfrontofplayer();
}
else texguinum = -1;
}
-
- void show()
- {
+ void show() {
if(!menuon) return;
filltexlist();
extern int usegui2d;
}
} gui;
-void g3d_texturemenu()
-{
+void g3d_texturemenu() {
gui.show();
}
-void showtexgui(int *n)
-{
+void showtexgui(int *n) {
if(!editmode) { conoutf(CON_ERROR, "operation only allowed in edit mode"); return; }
gui.showtextures(*n==0 ? !gui.menuon : *n==1);
}
// 0/noargs = toggle, 1 = on, other = off - will autoclose if too far away or exit editmode
COMMAND(showtexgui, "i");
-bool cleartexgui()
-{
+bool cleartexgui() {
if(!gui.menuon) return false;
gui.showtextures(false);
return true;
}
ICOMMAND(cleartexgui, "", (), intret(cleartexgui() ? 1 : 0));
-void rendertexturepanel(int w, int h)
-{
- if((texpaneltimer -= curtime)>0 && editmode)
- {
+void rendertexturepanel(int w, int h) {
+ if((texpaneltimer -= curtime)>0 && editmode) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
pushhudmatrix();
hudmatrix.scale(h/1800.0f, h/1800.0f, 1);
flushhudmatrix(false);
SETSHADER(hudrgb);
-
int y = 50, gap = 10;
-
gle::defvertex(2);
gle::deftexcoord0();
-
- loopi(7)
- {
+ loopi(7) {
int s = (i == 3 ? 285 : 220), ti = curtexindex+i-3;
- if(texmru.inrange(ti))
- {
- VSlot &vslot = lookupvslot(texmru[ti]), *layer = NULL;
+ if(texmru.inrange(ti)) {
+ VSlot &vslot = lookupvslot(texmru[ti]), *layer = NULL; (void) layer;
Slot &slot = *vslot.slot;
Texture *tex = slot.sts.empty() ? notexture : slot.sts[0].t;
- if(vslot.layer)
- {
+ if(vslot.layer) {
layer = &lookupvslot(vslot.layer);
}
float sx = min(1.0f, tex->xs/(float)tex->ys), sy = min(1.0f, tex->ys/(float)tex->xs);
vec2 tc[4] = { vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1) };
float xoff = vslot.offset.x, yoff = vslot.offset.y;
- if(vslot.rotation)
- {
+ if(vslot.rotation) {
const texrotation &r = texrotations[vslot.rotation];
if(r.swapxy) { swap(xoff, yoff); loopk(4) swap(tc[k].x, tc[k].y); }
if(r.flipx) { xoff *= -1; loopk(4) tc[k].x *= -1; }
}
y += s+gap;
}
-
pophudmatrix(true, false);
hudshader->set();
}
#include "engine.h"
-struct vboinfo
-{
+struct vboinfo {
int uses;
};
VAR(printvbo, 0, 0, 1);
VARFN(vbosize, maxvbosize, 0, 1<<14, 1<<16, allchanged());
-enum
-{
+enum {
VBO_VBUF = 0,
VBO_EBUF,
NUMVBO
static vector<vtxarray *> vbovas[NUMVBO];
static int vbosize[NUMVBO];
-void destroyvbo(GLuint vbo)
-{
+void destroyvbo(GLuint vbo) {
vboinfo *exists = vbos.access(vbo);
if(!exists) return;
vboinfo &vbi = *exists;
if(vbi.uses <= 0) return;
vbi.uses--;
- if(!vbi.uses)
- {
+ if(!vbi.uses) {
glDeleteBuffers_(1, &vbo);
vbos.remove(vbo);
}
}
-void genvbo(int type, void *buf, int len, vtxarray **vas, int numva)
-{
+void genvbo(int type, void *buf, int len, vtxarray **vas, int numva) {
gle::disable();
-
GLuint vbo;
glGenBuffers_(1, &vbo);
GLenum target = type==VBO_VBUF ? GL_ARRAY_BUFFER : GL_ELEMENT_ARRAY_BUFFER;
glBindBuffer_(target, vbo);
glBufferData_(target, len, buf, GL_STATIC_DRAW);
glBindBuffer_(target, 0);
-
vboinfo &vbi = vbos[vbo];
vbi.uses = numva;
-
if(printvbo) conoutf(CON_DEBUG, "vbo %d: type %d, size %d, %d uses", vbo, type, len, numva);
-
- loopi(numva)
- {
+ loopi(numva) {
vtxarray *va = vas[i];
- switch(type)
- {
+ switch(type) {
case VBO_VBUF:
va->vbuf = vbo;
break;
}
}
-bool readva(vtxarray *va, ushort *&edata, vertex *&vdata)
-{
+bool readva(vtxarray *va, ushort *&edata, vertex *&vdata) {
if(!va->vbuf || !va->ebuf) return false;
-
edata = new ushort[3*va->tris];
vdata = new vertex[va->verts];
-
gle::bindebo(va->ebuf);
glGetBufferSubData_(GL_ELEMENT_ARRAY_BUFFER, (size_t)va->edata, 3*va->tris*sizeof(ushort), edata);
gle::clearebo();
-
gle::bindvbo(va->vbuf);
glGetBufferSubData_(GL_ARRAY_BUFFER, va->voffset*sizeof(vertex), va->verts*sizeof(vertex), vdata);
gle::clearvbo();
return true;
}
-void flushvbo(int type = -1)
-{
- if(type < 0)
- {
+void flushvbo(int type = -1) {
+ if(type < 0) {
loopi(NUMVBO) flushvbo(i);
return;
}
-
vector<uchar> &data = vbodata[type];
if(data.empty()) return;
vector<vtxarray *> &vas = vbovas[type];
vbosize[type] = 0;
}
-uchar *addvbo(vtxarray *va, int type, int numelems, int elemsize)
-{
+uchar *addvbo(vtxarray *va, int type, int numelems, int elemsize) {
vbosize[type] += numelems;
-
vector<uchar> &data = vbodata[type];
vector<vtxarray *> &vas = vbovas[type];
-
vas.add(va);
-
int len = numelems*elemsize;
uchar *buf = data.reserve(len).buf;
data.advance(len);
return buf;
}
-struct verthash
-{
+struct verthash {
static const int SIZE = 1<<13;
int table[SIZE];
vector<vertex> verts;
vector<int> chain;
-
verthash() { clearverts(); }
-
- void clearverts()
- {
+ void clearverts() {
memset(table, -1, sizeof(table));
chain.setsize(0);
verts.setsize(0);
}
-
- int addvert(const vertex &v)
- {
+ int addvert(const vertex &v) {
uint h = hthash(v.pos)&(SIZE-1);
- for(int i = table[h]; i>=0; i = chain[i])
- {
+ for(int i = table[h]; i>=0; i = chain[i]) {
const vertex &c = verts[i];
if(c.pos==v.pos && c.tc==v.tc && c.norm==v.norm && c.tangent==v.tangent && (v.lm.iszero() || c.lm==v.lm))
return i;
chain.add(table[h]);
return table[h] = verts.length()-1;
}
-
- int addvert(const vec &pos, const vec2 &tc = vec2(0, 0), const svec2 &lm = svec2(0, 0), const bvec &norm = bvec(128, 128, 128), const bvec4 &tangent = bvec4(128, 128, 128, 128))
- {
+ int addvert(const vec &pos, const vec2 &tc = vec2(0, 0), const svec2 &lm = svec2(0, 0), const bvec &norm = bvec(128, 128, 128), const bvec4 &tangent = bvec4(128, 128, 128, 128)) {
vertex vtx;
vtx.pos = pos;
vtx.tc = tc;
}
};
-enum
-{
+enum {
NO_ALPHA = 0,
ALPHA_BACK,
ALPHA_FRONT
};
-struct sortkey
-{
+struct sortkey {
ushort tex, lmid;
uchar dim, layer, alpha;
-
sortkey() {}
sortkey(ushort tex, ushort lmid, uchar dim, uchar layer = LAYER_TOP, uchar alpha = NO_ALPHA)
: tex(tex), lmid(lmid), dim(dim), layer(layer), alpha(alpha)
{}
-
bool operator==(const sortkey &o) const { return tex==o.tex && lmid==o.lmid && dim==o.dim && layer==o.layer && alpha==o.alpha; }
};
-struct sortval
-{
+struct sortval {
int unlit;
vector<ushort> tris[2];
-
sortval() : unlit(0) {}
};
-static inline bool htcmp(const sortkey &x, const sortkey &y)
-{
+static inline bool htcmp(const sortkey &x, const sortkey &y) {
return x == y;
}
-static inline uint hthash(const sortkey &k)
-{
+static inline uint hthash(const sortkey &k) {
return k.tex + k.lmid*9741;
}
-struct vacollect : verthash
-{
+struct vacollect : verthash {
ivec origin;
int size;
hashtable<sortkey, sortval> indices;
vector<materialsurface> matsurfs;
vector<octaentities *> mapmodels;
int worldtris;
-
- void clear()
- {
+ void clear() {
clearverts();
worldtris = 0;
indices.clear();
mapmodels.setsize(0);
texs.setsize(0);
}
-
- void remapunlit(vector<sortkey> &remap)
- {
+ void remapunlit(vector<sortkey> &remap) {
uint lastlmid[8] = { LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT },
firstlmid[8] = { LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT, LMID_AMBIENT };
int firstlit[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
- loopv(texs)
- {
+ loopv(texs) {
sortkey &k = texs[i];
- if(k.lmid>=LMID_RESERVED)
- {
+ if(k.lmid>=LMID_RESERVED) {
LightMapTexture &lmtex = lightmaptexs[k.lmid];
int type = lmtex.type&LM_TYPE;
if(k.layer==LAYER_BLEND) type += 2;
else if(k.alpha) type += 4 + 2*(k.alpha-1);
lastlmid[type] = lmtex.unlitx>=0 ? (int) k.lmid : (int) LMID_AMBIENT;
- if(firstlmid[type]==LMID_AMBIENT && lastlmid[type]!=LMID_AMBIENT)
- {
+ if(firstlmid[type]==LMID_AMBIENT && lastlmid[type]!=LMID_AMBIENT) {
firstlit[type] = i;
firstlmid[type] = lastlmid[type];
}
}
- else if(k.lmid==LMID_AMBIENT)
- {
+ else if(k.lmid==LMID_AMBIENT) {
Shader *s = lookupvslot(k.tex, false).slot->shader;
int type = s->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
if(k.layer==LAYER_BLEND) type += 2;
else if(k.alpha) type += 4 + 2*(k.alpha-1);
- if(lastlmid[type]!=LMID_AMBIENT)
- {
+ if(lastlmid[type]!=LMID_AMBIENT) {
sortval &t = indices[k];
if(t.unlit<=0) t.unlit = lastlmid[type];
}
}
}
- loopj(2)
- {
+ loopj(2) {
int offset = 2*j;
if(firstlmid[offset]==LMID_AMBIENT && firstlmid[offset+1]==LMID_AMBIENT) continue;
- loopi(max(firstlit[offset], firstlit[offset+1]))
- {
+ loopi(max(firstlit[offset], firstlit[offset+1])) {
sortkey &k = texs[i];
if((j ? k.layer!=LAYER_BLEND : k.layer==LAYER_BLEND) || k.alpha) continue;
if(k.lmid!=LMID_AMBIENT) continue;
indices[k].unlit = firstlmid[type];
}
}
- loopj(2)
- {
+ loopj(2) {
int offset = 4 + 2*j;
if(firstlmid[offset]==LMID_AMBIENT && firstlmid[offset+1]==LMID_AMBIENT) continue;
- loopi(max(firstlit[offset], firstlit[offset+1]))
- {
+ loopi(max(firstlit[offset], firstlit[offset+1])) {
sortkey &k = texs[i];
if(k.alpha != j+1) continue;
if(k.lmid!=LMID_AMBIENT) continue;
indices[k].unlit = firstlmid[type];
}
}
- loopv(remap)
- {
+ loopv(remap) {
sortkey &k = remap[i];
sortval &t = indices[k];
if(t.unlit<=0) continue;
LightMapTexture &lm = lightmaptexs[t.unlit];
svec2 lmtc(short(ceil((lm.unlitx + 0.5f) * SHRT_MAX/lm.w)),
short(ceil((lm.unlity + 0.5f) * SHRT_MAX/lm.h)));
- loopl(2) loopvj(t.tris[l])
- {
+ loopl(2) loopvj(t.tris[l]) {
vertex &vtx = verts[t.tris[l][j]];
if(vtx.lm.iszero()) vtx.lm = lmtc;
- else if(vtx.lm != lmtc)
- {
+ else if(vtx.lm != lmtc) {
vertex vtx2 = vtx;
vtx2.lm = lmtc;
t.tris[l][j] = addvert(vtx2);
if(dst) loopl(2) loopvj(t.tris[l]) dst->tris[l].add(t.tris[l][j]);
}
}
-
- void optimize()
- {
+ void optimize() {
vector<sortkey> remap;
enumeratekt(indices, sortkey, k, sortval, t,
- loopl(2) if(t.tris[l].length() && t.unlit<=0)
- {
- if(k.lmid>=LMID_RESERVED && lightmaptexs[k.lmid].unlitx>=0)
- {
+ loopl(2) if(t.tris[l].length() && t.unlit<=0) {
+ if(k.lmid>=LMID_RESERVED && lightmaptexs[k.lmid].unlitx>=0) {
sortkey ukey(k.tex, LMID_AMBIENT, k.dim, k.layer, k.alpha);
sortval *uval = indices.access(ukey);
- if(uval && uval->unlit<=0)
- {
+ if(uval && uval->unlit<=0) {
if(uval->unlit<0) texs.removeobj(ukey);
else remap.add(ukey);
uval->unlit = k.lmid;
}
}
- else if(k.lmid==LMID_AMBIENT)
- {
+ else if(k.lmid==LMID_AMBIENT) {
remap.add(k);
t.unlit = -1;
}
}
);
texs.sort(texsort);
-
remapunlit(remap);
-
matsurfs.shrink(optimizematsurfs(matsurfs.getbuf(), matsurfs.length()));
}
-
- static inline bool texsort(const sortkey &x, const sortkey &y)
- {
+ static inline bool texsort(const sortkey &x, const sortkey &y) {
if(x.alpha < y.alpha) return true;
if(x.alpha > y.alpha) return false;
if(x.layer < y.layer) return true;
if(x.layer > y.layer) return false;
- if(x.tex == y.tex)
- {
+ if(x.tex == y.tex) {
if(x.lmid < y.lmid) return true;
if(x.lmid > y.lmid) return false;
if(x.dim < y.dim) return true;
else return false;
}
-#define GENVERTS(type, ptr, body) do \
- { \
+#define GENVERTS(type, ptr, body) do { \
+ \
type *f = (type *)ptr; \
- loopv(verts) \
- { \
+ loopv(verts) { \
+ \
const vertex &v = verts[i]; \
body; \
f++; \
} \
} while(0)
-
- void genverts(void *buf)
- {
+ void genverts(void *buf) {
GENVERTS(vertex, buf, { *f = v; f->norm.flip(); f->tangent.flip(); });
}
-
- void setupdata(vtxarray *va)
- {
+ void setupdata(vtxarray *va) {
va->verts = verts.length();
va->tris = worldtris/3;
va->vbuf = 0;
va->minvert = 0;
va->maxvert = va->verts-1;
va->voffset = 0;
- if(va->verts)
- {
+ if(va->verts) {
if(vbosize[VBO_VBUF] + verts.length() > maxvbosize ||
vbosize[VBO_EBUF] + worldtris > USHRT_MAX)
flushvbo();
-
va->voffset = vbosize[VBO_VBUF];
uchar *vdata = addvbo(va, VBO_VBUF, va->verts, sizeof(vertex));
genverts(vdata);
va->minvert += va->voffset;
va->maxvert += va->voffset;
}
-
va->matbuf = NULL;
va->matsurfs = matsurfs.length();
- if(va->matsurfs)
- {
+ if(va->matsurfs) {
va->matbuf = new materialsurface[matsurfs.length()];
memcpy(va->matbuf, matsurfs.getbuf(), matsurfs.length()*sizeof(materialsurface));
}
-
va->eslist = NULL;
va->texs = texs.length();
va->blendtris = 0;
va->ebuf = 0;
va->edata = 0;
va->texmask = 0;
- if(va->texs)
- {
+ if(va->texs) {
va->eslist = new elementset[va->texs];
va->edata += vbosize[VBO_EBUF];
ushort *edata = (ushort *)addvbo(va, VBO_EBUF, worldtris, sizeof(ushort)), *curbuf = edata;
- loopv(texs)
- {
+ loopv(texs) {
const sortkey &k = texs[i];
const sortval &t = indices[k];
elementset &e = va->eslist[i];
e.dim = k.dim;
e.layer = k.layer;
ushort *startbuf = curbuf;
- loopl(2)
- {
+ loopl(2) {
e.minvert[l] = USHRT_MAX;
e.maxvert[l] = 0;
-
- if(t.tris[l].length())
- {
+ if(t.tris[l].length()) {
memcpy(curbuf, t.tris[l].getbuf(), t.tris[l].length() * sizeof(ushort));
-
- loopvj(t.tris[l])
- {
+ loopvj(t.tris[l]) {
curbuf[j] += va->voffset;
e.minvert[l] = min(e.minvert[l], curbuf[j]);
e.maxvert[l] = max(e.maxvert[l], curbuf[j]);
}
-
curbuf += t.tris[l].length();
}
e.length[l] = curbuf-startbuf;
if(k.layer==LAYER_BLEND) { va->texs--; va->tris -= e.length[1]/3; va->blends++; va->blendtris += e.length[1]/3; }
else if(k.alpha==ALPHA_BACK) { va->texs--; va->tris -= e.length[1]/3; va->alphaback++; va->alphabacktris += e.length[1]/3; }
else if(k.alpha==ALPHA_FRONT) { va->texs--; va->tris -= e.length[1]/3; va->alphafront++; va->alphafronttris += e.length[1]/3; }
-
Slot &slot = *lookupvslot(k.tex, false).slot;
loopvj(slot.sts) va->texmask |= 1<<slot.sts[j].type;
}
}
-
va->alphatris = va->alphabacktris + va->alphafronttris;
-
if(mapmodels.length()) va->mapmodels.put(mapmodels.getbuf(), mapmodels.length());
}
-
- bool emptyva()
- {
+ bool emptyva() {
return verts.empty() && matsurfs.empty() && mapmodels.empty();
}
} vc;
vec shadowmapmin, shadowmapmax;
-int calcshadowmask(vec *pos, int numpos)
-{
+int calcshadowmask(vec *pos, int numpos) {
extern vec shadowdir;
int mask = 0, used = 1;
vec pe = vec(pos[1]).sub(pos[0]);
- loopk(numpos-2)
- {
+ loopk(numpos-2) {
vec e = vec(pos[k+2]).sub(pos[0]);
- if(vec().cross(pe, e).dot(shadowdir)>0)
- {
+ if(vec().cross(pe, e).dot(shadowdir)>0) {
mask |= 1<<k;
used |= 6<<k;
}
pe = e;
}
if(!mask) return 0;
- loopk(numpos) if(used&(1<<k))
- {
+ loopk(numpos) if(used&(1<<k)) {
const vec &v = pos[k];
shadowmapmin.min(v);
shadowmapmax.max(v);
VARFP(filltjoints, 0, 1, 1, allchanged());
-void reduceslope(ivec &n)
-{
+void reduceslope(ivec &n) {
int mindim = -1, minval = 64;
- loopi(3) if(n[i])
- {
+ loopi(3) if(n[i]) {
int val = abs(n[i]);
- if(mindim < 0 || val < minval)
- {
+ if(mindim < 0 || val < minval) {
mindim = i;
minval = val;
}
}
// [rotation][dimension]
-extern const vec orientation_tangent[8][3] =
-{
- { vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
- { vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) },
- { vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
- { vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) },
- { vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
- { vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
- { vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) },
- { vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) },
+extern const vec orientation_tangent[8][3] = {
+ {
+ vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, {
+ vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) }, {
+ vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, {
+ vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) }, {
+ vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, {
+ vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, {
+ vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) }, {
+ vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) },
};
-extern const vec orientation_bitangent[8][3] =
-{
- { vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) },
- { vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
- { vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) },
- { vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
- { vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) },
- { vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) },
- { vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) },
- { vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
+extern const vec orientation_bitangent[8][3] = {
+ {
+ vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) }, {
+ vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) }, {
+ vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) }, {
+ vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, {
+ vec(0, 0, -1), vec( 0, 0, -1), vec( 0, 1, 0) }, {
+ vec(0, 0, 1), vec( 0, 0, 1), vec( 0, -1, 0) }, {
+ vec(0, 1, 0), vec( 1, 0, 0), vec( 1, 0, 0) }, {
+ vec(0, -1, 0), vec(-1, 0, 0), vec(-1, 0, 0) },
};
-void addtris(const sortkey &key, int orient, vertex *verts, int *index, int numverts, int convex, int shadowmask, int tj)
-{
+void addtris(const sortkey &key, int orient, vertex *verts, int *index, int numverts, int convex, int shadowmask, int tj) {
int &total = vc.worldtris;
int edge = orient*(MAXFACEVERTS+1);
- loopi(numverts-2) if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0])
- {
+ loopi(numverts-2) if(index[0]!=index[i+1] && index[i+1]!=index[i+2] && index[i+2]!=index[0]) {
vector<ushort> &idxs = vc.indices[key].tris[(shadowmask>>i)&1];
int left = index[0], mid = index[i+1], right = index[i+2], start = left, i0 = left, i1 = -1;
- loopk(4)
- {
+ loopk(4) {
int i2 = -1, ctj = -1, cedge = -1;
- switch(k)
- {
+ switch(k) {
case 1: i1 = i2 = mid; cedge = edge+i+1; break;
case 2: if(i1 != mid || i0 == left) { i0 = i1; i1 = right; } i2 = right; if(i+1 == numverts-2) cedge = edge+i+2; break;
case 3: if(i0 == start) { i0 = i1; i1 = left; } i2 = left; // fall-through
default: if(!i) cedge = edge; break;
}
- if(i1 != i2)
- {
+ if(i1 != i2) {
if(total + 3 > USHRT_MAX) return;
total += 3;
idxs.add(i0);
idxs.add(i2);
i1 = i2;
}
- if(cedge >= 0)
- {
- for(ctj = tj;;)
- {
+ if(cedge >= 0) {
+ for(ctj = tj;;) {
if(ctj < 0) break;
if(tjoints[ctj].edge < cedge) { ctj = tjoints[ctj].next; continue; }
if(tjoints[ctj].edge != cedge) ctj = -1;
break;
}
}
- if(ctj >= 0)
- {
+ if(ctj >= 0) {
int e1 = cedge%(MAXFACEVERTS+1), e2 = (e1+1)%numverts;
vertex &v1 = verts[e1], &v2 = verts[e2];
ivec d(vec(v2.pos).sub(v1.pos).mul(8));
offset2 = (int(v2.pos[axis]*8) - origin) / d[axis];
vec o = vec(v1.pos).sub(vec(d).mul(offset1/8.0f));
float doffset = 1.0f / (offset2 - offset1);
-
- if(i1 < 0) for(;;)
- {
+ if(i1 < 0) for(;;) {
tjoint &t = tjoints[ctj];
if(t.next < 0 || tjoints[t.next].edge != cedge) break;
ctj = t.next;
}
- while(ctj >= 0)
- {
+ while(ctj >= 0) {
tjoint &t = tjoints[ctj];
if(t.edge != cedge) break;
float offset = (t.offset - offset1) * doffset;
vt.tangent.lerp(v1.tangent, v2.tangent, offset);
int i2 = vc.addvert(vt);
if(i2 < 0) return;
- if(i1 >= 0)
- {
+ if(i1 >= 0) {
if(total + 3 > USHRT_MAX) return;
total += 3;
idxs.add(i0);
}
}
-static inline void calctexgen(VSlot &vslot, int dim, vec4 &sgen, vec4 &tgen)
-{
+static inline void calctexgen(VSlot &vslot, int dim, vec4 &sgen, vec4 &tgen) {
Texture *tex = vslot.slot->sts.empty() ? notexture : vslot.slot->sts[0].t;
const texrotation &r = texrotations[vslot.rotation];
float k = TEX_SCALE/vslot.scale,
int sdim = si[dim], tdim = ti[dim];
sgen = vec4(0, 0, 0, soff);
tgen = vec4(0, 0, 0, toff);
- if(r.swapxy)
- {
+ if(r.swapxy) {
sgen[tdim] = (dim <= 1 ? -sk : sk);
tgen[sdim] = tk;
}
- else
- {
+ else {
sgen[sdim] = sk;
tgen[tdim] = (dim <= 1 ? -tk : tk);
}
}
-ushort encodenormal(const vec &n)
-{
+ushort encodenormal(const vec &n) {
if(n.iszero()) return 0;
int yaw = int(-atan2(n.x, n.y)/RAD), pitch = int(asin(n.z)/RAD);
return ushort(clamp(pitch + 90, 0, 180)*360 + (yaw < 0 ? yaw%360 + 360 : yaw%360) + 1);
}
-vec decodenormal(ushort norm)
-{
+vec decodenormal(ushort norm) {
if(!norm) return vec(0, 0, 1);
norm--;
const vec2 &yaw = sincos360[norm%360], &pitch = sincos360[norm/360+270];
return vec(-yaw.y*pitch.x, yaw.x*pitch.x, pitch.y);
}
-void guessnormals(const vec *pos, int numverts, vec *normals)
-{
+void guessnormals(const vec *pos, int numverts, vec *normals) {
vec n1, n2;
n1.cross(pos[0], pos[1], pos[2]);
- if(numverts != 4)
- {
+ if(numverts != 4) {
n1.normalize();
loopk(numverts) normals[k] = n1;
return;
}
n2.cross(pos[0], pos[2], pos[3]);
- if(n1.iszero())
- {
+ if(n1.iszero()) {
n2.normalize();
loopk(4) normals[k] = n2;
return;
}
else n1.normalize();
- if(n2.iszero())
- {
+ if(n2.iszero()) {
loopk(4) normals[k] = n1;
return;
}
normals[3] = n2;
}
-void addcubeverts(VSlot &vslot, int orient, int size, vec *pos, int convex, ushort texture, ushort lmid, vertinfo *vinfo, int numverts, int tj = -1, int grassy = 0, bool alpha = false, int layer = LAYER_TOP)
-{
+void addcubeverts(VSlot &vslot, int orient, int size, vec *pos, int convex, ushort texture, ushort lmid, vertinfo *vinfo, int numverts, int tj = -1, int grassy = 0, bool alpha = false, int layer = LAYER_TOP) {
(void) grassy;
int dim = dimension(orient);
int shadowmask = alpha ? 0 : calcshadowmask(pos, numverts);
-
LightMap *lm = NULL;
LightMapTexture *lmtex = NULL;
- if(lightmaps.inrange(lmid-LMID_RESERVED))
- {
+ if(lightmaps.inrange(lmid-LMID_RESERVED)) {
lm = &lightmaps[lmid-LMID_RESERVED];
if((lm->type&LM_TYPE)==LM_DIFFUSE ||
((lm->type&LM_TYPE)==LM_BUMPMAP0 &&
lmtex = &lightmaptexs[lm->tex];
else lm = NULL;
}
-
vec4 sgen, tgen;
calctexgen(vslot, dim, sgen, tgen);
vertex verts[MAXFACEVERTS];
int index[MAXFACEVERTS];
- loopk(numverts)
- {
+ loopk(numverts) {
vertex &v = verts[k];
v.pos = pos[k];
v.tc = vec2(sgen.dot(v.pos), tgen.dot(v.pos));
- if(lmtex)
- {
+ if(lmtex) {
v.lm = svec2(short(ceil((lm->offsetx + vinfo[k].u*(float(LM_PACKW)/float(USHRT_MAX+1)) + 0.5f) * float(SHRT_MAX)/lmtex->w)),
short(ceil((lm->offsety + vinfo[k].v*(float(LM_PACKH)/float(USHRT_MAX+1)) + 0.5f) * float(SHRT_MAX)/lmtex->h)));
}
else v.lm = svec2(0, 0);
- if(vinfo && vinfo[k].norm)
- {
+ if(vinfo && vinfo[k].norm) {
vec n = decodenormal(vinfo[k].norm), t = orientation_tangent[vslot.rotation][dim];
t.project(n).normalize();
v.norm = bvec(n);
v.tangent = bvec4(bvec(t), orientation_bitangent[vslot.rotation][dim].scalartriple(n, t) < 0 ? 0 : 255);
}
- else
- {
+ else {
v.norm = bvec(128, 128, 255);
v.tangent = bvec4(255, 128, 128, 255);
}
index[k] = vc.addvert(v);
if(index[k] < 0) return;
}
-
if(lmid >= LMID_RESERVED) lmid = lm ? lm->tex : LMID_AMBIENT;
-
sortkey key(texture, lmid, !vslot.scroll.iszero() ? dim : 3, layer == LAYER_BLEND ? LAYER_BLEND : LAYER_TOP, alpha ? (vslot.alphaback ? ALPHA_BACK : (vslot.alphafront ? ALPHA_FRONT : NO_ALPHA)) : NO_ALPHA);
addtris(key, orient, verts, index, numverts, convex, shadowmask, tj);
}
-struct edgegroup
-{
+struct edgegroup {
ivec slope, origin;
int axis;
};
-static uint hthash(const edgegroup &g)
-{
+static uint hthash(const edgegroup &g) {
return g.slope.x^(g.slope.y<<2)^(g.slope.z<<4)^g.origin.x^g.origin.y^g.origin.z;
}
-static bool htcmp(const edgegroup &x, const edgegroup &y)
-{
+static bool htcmp(const edgegroup &x, const edgegroup &y) {
return x.slope==y.slope && x.origin==y.origin;
}
-enum
-{
+enum {
CE_START = 1<<0,
CE_END = 1<<1,
CE_FLIP = 1<<2,
CE_DUP = 1<<3
};
-struct cubeedge
-{
+struct cubeedge {
cube *c;
int next, offset;
ushort size;
vector<cubeedge> cubeedges;
hashtable<edgegroup, int> edgegroups(1<<13);
-void gencubeedges(cube &c, const ivec &co, int size)
-{
+void gencubeedges(cube &c, const ivec &co, int size) {
ivec pos[MAXFACEVERTS];
int vis;
- loopi(6) if((vis = visibletris(c, i, co, size)))
- {
+ loopi(6) if((vis = visibletris(c, i, co, size))) {
int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0;
- if(numverts)
- {
+ if(numverts) {
vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
ivec vo = ivec(co).mask(~0xFFF).shl(3);
- loopj(numverts)
- {
+ loopj(numverts) {
vertinfo &v = verts[j];
pos[j] = ivec(v.x, v.y, v.z).add(vo);
}
}
else if(c.merged&(1<<i)) continue;
- else
- {
+ else {
ivec v[4];
genfaceverts(c, i, v);
int order = vis&4 || (!flataxisface(c, i) && faceconvexity(v) < 0) ? 1 : 0;
pos[numverts++] = v[order+2].mul(size).add(vo);
if(vis&2) pos[numverts++] = v[(order+3)&3].mul(size).add(vo);
}
- loopj(numverts)
- {
+ loopj(numverts) {
int e1 = j, e2 = j+1 < numverts ? j+1 : 0;
ivec d = pos[e2];
d.sub(pos[e1]);
if(d.iszero()) continue;
int axis = abs(d.x) > abs(d.y) ? (abs(d.x) > abs(d.z) ? 0 : 2) : (abs(d.y) > abs(d.z) ? 1 : 2);
- if(d[axis] < 0)
- {
+ if(d[axis] < 0) {
d.neg();
swap(e1, e2);
}
reduceslope(d);
-
int t1 = pos[e1][axis]/d[axis],
t2 = pos[e2][axis]/d[axis];
edgegroup g;
ce.index = i*(MAXFACEVERTS+1)+j;
ce.flags = CE_START | CE_END | (e1!=j ? CE_FLIP : 0);
ce.next = -1;
-
bool insert = true;
int *exists = edgegroups.access(g);
- if(exists)
- {
+ if(exists) {
int prev = -1, cur = *exists;
- while(cur >= 0)
- {
+ while(cur >= 0) {
cubeedge &p = cubeedges[cur];
- if(ce.offset <= p.offset+p.size)
- {
+ if(ce.offset <= p.offset+p.size) {
if(ce.offset < p.offset) break;
if(p.flags&CE_DUP ?
ce.offset+ce.size <= p.offset+p.size :
- ce.offset==p.offset && ce.size==p.size)
- {
+ ce.offset==p.offset && ce.size==p.size) {
p.flags |= CE_DUP;
insert = false;
break;
prev = cur;
cur = p.next;
}
- if(insert)
- {
+ if(insert) {
ce.next = cur;
- while(cur >= 0)
- {
+ while(cur >= 0) {
cubeedge &p = cubeedges[cur];
if(ce.offset+ce.size==p.offset) { ce.flags &= ~CE_END; break; }
cur = p.next;
}
}
else edgegroups[g] = cubeedges.length();
-
if(insert) cubeedges.add(ce);
}
}
}
-void gencubeedges(cube *c = worldroot, const ivec &co = ivec(0, 0, 0), int size = worldsize>>1)
-{
+void gencubeedges(cube *c = worldroot, const ivec &co = ivec(0, 0, 0), int size = worldsize>>1) {
progress("fixing t-joints...");
neighbourstack[++neighbourdepth] = c;
- loopi(8)
- {
+ loopi(8) {
ivec o(i, co, size);
if(c[i].ext) c[i].ext->tjoints = -1;
if(c[i].children) gencubeedges(c[i].children, o, size>>1);
--neighbourdepth;
}
-void gencubeverts(cube &c, const ivec &co, int size, int csi)
-{
+void gencubeverts(cube &c, const ivec &co, int size, int csi) {
if(!(c.visible&0xC0)) return;
-
int vismask = ~c.merged & 0x3F;
if(!(c.visible&0x80)) vismask &= c.visible;
if(!vismask) return;
-
int tj = filltjoints && c.ext ? c.ext->tjoints : -1, vis;
- loopi(6) if(vismask&(1<<i) && (vis = visibletris(c, i, co, size)))
- {
+ loopi(6) if(vismask&(1<<i) && (vis = visibletris(c, i, co, size))) {
vec pos[MAXFACEVERTS];
vertinfo *verts = NULL;
int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0, convex = 0;
- if(numverts)
- {
+ if(numverts) {
verts = c.ext->verts() + c.ext->surfaces[i].verts;
vec vo(ivec(co).mask(~0xFFF));
loopj(numverts) pos[j] = vec(verts[j].getxyz()).mul(1.0f/8).add(vo);
if(!flataxisface(c, i)) convex = faceconvexity(verts, numverts, size);
}
- else
- {
+ else {
ivec v[4];
genfaceverts(c, i, v);
if(!flataxisface(c, i)) convex = faceconvexity(v);
pos[numverts++] = vec(v[order+2]).mul(size/8.0f).add(vo);
if(vis&2) pos[numverts++] = vec(v[(order+3)&3]).mul(size/8.0f).add(vo);
}
-
VSlot &vslot = lookupvslot(c.texture[i], true),
*layer = vslot.layer && !(c.material&MAT_ALPHA) ? &lookupvslot(vslot.layer, true) : NULL;
while(tj >= 0 && tjoints[tj].edge < i*(MAXFACEVERTS+1)) tj = tjoints[tj].next;
int hastj = tj >= 0 && tjoints[tj].edge < (i+1)*(MAXFACEVERTS+1) ? tj : -1;
if(!c.ext)
addcubeverts(vslot, i, size, pos, convex, c.texture[i], LMID_AMBIENT, NULL, numverts, hastj, 0, (c.material&MAT_ALPHA)!=0);
- else
- {
+ else {
const surfaceinfo &surf = c.ext->surfaces[i];
if(!surf.numverts || surf.numverts&LAYER_TOP)
addcubeverts(vslot, i, size, pos, convex, c.texture[i], surf.lmid[0], verts, numverts, hastj, 0, (c.material&MAT_ALPHA)!=0, LAYER_TOP|(surf.numverts&LAYER_BLEND));
int wtris = 0, wverts = 0, vtris = 0, vverts = 0, glde = 0, gbatches = 0;
vector<vtxarray *> valist, varoot;
-vtxarray *newva(const ivec &co, int size)
-{
+vtxarray *newva(const ivec &co, int size) {
vc.optimize();
-
vtxarray *va = new vtxarray;
va->parent = NULL;
va->o = co;
va->bbmax = ivec(-1, -1, -1);
va->hasmerges = 0;
va->mergelevel = -1;
-
vc.setupdata(va);
-
wverts += va->verts;
wtris += va->tris + va->blends + va->alphatris;
allocva++;
valist.add(va);
-
return va;
}
-void destroyva(vtxarray *va, bool reparent)
-{
+void destroyva(vtxarray *va, bool reparent) {
wverts -= va->verts;
wtris -= va->tris + va->blends + va->alphatris;
allocva--;
valist.removeobj(va);
if(!va->parent) varoot.removeobj(va);
- if(reparent)
- {
+ if(reparent) {
if(va->parent) va->parent->children.removeobj(va);
- loopv(va->children)
- {
+ loopv(va->children) {
vtxarray *child = va->children[i];
child->parent = va->parent;
if(child->parent) child->parent->children.add(child);
delete va;
}
-void clearvas(cube *c)
-{
- loopi(8)
- {
- if(c[i].ext)
- {
+void clearvas(cube *c) {
+ loopi(8) {
+ if(c[i].ext) {
if(c[i].ext->va) destroyva(c[i].ext->va, false);
c[i].ext->va = NULL;
c[i].ext->tjoints = -1;
}
}
-void updatevabb(vtxarray *va, bool force)
-{
+void updatevabb(vtxarray *va, bool force) {
if(!force && va->bbmin.x >= 0) return;
-
va->bbmin = va->geommin;
va->bbmax = va->geommax;
va->bbmin.min(va->matmin);
va->bbmax.max(va->matmax);
- loopv(va->children)
- {
+ loopv(va->children) {
vtxarray *child = va->children[i];
updatevabb(child, force);
va->bbmin.min(child->bbmin);
va->bbmax.max(child->bbmax);
}
- loopv(va->mapmodels)
- {
+ loopv(va->mapmodels) {
octaentities *oe = va->mapmodels[i];
va->bbmin.min(oe->bbmin);
va->bbmax.max(oe->bbmax);
va->bbmax.min(ivec(va->o).add(va->size));
}
-void updatevabbs(bool force)
-{
+void updatevabbs(bool force) {
loopv(varoot) updatevabb(varoot[i], force);
}
-struct mergedface
-{
+struct mergedface {
uchar orient, lmid, numverts;
ushort mat, tex;
vertinfo *verts;
static int vahasmerges = 0, vamergemax = 0;
static vector<mergedface> vamerges[MAXMERGELEVEL+1];
-int genmergedfaces(cube &c, const ivec &co, int size, int minlevel = -1)
-{
+int genmergedfaces(cube &c, const ivec &co, int size, int minlevel = -1) {
if(!c.ext || isempty(c)) return -1;
int tj = c.ext->tjoints, maxlevel = -1;
- loopi(6) if(c.merged&(1<<i))
- {
+ loopi(6) if(c.merged&(1<<i)) {
surfaceinfo &surf = c.ext->surfaces[i];
int numverts = surf.numverts&MAXFACEVERTS;
- if(!numverts)
- {
+ if(!numverts) {
if(minlevel < 0) vahasmerges |= MERGE_PART;
continue;
}
mf.verts = c.ext->verts() + surf.verts;
mf.tjoints = -1;
int level = calcmergedsize(i, co, size, mf.verts, mf.numverts&MAXFACEVERTS);
- if(level > minlevel)
- {
+ if(level > minlevel) {
maxlevel = max(maxlevel, level);
-
while(tj >= 0 && tjoints[tj].edge < i*(MAXFACEVERTS+1)) tj = tjoints[tj].next;
if(tj >= 0 && tjoints[tj].edge < (i+1)*(MAXFACEVERTS+1)) mf.tjoints = tj;
-
VSlot &vslot = lookupvslot(mf.tex, true);
-
if(surf.numverts&LAYER_TOP) vamerges[level].add(mf);
- if(surf.numverts&LAYER_BOTTOM)
- {
+ if(surf.numverts&LAYER_BOTTOM) {
mf.tex = vslot.layer;
mf.lmid = surf.lmid[1];
mf.numverts &= ~LAYER_TOP;
}
}
}
- if(maxlevel >= 0)
- {
+ if(maxlevel >= 0) {
vamergemax = max(vamergemax, maxlevel);
vahasmerges |= MERGE_ORIGIN;
}
return maxlevel;
}
-int findmergedfaces(cube &c, const ivec &co, int size, int csi, int minlevel)
-{
+int findmergedfaces(cube &c, const ivec &co, int size, int csi, int minlevel) {
if(c.ext && c.ext->va && !(c.ext->va->hasmerges&MERGE_ORIGIN)) return c.ext->va->mergelevel;
- else if(c.children)
- {
+ else if(c.children) {
int maxlevel = -1;
- loopi(8)
- {
+ loopi(8) {
ivec o(i, co, size/2);
int level = findmergedfaces(c.children[i], o, size/2, csi-1, minlevel);
maxlevel = max(maxlevel, level);
else return -1;
}
-void addmergedverts(int level, const ivec &o)
-{
+void addmergedverts(int level, const ivec &o) {
vector<mergedface> &mfl = vamerges[level];
if(mfl.empty()) return;
vec vo(ivec(o).mask(~0xFFF));
vec pos[MAXFACEVERTS];
- loopv(mfl)
- {
+ loopv(mfl) {
mergedface &mf = mfl[i];
int numverts = mf.numverts&MAXFACEVERTS;
- loopi(numverts)
- {
+ loopi(numverts) {
vertinfo &v = mf.verts[i];
pos[i] = vec(v.x, v.y, v.z).mul(1.0f/8).add(vo);
}
mfl.setsize(0);
}
-void rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel) // creates vertices and indices ready to be put into a va
-{
+void rendercube(cube &c, const ivec &co, int size, int csi, int &maxlevel) { // creates vertices and indices ready to be put into a va {
//if(size<=16) return;
- if(c.ext && c.ext->va)
- {
+ if(c.ext && c.ext->va) {
maxlevel = max(maxlevel, c.ext->va->mergelevel);
return; // don't re-render
}
-
- if(c.children)
- {
+ if(c.children) {
neighbourstack[++neighbourdepth] = c.children;
c.escaped = 0;
- loopi(8)
- {
+ loopi(8) {
ivec o(i, co, size/2);
int level = -1;
rendercube(c.children[i], o, size/2, csi-1, level);
maxlevel = max(maxlevel, level);
}
--neighbourdepth;
-
if(csi <= MAXMERGELEVEL && vamerges[csi].length()) addmergedverts(csi, co);
-
- if(c.ext)
- {
+ if(c.ext) {
if(c.ext->ents && c.ext->ents->mapmodels.length()) vc.mapmodels.add(c.ext->ents);
}
return;
}
-
- if(!isempty(c))
- {
+ if(!isempty(c)) {
gencubeverts(c, co, size, csi);
if(c.merged) maxlevel = max(maxlevel, genmergedfaces(c, co, size));
}
if(c.material != MAT_AIR) genmatsurfs(c, co, size, vc.matsurfs);
-
- if(c.ext)
- {
+ if(c.ext) {
if(c.ext->ents && c.ext->ents->mapmodels.length()) vc.mapmodels.add(c.ext->ents);
}
-
if(csi <= MAXMERGELEVEL && vamerges[csi].length()) addmergedverts(csi, co);
}
-void calcgeombb(const ivec &co, int size, ivec &bbmin, ivec &bbmax)
-{
+void calcgeombb(const ivec &co, int size, ivec &bbmin, ivec &bbmax) {
vec vmin(co), vmax = vmin;
vmin.add(size);
-
- loopv(vc.verts)
- {
+ loopv(vc.verts) {
const vec &v = vc.verts[i].pos;
vmin.min(v);
vmax.max(v);
}
-
bbmin = ivec(vmin.mul(8)).shr(3);
bbmax = ivec(vmax.mul(8)).add(7).shr(3);
}
-void calcmatbb(const ivec &co, int size, ivec &bbmin, ivec &bbmax)
-{
+void calcmatbb(const ivec &co, int size, ivec &bbmin, ivec &bbmax) {
bbmax = co;
(bbmin = bbmax).add(size);
- loopv(vc.matsurfs)
- {
+ loopv(vc.matsurfs) {
materialsurface &m = vc.matsurfs[i];
-
int dim = dimension(m.orient),
r = R[dim],
c = C[dim];
bbmin[dim] = min(bbmin[dim], m.o[dim]);
bbmax[dim] = max(bbmax[dim], m.o[dim]);
-
bbmin[r] = min(bbmin[r], m.o[r]);
bbmax[r] = max(bbmax[r], m.o[r] + m.rsize);
-
bbmin[c] = min(bbmin[c], m.o[c]);
bbmax[c] = max(bbmax[c], m.o[c] + m.csize);
}
}
-void setva(cube &c, const ivec &co, int size, int csi)
-{
+void setva(cube &c, const ivec &co, int size, int csi) {
ASSERT(size <= 0x1000);
-
int vamergeoffset[MAXMERGELEVEL+1];
loopi(MAXMERGELEVEL+1) vamergeoffset[i] = vamerges[i].length();
-
vc.origin = co;
vc.size = size;
-
shadowmapmin = vec(co).add(size);
shadowmapmax = vec(co);
-
int maxlevel = -1;
rendercube(c, co, size, csi, maxlevel);
-
ivec bbmin, bbmax;
-
calcgeombb(co, size, bbmin, bbmax);
-
- if(size == min(0x1000, worldsize/2) || !vc.emptyva())
- {
+ if(size == min(0x1000, worldsize/2) || !vc.emptyva()) {
vtxarray *va = newva(co, size);
ext(c).va = va;
va->geommin = bbmin;
va->hasmerges = vahasmerges;
va->mergelevel = vamergemax;
}
- else
- {
+ else {
loopi(MAXMERGELEVEL+1) vamerges[i].setsize(vamergeoffset[i]);
}
-
vc.clear();
}
-static inline int setcubevisibility(cube &c, const ivec &co, int size)
-{
+static inline int setcubevisibility(cube &c, const ivec &co, int size) {
int numvis = 0, vismask = 0, collidemask = 0, checkmask = 0;
- loopi(6)
- {
+ loopi(6) {
int facemask = classifyface(c, i, co, size);
- if(facemask&1)
- {
+ if(facemask&1) {
vismask |= 1<<i;
- if(c.merged&(1<<i))
- {
+ if(c.merged&(1<<i)) {
if(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS) numvis++;
}
- else
- {
+ else {
numvis++;
if(!(c.ext && c.ext->surfaces[i].numverts&MAXFACEVERTS)) checkmask |= 1<<i;
}
VARF(vafacemin, 0, 96, 256*256, allchanged());
VARF(vacubesize, 32, 128, 0x1000, allchanged());
-int updateva(cube *c, const ivec &co, int size, int csi)
-{
+int updateva(cube *c, const ivec &co, int size, int csi) {
progress("recalculating geometry...");
int ccount = 0, cmergemax = vamergemax, chasmerges = vahasmerges;
neighbourstack[++neighbourdepth] = c;
- loopi(8) // counting number of semi-solid/solid children cubes
- {
+ loopi(8) { // counting number of semi-solid/solid children cubes {
int count = 0, childpos = varoot.length();
ivec o(i, co, size);
vamergemax = 0;
vahasmerges = 0;
- if(c[i].ext && c[i].ext->va)
- {
+ if(c[i].ext && c[i].ext->va) {
varoot.add(c[i].ext->va);
if(c[i].ext->va->hasmerges&MERGE_ORIGIN) findmergedfaces(c[i], o, size, csi, csi);
}
- else
- {
+ else {
if(c[i].children) count += updateva(c[i].children, o, size/2, csi-1);
- else
- {
+ else {
if(!isempty(c[i])) count += setcubevisibility(c[i], o, size);
}
int tcount = count + (csi <= MAXMERGELEVEL ? vamerges[csi].length() : 0);
- if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == min(0x1000, worldsize/2))
- {
+ if(tcount > vafacemax || (tcount >= vafacemin && size >= vacubesize) || size == min(0x1000, worldsize/2)) {
loadprogress = clamp(recalcprogress/float(allocnodes), 0.0f, 1.0f);
setva(c[i], o, size, csi);
- if(c[i].ext && c[i].ext->va)
- {
- while(varoot.length() > childpos)
- {
+ if(c[i].ext && c[i].ext->va) {
+ while(varoot.length() > childpos) {
vtxarray *child = varoot.pop();
c[i].ext->va->children.add(child);
child->parent = c[i].ext->va;
}
varoot.add(c[i].ext->va);
- if(vamergemax > size)
- {
+ if(vamergemax > size) {
cmergemax = max(cmergemax, vamergemax);
chasmerges |= vahasmerges&~MERGE_USE;
}
--neighbourdepth;
vamergemax = cmergemax;
vahasmerges = chasmerges;
-
return ccount;
}
-void addtjoint(const edgegroup &g, const cubeedge &e, int offset)
-{
+void addtjoint(const edgegroup &g, const cubeedge &e, int offset) {
int vcoord = (g.slope[g.axis]*offset + g.origin[g.axis]) & 0x7FFF;
tjoint &tj = tjoints.add();
tj.offset = vcoord / g.slope[g.axis];
tj.edge = e.index;
-
int prev = -1, cur = ext(*e.c).tjoints;
- while(cur >= 0)
- {
+ while(cur >= 0) {
tjoint &o = tjoints[cur];
if(tj.edge < o.edge || (tj.edge==o.edge && (e.flags&CE_FLIP ? tj.offset > o.offset : tj.offset < o.offset))) break;
prev = cur;
cur = o.next;
}
-
tj.next = cur;
if(prev < 0) e.c->ext->tjoints = tjoints.length()-1;
else tjoints[prev].next = tjoints.length()-1;
}
-void findtjoints(int cur, const edgegroup &g)
-{
+void findtjoints(int cur, const edgegroup &g) {
int active = -1;
- while(cur >= 0)
- {
+ while(cur >= 0) {
cubeedge &e = cubeedges[cur];
int prevactive = -1, curactive = active;
- while(curactive >= 0)
- {
+ while(curactive >= 0) {
cubeedge &a = cubeedges[curactive];
- if(a.offset+a.size <= e.offset)
- {
+ if(a.offset+a.size <= e.offset) {
if(prevactive >= 0) cubeedges[prevactive].next = a.next;
else active = a.next;
}
- else
- {
+ else {
prevactive = curactive;
- if(!(a.flags&CE_DUP))
- {
+ if(!(a.flags&CE_DUP)) {
if(e.flags&CE_START && e.offset > a.offset && e.offset < a.offset+a.size)
addtjoint(g, a, e.offset);
if(e.flags&CE_END && e.offset+e.size > a.offset && e.offset+e.size < a.offset+a.size)
addtjoint(g, a, e.offset+e.size);
}
- if(!(e.flags&CE_DUP))
- {
+ if(!(e.flags&CE_DUP)) {
if(a.flags&CE_START && a.offset > e.offset && a.offset < e.offset+e.size)
addtjoint(g, e, a.offset);
if(a.flags&CE_END && a.offset+a.size > e.offset && a.offset+a.size < e.offset+e.size)
}
}
-void findtjoints()
-{
+void findtjoints() {
recalcprogress = 0;
gencubeedges();
tjoints.setsize(0);
edgegroups.clear();
}
-void octarender() // creates va s for all leaf cubes that don't already have them
-{
+void octarender() { // creates va s for all leaf cubes that don't already have them {
int csi = 0;
while(1<<csi < worldsize) csi++;
-
recalcprogress = 0;
varoot.setsize(0);
updateva(worldroot, ivec(0, 0, 0), worldsize/2, csi-1);
loadprogress = 0;
flushvbo();
-
visibleva = NULL;
}
-void precachetextures()
-{
+void precachetextures() {
vector<int> texs;
- loopv(valist)
- {
+ loopv(valist) {
vtxarray *va = valist[i];
loopj(va->texs + va->blends) if(texs.find(va->eslist[j].texture) < 0) texs.add(va->eslist[j].texture);
}
- loopv(texs)
- {
+ loopv(texs) {
loadprogress = float(i+1)/texs.length();
lookupvslot(texs[i]);
}
loadprogress = 0;
}
-void allchanged(bool load)
-{
+void allchanged(bool load) {
renderprogress(0, "clearing vertex arrays...");
clearvas(worldroot);
resetqueries();
setupmaterials();
updatevabbs(true);
lightents();
- if(load)
- {
+ if(load) {
seedparticles();
drawtextures();
}
}
-void recalc()
-{
+void recalc() {
allchanged(true);
}
static clipplanes clipcache[MAXCLIPPLANES];
static int clipcacheversion = -2;
-static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size, bool collide = true, int offset = 0)
-{
+static inline clipplanes &getclipplanes(const cube &c, const ivec &o, int size, bool collide = true, int offset = 0) {
clipplanes &p = clipcache[int(&c - worldroot)&(MAXCLIPPLANES-1)];
- if(p.owner != &c || p.version != clipcacheversion+offset)
- {
+ if(p.owner != &c || p.version != clipcacheversion+offset) {
p.owner = &c;
p.version = clipcacheversion+offset;
genclipplanes(c, o, size, p, collide);
return p;
}
-void resetclipplanes()
-{
+void resetclipplanes() {
clipcacheversion += 2;
- if(!clipcacheversion)
- {
+ if(!clipcacheversion) {
memclear(clipcache);
clipcacheversion = 2;
}
#define INTERSECTPLANES(setentry, exit) \
float enterdist = -1e16f, exitdist = 1e16f; \
- loopi(p.size) \
- { \
+ loopi(p.size) { \
+ \
float pdist = p.p[i].dist(v), facing = ray.dot(p.p[i]); \
- if(facing < 0) \
- { \
+ if(facing < 0) { \
+ \
pdist /= -facing; \
- if(pdist > enterdist) \
- { \
+ if(pdist > enterdist) { \
+ \
if(pdist > exitdist) exit; \
enterdist = pdist; \
setentry; \
} \
} \
- else if(facing > 0) \
- { \
+ else if(facing > 0) { \
+ \
pdist /= -facing; \
- if(pdist < exitdist) \
- { \
+ if(pdist < exitdist) { \
+ \
if(pdist < enterdist) exit; \
exitdist = pdist; \
} \
}
#define INTERSECTBOX(setentry, exit) \
- loop(i, 3) \
- { \
- if(ray[i]) \
- { \
+ loop(i, 3) { \
+ \
+ if(ray[i]) { \
+ \
float prad = fabs(p.r[i] * invray[i]), pdist = (p.o[i] - v[i]) * invray[i], pmin = pdist - prad, pmax = pdist + prad; \
- if(pmin > enterdist) \
- { \
+ if(pmin > enterdist) { \
+ \
if(pmin > exitdist) exit; \
enterdist = pmin; \
setentry; \
} \
- if(pmax < exitdist) \
- { \
+ if(pmax < exitdist) { \
+ \
if(pmax < enterdist) exit; \
exitdist = pmax; \
} \
vec hitsurface;
-static inline bool raycubeintersect(const clipplanes &p, const cube &c, const vec &v, const vec &ray, const vec &invray, float &dist)
-{
+static inline bool raycubeintersect(const clipplanes &p, const cube &c, const vec &v, const vec &ray, const vec &invray, float &dist) {
int entry = -1, bbentry = -1;
INTERSECTPLANES(entry = i, return false);
INTERSECTBOX(bbentry = i, return false);
float hitentdist;
int hitent, hitorient;
-static float disttoent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t)
-{
+static float disttoent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
vec eo, es;
int orient = -1;
float dist = radius, f = 0.0f;
const vector<extentity *> &ents = entities::getents();
-
#define entintersect(mask, type, func) {\
- if((mode&(mask))==(mask)) loopv(oc->type) \
- { \
+ if((mode&(mask))==(mask)) loopv(oc->type) { \
+ \
extentity &e = *ents[oc->type[i]]; \
if(!(e.flags&EF_OCTA) || &e==t) continue; \
func; \
- if(f<dist && f>0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) \
- { \
+ if(f<dist && f>0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) { \
+ \
hitentdist = dist = f; \
hitent = oc->type[i]; \
hitorient = orient; \
} \
} \
}
-
entintersect(RAY_POLY, mapmodels,
if(!mmintersect(e, o, ray, radius, mode, f)) continue;
);
-
entintersect(RAY_ENTS, other,
entselectionbox(e, eo, es);
if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
);
-
entintersect(RAY_ENTS, mapmodels,
entselectionbox(e, eo, es);
if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
);
-
return dist;
}
-static float disttooutsideent(const vec &o, const vec &ray, float radius, int mode, extentity *t)
-{
+static float disttooutsideent(const vec &o, const vec &ray, float radius, int mode, extentity *t) {
vec eo, es;
int orient;
float dist = radius, f = 0.0f;
const vector<extentity *> &ents = entities::getents();
- loopv(outsideents)
- {
+ loopv(outsideents) {
extentity &e = *ents[outsideents[i]];
if(!(e.flags&EF_OCTA) || &e==t) continue;
entselectionbox(e, eo, es);
if(!rayboxintersect(eo, es, o, ray, f, orient)) continue;
- if(f<dist && f>0)
- {
+ if(f<dist && f>0) {
hitentdist = dist = f;
hitent = outsideents[i];
hitorient = orient;
}
// optimized shadow version
-static float shadowent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t)
-{
+static float shadowent(octaentities *oc, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
float dist = radius, f = 0.0f;
const vector<extentity *> &ents = entities::getents();
- loopv(oc->mapmodels)
- {
+ loopv(oc->mapmodels) {
extentity &e = *ents[oc->mapmodels[i]];
if(!(e.flags&EF_OCTA) || &e==t) continue;
if(!mmintersect(e, o, ray, radius, mode, f)) continue;
ivec lsizemask(invray.x>0 ? 1 : 0, invray.y>0 ? 1 : 0, invray.z>0 ? 1 : 0); \
#define CHECKINSIDEWORLD \
- if(!insideworld(o)) \
- { \
+ if(!insideworld(o)) { \
+ \
float disttoworld = 0, exitworld = 1e16f; \
- loopi(3) \
- { \
+ loopi(3) { \
+ \
float c = v[i]; \
- if(c<0 || c>=worldsize) \
- { \
+ if(c<0 || c>=worldsize) { \
+ \
float d = ((invray[i]>0?0:worldsize)-c)*invray[i]; \
if(d<0) return (radius>0?radius:-1); \
disttoworld = max(disttoworld, 0.1f + d); \
#define DOWNOCTREE(disttoent, earlyexit) \
cube *lc = levels[lshift]; \
- for(;;) \
- { \
+ for(;;) { \
+ \
lshift--; \
lc += octastep(x, y, z, lshift); \
- if(lc->ext && lc->ext->ents && lshift < elvl) \
- { \
+ if(lc->ext && lc->ext->ents && lshift < elvl) { \
+ \
float edist = disttoent(lc->ext->ents, o, ray, dent, mode, t); \
- if(edist < dent) \
- { \
+ if(edist < dent) { \
+ \
earlyexit return min(edist, dist); \
elvl = lshift; \
dent = min(dent, edist); \
if(diff >= uint(worldsize)) exitworld; \
diff >>= lshift; \
if(!diff) exitworld; \
- do \
- { \
+ do { \
+ \
lshift++; \
diff >>= 1; \
} while(diff);
-float raycube(const vec &o, const vec &ray, float radius, int mode, int size, extentity *t)
-{
+float raycube(const vec &o, const vec &ray, float radius, int mode, int size, extentity *t) {
if(ray.iszero()) return 0;
-
INITRAYCUBE;
CHECKINSIDEWORLD;
-
int closest = -1, x = int(v.x), y = int(v.y), z = int(v.z);
- for(;;)
- {
+ for(;;) {
DOWNOCTREE(disttoent, if(mode&RAY_SHADOW));
-
int lsize = 1<<lshift;
-
cube &c = *lc;
if((dist>0 || !(mode&RAY_SKIPFIRST)) &&
(((mode&RAY_EDITMAT) && c.material != MAT_AIR) ||
(!(mode&RAY_PASS) && lsize==size && !isempty(c)) ||
isentirelysolid(c) ||
- dent < dist))
- {
+ dent < dist)) {
if(closest >= 0) { hitsurface = vec(0, 0, 0); hitsurface[closest] = ray[closest]>0 ? -1 : 1; }
return min(dent, dist);
}
-
ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
-
- if(!isempty(c))
- {
+ if(!isempty(c)) {
const clipplanes &p = getclipplanes(c, lo, lsize, false, 1);
float f = 0;
if(raycubeintersect(p, c, v, ray, invray, f) && (dist+f>0 || !(mode&RAY_SKIPFIRST)))
return min(dent, dist+f);
}
-
FINDCLOSEST(closest = 0, closest = 1, closest = 2);
-
if(radius>0 && dist>=radius) return min(dent, dist);
-
UPOCTREE(return min(dent, radius>0 ? radius : dist));
}
}
// optimized version for lightmap shadowing... every cycle here counts!!!
-float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t)
-{
+float shadowray(const vec &o, const vec &ray, float radius, int mode, extentity *t) {
INITRAYCUBE;
CHECKINSIDEWORLD;
-
- int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z);
- for(;;)
- {
+ int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); (void) side;
+ for(;;) {
DOWNOCTREE(shadowent, );
-
cube &c = *lc;
ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
-
- if(!isempty(c) && !(c.material&MAT_ALPHA))
- {
- if(isentirelysolid(c))
- {
+ if(!isempty(c) && !(c.material&MAT_ALPHA)) {
+ if(isentirelysolid(c)) {
return dist;
}
- else
- {
+ else {
const clipplanes &p = getclipplanes(c, lo, 1<<lshift, false, 1);
INTERSECTPLANES(side = p.side[i], goto nextcube);
INTERSECTBOX(side = (i<<1) + 1 - lsizemask[i], goto nextcube);
- if(exitdist >= 0)
- {
+ if(exitdist >= 0) {
return dist+max(enterdist+0.1f, 0.0f);
}
}
}
-
nextcube:
FINDCLOSEST(side = O_RIGHT - lsizemask.x, side = O_FRONT - lsizemask.y, side = O_TOP - lsizemask.z);
-
if(dist>=radius) return dist;
-
UPOCTREE(return radius);
}
}
// thread safe version
-struct ShadowRayCache
-{
+struct ShadowRayCache {
clipplanes clipcache[MAXCLIPPLANES];
int version;
-
ShadowRayCache() : version(-1) {}
};
void freeshadowraycache(ShadowRayCache *&cache) { delete cache; cache = NULL; }
-void resetshadowraycache(ShadowRayCache *cache)
-{
+void resetshadowraycache(ShadowRayCache *cache) {
cache->version++;
- if(!cache->version)
- {
+ if(!cache->version) {
memclear(cache->clipcache);
cache->version = 1;
}
}
-float shadowray(ShadowRayCache *cache, const vec &o, const vec &ray, float radius, int mode, extentity *t)
-{
+float shadowray(ShadowRayCache *cache, const vec &o, const vec &ray, float radius, int mode, extentity *t) {
INITRAYCUBE;
CHECKINSIDEWORLD;
-
- int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z);
- for(;;)
- {
+ int side = O_BOTTOM, x = int(v.x), y = int(v.y), z = int(v.z); (void) side;
+ for(;;) {
DOWNOCTREE(shadowent, );
-
cube &c = *lc;
ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
-
- if(!isempty(c) && !(c.material&MAT_ALPHA))
- {
- if(isentirelysolid(c))
- {
+ if(!isempty(c) && !(c.material&MAT_ALPHA)) {
+ if(isentirelysolid(c)) {
return dist;
}
- else
- {
+ else {
clipplanes &p = cache->clipcache[int(&c - worldroot)&(MAXCLIPPLANES-1)];
if(p.owner != &c || p.version != cache->version) { p.owner = &c; p.version = cache->version; genclipplanes(c, lo, 1<<lshift, p, false); }
INTERSECTPLANES(side = p.side[i], goto nextcube);
INTERSECTBOX(side = (i<<1) + 1 - lsizemask[i], goto nextcube);
- if(exitdist >= 0)
- {
+ if(exitdist >= 0) {
return dist+max(enterdist+0.1f, 0.0f);
}
}
}
-
nextcube:
FINDCLOSEST(side = O_RIGHT - lsizemask.x, side = O_FRONT - lsizemask.y, side = O_TOP - lsizemask.z);
-
if(dist>=radius) return dist;
-
UPOCTREE(return radius);
}
}
-float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent)
-{
+float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent) {
hitent = -1;
hitentdist = radius;
hitorient = -1;
float dist = raycube(o, ray, radius, mode, size);
- if((mode&RAY_ENTS) == RAY_ENTS)
- {
+ if((mode&RAY_ENTS) == RAY_ENTS) {
float dent = disttooutsideent(o, ray, dist < 0 ? 1e16f : dist, mode, NULL);
if(dent < 1e15f && (dist < 0 || dent < dist)) dist = dent;
}
return dist;
}
-float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mode, int size)
-{
+float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mode, int size) {
hitpos = ray;
float dist = raycube(o, ray, radius, mode, size);
if(radius>0 && dist>=radius) dist = radius;
return dist;
}
-bool raycubelos(const vec &o, const vec &dest, vec &hitpos)
-{
+bool raycubelos(const vec &o, const vec &dest, vec &hitpos) {
vec ray(dest);
ray.sub(o);
float mag = ray.magnitude();
return distance >= mag;
}
-float rayfloor(const vec &o, vec &floor, int mode, float radius)
-{
+float rayfloor(const vec &o, vec &floor, int mode, float radius) {
if(o.z<=0) return -1;
hitsurface = vec(0, 0, 1);
float dist = raycube(o, vec(0, 0, -1), radius, mode);
extern const float JUMPVEL = 125.0f;
extern const float GRAVITY = 200.0f;
-bool ellipseboxcollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo)
-{
+bool ellipseboxcollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo) {
float below = (o.z+center.z-lo) - (d->o.z+d->aboveeye),
above = (d->o.z-d->eyeheight) - (o.z+center.z+hi);
if(below>=0 || above>=0) return false;
-
vec yo(d->o);
yo.sub(o);
yo.rotate_around_z(-yaw*RAD);
yo.sub(center);
-
float dx = clamp(yo.x, -xr, xr) - yo.x, dy = clamp(yo.y, -yr, yr) - yo.y,
dist = sqrtf(dx*dx + dy*dy) - d->radius;
- if(dist < 0)
- {
+ if(dist < 0) {
int sx = yo.x <= -xr ? -1 : (yo.x >= xr ? 1 : 0),
sy = yo.y <= -yr ? -1 : (yo.y >= yr ? 1 : 0);
- if(dist > (yo.z < 0 ? below : above) && (sx || sy))
- {
+ if(dist > (yo.z < 0 ? below : above) && (sx || sy)) {
vec ydir(dir);
ydir.rotate_around_z(-yaw*RAD);
- if(sx*yo.x - xr > sy*yo.y - yr)
- {
- if(dir.iszero() || sx*ydir.x < -1e-6f)
- {
+ if(sx*yo.x - xr > sy*yo.y - yr) {
+ if(dir.iszero() || sx*ydir.x < -1e-6f) {
collidewall = vec(sx, 0, 0);
collidewall.rotate_around_z(yaw*RAD);
return true;
}
}
- else if(dir.iszero() || sy*ydir.y < -1e-6f)
- {
+ else if(dir.iszero() || sy*ydir.y < -1e-6f) {
collidewall = vec(0, sy, 0);
collidewall.rotate_around_z(yaw*RAD);
return true;
}
}
- if(yo.z < 0)
- {
- if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f)))
- {
+ if(yo.z < 0) {
+ if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f))) {
collidewall = vec(0, 0, -1);
return true;
}
}
- else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f)))
- {
+ else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f))) {
collidewall = vec(0, 0, 1);
return true;
}
return false;
}
-bool ellipsecollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo)
-{
+bool ellipsecollide(physent *d, const vec &dir, const vec &o, const vec ¢er, float yaw, float xr, float yr, float hi, float lo) {
float below = (o.z+center.z-lo) - (d->o.z+d->aboveeye),
above = (d->o.z-d->eyeheight) - (o.z+center.z+hi);
if(below>=0 || above>=0) return false;
float dx = d->xradius*cosf(dangle), dy = d->yradius*sinf(dangle);
float ex = xr*cosf(eangle), ey = yr*sinf(eangle);
float dist = sqrtf(x*x + y*y) - sqrtf(dx*dx + dy*dy) - sqrtf(ex*ex + ey*ey);
- if(dist < 0)
- {
- if(dist > (d->o.z < yo.z ? below : above) && (dir.iszero() || x*dir.x + y*dir.y > 0))
- {
+ if(dist < 0) {
+ if(dist > (d->o.z < yo.z ? below : above) && (dir.iszero() || x*dir.x + y*dir.y > 0)) {
collidewall = vec(-x, -y, 0);
if(!collidewall.iszero()) collidewall.normalize();
return true;
}
- if(d->o.z < yo.z)
- {
- if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f)))
- {
+ if(d->o.z < yo.z) {
+ if(dir.iszero() || (dir.z > 0 && (d->type>=ENT_INANIMATE || below >= d->zmargin-(d->eyeheight+d->aboveeye)/4.0f))) {
collidewall = vec(0, 0, -1);
return true;
}
}
- else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f)))
- {
+ else if(dir.iszero() || (dir.z < 0 && (d->type>=ENT_INANIMATE || above >= d->zmargin-(d->eyeheight+d->aboveeye)/3.0f))) {
collidewall = vec(0, 0, 1);
return true;
}
static uint dynentframe = 0;
-static struct dynentcacheentry
-{
+static struct dynentcacheentry {
int x, y;
uint frame;
vector<physent *> dynents;
} dynentcache[DYNENTCACHESIZE];
-void cleardynentcache()
-{
+void cleardynentcache() {
dynentframe++;
if(!dynentframe || dynentframe == 1) loopi(DYNENTCACHESIZE) dynentcache[i].frame = 0;
if(!dynentframe) dynentframe = 1;
#define DYNENTHASH(x, y) (((((x)^(y))<<5) + (((x)^(y))>>5)) & (DYNENTCACHESIZE - 1))
-const vector<physent *> &checkdynentcache(int x, int y)
-{
+const vector<physent *> &checkdynentcache(int x, int y) {
dynentcacheentry &dec = dynentcache[DYNENTHASH(x, y)];
if(dec.x == x && dec.y == y && dec.frame == dynentframe) return dec.dynents;
dec.x = x;
dec.frame = dynentframe;
dec.dynents.shrink(0);
int numdyns = game::numdynents(), dsize = 1<<dynentsize, dx = x<<dynentsize, dy = y<<dynentsize;
- loopi(numdyns)
- {
+ loopi(numdyns) {
dynent *d = game::iterdynents(i);
if(d->state != CS_ALIVE ||
d->o.x+d->radius <= dx || d->o.x-d->radius >= dx+dsize ||
for(int curx = max(int(o.x-radius), 0)>>dynentsize, endx = min(int(o.x+radius), worldsize-1)>>dynentsize; curx <= endx; curx++) \
for(int cury = max(int(o.y-radius), 0)>>dynentsize, endy = min(int(o.y+radius), worldsize-1)>>dynentsize; cury <= endy; cury++)
-void updatedynentcache(physent *d)
-{
- loopdynentcache(x, y, d->o, d->radius)
- {
+void updatedynentcache(physent *d) {
+ loopdynentcache(x, y, d->o, d->radius) {
dynentcacheentry &dec = dynentcache[DYNENTHASH(x, y)];
if(dec.x != x || dec.y != y || dec.frame != dynentframe || dec.dynents.find(d) >= 0) continue;
dec.dynents.add(d);
}
}
-bool overlapsdynent(const vec &o, float radius)
-{
- loopdynentcache(x, y, o, radius)
- {
+bool overlapsdynent(const vec &o, float radius) {
+ loopdynentcache(x, y, o, radius) {
const vector<physent *> &dynents = checkdynentcache(x, y);
- loopv(dynents)
- {
+ loopv(dynents) {
physent *d = dynents[i];
if(o.dist(d->o)-d->radius < radius) return true;
}
}
template<class E, class O>
-static inline bool plcollide(physent *d, const vec &dir, physent *o)
-{
+static inline bool plcollide(physent *d, const vec &dir, physent *o) {
E entvol(d);
O obvol(o);
vec cp;
- if(mpr::collide(entvol, obvol, NULL, NULL, &cp))
- {
+ if(mpr::collide(entvol, obvol, NULL, NULL, &cp)) {
vec wn = vec(cp).sub(obvol.center());
collidewall = obvol.contactface(wn, dir.iszero() ? vec(wn).neg() : dir);
if(!collidewall.iszero()) return true;
return false;
}
-static inline bool plcollide(physent *d, const vec &dir, physent *o)
-{
- switch(d->collidetype)
- {
+static inline bool plcollide(physent *d, const vec &dir, physent *o) {
+ switch(d->collidetype) {
case COLLIDE_ELLIPSE:
case COLLIDE_ELLIPSE_PRECISE:
if(o->collidetype == COLLIDE_OBB) return ellipseboxcollide(d, dir, o->o, vec(0, 0, 0), o->yaw, o->xradius, o->yradius, o->aboveeye, o->eyeheight);
}
}
-bool plcollide(physent *d, const vec &dir, bool insideplayercol) // collide with player or monster
-{
+bool plcollide(physent *d, const vec &dir, bool insideplayercol) { // collide with player or monster {
if(d->type==ENT_CAMERA || d->state!=CS_ALIVE) return false;
int lastinside = collideinside;
physent *insideplayer = NULL;
- loopdynentcache(x, y, d->o, d->radius)
- {
+ loopdynentcache(x, y, d->o, d->radius) {
const vector<physent *> &dynents = checkdynentcache(x, y);
- loopv(dynents)
- {
+ loopv(dynents) {
physent *o = dynents[i];
if(o==d || d->o.reject(o->o, d->radius+o->radius)) continue;
- if(plcollide(d, dir, o))
- {
+ if(plcollide(d, dir, o)) {
collideplayer = o;
game::dynentcollide(d, o, collidewall);
return true;
}
- if(collideinside > lastinside)
- {
+ if(collideinside > lastinside) {
lastinside = collideinside;
insideplayer = o;
}
}
}
- if(insideplayer && insideplayercol)
- {
+ if(insideplayer && insideplayercol) {
collideplayer = insideplayer;
game::dynentcollide(d, insideplayer, vec(0, 0, 0));
return true;
return false;
}
-void rotatebb(vec ¢er, vec &radius, int yaw)
-{
+void rotatebb(vec ¢er, vec &radius, int yaw) {
if(yaw < 0) yaw = 360 + yaw%360;
else if(yaw >= 360) yaw %= 360;
const vec2 &rot = sincos360[yaw];
}
template<class E, class M>
-static inline bool mmcollide(physent *d, const vec &dir, const extentity &e, const vec ¢er, const vec &radius, float yaw)
-{
+static inline bool mmcollide(physent *d, const vec &dir, const extentity &e, const vec ¢er, const vec &radius, float yaw) {
E entvol(d);
M mdlvol(e.o, center, radius, yaw);
vec cp;
- if(mpr::collide(entvol, mdlvol, NULL, NULL, &cp))
- {
+ if(mpr::collide(entvol, mdlvol, NULL, NULL, &cp)) {
vec wn = vec(cp).sub(mdlvol.center());
collidewall = mdlvol.contactface(wn, dir.iszero() ? vec(wn).neg() : dir);
if(!collidewall.iszero()) return true;
return false;
}
-bool mmcollide(physent *d, const vec &dir, octaentities &oc) // collide with a mapmodel
-{
+bool mmcollide(physent *d, const vec &dir, octaentities &oc) { // collide with a mapmodel {
const vector<extentity *> &ents = entities::getents();
- loopv(oc.mapmodels)
- {
+ loopv(oc.mapmodels) {
extentity &e = *ents[oc.mapmodels[i]];
if(e.flags&EF_NOCOLLIDE) continue;
model *m = loadmapmodel(e.attr2);
if(!m || !m->collide) continue;
-
vec center, radius;
float rejectradius = m->collisionbox(center, radius);
if(d->o.reject(e.o, d->radius + rejectradius)) continue;
-
float yaw = e.attr1;
- switch(d->collidetype)
- {
+ switch(d->collidetype) {
case COLLIDE_ELLIPSE:
case COLLIDE_ELLIPSE_PRECISE:
- if(m->ellipsecollide)
- {
+ if(m->ellipsecollide) {
if(ellipsecollide(d, dir, e.o, center, yaw, radius.x, radius.y, radius.z, radius.z)) return true;
}
else if(ellipseboxcollide(d, dir, e.o, center, yaw, radius.x, radius.y, radius.z, radius.z)) return true;
break;
case COLLIDE_OBB:
- if(m->ellipsecollide)
- {
+ if(m->ellipsecollide) {
if(mmcollide<mpr::EntOBB, mpr::ModelEllipse>(d, dir, e, center, radius, yaw)) return true;
}
else if(mmcollide<mpr::EntOBB, mpr::ModelOBB>(d, dir, e, center, radius, yaw)) return true;
}
template<class E>
-static bool fuzzycollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with solid cube geometry
-{
+static bool fuzzycollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with solid cube geometry {
int crad = size/2;
if(fabs(d->o.x - co.x - crad) > d->radius + crad || fabs(d->o.y - co.y - crad) > d->radius + crad ||
d->o.z + d->aboveeye < co.z || d->o.z - d->eyeheight > co.z + size)
return false;
-
E entvol(d);
collidewall = vec(0, 0, 0);
float bestdist = -1e10f;
int visible = isentirelysolid(c) ? c.visible : 0xFF;
- #define CHECKSIDE(side, distval, dotval, margin, normal) if(visible&(1<<side)) do \
- { \
+ #define CHECKSIDE(side, distval, dotval, margin, normal) if(visible&(1<<side)) do { \
+ \
float dist = distval; \
if(dist > 0) return false; \
if(dist <= bestdist) continue; \
- if(!dir.iszero()) \
- { \
+ if(!dir.iszero()) { \
+ \
if(dotval >= -cutoff*dir.magnitude()) continue; \
if(d->type<ENT_CAMERA && dotval < 0 && dist < margin) continue; \
} \
CHECKSIDE(O_FRONT, d->o.y - d->radius - (co.y + size), dir.y, -d->radius, vec(0, 1, 0));
CHECKSIDE(O_BOTTOM, co.z - (d->o.z + d->aboveeye), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1));
CHECKSIDE(O_TOP, d->o.z - d->eyeheight - (co.z + size), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1));
-
- if(collidewall.iszero())
- {
+ if(collidewall.iszero()) {
collideinside++;
return false;
}
}
template<class E>
-static inline bool clampcollide(const clipplanes &p, const E &entvol, const plane &w, const vec &pw)
-{
- if(w.x && (w.y || w.z) && fabs(pw.x - p.o.x) > p.r.x)
- {
+static inline bool clampcollide(const clipplanes &p, const E &entvol, const plane &w, const vec &pw) {
+ if(w.x && (w.y || w.z) && fabs(pw.x - p.o.x) > p.r.x) {
vec c = entvol.center();
float fv = pw.x < p.o.x ? p.o.x-p.r.x : p.o.x+p.r.x, fdist = (w.x*fv + w.y*c.y + w.z*c.z + w.offset) / (w.y*w.y + w.z*w.z);
vec fdir(fv - c.x, -w.y*fdist, -w.z*fdist);
if((pw.y-c.y-fdir.y)*w.y + (pw.z-c.z-fdir.z)*w.z >= 0 && entvol.supportpoint(fdir).squaredist(c) < fdir.squaredlen()) return true;
}
- if(w.y && (w.x || w.z) && fabs(pw.y - p.o.y) > p.r.y)
- {
+ if(w.y && (w.x || w.z) && fabs(pw.y - p.o.y) > p.r.y) {
vec c = entvol.center();
float fv = pw.y < p.o.y ? p.o.y-p.r.y : p.o.y+p.r.y, fdist = (w.x*c.x + w.y*fv + w.z*c.z + w.offset) / (w.x*w.x + w.z*w.z);
vec fdir(-w.x*fdist, fv - c.y, -w.z*fdist);
if((pw.x-c.x-fdir.x)*w.x + (pw.z-c.z-fdir.z)*w.z >= 0 && entvol.supportpoint(fdir).squaredist(c) < fdir.squaredlen()) return true;
}
- if(w.z && (w.x || w.y) && fabs(pw.z - p.o.z) > p.r.z)
- {
+ if(w.z && (w.x || w.y) && fabs(pw.z - p.o.z) > p.r.z) {
vec c = entvol.center();
float fv = pw.z < p.o.z ? p.o.z-p.r.z : p.o.z+p.r.z, fdist = (w.x*c.x + w.y*c.y + w.z*fv + w.offset) / (w.x*w.x + w.y*w.y);
vec fdir(-w.x*fdist, -w.y*fdist, fv - c.z);
}
template<class E>
-static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with deformed cube geometry
-{
+static bool fuzzycollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with deformed cube geometry {
const clipplanes &p = getclipplanes(c, co, size);
-
if(fabs(d->o.x - p.o.x) > p.r.x + d->radius || fabs(d->o.y - p.o.y) > p.r.y + d->radius ||
d->o.z + d->aboveeye < p.o.z - p.r.z || d->o.z - d->eyeheight > p.o.z + p.r.z)
return false;
-
collidewall = vec(0, 0, 0);
float bestdist = -1e10f;
int visible = p.visible;
CHECKSIDE(O_FRONT, d->o.y - d->radius - (p.o.y + p.r.y), dir.y, -d->radius, vec(0, 1, 0));
CHECKSIDE(O_BOTTOM, p.o.z - p.r.z - (d->o.z + d->aboveeye), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1));
CHECKSIDE(O_TOP, d->o.z - d->eyeheight - (p.o.z + p.r.z), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1));
-
E entvol(d);
int bestplane = -1;
- loopi(p.size)
- {
+ loopi(p.size) {
const plane &w = p.p[i];
vec pw = entvol.supportpoint(vec(w).neg());
float dist = w.dist(pw);
if(dist <= bestdist) continue;
bestplane = -1;
bestdist = dist;
- if(!dir.iszero())
- {
+ if(!dir.iszero()) {
if(w.dot(dir) >= -cutoff*dir.magnitude()) continue;
if(d->type<ENT_CAMERA &&
dist < (dir.z*w.z < 0 ?
bestplane = i;
}
if(bestplane >= 0) collidewall = p.p[bestplane];
- else if(collidewall.iszero())
- {
+ else if(collidewall.iszero()) {
collideinside++;
return false;
}
}
template<class E>
-static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with solid cube geometry
-{
+static bool cubecollidesolid(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with solid cube geometry {
int crad = size/2;
if(fabs(d->o.x - co.x - crad) > d->radius + crad || fabs(d->o.y - co.y - crad) > d->radius + crad ||
d->o.z + d->aboveeye < co.z || d->o.z - d->eyeheight > co.z + size)
return false;
-
E entvol(d);
bool collided = mpr::collide(mpr::SolidCube(co, size), entvol);
if(!collided) return false;
-
collidewall = vec(0, 0, 0);
float bestdist = -1e10f;
int visible = isentirelysolid(c) ? c.visible : 0xFF;
CHECKSIDE(O_FRONT, entvol.back() - (co.y + size), dir.y, -d->radius, vec(0, 1, 0));
CHECKSIDE(O_BOTTOM, co.z - entvol.top(), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1));
CHECKSIDE(O_TOP, entvol.bottom() - (co.z + size), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1));
-
- if(collidewall.iszero())
- {
+ if(collidewall.iszero()) {
collideinside++;
return false;
}
}
template<class E>
-static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) // collide with deformed cube geometry
-{
+static bool cubecollideplanes(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size) { // collide with deformed cube geometry {
const clipplanes &p = getclipplanes(c, co, size);
-
if(fabs(d->o.x - p.o.x) > p.r.x + d->radius || fabs(d->o.y - p.o.y) > p.r.y + d->radius ||
d->o.z + d->aboveeye < p.o.z - p.r.z || d->o.z - d->eyeheight > p.o.z + p.r.z)
return false;
-
E entvol(d);
bool collided = mpr::collide(mpr::CubePlanes(p), entvol);
if(!collided) return false;
-
collidewall = vec(0, 0, 0);
float bestdist = -1e10f;
int visible = p.visible;
CHECKSIDE(O_FRONT, entvol.back() - (p.o.y + p.r.y), dir.y, -d->radius, vec(0, 1, 0));
CHECKSIDE(O_BOTTOM, p.o.z - p.r.z - entvol.top(), -dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/4.0f, vec(0, 0, -1));
CHECKSIDE(O_TOP, entvol.bottom() - (p.o.z + p.r.z), dir.z, d->zmargin-(d->eyeheight+d->aboveeye)/3.0f, vec(0, 0, 1));
-
int bestplane = -1;
- loopi(p.size)
- {
+ loopi(p.size) {
const plane &w = p.p[i];
vec pw = entvol.supportpoint(vec(w).neg());
float dist = w.dist(pw);
if(dist <= bestdist) continue;
bestplane = -1;
bestdist = dist;
- if(!dir.iszero())
- {
+ if(!dir.iszero()) {
if(w.dot(dir) >= -cutoff*dir.magnitude()) continue;
if(d->type<ENT_CAMERA &&
dist < (dir.z*w.z < 0 ?
bestplane = i;
}
if(bestplane >= 0) collidewall = p.p[bestplane];
- else if(collidewall.iszero())
- {
+ else if(collidewall.iszero()) {
collideinside++;
return false;
}
return true;
}
-static inline bool cubecollide(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size, bool solid)
-{
- switch(d->collidetype)
- {
+static inline bool cubecollide(physent *d, const vec &dir, float cutoff, const cube &c, const ivec &co, int size, bool solid) {
+ switch(d->collidetype) {
case COLLIDE_OBB:
if(isentirelysolid(c) || solid) return cubecollidesolid<mpr::EntOBB>(d, dir, cutoff, c, co, size);
else return cubecollideplanes<mpr::EntOBB>(d, dir, cutoff, c, co, size);
}
}
-static inline bool octacollide(physent *d, const vec &dir, float cutoff, const ivec &bo, const ivec &bs, const cube *c, const ivec &cor, int size) // collide with octants
-{
- loopoctabox(cor, size, bo, bs)
- {
+static inline bool octacollide(physent *d, const vec &dir, float cutoff, const ivec &bo, const ivec &bs, const cube *c, const ivec &cor, int size) { // collide with octants {
+ loopoctabox(cor, size, bo, bs) {
if(c[i].ext && c[i].ext->ents) if(mmcollide(d, dir, *c[i].ext->ents)) return true;
ivec o(i, cor, size);
- if(c[i].children)
- {
+ if(c[i].children) {
if(octacollide(d, dir, cutoff, bo, bs, c[i].children, o, size>>1)) return true;
}
- else
- {
+ else {
bool solid = false;
- switch(c[i].material&MATF_CLIP)
- {
+ switch(c[i].material&MATF_CLIP) {
case MAT_NOCLIP: continue;
case MAT_GAMECLIP: if(d->type==ENT_AI) solid = true; break;
case MAT_CLIP: if(d->type<ENT_CAMERA) solid = true; break;
return false;
}
-static inline bool octacollide(physent *d, const vec &dir, float cutoff, const ivec &bo, const ivec &bs)
-{
+static inline bool octacollide(physent *d, const vec &dir, float cutoff, const ivec &bo, const ivec &bs) {
int diff = (bo.x^bs.x) | (bo.y^bs.y) | (bo.z^bs.z),
scale = worldscale-1;
if(diff&~((1<<scale)-1) || uint(bo.x|bo.y|bo.z|bs.x|bs.y|bs.z) >= uint(worldsize))
const cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)];
if(c->ext && c->ext->ents && mmcollide(d, dir, *c->ext->ents)) return true;
scale--;
- while(c->children && !(diff&(1<<scale)))
- {
+ while(c->children && !(diff&(1<<scale))) {
c = &c->children[octastep(bo.x, bo.y, bo.z, scale)];
if(c->ext && c->ext->ents && mmcollide(d, dir, *c->ext->ents)) return true;
scale--;
}
if(c->children) return octacollide(d, dir, cutoff, bo, bs, c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale);
bool solid = false;
- switch(c->material&MATF_CLIP)
- {
+ switch(c->material&MATF_CLIP) {
case MAT_NOCLIP: return false;
case MAT_GAMECLIP: if(d->type==ENT_AI) solid = true; break;
case MAT_CLIP: if(d->type<ENT_CAMERA) solid = true; break;
}
// all collision happens here
-bool collide(physent *d, const vec &dir, float cutoff, bool playercol, bool insideplayercol)
-{
+bool collide(physent *d, const vec &dir, float cutoff, bool playercol, bool insideplayercol) {
collideinside = 0;
collideplayer = NULL;
collidewall = vec(0, 0, 0);
return octacollide(d, dir, cutoff, bo, bs) || (playercol && plcollide(d, dir, insideplayercol));
}
-void recalcdir(physent *d, const vec &oldvel, vec &dir)
-{
+void recalcdir(physent *d, const vec &oldvel, vec &dir) {
float speed = oldvel.magnitude();
- if(speed > 1e-6f)
- {
+ if(speed > 1e-6f) {
float step = dir.magnitude();
dir = d->vel;
dir.add(d->falling);
}
}
-void slideagainst(physent *d, vec &dir, const vec &obstacle, bool foundfloor, bool slidecollide)
-{
+void slideagainst(physent *d, vec &dir, const vec &obstacle, bool foundfloor, bool slidecollide) {
vec wall(obstacle);
- if(foundfloor ? wall.z > 0 : slidecollide)
- {
+ if(foundfloor ? wall.z > 0 : slidecollide) {
wall.z = 0;
if(!wall.iszero()) wall.normalize();
}
recalcdir(d, oldvel, dir);
}
-void switchfloor(physent *d, vec &dir, const vec &floor)
-{
+void switchfloor(physent *d, vec &dir, const vec &floor) {
if(floor.z >= FLOORZ) d->falling = vec(0, 0, 0);
-
vec oldvel(d->vel);
oldvel.add(d->falling);
- if(dir.dot(floor) >= 0)
- {
+ if(dir.dot(floor) >= 0) {
if(d->physstate < PHYS_SLIDE || fabs(dir.dot(d->floor)) > 0.01f*dir.magnitude()) return;
d->vel.projectxy(floor, 0.0f);
}
recalcdir(d, oldvel, dir);
}
-bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const vec &floor)
-{
+bool trystepup(physent *d, vec &dir, const vec &obstacle, float maxstep, const vec &floor) {
vec old(d->o), stairdir = (obstacle.z >= 0 && obstacle.z < SLOPEZ ? vec(-obstacle.x, -obstacle.y, 0) : vec(dir.x, dir.y, 0)).rescale(1);
bool cansmooth = true;
/* check if there is space atop the stair to move to */
- if(d->physstate != PHYS_STEP_UP)
- {
+ if(d->physstate != PHYS_STEP_UP) {
vec checkdir = stairdir;
checkdir.mul(0.1f);
checkdir.z += maxstep + 0.1f;
d->o.add(checkdir);
- if(collide(d))
- {
+ if(collide(d)) {
d->o = old;
if(!collide(d, vec(0, 0, -1), SLOPEZ)) return false;
cansmooth = false;
}
}
-
- if(cansmooth)
- {
+ if(cansmooth) {
vec checkdir = stairdir;
checkdir.z += 1;
checkdir.mul(maxstep);
d->o = old;
d->o.add(checkdir);
int scale = 2;
- if(collide(d, checkdir))
- {
- if(!collide(d, vec(0, 0, -1), SLOPEZ))
- {
+ if(collide(d, checkdir)) {
+ if(!collide(d, vec(0, 0, -1), SLOPEZ)) {
d->o = old;
return false;
}
d->o.add(checkdir);
if(collide(d, vec(0, 0, -1), SLOPEZ)) scale = 1;
}
- if(scale != 1)
- {
+ if(scale != 1) {
d->o = old;
d->o.sub(checkdir.mul(vec(2, 2, 1)));
if(!collide(d, vec(0, 0, -1), SLOPEZ)) scale = 1;
}
-
d->o = old;
vec smoothdir(dir.x, dir.y, 0);
float magxy = smoothdir.magnitude();
- if(magxy > 1e-9f)
- {
- if(magxy > scale*dir.z)
- {
+ if(magxy > 1e-9f) {
+ if(magxy > scale*dir.z) {
smoothdir.mul(1/magxy);
smoothdir.z = 1.0f/scale;
smoothdir.mul(dir.magnitude()/smoothdir.magnitude());
else smoothdir.z = dir.z;
d->o.add(smoothdir);
d->o.z += maxstep + 0.1f;
- if(!collide(d, smoothdir))
- {
+ if(!collide(d, smoothdir)) {
d->o.z -= maxstep + 0.1f;
- if(d->physstate == PHYS_FALL || d->floor != floor)
- {
+ if(d->physstate == PHYS_FALL || d->floor != floor) {
d->timeinair = 0;
d->floor = floor;
switchfloor(d, dir, d->floor);
}
}
}
-
/* try stepping up */
d->o = old;
d->o.z += dir.magnitude();
- if(!collide(d, vec(0, 0, 1)))
- {
- if(d->physstate == PHYS_FALL || d->floor != floor)
- {
+ if(!collide(d, vec(0, 0, 1))) {
+ if(d->physstate == PHYS_FALL || d->floor != floor) {
d->timeinair = 0;
d->floor = floor;
switchfloor(d, dir, d->floor);
return false;
}
-bool trystepdown(physent *d, vec &dir, float step, float xy, float z, bool init = false)
-{
+bool trystepdown(physent *d, vec &dir, float step, float xy, float z, bool init = false) {
vec stepdir(dir.x, dir.y, 0);
stepdir.z = -stepdir.magnitude2()*z/xy;
if(!stepdir.z) return false;
stepdir.normalize();
-
vec old(d->o);
d->o.add(vec(stepdir).mul(STAIRHEIGHT/fabs(stepdir.z))).z -= STAIRHEIGHT;
d->zmargin = -STAIRHEIGHT;
- if(collide(d, vec(0, 0, -1), SLOPEZ))
- {
+ if(collide(d, vec(0, 0, -1), SLOPEZ)) {
d->o = old;
d->o.add(vec(stepdir).mul(step));
d->zmargin = 0;
- if(!collide(d, vec(0, 0, -1)))
- {
+ if(!collide(d, vec(0, 0, -1))) {
vec stepfloor(stepdir);
stepfloor.mul(-stepfloor.z).z += 1;
stepfloor.normalize();
- if(d->physstate >= PHYS_SLOPE && d->floor != stepfloor)
- {
+ if(d->physstate >= PHYS_SLOPE && d->floor != stepfloor) {
// prevent alternating step-down/step-up states if player would keep bumping into the same floor
vec stepped(d->o);
d->o.z -= 0.5f;
d->zmargin = -0.5f;
- if(collide(d, stepdir) && collidewall == d->floor)
- {
+ if(collide(d, stepdir) && collidewall == d->floor) {
d->o = old;
if(!init) { d->o.x += dir.x; d->o.y += dir.y; if(dir.z <= 0 || collide(d, dir)) d->o.z += dir.z; }
d->zmargin = 0;
return false;
}
-bool trystepdown(physent *d, vec &dir, bool init = false)
-{
+bool trystepdown(physent *d, vec &dir, bool init = false) {
if((!d->move && !d->strafe) || !game::allowmove(d)) return false;
vec old(d->o);
d->o.z -= STAIRHEIGHT;
d->zmargin = -STAIRHEIGHT;
- if(!collide(d, vec(0, 0, -1), SLOPEZ))
- {
+ if(!collide(d, vec(0, 0, -1), SLOPEZ)) {
d->o = old;
d->zmargin = 0;
return false;
return false;
}
-void falling(physent *d, vec &dir, const vec &floor)
-{
- if(floor.z > 0.0f && floor.z < SLOPEZ)
- {
+void falling(physent *d, vec &dir, const vec &floor) {
+ if(floor.z > 0.0f && floor.z < SLOPEZ) {
if(floor.z >= WALLZ) switchfloor(d, dir, floor);
d->timeinair = 0;
d->physstate = PHYS_SLIDE;
d->physstate = PHYS_FALL;
}
-void landing(physent *d, vec &dir, const vec &floor, bool collided)
-{
+void landing(physent *d, vec &dir, const vec &floor, bool collided) {
#if 0
- if(d->physstate == PHYS_FALL)
- {
+ if(d->physstate == PHYS_FALL) {
d->timeinair = 0;
if(dir.z < 0.0f) dir.z = d->vel.z = 0.0f;
}
d->floor = floor;
}
-bool findfloor(physent *d, bool collided, const vec &obstacle, bool &slide, vec &floor)
-{
+bool findfloor(physent *d, bool collided, const vec &obstacle, bool &slide, vec &floor) {
bool found = false;
vec moved(d->o);
d->o.z -= 0.1f;
- if(collide(d, vec(0, 0, -1), d->physstate == PHYS_SLOPE || d->physstate == PHYS_STEP_DOWN ? SLOPEZ : FLOORZ))
- {
+ if(collide(d, vec(0, 0, -1), d->physstate == PHYS_SLOPE || d->physstate == PHYS_STEP_DOWN ? SLOPEZ : FLOORZ)) {
floor = collidewall;
found = true;
}
- else if(collided && obstacle.z >= SLOPEZ)
- {
+ else if(collided && obstacle.z >= SLOPEZ) {
floor = obstacle;
found = true;
slide = false;
}
- else if(d->physstate == PHYS_STEP_UP || d->physstate == PHYS_SLIDE)
- {
- if(collide(d, vec(0, 0, -1)) && collidewall.z > 0.0f)
- {
+ else if(d->physstate == PHYS_STEP_UP || d->physstate == PHYS_SLIDE) {
+ if(collide(d, vec(0, 0, -1)) && collidewall.z > 0.0f) {
floor = collidewall;
if(floor.z >= SLOPEZ) found = true;
}
}
- else if(d->physstate >= PHYS_SLOPE && d->floor.z < 1.0f)
- {
- if(collide(d, vec(d->floor).neg(), 0.95f) || collide(d, vec(0, 0, -1)))
- {
+ else if(d->physstate >= PHYS_SLOPE && d->floor.z < 1.0f) {
+ if(collide(d, vec(d->floor).neg(), 0.95f) || collide(d, vec(0, 0, -1))) {
floor = collidewall;
if(floor.z >= SLOPEZ && floor.z < 1.0f) found = true;
}
}
- if(collided && (!found || obstacle.z > floor.z))
- {
+ if(collided && (!found || obstacle.z > floor.z)) {
floor = obstacle;
slide = !found && (floor.z < WALLZ || floor.z >= SLOPEZ);
}
return found;
}
-bool move(physent *d, vec &dir)
-{
+bool move(physent *d, vec &dir) {
vec old(d->o);
bool collided = false, slidecollide = false;
vec obstacle = vec(0, 0, 0);
d->o.add(dir);
- if(collide(d, dir) || ((d->type==ENT_AI || d->type==ENT_INANIMATE) && collide(d, vec(0, 0, 0), 0, false)))
- {
+ if(collide(d, dir) || ((d->type==ENT_AI || d->type==ENT_INANIMATE) && collide(d, vec(0, 0, 0), 0, false))) {
obstacle = collidewall;
/* check to see if there is an obstacle that would prevent this one from being used as a floor (or ceiling bump) */
- if(d->type==ENT_PLAYER && ((collidewall.z>=SLOPEZ && dir.z<0) || (collidewall.z<=-SLOPEZ && dir.z>0)) && (dir.x || dir.y) && collide(d, vec(dir.x, dir.y, 0)))
- {
+ if(d->type==ENT_PLAYER && ((collidewall.z>=SLOPEZ && dir.z<0) || (collidewall.z<=-SLOPEZ && dir.z>0)) && (dir.x || dir.y) && collide(d, vec(dir.x, dir.y, 0))) {
if(collidewall.dot(dir) >= 0) slidecollide = true;
obstacle = collidewall;
}
d->o = old;
d->o.z -= STAIRHEIGHT;
d->zmargin = -STAIRHEIGHT;
- if(d->physstate == PHYS_SLOPE || d->physstate == PHYS_FLOOR || (collide(d, vec(0, 0, -1), SLOPEZ) && (d->physstate==PHYS_STEP_UP || d->physstate==PHYS_STEP_DOWN || collidewall.z>=FLOORZ)))
- {
+ if(d->physstate == PHYS_SLOPE || d->physstate == PHYS_FLOOR || (collide(d, vec(0, 0, -1), SLOPEZ) && (d->physstate==PHYS_STEP_UP || d->physstate==PHYS_STEP_DOWN || collidewall.z>=FLOORZ))) {
d->o = old;
d->zmargin = 0;
if(trystepup(d, dir, obstacle, STAIRHEIGHT, d->physstate == PHYS_SLOPE || d->physstate == PHYS_FLOOR ? d->floor : vec(collidewall))) return true;
}
- else
- {
+ else {
d->o = old;
d->zmargin = 0;
}
/* can't step over the obstacle, so just slide against it */
collided = true;
}
- else if(d->physstate == PHYS_STEP_UP)
- {
- if(collide(d, vec(0, 0, -1), SLOPEZ))
- {
+ else if(d->physstate == PHYS_STEP_UP) {
+ if(collide(d, vec(0, 0, -1), SLOPEZ)) {
d->o = old;
if(trystepup(d, dir, vec(0, 0, 1), STAIRHEIGHT, vec(collidewall))) return true;
d->o.add(dir);
}
}
- else if(d->physstate == PHYS_STEP_DOWN && dir.dot(d->floor) <= 1e-6f)
- {
+ else if(d->physstate == PHYS_STEP_DOWN && dir.dot(d->floor) <= 1e-6f) {
vec moved(d->o);
d->o = old;
if(trystepdown(d, dir)) return true;
vec floor(0, 0, 0);
bool slide = collided,
found = findfloor(d, collided, obstacle, slide, floor);
- if(slide || (!collided && floor.z > 0 && floor.z < WALLZ))
- {
+ if(slide || (!collided && floor.z > 0 && floor.z < WALLZ)) {
slideagainst(d, dir, slide ? obstacle : floor, found, slidecollide);
//if(d->type == ENT_AI || d->type == ENT_INANIMATE)
d->blocked = true;
return !collided;
}
-bool bounce(physent *d, float secs, float elasticity, float grav)
-{
+bool bounce(physent *d, float secs, float elasticity, float grav) {
// make sure bouncers don't start inside geometry
if(d->physstate!=PHYS_BOUNCE && collide(d, vec(0, 0, 0), 0, false)) return true;
d->vel.z -= grav*GRAVITY*secs;
vec old(d->o);
- loopi(2)
- {
+ loopi(2) {
vec dir(d->vel);
dir.mul(secs);
d->o.add(dir);
- if(!collide(d, dir, 0, true, true))
- {
- if(collideinside)
- {
+ if(!collide(d, dir, 0, true, true)) {
+ if(collideinside) {
d->o = old;
d->vel.mul(-elasticity);
}
d->vel.mul(k);
d->vel.sub(vec(collidewall).mul(elasticity*2.0f*c));
}
- if(d->physstate!=PHYS_BOUNCE)
- {
+ if(d->physstate!=PHYS_BOUNCE) {
// make sure bouncers don't start inside geometry
if(d->o == old) return !collideplayer;
d->physstate = PHYS_BOUNCE;
return collideplayer!=NULL;
}
-void avoidcollision(physent *d, const vec &dir, physent *obstacle, float space)
-{
+void avoidcollision(physent *d, const vec &dir, physent *obstacle, float space) {
float rad = obstacle->radius+d->radius;
vec bbmin(obstacle->o);
bbmin.x -= rad;
bbmax.y += rad;
bbmax.z += obstacle->aboveeye+d->eyeheight;
bbmax.add(space);
-
loopi(3) if(d->o[i] <= bbmin[i] || d->o[i] >= bbmax[i]) return;
-
float mindist = 1e16f;
- loopi(3) if(dir[i] != 0)
- {
+ loopi(3) if(dir[i] != 0) {
float dist = ((dir[i] > 0 ? bbmax[i] : bbmin[i]) - d->o[i]) / dir[i];
mindist = min(mindist, dist);
}
if(mindist >= 0.0f && mindist < 1e15f) d->o.add(vec(dir).mul(mindist));
}
-bool movecamera(physent *pl, const vec &dir, float dist, float stepdist)
-{
+bool movecamera(physent *pl, const vec &dir, float dist, float stepdist) {
int steps = (int)ceil(dist/stepdist);
if(steps <= 0) return true;
-
vec d(dir);
d.mul(dist/steps);
- loopi(steps)
- {
+ loopi(steps) {
vec oldpos(pl->o);
pl->o.add(d);
- if(collide(pl, vec(0, 0, 0), 0, false))
- {
+ if(collide(pl, vec(0, 0, 0), 0, false)) {
pl->o = oldpos;
return false;
}
return true;
}
-void dropenttofloor(entity *e)
-{
+void dropenttofloor(entity *e) {
float radius = 1.0f;
float height = 4.0f;
vec o = e->o;
- static struct dropent : physent
- {
- dropent()
- {
+ static struct dropent : physent {
+ dropent() {
type = ENT_BOUNCE;
vel = vec(0, 0, -1);
}
} d;
d.o = o;
- if(!insideworld(d.o))
- {
+ if(!insideworld(d.o)) {
if(d.o.z < worldsize) return;
d.o.z = worldsize - 1e-3f;
if(!insideworld(d.o)) return;
o = d.o;
}
-void vecfromyawpitch(float yaw, float pitch, int move, int strafe, vec &m)
-{
- if(move)
- {
+void vecfromyawpitch(float yaw, float pitch, int move, int strafe, vec &m) {
+ if(move) {
m.x = move*-sinf(RAD*yaw);
m.y = move*cosf(RAD*yaw);
}
else m.x = m.y = 0;
-
- if(pitch)
- {
+ if(pitch) {
m.x *= cosf(RAD*pitch);
m.y *= cosf(RAD*pitch);
m.z = move*sinf(RAD*pitch);
}
else m.z = 0;
-
- if(strafe)
- {
+ if(strafe) {
m.x += strafe*cosf(RAD*yaw);
m.y += strafe*sinf(RAD*yaw);
}
}
-void vectoyawpitch(const vec &v, float &yaw, float &pitch)
-{
+void vectoyawpitch(const vec &v, float &yaw, float &pitch) {
if(v.iszero()) yaw = pitch = 0;
- else
- {
+ else {
yaw = -atan2(v.x, v.y)/RAD;
pitch = asin(v.z/v.magnitude())/RAD;
}
FVAR(faderoll, 0, 0.95f, 1);
VAR(floatspeed, 1, 100, 10000);
-void modifyvelocity(physent *pl, bool local, bool floating, int curtime)
-{
+void modifyvelocity(physent *pl, bool local, bool floating, int curtime) {
bool allowmove = game::allowmove(pl);
- if(floating)
- {
- if(pl->jumping && allowmove)
- {
+ if(floating) {
+ if(pl->jumping && allowmove) {
pl->jumping = false;
pl->vel.z = max(pl->vel.z, JUMPVEL);
}
}
- else if(pl->physstate >= PHYS_SLOPE)
- {
+ else if(pl->physstate >= PHYS_SLOPE) {
if(!pl->inwater) pl->vel.div(8);
- if(pl->jumping && allowmove)
- {
+ if(pl->jumping && allowmove) {
pl->jumping = false;
-
pl->vel.z = max(pl->vel.z, JUMPVEL); // physics impulse upwards
-
game::physicstrigger(pl, local, 1);
}
}
if(!floating && pl->physstate == PHYS_FALL) pl->timeinair = min(pl->timeinair + curtime, 1000);
-
vec m(0.0f, 0.0f, 0.0f);
- if((pl->move || pl->strafe) && allowmove)
- {
+ if((pl->move || pl->strafe) && allowmove) {
vecfromyawpitch(pl->yaw, floating || pl->type==ENT_CAMERA ? pl->pitch : 0, pl->move, pl->strafe, m);
-
if(!floating && pl->physstate >= PHYS_SLOPE)
m.z = -(m.x*pl->floor.x + m.y*pl->floor.y)/pl->floor.z; // move up or down slopes in air
-
m.normalize();
}
-
vec d(m);
speedmodifier*=(pl->physstate!=PHYS_FLOOR)*(speedmodifier>0);
speedmodifier=(speedmodifier>100.0f)?100.0f:speedmodifier;
d.mul(pl->maxspeed + speedmodifier);
-
- if(pl->type==ENT_PLAYER)
- {
- if(floating)
- {
+ if(pl->type==ENT_PLAYER) {
+ if(floating) {
if(pl==player) d.mul(floatspeed/100.0f);
}
else if(allowmove) d.mul((pl->move && !pl->strafe ? 1.3f : 1.0f) * (pl->physstate < PHYS_SLOPE ? 1.3f : 1.0f));
pl->vel.lerp(d, pl->vel, pow(1 - 1/fric, curtime/20.0f));
}
-void modifygravity(physent *pl, int curtime)
-{
+void modifygravity(physent *pl, int curtime) {
float secs = curtime/1000.0f;
vec g(0, 0, 0);
if(pl->physstate == PHYS_FALL) g.z -= GRAVITY*secs;
- else if(pl->floor.z > 0 && pl->floor.z < FLOORZ)
- {
+ else if(pl->floor.z > 0 && pl->floor.z < FLOORZ) {
g.z = -1;
g.project(pl->floor);
g.normalize();
g.mul(GRAVITY*secs);
}
if(!game::allowmove(pl) || (!pl->move && !pl->strafe)) pl->falling.add(g);
-
- if(pl->physstate >= PHYS_SLOPE)
- {
+ if(pl->physstate >= PHYS_SLOPE) {
float fric = 6.0f,
c = clamp((pl->floor.z - SLOPEZ)/(FLOORZ-SLOPEZ), 0.0f, 1.0f);
pl->falling.mul(pow(1 - c/fric, curtime/20.0f));
// moveres indicated the physics precision (which is lower for monsters and multiplayer prediction)
// local is false for multiplayer prediction
-bool moveplayer(physent *pl, int moveres, bool local, int curtime)
-{
+bool moveplayer(physent *pl, int moveres, bool local, int curtime) {
int material = lookupmaterial(vec(pl->o.x, pl->o.y, pl->o.z + (3*pl->aboveeye - pl->eyeheight)/4));
bool floating = pl->type==ENT_PLAYER && (pl->state==CS_EDITING || pl->state==CS_SPECTATOR);
float secs = curtime/1000.f;
-
// apply gravity
if(!floating) modifygravity(pl, curtime);
// apply any player generated changes in velocity
modifyvelocity(pl, local, floating, curtime);
-
vec d(pl->vel);
if(!floating) d.mul(0.5f);
d.add(pl->falling);
d.mul(secs);
-
pl->blocked = false;
-
- if(floating) // just apply velocity
- {
- if(pl->physstate != PHYS_FLOAT)
- {
+ if(floating) { // just apply velocity {
+ if(pl->physstate != PHYS_FLOAT) {
pl->physstate = PHYS_FLOAT;
pl->timeinair = 0;
pl->falling = vec(0, 0, 0);
}
pl->o.add(d);
}
- else // apply velocity with collision
- {
+ else { // apply velocity with collision {
const float f = 1.0f/moveres;
const int timeinair = pl->timeinair;
int collisions = 0;
-
d.mul(f);
loopi(moveres) if(!move(pl, d) && ++collisions<5) i--; // discrete steps collision detection & sliding
- if(timeinair > 800 && !pl->timeinair) // if we land after long time must have been a high jump, make thud sound
- {
+ if(timeinair > 800 && !pl->timeinair) { // if we land after long time must have been a high jump, make thud sound {
game::physicstrigger(pl, local, -1);
}
}
-
if(pl->state==CS_ALIVE) updatedynentcache(pl);
-
// automatically apply smooth roll when strafing
-
if(pl->strafe && maxroll) pl->roll = clamp(pl->roll - pow(clamp(1.0f + pl->strafe*pl->roll/maxroll, 0.0f, 1.0f), 0.33f)*pl->strafe*curtime*straferoll, -maxroll, maxroll);
else pl->roll *= curtime == PHYSFRAMETIME ? faderoll : pow(faderoll, curtime/float(PHYSFRAMETIME));
-
if(pl->inwater) game::physicstrigger(pl, local, 0, pl->inwater);
pl->inwater = MAT_AIR;
-
if(pl->state==CS_ALIVE && (pl->o.z < 0 || material&MAT_DEATH)) game::suicide(pl);
-
return true;
}
int physsteps = 0, physframetime = PHYSFRAMETIME, lastphysframe = 0;
-void physicsframe() // optimally schedule physics frames inside the graphics frames
-{
+void physicsframe() { // optimally schedule physics frames inside the graphics frames {
int diff = lastmillis - lastphysframe;
if(diff <= 0) physsteps = 0;
- else
- {
+ else {
physframetime = clamp(game::scaletime(PHYSFRAMETIME)/100, 1, PHYSFRAMETIME);
physsteps = (diff + physframetime - 1)/physframetime;
lastphysframe += physsteps * physframetime;
VAR(physinterp, 0, 1, 1);
-void interppos(physent *pl)
-{
+void interppos(physent *pl) {
pl->o = pl->newpos;
-
int diff = lastphysframe - lastmillis;
if(diff <= 0 || !physinterp) return;
-
vec deltapos(pl->deltapos);
deltapos.mul(min(diff, physframetime)/float(physframetime));
pl->o.add(deltapos);
}
-void moveplayer(physent *pl, int moveres, bool local)
-{
- if(physsteps <= 0)
- {
+void moveplayer(physent *pl, int moveres, bool local) {
+ if(physsteps <= 0) {
if(local) interppos(pl);
return;
}
-
if(local) pl->o = pl->newpos;
loopi(physsteps-1) moveplayer(pl, moveres, local, physframetime);
if(local) pl->deltapos = pl->o;
moveplayer(pl, moveres, local, physframetime);
- if(local)
- {
+ if(local) {
pl->newpos = pl->o;
pl->deltapos.sub(pl->newpos);
interppos(pl);
}
}
-bool bounce(physent *d, float elasticity, float grav)
-{
- if(physsteps <= 0)
- {
+bool bounce(physent *d, float elasticity, float grav) {
+ if(physsteps <= 0) {
interppos(d);
return false;
}
-
d->o = d->newpos;
bool hitplayer = false;
- loopi(physsteps-1)
- {
+ loopi(physsteps-1) {
if(bounce(d, physframetime/1000.0f, elasticity, grav)) hitplayer = true;
}
d->deltapos = d->o;
return hitplayer;
}
-void updatephysstate(physent *d)
-{
+void updatephysstate(physent *d) {
if(d->physstate == PHYS_FALL) return;
d->timeinair = 0;
vec old(d->o);
* May be inaccurate since movement collisions are not considered.
* If good floor is not found, just keep the old floor and hope it's correct enough.
*/
- switch(d->physstate)
- {
+ switch(d->physstate) {
case PHYS_SLOPE:
case PHYS_FLOOR:
case PHYS_STEP_DOWN:
if(collide(d, vec(0, 0, -1), d->physstate == PHYS_SLOPE || d->physstate == PHYS_STEP_DOWN ? SLOPEZ : FLOORZ))
d->floor = collidewall;
break;
-
case PHYS_STEP_UP:
d->o.z -= STAIRHEIGHT+0.15f;
if(collide(d, vec(0, 0, -1), SLOPEZ))
d->floor = collidewall;
break;
-
case PHYS_SLIDE:
d->o.z -= 0.15f;
if(collide(d, vec(0, 0, -1)) && collidewall.z < SLOPEZ)
ICOMMAND(jump, "D", (int *down), { if(!*down || game::canjump()) player->jumping = *down!=0; });
ICOMMAND(attack, "D", (int *down), { game::doattack(*down!=0); });
-bool entinmap(dynent *d, bool avoidplayers) // brute force but effective way to find a free spawn spot in the map
-{
+bool entinmap(dynent *d, bool avoidplayers) { // brute force but effective way to find a free spawn spot in the map {
d->o.z += d->eyeheight; // pos specified is at feet
vec orig = d->o;
- loopi(100) // try max 100 times
- {
- if(i)
- {
+ loopi(100) { // try max 100 times {
+ if(i) {
d->o = orig;
d->o.x += (rnd(21)-10)*i/5; // increasing distance
d->o.y += (rnd(21)-10)*i/5;
d->o.z += (rnd(21)-10)*i/5;
}
-
- if(!collide(d) && !collideinside)
- {
- if(collideplayer)
- {
+ if(!collide(d) && !collideinside) {
+ if(collideplayer) {
if(!avoidplayers) continue;
d->o = orig;
d->resetinterp();
return false;
}
-
d->resetinterp();
return true;
}
-struct ragdollskel
-{
- struct vert
- {
+struct ragdollskel {
+ struct vert {
vec pos;
float radius, weight;
};
-
- struct tri
- {
+ struct tri {
int vert[3];
-
- bool shareverts(const tri &t) const
- {
+ bool shareverts(const tri &t) const {
loopi(3) loopj(3) if(vert[i] == t.vert[j]) return true;
return false;
}
};
-
- struct distlimit
- {
+ struct distlimit {
int vert[2];
float mindist, maxdist;
};
-
- struct rotlimit
- {
+ struct rotlimit {
int tri[2];
float maxangle;
matrix3 middle;
};
-
- struct rotfriction
- {
+ struct rotfriction {
int tri[2];
matrix3 middle;
};
-
- struct joint
- {
+ struct joint {
int bone, tri, vert[3];
float weight;
matrix4x3 orient;
};
-
- struct reljoint
- {
+ struct reljoint {
int bone, parent;
};
-
bool loaded, animjoints;
int eye;
vector<vert> verts;
vector<rotfriction> rotfrictions;
vector<joint> joints;
vector<reljoint> reljoints;
-
ragdollskel() : loaded(false), animjoints(false), eye(-1) {}
-
- void setupjoints()
- {
+ void setupjoints() {
loopv(verts) verts[i].weight = 0;
- loopv(joints)
- {
+ loopv(joints) {
joint &j = joints[i];
j.weight = 0;
vec pos(0, 0, 0);
- loopk(3) if(j.vert[k]>=0)
- {
+ loopk(3) if(j.vert[k]>=0) {
pos.add(verts[j.vert[k]].pos);
j.weight++;
verts[j.vert[k]].weight++;
}
if(j.weight) j.weight = 1/j.weight;
pos.mul(j.weight);
-
tri &t = tris[j.tri];
matrix4x3 &m = j.orient;
const vec &v1 = verts[t.vert[0]].pos,
loopv(verts) if(verts[i].weight) verts[i].weight = 1/verts[i].weight;
reljoints.shrink(0);
}
-
- void setuprotfrictions()
- {
+ void setuprotfrictions() {
rotfrictions.shrink(0);
- loopv(tris) for(int j = i+1; j < tris.length(); j++) if(tris[i].shareverts(tris[j]))
- {
+ loopv(tris) for(int j = i+1; j < tris.length(); j++) if(tris[i].shareverts(tris[j])) {
rotfriction &r = rotfrictions.add();
r.tri[0] = i;
r.tri[1] = j;
}
}
-
- void setup()
- {
+ void setup() {
setupjoints();
setuprotfrictions();
-
loaded = true;
}
-
- void addreljoint(int bone, int parent)
- {
+ void addreljoint(int bone, int parent) {
reljoint &r = reljoints.add();
r.bone = bone;
r.parent = parent;
}
};
-struct ragdolldata
-{
- struct vert
- {
+struct ragdolldata {
+ struct vert {
vec oldpos, pos, newpos;
float weight;
bool collided, stuck;
-
vert() : pos(0, 0, 0), newpos(0, 0, 0), weight(0), collided(false), stuck(true) {}
};
-
ragdollskel *skel;
int millis, collidemillis, collisions, floating, lastmove, unsticks;
vec offset, center;
matrix3 *tris;
matrix4x3 *animjoints;
dualquat *reljoints;
-
ragdolldata(ragdollskel *skel, float scale = 1)
: skel(skel),
millis(lastmillis),
verts(new vert[skel->verts.length()]),
tris(new matrix3[skel->tris.length()]),
animjoints(!skel->animjoints || skel->joints.empty() ? NULL : new matrix4x3[skel->joints.length()]),
- reljoints(skel->reljoints.empty() ? NULL : new dualquat[skel->reljoints.length()])
- {
+ reljoints(skel->reljoints.empty() ? NULL : new dualquat[skel->reljoints.length()]) {
}
-
- ~ragdolldata()
- {
+ ~ragdolldata() {
delete[] verts;
delete[] tris;
if(animjoints) delete[] animjoints;
if(reljoints) delete[] reljoints;
}
-
- void calcanimjoint(int i, const matrix4x3 &anim)
- {
+ void calcanimjoint(int i, const matrix4x3 &anim) {
if(!animjoints) return;
ragdollskel::joint &j = skel->joints[i];
vec pos(0, 0, 0);
loopk(3) if(j.vert[k]>=0) pos.add(verts[j.vert[k]].pos);
pos.mul(j.weight);
-
ragdollskel::tri &t = skel->tris[j.tri];
matrix4x3 m;
const vec &v1 = verts[t.vert[0]].pos,
m.d = pos;
animjoints[i].transposemul(m, anim);
}
-
- void calctris()
- {
- loopv(skel->tris)
- {
+ void calctris() {
+ loopv(skel->tris) {
ragdollskel::tri &t = skel->tris[i];
matrix3 &m = tris[i];
const vec &v1 = verts[t.vert[0]].pos,
m.b.cross(m.c, m.a);
}
}
-
- void calcboundsphere()
- {
+ void calcboundsphere() {
center = vec(0, 0, 0);
loopv(skel->verts) center.add(verts[i].pos);
center.div(skel->verts.length());
radius = 0;
loopv(skel->verts) radius = max(radius, verts[i].pos.dist(center));
}
-
- void init(dynent *d)
- {
+ void init(dynent *d) {
extern int ragdolltimestepmin;
float ts = ragdolltimestepmin/1000.0f;
loopv(skel->verts) (verts[i].oldpos = verts[i].pos).sub(vec(d->vel).add(d->falling).mul(ts));
timestep = ts;
-
calctris();
calcboundsphere();
offset = d->o;
offset.sub(skel->eye >= 0 ? verts[skel->eye].pos : center);
offset.z += (d->eyeheight + d->aboveeye)/2;
}
-
void move(dynent *pl, float ts);
void updatepos();
void constrain();
void calcrotfriction();
void applyrotfriction(float ts);
void tryunstick(float speed);
-
- static inline bool collidevert(const vec &pos, const vec &dir, float radius)
- {
- static struct vertent : physent
- {
- vertent()
- {
+ static inline bool collidevert(const vec &pos, const vec &dir, float radius) {
+ static struct vertent : physent {
+ vertent() {
type = ENT_BOUNCE;
radius = xradius = yradius = eyeheight = aboveeye = 1;
}
parented transform = parent{invert(curtri) * origtrig} * (invert(parent{base2anim}) * base2anim)
*/
-void ragdolldata::constraindist()
-{
+void ragdolldata::constraindist() {
float invscale = 1.0f/scale;
- loopv(skel->distlimits)
- {
+ loopv(skel->distlimits) {
ragdollskel::distlimit &d = skel->distlimits[i];
vert &v1 = verts[d.vert[0]], &v2 = verts[d.vert[1]];
vec dir = vec(v2.pos).sub(v1.pos);
}
}
-inline void ragdolldata::applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t2, float angle, const vec &axis)
-{
+inline void ragdolldata::applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t2, float angle, const vec &axis) {
vert &v1a = verts[t1.vert[0]], &v1b = verts[t1.vert[1]], &v1c = verts[t1.vert[2]],
&v2a = verts[t2.vert[0]], &v2b = verts[t2.vert[1]], &v2c = verts[t2.vert[2]];
vec m1 = vec(v1a.pos).add(v1b.pos).add(v1c.pos).div(3),
v2c.weight++;
}
-void ragdolldata::constrainrot()
-{
- loopv(skel->rotlimits)
- {
+void ragdolldata::constrainrot() {
+ loopv(skel->rotlimits) {
ragdollskel::rotlimit &r = skel->rotlimits[i];
matrix3 rot;
rot.mul(tris[r.tri[0]], r.middle);
rot.multranspose(tris[r.tri[1]]);
-
vec axis;
float angle;
if(!rot.calcangleaxis(angle, axis)) continue;
angle = r.maxangle - fabs(angle);
if(angle >= 0) continue;
angle += 1e-3f;
-
applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis);
}
}
FVAR(ragdollrotfric, 0, 0.85f, 1);
FVAR(ragdollrotfricstop, 0, 0.1f, 1);
-void ragdolldata::calcrotfriction()
-{
- loopv(skel->rotfrictions)
- {
+void ragdolldata::calcrotfriction() {
+ loopv(skel->rotfrictions) {
ragdollskel::rotfriction &r = skel->rotfrictions[i];
r.middle.transposemul(tris[r.tri[0]], tris[r.tri[1]]);
}
}
-void ragdolldata::applyrotfriction(float ts)
-{
+void ragdolldata::applyrotfriction(float ts) {
calctris();
float stopangle = 2*M_PI*ts*ragdollrotfricstop, rotfric = 1.0f - pow(ragdollrotfric, ts*1000.0f/ragdolltimestepmin);
- loopv(skel->rotfrictions)
- {
+ loopv(skel->rotfrictions) {
ragdollskel::rotfriction &r = skel->rotfrictions[i];
matrix3 rot;
rot.mul(tris[r.tri[0]], r.middle);
rot.multranspose(tris[r.tri[1]]);
-
vec axis;
float angle;
- if(rot.calcangleaxis(angle, axis))
- {
+ if(rot.calcangleaxis(angle, axis)) {
angle *= -(fabs(angle) >= stopangle ? rotfric : 1.0f);
applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis);
}
}
- loopv(skel->verts)
- {
+ loopv(skel->verts) {
vert &v = verts[i];
if(v.weight) v.pos = v.newpos.div(v.weight);
v.newpos = vec(0, 0, 0);
}
}
-void ragdolldata::tryunstick(float speed)
-{
+void ragdolldata::tryunstick(float speed) {
vec unstuck(0, 0, 0);
int stuck = 0;
- loopv(skel->verts)
- {
+ loopv(skel->verts) {
vert &v = verts[i];
- if(v.stuck)
- {
+ if(v.stuck) {
if(collidevert(v.pos, vec(0, 0, 0), skel->verts[i].radius)) { stuck++; continue; }
v.stuck = false;
}
unsticks = 0;
if(!stuck || stuck >= skel->verts.length()) return;
unstuck.div(skel->verts.length() - stuck);
- loopv(skel->verts)
- {
+ loopv(skel->verts) {
vert &v = verts[i];
- if(v.stuck)
- {
+ if(v.stuck) {
v.pos.add(vec(unstuck).sub(v.pos).rescale(speed));
unsticks++;
}
}
}
-void ragdolldata::updatepos()
-{
- loopv(skel->verts)
- {
+void ragdolldata::updatepos() {
+ loopv(skel->verts) {
vert &v = verts[i];
- if(v.weight)
- {
+ if(v.weight) {
v.newpos.div(v.weight);
if(!collidevert(v.newpos, vec(v.newpos).sub(v.pos), skel->verts[i].radius)) v.pos = v.newpos;
- else
- {
+ else {
vec dir = vec(v.newpos).sub(v.oldpos);
if(dir.dot(collidewall) < 0) v.oldpos = vec(v.pos).sub(dir.reflect(collidewall));
v.collided = true;
VAR(ragdollconstrain, 1, 5, 100);
-void ragdolldata::constrain()
-{
- loopi(ragdollconstrain)
- {
+void ragdolldata::constrain() {
+ loopi(ragdollconstrain) {
constraindist();
updatepos();
-
calctris();
constrainrot();
updatepos();
FVAR(ragdollunstick, 0, 10, 1e3f);
VAR(ragdollexpireoffset, 0, 1500, 30000);
-void ragdolldata::move(dynent *pl, float ts)
-{
+void ragdolldata::move(dynent *pl, float ts) {
extern const float GRAVITY;
if(collidemillis && lastmillis > collidemillis) return;
-
pl->inwater = MAT_AIR;
-
calcrotfriction();
float tsfric = timestep ? ts/timestep : 1,
airfric = ragdollairfric + min((ragdollbodyfricscale*collisions)/skel->verts.length(), 1.0f)*(ragdollbodyfric - ragdollairfric);
collisions = 0;
- loopv(skel->verts)
- {
+ loopv(skel->verts) {
vert &v = verts[i];
vec dpos = vec(v.pos).sub(v.oldpos);
dpos.z -= GRAVITY*ts*ts;
v.pos.add(dpos);
}
applyrotfriction(ts);
- loopv(skel->verts)
- {
+ loopv(skel->verts) {
vert &v = verts[i];
if(v.pos.z < 0) { v.pos.z = 0; v.oldpos = v.pos; collisions++; }
vec dir = vec(v.pos).sub(v.oldpos);
v.collided = collidevert(v.pos, dir, skel->verts[i].radius);
- if(v.collided)
- {
+ if(v.collided) {
v.pos = v.oldpos;
v.oldpos.sub(dir.reflect(collidewall));
collisions++;
}
}
-
if(unsticks && ragdollunstick) tryunstick(ts*ragdollunstick);
-
timestep = ts;
- if(collisions)
- {
+ if(collisions) {
floating = 0;
if(!collidemillis) collidemillis = lastmillis + ragdollexpireoffset;
}
else if(++floating > 1 && lastmillis < collidemillis) collidemillis = 0;
-
constrain();
calctris();
calcboundsphere();
FVAR(ragdolleyesmooth, 0, 0.5f, 1);
VAR(ragdolleyesmoothmillis, 1, 250, 10000);
-void moveragdoll(dynent *d)
-{
+void moveragdoll(dynent *d) {
if(!curtime || !d->ragdoll) return;
-
- if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis)
- {
+ if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis) {
int lastmove = d->ragdoll->lastmove;
- while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis)
- {
+ while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis) {
int timestep = min(ragdolltimestepmax, lastmillis - d->ragdoll->lastmove);
d->ragdoll->move(d, timestep/1000.0f);
d->ragdoll->lastmove += timestep;
}
}
-
vec eye = d->ragdoll->skel->eye >= 0 ? d->ragdoll->verts[d->ragdoll->skel->eye].pos : d->ragdoll->center;
eye.add(d->ragdoll->offset);
float k = pow(ragdolleyesmooth, float(curtime)/ragdolleyesmoothmillis);
d->o.mul(k).add(eye.mul(1-k));
}
-void cleanragdoll(dynent *d)
-{
+void cleanragdoll(dynent *d) {
DELETEP(d->ragdoll);
}
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays_ = NULL;
PFNGLISVERTEXARRAYPROC glIsVertexArray_ = NULL;
-void *getprocaddress(const char *name)
-{
+void *getprocaddress(const char *name) {
return SDL_GL_GetProcAddress(name);
}
hashset<const char *> glexts;
-void parseglexts()
-{
- if(glversion >= 300)
- {
+void parseglexts() {
+ if(glversion >= 300) {
GLint numexts = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numexts);
- loopi(numexts)
- {
+ loopi(numexts) {
const char *ext = (const char *)glGetStringi_(GL_EXTENSIONS, i);
glexts.add(newstring(ext));
}
}
- else
- {
+ else {
const char *exts = (const char *)glGetString(GL_EXTENSIONS);
- for(;;)
- {
+ for(;;) {
while(*exts == ' ') exts++;
if(!*exts) break;
const char *ext = exts;
}
}
-bool hasext(const char *ext)
-{
+bool hasext(const char *ext) {
return glexts.access(ext)!=NULL;
}
-void gl_checkextensions()
-{
+void gl_checkextensions() {
const char *vendor = (const char *)glGetString(GL_VENDOR);
const char *renderer = (const char *)glGetString(GL_RENDERER);
const char *version = (const char *)glGetString(GL_VERSION);
conoutf(CON_INIT, "Renderer: %s (%s)", renderer, vendor);
conoutf(CON_INIT, "Driver: %s", version);
-
- bool mesa = false, intel = false, ati = false, nvidia = false;
- if(strstr(renderer, "Mesa") || strstr(version, "Mesa"))
- {
+ bool mesa = false, ati = false, nvidia = false;
+ if(strstr(renderer, "Mesa") || strstr(version, "Mesa")) {
mesa = true;
- if(strstr(renderer, "Intel")) intel = true;
}
else if(strstr(vendor, "NVIDIA"))
nvidia = true;
else if(strstr(vendor, "ATI") || strstr(vendor, "Advanced Micro Devices"))
ati = true;
- else if(strstr(vendor, "Intel"))
- intel = true;
-
uint glmajorversion, glminorversion;
if(sscanf(version, " %u.%u", &glmajorversion, &glminorversion) != 2) glversion = 100;
else glversion = glmajorversion*100 + glminorversion*10;
-
if(glversion < 200) fatal("OpenGL 2.0 or greater is required!");
-
glMultiDrawArrays_ = (PFNGLMULTIDRAWARRAYSPROC) getprocaddress("glMultiDrawArrays");
glMultiDrawElements_ = (PFNGLMULTIDRAWELEMENTSPROC) getprocaddress("glMultiDrawElements");
-
glBlendFuncSeparate_ = (PFNGLBLENDFUNCSEPARATEPROC) getprocaddress("glBlendFuncSeparate");
glBlendEquationSeparate_ = (PFNGLBLENDEQUATIONSEPARATEPROC) getprocaddress("glBlendEquationSeparate");
glStencilOpSeparate_ = (PFNGLSTENCILOPSEPARATEPROC) getprocaddress("glStencilOpSeparate");
glStencilFuncSeparate_ = (PFNGLSTENCILFUNCSEPARATEPROC) getprocaddress("glStencilFuncSeparate");
glStencilMaskSeparate_ = (PFNGLSTENCILMASKSEPARATEPROC) getprocaddress("glStencilMaskSeparate");
-
glGenBuffers_ = (PFNGLGENBUFFERSPROC) getprocaddress("glGenBuffers");
glBindBuffer_ = (PFNGLBINDBUFFERPROC) getprocaddress("glBindBuffer");
glMapBuffer_ = (PFNGLMAPBUFFERPROC) getprocaddress("glMapBuffer");
glBufferSubData_ = (PFNGLBUFFERSUBDATAPROC) getprocaddress("glBufferSubData");
glDeleteBuffers_ = (PFNGLDELETEBUFFERSPROC) getprocaddress("glDeleteBuffers");
glGetBufferSubData_ = (PFNGLGETBUFFERSUBDATAPROC) getprocaddress("glGetBufferSubData");
-
glGetQueryiv_ = (PFNGLGETQUERYIVPROC) getprocaddress("glGetQueryiv");
glGenQueries_ = (PFNGLGENQUERIESPROC) getprocaddress("glGenQueries");
glDeleteQueries_ = (PFNGLDELETEQUERIESPROC) getprocaddress("glDeleteQueries");
glEndQuery_ = (PFNGLENDQUERYPROC) getprocaddress("glEndQuery");
glGetQueryObjectiv_ = (PFNGLGETQUERYOBJECTIVPROC) getprocaddress("glGetQueryObjectiv");
glGetQueryObjectuiv_ = (PFNGLGETQUERYOBJECTUIVPROC) getprocaddress("glGetQueryObjectuiv");
-
glCreateProgram_ = (PFNGLCREATEPROGRAMPROC) getprocaddress("glCreateProgram");
glDeleteProgram_ = (PFNGLDELETEPROGRAMPROC) getprocaddress("glDeleteProgram");
glUseProgram_ = (PFNGLUSEPROGRAMPROC) getprocaddress("glUseProgram");
glGetActiveUniform_ = (PFNGLGETACTIVEUNIFORMPROC) getprocaddress("glGetActiveUniform");
glEnableVertexAttribArray_ = (PFNGLENABLEVERTEXATTRIBARRAYPROC) getprocaddress("glEnableVertexAttribArray");
glDisableVertexAttribArray_ = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) getprocaddress("glDisableVertexAttribArray");
-
glVertexAttrib1f_ = (PFNGLVERTEXATTRIB1FPROC) getprocaddress("glVertexAttrib1f");
glVertexAttrib1fv_ = (PFNGLVERTEXATTRIB1FVPROC) getprocaddress("glVertexAttrib1fv");
glVertexAttrib1s_ = (PFNGLVERTEXATTRIB1SPROC) getprocaddress("glVertexAttrib1s");
glVertexAttrib4Nuiv_ = (PFNGLVERTEXATTRIB4NUIVPROC) getprocaddress("glVertexAttrib4Nuiv");
glVertexAttrib4Nusv_ = (PFNGLVERTEXATTRIB4NUSVPROC) getprocaddress("glVertexAttrib4Nusv");
glVertexAttribPointer_ = (PFNGLVERTEXATTRIBPOINTERPROC) getprocaddress("glVertexAttribPointer");
-
glDrawBuffers_ = (PFNGLDRAWBUFFERSPROC) getprocaddress("glDrawBuffers");
-
- if(glversion >= 300)
- {
+ if(glversion >= 300) {
glGetStringi_ = (PFNGLGETSTRINGIPROC) getprocaddress("glGetStringi");
glBindFragDataLocation_ = (PFNGLBINDFRAGDATALOCATIONPROC)getprocaddress("glBindFragDataLocation");
}
-
const char *glslstr = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
uint glslmajorversion, glslminorversion;
if(glslstr && sscanf(glslstr, " %u.%u", &glslmajorversion, &glslminorversion) == 2) glslversion = glslmajorversion*100 + glslminorversion;
-
if(glslversion < 120) fatal("GLSL 1.20 or greater is required!");
-
parseglexts();
-
GLint val;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &val);
hwtexsize = val;
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &val);
hwcubetexsize = val;
-
- if(glversion >= 300 || hasext("GL_ARB_texture_float") || hasext("GL_ATI_texture_float"))
- {
+ if(glversion >= 300 || hasext("GL_ARB_texture_float") || hasext("GL_ATI_texture_float")) {
hasTF = true;
shadowmap = 1;
extern int smoothshadowmappeel;
smoothshadowmappeel = 1;
}
-
- if(glversion >= 300 || hasext("GL_ARB_texture_rg"))
- {
+ if(glversion >= 300 || hasext("GL_ARB_texture_rg")) {
hasTRG = true;
}
-
- if(glversion >= 300 || hasext("GL_ARB_framebuffer_object"))
- {
+ if(glversion >= 300 || hasext("GL_ARB_framebuffer_object")) {
glBindRenderbuffer_ = (PFNGLBINDRENDERBUFFERPROC) getprocaddress("glBindRenderbuffer");
glDeleteRenderbuffers_ = (PFNGLDELETERENDERBUFFERSPROC) getprocaddress("glDeleteRenderbuffers");
glGenRenderbuffers_ = (PFNGLGENFRAMEBUFFERSPROC) getprocaddress("glGenRenderbuffers");
glBlitFramebuffer_ = (PFNGLBLITFRAMEBUFFERPROC) getprocaddress("glBlitFramebuffer");
hasAFBO = hasFBO = hasFBB = hasDS = true;
}
- else if(hasext("GL_EXT_framebuffer_object"))
- {
+ else if(hasext("GL_EXT_framebuffer_object")) {
glBindRenderbuffer_ = (PFNGLBINDRENDERBUFFERPROC) getprocaddress("glBindRenderbufferEXT");
glDeleteRenderbuffers_ = (PFNGLDELETERENDERBUFFERSPROC) getprocaddress("glDeleteRenderbuffersEXT");
glGenRenderbuffers_ = (PFNGLGENFRAMEBUFFERSPROC) getprocaddress("glGenRenderbuffersEXT");
glFramebufferRenderbuffer_ = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)getprocaddress("glFramebufferRenderbufferEXT");
glGenerateMipmap_ = (PFNGLGENERATEMIPMAPPROC) getprocaddress("glGenerateMipmapEXT");
hasFBO = true;
-
- if(hasext("GL_EXT_framebuffer_blit"))
- {
+ if(hasext("GL_EXT_framebuffer_blit")) {
glBlitFramebuffer_ = (PFNGLBLITFRAMEBUFFERPROC) getprocaddress("glBlitFramebufferEXT");
hasFBB = true;
}
-
- if(hasext("GL_EXT_packed_depth_stencil") || hasext("GL_NV_packed_depth_stencil"))
- {
+ if(hasext("GL_EXT_packed_depth_stencil") || hasext("GL_NV_packed_depth_stencil")) {
hasDS = true;
}
}
else fatal("Framebuffer object support is required!");
-
- if(ati)
- {
+ if(ati) {
minimizetcusage = 1;
// On Catalyst 10.2, issuing an occlusion query on the first draw using a given cubemap texture causes a nasty crash
ati_cubemap_bug = 1;
}
- else if(nvidia)
- {
+ else if(nvidia) {
reservevpparams = 10;
rtsharefb = 0; // work-around for strange driver stalls involving when using many FBOs
extern int filltjoints;
if(glversion < 300 && !hasext("GL_EXT_gpu_shader4")) filltjoints = 0; // DX9 or less NV cards seem to not cause many sparklies
}
- else
- {
+ else {
reservevpparams = 20;
-
if(mesa) mesa_swap_bug = 1;
}
-
- if(glversion >= 300 || hasext("GL_ARB_map_buffer_range"))
- {
+ if(glversion >= 300 || hasext("GL_ARB_map_buffer_range")) {
glMapBufferRange_ = (PFNGLMAPBUFFERRANGEPROC) getprocaddress("glMapBufferRange");
glFlushMappedBufferRange_ = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)getprocaddress("glFlushMappedBufferRange");
hasMBR = true;
}
-
- if(glversion >= 310 || hasext("GL_ARB_uniform_buffer_object"))
- {
+ if(glversion >= 310 || hasext("GL_ARB_uniform_buffer_object")) {
glGetUniformIndices_ = (PFNGLGETUNIFORMINDICESPROC) getprocaddress("glGetUniformIndices");
glGetActiveUniformsiv_ = (PFNGLGETACTIVEUNIFORMSIVPROC) getprocaddress("glGetActiveUniformsiv");
glGetUniformBlockIndex_ = (PFNGLGETUNIFORMBLOCKINDEXPROC) getprocaddress("glGetUniformBlockIndex");
glUniformBlockBinding_ = (PFNGLUNIFORMBLOCKBINDINGPROC) getprocaddress("glUniformBlockBinding");
glBindBufferBase_ = (PFNGLBINDBUFFERBASEPROC) getprocaddress("glBindBufferBase");
glBindBufferRange_ = (PFNGLBINDBUFFERRANGEPROC) getprocaddress("glBindBufferRange");
-
useubo = 1;
hasUBO = true;
}
-
- if(glversion >= 300 || hasext("GL_ARB_vertex_array_object"))
- {
+ if(glversion >= 300 || hasext("GL_ARB_vertex_array_object")) {
glBindVertexArray_ = (PFNGLBINDVERTEXARRAYPROC) getprocaddress("glBindVertexArray");
glDeleteVertexArrays_ = (PFNGLDELETEVERTEXARRAYSPROC)getprocaddress("glDeleteVertexArrays");
glGenVertexArrays_ = (PFNGLGENVERTEXARRAYSPROC) getprocaddress("glGenVertexArrays");
glIsVertexArray_ = (PFNGLISVERTEXARRAYPROC) getprocaddress("glIsVertexArray");
hasVAO = true;
}
- else if(hasext("GL_APPLE_vertex_array_object"))
- {
+ else if(hasext("GL_APPLE_vertex_array_object")) {
glBindVertexArray_ = (PFNGLBINDVERTEXARRAYPROC) getprocaddress("glBindVertexArrayAPPLE");
glDeleteVertexArrays_ = (PFNGLDELETEVERTEXARRAYSPROC)getprocaddress("glDeleteVertexArraysAPPLE");
glGenVertexArrays_ = (PFNGLGENVERTEXARRAYSPROC) getprocaddress("glGenVertexArraysAPPLE");
glIsVertexArray_ = (PFNGLISVERTEXARRAYPROC) getprocaddress("glIsVertexArrayAPPLE");
hasVAO = true;
}
-
- if(glversion >= 330 || hasext("GL_ARB_texture_swizzle") || hasext("GL_EXT_texture_swizzle"))
- {
+ if(glversion >= 330 || hasext("GL_ARB_texture_swizzle") || hasext("GL_EXT_texture_swizzle")) {
hasTSW = true;
}
-
- if(hasext("GL_EXT_texture_compression_s3tc"))
- {
+ if(hasext("GL_EXT_texture_compression_s3tc")) {
hasS3TC = true;
if(!mesa) usetexcompress = 2;
}
- else if(hasext("GL_EXT_texture_compression_dxt1") && hasext("GL_ANGLE_texture_compression_dxt3") && hasext("GL_ANGLE_texture_compression_dxt5"))
- {
+ else if(hasext("GL_EXT_texture_compression_dxt1") && hasext("GL_ANGLE_texture_compression_dxt3") && hasext("GL_ANGLE_texture_compression_dxt5")) {
hasS3TC = true;
}
- if(hasext("GL_3DFX_texture_compression_FXT1"))
- {
+ if(hasext("GL_3DFX_texture_compression_FXT1")) {
hasFXT1 = true;
if(mesa) usetexcompress = max(usetexcompress, 1);
}
- if(hasext("GL_EXT_texture_compression_latc"))
- {
+ if(hasext("GL_EXT_texture_compression_latc")) {
hasLATC = true;
}
- if(glversion >= 300 || hasext("GL_ARB_texture_compression_rgtc") || hasext("GL_EXT_texture_compression_rgtc"))
- {
+ if(glversion >= 300 || hasext("GL_ARB_texture_compression_rgtc") || hasext("GL_EXT_texture_compression_rgtc")) {
hasRGTC = true;
}
-
- if(hasext("GL_EXT_texture_filter_anisotropic"))
- {
+ if(hasext("GL_EXT_texture_filter_anisotropic")) {
GLint val;
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val);
hwmaxaniso = val;
hasAF = true;
}
-
- if(glversion >= 300 || hasext("GL_EXT_gpu_shader4"))
- {
+ if(glversion >= 300 || hasext("GL_EXT_gpu_shader4")) {
// on DX10 or above class cards (i.e. GF8 or RadeonHD) enable expensive features
extern int maxdynlights, texcompress;
maxdynlights = MAXDYNLIGHTS;
}
}
-void glext(char *ext)
-{
+void glext(char *ext) {
intret(hasext(ext) ? 1 : 0);
}
COMMAND(glext, "s");
-void gl_resize()
-{
+void gl_resize() {
glViewport(0, 0, screenw, screenh);
}
-void gl_init()
-{
+void gl_init() {
glClearColor(0, 0, 0, 0);
glClearDepth(1);
glDepthFunc(GL_LESS);
glDisable(GL_DEPTH_TEST);
-
glEnable(GL_LINE_SMOOTH);
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
-
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
-
gle::setup();
-
setupshaders();
-
setuptexcompress();
-
gl_resize();
}
ICOMMAND(getcamyaw, "", (), floatret(camera1->yaw));
ICOMMAND(getcampitch, "", (), floatret(camera1->pitch));
ICOMMAND(getcamroll, "", (), floatret(camera1->roll));
-ICOMMAND(getcampos, "", (),
-{
+ICOMMAND(getcampos, "", (), {
defformatstring(pos, "%s %s %s", floatstr(camera1->o.x), floatstr(camera1->o.y), floatstr(camera1->o.z));
result(pos);
});
vec worldpos, camdir, camright, camup;
-void setcammatrix()
-{
+void setcammatrix() {
// move from RH to Z-up LH quake style worldspace
cammatrix = viewmatrix;
cammatrix.rotate_around_y(camera1->roll*RAD);
cammatrix.rotate_around_x(camera1->pitch*-RAD);
cammatrix.rotate_around_z(camera1->yaw*-RAD);
cammatrix.translate(vec(camera1->o).neg());
-
cammatrix.transposedtransformnormal(vec(viewmatrix.b), camdir);
cammatrix.transposedtransformnormal(vec(viewmatrix.a).neg(), camright);
cammatrix.transposedtransformnormal(vec(viewmatrix.c), camup);
-
- if(!drawtex)
- {
+ if(!drawtex) {
if(raycubepos(camera1->o, camdir, worldpos, 0, RAY_CLIPMAT|RAY_SKIPFIRST) == -1)
worldpos = vec(camdir).mul(2*worldsize).add(camera1->o); // if nothing is hit, just far away in the view direction
}
}
-void setcamprojmatrix(bool init = true, bool flush = false)
-{
- if(init)
- {
+void setcamprojmatrix(bool init = true, bool flush = false) {
+ if(init) {
setcammatrix();
}
-
camprojmatrix.muld(projmatrix, cammatrix);
-
- if(init)
- {
+ if(init) {
invcammatrix.invert(cammatrix);
invcamprojmatrix.invert(camprojmatrix);
}
-
GLOBALPARAM(camprojmatrix, camprojmatrix);
-
if(flush && Shader::lastshader) Shader::lastshader->flushparams();
}
matrix4 hudmatrix, hudmatrixstack[64];
int hudmatrixpos = 0;
-void resethudmatrix()
-{
+void resethudmatrix() {
hudmatrixpos = 0;
GLOBALPARAM(hudmatrix, hudmatrix);
}
-void pushhudmatrix()
-{
+void pushhudmatrix() {
if(hudmatrixpos >= 0 && hudmatrixpos < int(sizeof(hudmatrixstack)/sizeof(hudmatrixstack[0]))) hudmatrixstack[hudmatrixpos] = hudmatrix;
++hudmatrixpos;
}
-void flushhudmatrix(bool flushparams)
-{
+void flushhudmatrix(bool flushparams) {
GLOBALPARAM(hudmatrix, hudmatrix);
if(flushparams && Shader::lastshader) Shader::lastshader->flushparams();
}
-void pophudmatrix(bool flush, bool flushparams)
-{
+void pophudmatrix(bool flush, bool flushparams) {
--hudmatrixpos;
- if(hudmatrixpos >= 0 && hudmatrixpos < int(sizeof(hudmatrixstack)/sizeof(hudmatrixstack[0])))
- {
+ if(hudmatrixpos >= 0 && hudmatrixpos < int(sizeof(hudmatrixstack)/sizeof(hudmatrixstack[0]))) {
hudmatrix = hudmatrixstack[hudmatrixpos];
if(flush) flushhudmatrix(flushparams);
}
}
-void pushhudscale(float sx, float sy)
-{
+void pushhudscale(float sx, float sy) {
if(!sy) sy = sx;
pushhudmatrix();
hudmatrix.scale(sx, sy, 1);
flushhudmatrix();
}
-void pushhudtranslate(float tx, float ty, float sx, float sy)
-{
+void pushhudtranslate(float tx, float ty, float sx, float sy) {
if(!sy) sy = sx;
pushhudmatrix();
hudmatrix.translate(tx, ty, 0);
static float zoomprogress = 0;
VAR(zoom, -1, 0, 1);
-void disablezoom()
-{
+void disablezoom() {
zoom = 0;
zoomprogress = 0;
}
-void computezoom()
-{
+void computezoom() {
if(!zoom) { zoomprogress = 0; curfov = fov; curavatarfov = avatarfov; return; }
if(zoom > 0) zoomprogress = zoominvel ? min(zoomprogress + float(elapsedtime) / zoominvel, 1.0f) : 1;
- else
- {
+ else {
zoomprogress = zoomoutvel ? max(zoomprogress - float(elapsedtime) / zoomoutvel, 0.0f) : 0;
if(zoomprogress <= 0) zoom = 0;
}
bool detachedcamera = false;
bool isthirdperson() { return player!=camera1 || detachedcamera; }
-void fixcamerarange()
-{
+void fixcamerarange() {
const float MAXPITCH = 90.0f;
if(camera1->pitch>MAXPITCH) camera1->pitch = MAXPITCH;
if(camera1->pitch<-MAXPITCH) camera1->pitch = -MAXPITCH;
while(camera1->yaw>=360.0f) camera1->yaw -= 360.0f;
}
-void mousemove(int dx, int dy)
-{
+void mousemove(int dx, int dy) {
if(!game::allowmouselook()) return;
float cursens = sensitivity, curaccel = mouseaccel;
- if(zoom)
- {
- if(zoomautosens)
- {
+ if(zoom) {
+ if(zoomautosens) {
cursens = float(sensitivity*zoomfov)/fov;
curaccel = float(mouseaccel*zoomfov)/fov;
}
- else
- {
+ else {
cursens = zoomsens;
curaccel = zoomaccel;
}
camera1->yaw += dx*cursens;
camera1->pitch -= dy*cursens*(invmouse ? -1 : 1);
fixcamerarange();
- if(camera1!=player && !detachedcamera)
- {
+ if(camera1!=player && !detachedcamera) {
player->yaw = camera1->yaw;
player->pitch = camera1->pitch;
}
speedmodifier += abs(dx)-abs(dy);
}
-void recomputecamera()
-{
+void recomputecamera() {
game::setupcamera();
computezoom();
-
bool allowthirdperson = game::allowthirdperson();
bool shoulddetach = (allowthirdperson && thirdperson > 1) || game::detachcamera();
- if((!allowthirdperson || !thirdperson) && !shoulddetach)
- {
+ if((!allowthirdperson || !thirdperson) && !shoulddetach) {
camera1 = player;
detachedcamera = false;
}
- else
- {
+ else {
static physent tempcamera;
camera1 = &tempcamera;
if(detachedcamera && shoulddetach) camera1->o = player->o;
- else
- {
+ else {
*camera1 = *player;
detachedcamera = shoulddetach;
}
camera1->type = ENT_CAMERA;
camera1->move = -1;
camera1->eyeheight = camera1->aboveeye = camera1->radius = camera1->xradius = camera1->yradius = 2;
-
matrix3 orient;
orient.identity();
orient.rotate_around_z(camera1->yaw*RAD);
orient.rotate_around_x(camera1->pitch*RAD);
orient.rotate_around_y(camera1->roll*-RAD);
vec dir = vec(orient.b).neg(), side = vec(orient.a).neg(), up = orient.c;
-
- if(game::collidecamera())
- {
+ if(game::collidecamera()) {
movecamera(camera1, dir, thirdpersondistance, 1);
movecamera(camera1, dir, clamp(thirdpersondistance - camera1->o.dist(player->o), 0.0f, 1.0f), 0.1f);
- if(thirdpersonup)
- {
+ if(thirdpersonup) {
vec pos = camera1->o;
float dist = fabs(thirdpersonup);
if(thirdpersonup < 0) up.neg();
movecamera(camera1, up, dist, 1);
movecamera(camera1, up, clamp(dist - camera1->o.dist(pos), 0.0f, 1.0f), 0.1f);
}
- if(thirdpersonside)
- {
+ if(thirdpersonside) {
vec pos = camera1->o;
float dist = fabs(thirdpersonside);
if(thirdpersonside < 0) side.neg();
movecamera(camera1, side, clamp(dist - camera1->o.dist(pos), 0.0f, 1.0f), 0.1f);
}
}
- else
- {
+ else {
camera1->o.add(vec(dir).mul(thirdpersondistance));
if(thirdpersonup) camera1->o.add(vec(up).mul(thirdpersonup));
if(thirdpersonside) camera1->o.add(vec(side).mul(thirdpersonside));
FVAR(nearplane, 0.01f, 0.54f, 2.0f);
-vec calcavatarpos(const vec &pos, float dist)
-{
+vec calcavatarpos(const vec &pos, float dist) {
vec eyepos;
cammatrix.transform(pos, eyepos);
GLdouble ydist = nearplane * tan(curavatarfov/2*RAD), xdist = ydist * aspect;
scrpos.y = eyepos.y*nearplane/ydist;
scrpos.z = (eyepos.z*(farplane + nearplane) - 2*nearplane*farplane) / (farplane - nearplane);
scrpos.w = -eyepos.z;
-
vec worldpos = invcamprojmatrix.perspectivetransform(scrpos);
vec dir = vec(worldpos).sub(camera1->o).rescale(dist);
return dir.add(camera1->o);
matrix4 clipmatrix, noclipmatrix;
-void renderavatar()
-{
+void renderavatar() {
if(isthirdperson()) return;
-
matrix4 oldprojmatrix = projmatrix;
projmatrix.perspective(curavatarfov, aspect, nearplane, farplane);
projmatrix.scalez(avatardepth);
setcamprojmatrix(false);
-
game::renderavatar();
-
projmatrix = oldprojmatrix;
setcamprojmatrix(false);
}
matrix4 nooffsetmatrix;
-void enablepolygonoffset(GLenum type)
-{
- if(!depthoffset)
- {
+void enablepolygonoffset(GLenum type) {
+ if(!depthoffset) {
glPolygonOffset(polygonoffsetfactor, polygonoffsetunits);
glEnable(type);
return;
}
-
bool clipped = false;
-
nooffsetmatrix = projmatrix;
projmatrix.d.z += depthoffset * (clipped ? noclipmatrix.c.z : projmatrix.c.z);
setcamprojmatrix(false, true);
}
-void disablepolygonoffset(GLenum type)
-{
- if(!depthoffset)
- {
+void disablepolygonoffset(GLenum type) {
+ if(!depthoffset) {
glDisable(type);
return;
}
-
projmatrix = nooffsetmatrix;
setcamprojmatrix(false, true);
}
-void calcspherescissor(const vec ¢er, float size, float &sx1, float &sy1, float &sx2, float &sy2)
-{
+void calcspherescissor(const vec ¢er, float size, float &sx1, float &sy1, float &sx2, float &sy2) {
vec worldpos(center), e;
cammatrix.transform(worldpos, e);
if(e.z > 2*size) { sx1 = sy1 = 1; sx2 = sy2 = -1; return; }
do { \
float nzc = (cz*cz + 1) / (cz dir drt) - cz, \
pz = (d##c)/(nzc*e.c - e.z); \
- if(pz > 0) \
- { \
+ if(pz > 0) { \
+ \
float c = (focaldist)*nzc, \
pc = pz*nzc; \
if(pc < e.c) low = c; \
else if(pc > e.c) high = c; \
} \
} while(0)
- if(dx > 0)
- {
+ if(dx > 0) {
float cz = e.x/e.z, drt = sqrtf(dx)/size;
CHECKPLANE(x, -, focaldist/aspect, sx1, sx2);
CHECKPLANE(x, +, focaldist/aspect, sx1, sx2);
}
- if(dy > 0)
- {
+ if(dy > 0) {
float cz = e.y/e.z, drt = sqrtf(dy)/size;
CHECKPLANE(y, -, focaldist, sy1, sy2);
CHECKPLANE(y, +, focaldist, sy1, sy2);
static int scissoring = 0;
static GLint oldscissor[4];
-int pushscissor(float sx1, float sy1, float sx2, float sy2)
-{
+int pushscissor(float sx1, float sy1, float sx2, float sy2) {
scissoring = 0;
-
if(sx1 <= -1 && sy1 <= -1 && sx2 >= 1 && sy2 >= 1) return 0;
-
sx1 = max(sx1, -1.0f);
sy1 = max(sy1, -1.0f);
sx2 = min(sx2, 1.0f);
sy2 = min(sy2, 1.0f);
-
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
int sx = viewport[0] + int(floor((sx1+1)*0.5f*viewport[2])),
sw = viewport[0] + int(ceil((sx2+1)*0.5f*viewport[2])) - sx,
sh = viewport[1] + int(ceil((sy2+1)*0.5f*viewport[3])) - sy;
if(sw <= 0 || sh <= 0) return 0;
-
- if(glIsEnabled(GL_SCISSOR_TEST))
- {
+ if(glIsEnabled(GL_SCISSOR_TEST)) {
glGetIntegerv(GL_SCISSOR_BOX, oldscissor);
sw += sx;
sh += sy;
scissoring = 2;
}
else scissoring = 1;
-
glScissor(sx, sy, sw, sh);
if(scissoring<=1) glEnable(GL_SCISSOR_TEST);
-
return scissoring;
}
-void popscissor()
-{
+void popscissor() {
if(scissoring>1) glScissor(oldscissor[0], oldscissor[1], oldscissor[2], oldscissor[3]);
else if(scissoring) glDisable(GL_SCISSOR_TEST);
scissoring = 0;
static GLuint screenquadvbo = 0;
-static void setupscreenquad()
-{
- if(!screenquadvbo)
- {
+static void setupscreenquad() {
+ if(!screenquadvbo) {
glGenBuffers_(1, &screenquadvbo);
gle::bindvbo(screenquadvbo);
vec2 verts[4] = { vec2(1, -1), vec2(-1, -1), vec2(1, 1), vec2(-1, 1) };
}
}
-static void cleanupscreenquad()
-{
+static void cleanupscreenquad() {
if(screenquadvbo) { glDeleteBuffers_(1, &screenquadvbo); screenquadvbo = 0; }
}
-void screenquad()
-{
+void screenquad() {
setupscreenquad();
gle::bindvbo(screenquadvbo);
gle::enablevertex();
static LocalShaderParam screentexcoord[2] = { LocalShaderParam("screentexcoord0"), LocalShaderParam("screentexcoord1") };
-static inline void setscreentexcoord(int i, float w, float h, float x = 0, float y = 0)
-{
+static inline void setscreentexcoord(int i, float w, float h, float x = 0, float y = 0) {
screentexcoord[i].setf(w*0.5f, h*0.5f, x + w*0.5f, y + fabs(h)*0.5f);
}
-void screenquad(float sw, float sh)
-{
+void screenquad(float sw, float sh) {
setscreentexcoord(0, sw, sh);
screenquad();
}
-void screenquadflipped(float sw, float sh)
-{
+void screenquadflipped(float sw, float sh) {
setscreentexcoord(0, sw, -sh);
screenquad();
}
-void screenquad(float sw, float sh, float sw2, float sh2)
-{
+void screenquad(float sw, float sh, float sw2, float sh2) {
setscreentexcoord(0, sw, sh);
setscreentexcoord(1, sw2, sh2);
screenquad();
}
-void screenquadoffset(float x, float y, float w, float h)
-{
+void screenquadoffset(float x, float y, float w, float h) {
setscreentexcoord(0, w, h, x, y);
screenquad();
}
-void screenquadoffset(float x, float y, float w, float h, float x2, float y2, float w2, float h2)
-{
+void screenquadoffset(float x, float y, float w, float h, float x2, float y2, float w2, float h2) {
setscreentexcoord(0, w, h, x, y);
setscreentexcoord(1, w2, h2, x2, y2);
screenquad();
gle::end(); \
}
-void hudquad(float x, float y, float w, float h, float tx, float ty, float tw, float th)
-{
+void hudquad(float x, float y, float w, float h, float tx, float ty, float tw, float th) {
HUDQUAD(x, y, x+w, y+h, tx, ty, tx+tw, ty+th);
}
bool renderedgame = false;
-void rendergame(bool mainpass)
-{
+void rendergame(bool mainpass) {
game::rendergame(mainpass);
if(!shadowmapping) renderedgame = true;
}
VAR(modelpreviewfov, 10, 20, 100);
VAR(modelpreviewpitch, -90, -15, 90);
-namespace modelpreview
-{
+namespace modelpreview {
physent *oldcamera;
physent camera;
-
float oldaspect, oldfovy, oldfov;
int oldfarplane;
matrix4 oldprojmatrix;
-
- void start(int x, int y, int w, int h, bool background)
- {
+ void start(int x, int y, int w, int h, bool background) {
drawtex = DRAWTEX_MODELPREVIEW;
-
glViewport(x, y, w, h);
glScissor(x, y, w, h);
glEnable(GL_SCISSOR_TEST);
-
oldcamera = camera1;
camera = *camera1;
camera.reset();
camera.pitch = modelpreviewpitch;
camera.roll = 0;
camera1 = &camera;
-
oldaspect = aspect;
oldfovy = fovy;
oldfov = curfov;
oldfarplane = farplane;
oldprojmatrix = projmatrix;
-
aspect = w/float(h);
fovy = modelpreviewfov;
curfov = 2*atan2(tan(fovy/2*RAD), 1/aspect)/RAD;
farplane = 1024;
-
glClearColor(0, 0, 0, 1);
-
glClear((background ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT);
-
projmatrix.perspective(fovy, aspect, nearplane, farplane);
setcamprojmatrix();
-
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
}
-
- void end()
- {
+ void end() {
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
-
aspect = oldaspect;
fovy = oldfovy;
curfov = oldfov;
farplane = oldfarplane;
-
camera1 = oldcamera;
drawtex = 0;
-
glDisable(GL_SCISSOR_TEST);
glViewport(0, 0, screenw, screenh);
-
projmatrix = oldprojmatrix;
setcamprojmatrix();
}
}
-vec calcmodelpreviewpos(const vec &radius, float &yaw)
-{
+vec calcmodelpreviewpos(const vec &radius, float &yaw) {
yaw = fmod(lastmillis/10000.0f*360.0f, 360.0f);
float dist = 1.15f*max(radius.magnitude2()/aspect, radius.magnitude())/sinf(fovy/2*RAD);
return vec(0, dist, 0).rotate_around_x(camera1->pitch*RAD);
bool deferdrawtextures = false;
-void drawtextures()
-{
+void drawtextures() {
if(minimized) { deferdrawtextures = true; return; }
deferdrawtextures = false;
}
int xtraverts, xtravertsva;
-void gl_drawframe()
-{
+void gl_drawframe() {
if(deferdrawtextures) drawtextures();
-
updatedynlights();
-
int w = screenw, h = screenh;
aspect = forceaspect ? forceaspect : w/float(h);
fovy = 2*atan2(tan(curfov/2*RAD), aspect)/RAD;
-
farplane = worldsize*2;
-
projmatrix.perspective(fovy, aspect, nearplane, farplane);
setcamprojmatrix();
-
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
-
xtravertsva = xtraverts = glde = gbatches = 0;
-
visiblecubes();
-
glClear(GL_DEPTH_BUFFER_BIT|(wireframe && editmode ? GL_COLOR_BUFFER_BIT : 0));
-
if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
rendergeom();
-
extern int outline;
if(!wireframe && editmode && outline) renderoutline();
-
renderdecals(true);
-
rendermapmodels();
rendergame(true);
renderavatar();
-
if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
rendermaterials();
renderalphageom();
-
if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
renderparticles(true);
-
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
-
gl_drawhud();
-
renderedgame = false;
}
-void gl_drawmainmenu()
-{
+void gl_drawmainmenu() {
xtravertsva = xtraverts = glde = gbatches = 0;
renderbackground(NULL, NULL, NULL, NULL, true, true);
gl_drawhud();
float damagedirs[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-void damagecompass(int n, const vec &loc)
-{
+void damagecompass(int n, const vec &loc) {
if(!usedamagecompass || minimized) return;
vec delta(loc);
delta.sub(camera1->o);
float yaw = 0, pitch;
- if(delta.magnitude() > 4)
- {
+ if(delta.magnitude() > 4) {
vectoyawpitch(delta, yaw, pitch);
yaw -= camera1->yaw;
}
if(damagedirs[dir]>1) damagedirs[dir] = 1;
}
-void drawdamagecompass(int w, int h)
-{
+void drawdamagecompass(int w, int h) {
hudnotextureshader->set();
-
int dirs = 0;
float size = damagecompasssize/100.0f*min(h, w)/2.0f;
- loopi(8) if(damagedirs[i]>0)
- {
- if(!dirs)
- {
+ loopi(8) if(damagedirs[i]>0) {
+ if(!dirs) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gle::colorf(1, 0, 0, damagecompassalpha/100.0f);
gle::defvertex();
gle::begin(GL_TRIANGLES);
}
dirs++;
-
float logscale = 32,
scale = log(1 + (logscale - 1)*damagedirs[i]) / log(logscale),
offset = -size/2.0f-min(h, w)/4.0f;
m.rotate_around_z(i*45*RAD);
m.translate(0, offset, 0);
m.scale(size*scale);
-
gle::attrib(m.transform(vec2(1, 1)));
gle::attrib(m.transform(vec2(-1, 1)));
gle::attrib(m.transform(vec2(0, 0)));
-
// fade in log space so short blips don't disappear too quickly
scale -= float(curtime)/damagecompassfade;
damagedirs[i] = scale > 0 ? (pow(logscale, scale) - 1) / (logscale - 1) : 0;
#define MAXCROSSHAIRS 4
static Texture *crosshairs[MAXCROSSHAIRS] = { NULL, NULL, NULL, NULL };
-void loadcrosshair(const char *name, int i)
-{
+void loadcrosshair(const char *name, int i) {
if(i < 0 || i >= MAXCROSSHAIRS) return;
crosshairs[i] = name ? textureload(name, 3, true) : notexture;
- if(crosshairs[i] == notexture)
- {
+ if(crosshairs[i] == notexture) {
name = game::defaultcrosshair(i);
if(!name) name = "data/crosshair.png";
crosshairs[i] = textureload(name, 3, true);
}
}
-void loadcrosshair_(const char *name, int *i)
-{
+void loadcrosshair_(const char *name, int *i) {
loadcrosshair(name, *i);
}
COMMANDN(loadcrosshair, loadcrosshair_, "si");
-ICOMMAND(getcrosshair, "i", (int *i),
-{
+ICOMMAND(getcrosshair, "i", (int *i), {
const char *name = "";
- if(*i >= 0 && *i < MAXCROSSHAIRS)
- {
+ if(*i >= 0 && *i < MAXCROSSHAIRS) {
name = crosshairs[*i] ? crosshairs[*i]->name : game::defaultcrosshair(*i);
if(!name) name = "data/crosshair.png";
}
result(name);
});
-void writecrosshairs(stream *f)
-{
+void writecrosshairs(stream *f) {
loopi(MAXCROSSHAIRS) if(crosshairs[i] && crosshairs[i]!=notexture)
f->printf("loadcrosshair %s %d\n", escapestring(crosshairs[i]->name), i);
f->printf("\n");
}
-void drawcrosshair(int w, int h)
-{
+void drawcrosshair(int w, int h) {
bool windowhit = g3d_windowhit(true, false);
if(!windowhit && (hidehud || mainmenu)) return; //(hidehud || player->state==CS_SPECTATOR || player->state==CS_DEAD)) return;
-
vec color(1, 1, 1);
float cx = 0.5f, cy = 0.5f, chsize;
Texture *crosshair;
- if(windowhit)
- {
+ if(windowhit) {
static Texture *cursor = NULL;
if(!cursor) cursor = textureload("data/guicursor.png", 3, true);
crosshair = cursor;
chsize = cursorsize*w/900.0f;
g3d_cursorpos(cx, cy);
}
- else
- {
+ else {
int index = game::selectcrosshair(color);
if(index < 0) return;
if(!crosshairfx) index = 0;
if(!crosshairfx || !crosshaircolors) color = vec(1, 1, 1);
crosshair = crosshairs[index];
- if(!crosshair)
- {
+ if(!crosshair) {
loadcrosshair(NULL, index);
crosshair = crosshairs[index];
}
float x = cx*w - (windowhit ? 0 : chsize/2.0f);
float y = cy*h - (windowhit ? 0 : chsize/2.0f);
glBindTexture(GL_TEXTURE_2D, crosshair->id);
-
hudshader->set();
gle::color(color);
hudquad(x, y, chsize, chsize);
FVARP(conscale, 1e-3f, 0.33f, 1e3f);
-void gl_drawhud()
-{
+void gl_drawhud() {
g3d_render();
-
int w = screenw, h = screenh;
if(forceaspect) w = int(ceil(h*forceaspect));
-
- if(editmode && !hidehud && !mainmenu)
- {
+ if(editmode && !hidehud && !mainmenu) {
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
-
rendereditcursor();
-
glDepthMask(GL_TRUE);
glDisable(GL_DEPTH_TEST);
}
-
gettextres(w, h);
-
hudmatrix.ortho(0, w, h, 0, -1, 1);
resethudmatrix();
-
gle::colorf(1, 1, 1);
-
glEnable(GL_BLEND);
-
- if(!mainmenu)
- {
+ if(!mainmenu) {
drawdamagecompass(w, h);
}
-
hudshader->set();
-
int conw = int(w/conscale), conh = int(h/conscale), abovehud = conh - FONTH, limitgui = abovehud;
- if(!hidehud && !mainmenu)
- {
- if(!hidestats)
- {
+ if(!hidehud && !mainmenu) {
+ if(!hidestats) {
pushhudmatrix();
hudmatrix.scale(conscale, conscale, 1);
flushhudmatrix();
-
int roffset = 0;
- if(showfps)
- {
+ if(showfps) {
static int lastfps = 0, prevfps[3] = { 0, 0, 0 }, curfps[3] = { 0, 0, 0 };
- if(totalmillis - lastfps >= statrate)
- {
+ if(totalmillis - lastfps >= statrate) {
memcpy(prevfps, curfps, sizeof(prevfps));
lastfps = totalmillis - (totalmillis%statrate);
}
else draw_textf("fps %d", conw-5*FONTH, conh-FONTH*3/2, curfps[0]);
roffset += FONTH;
}
-
- if(editmode || showeditstats)
- {
+ if(editmode || showeditstats) {
static int laststats = 0, prevstats[8] = { 0, 0, 0, 0, 0, 0, 0 }, curstats[8] = { 0, 0, 0, 0, 0, 0, 0 };
- if(totalmillis - laststats >= statrate)
- {
+ if(totalmillis - laststats >= statrate) {
memcpy(prevstats, curstats, sizeof(prevstats));
laststats = totalmillis - (totalmillis%statrate);
}
- int nextstats[8] =
- {
+ int nextstats[8] = {
vtris*100/max(wtris, 1),
vverts*100/max(wverts, 1),
xtraverts/1024,
getnumqueries()
};
loopi(8) if(prevstats[i]==curstats[i]) curstats[i] = nextstats[i];
-
abovehud -= 2*FONTH;
draw_textf("wtr:%dk(%d%%) wvt:%dk(%d%%) evt:%dk eva:%dk", FONTH/2, abovehud, wtris/1024, curstats[0], wverts/1024, curstats[1], curstats[2], curstats[3]);
draw_textf("ond:%d va:%d gl:%d(%d) oq:%d lm:%d rp:%d", FONTH/2, abovehud+FONTH, allocnodes*8, allocva, curstats[4], curstats[5], curstats[6], lightmaps.length(), curstats[7]);
limitgui = abovehud;
}
-
- if(editmode)
- {
+ if(editmode) {
abovehud -= FONTH;
draw_textf("cube %s%d%s", FONTH/2, abovehud, selchildcount<0 ? "1/" : "", abs(selchildcount), showmat && selchildmat > 0 ? getmaterialdesc(selchildmat, ": ") : "");
-
- if(char *editinfo = execidentstr("edithud"))
- {
- if(editinfo[0])
- {
+ if(char *editinfo = execidentstr("edithud")) {
+ if(editinfo[0]) {
int tw, th;
text_bounds(editinfo, tw, th);
th += FONTH-1; th -= th%FONTH;
DELETEA(editinfo);
}
}
- else if(char *gameinfo = execidentstr("gamehud"))
- {
- if(gameinfo[0])
- {
+ else if(char *gameinfo = execidentstr("gamehud")) {
+ if(gameinfo[0]) {
int tw, th;
text_bounds(gameinfo, tw, th);
th += FONTH-1; th -= th%FONTH;
}
DELETEA(gameinfo);
}
-
pophudmatrix();
}
-
- if(hidestats || (!editmode && !showeditstats))
- {
+ if(hidestats || (!editmode && !showeditstats)) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
game::gameplayhud(w, h);
limitgui = abovehud = min(abovehud, int(conh*game::abovegameplayhud(w, h)));
}
-
rendertexturepanel(w, h);
}
-
glDisable(GL_BLEND);
-
g3d_limitscale((2*limitgui - conh) / float(conh));
g3d_render2d();
-
glEnable(GL_BLEND);
-
hudmatrix.ortho(0, w, h, 0, -1, 1);
resethudmatrix();
-
pushhudmatrix();
hudmatrix.scale(conscale, conscale, 1);
flushhudmatrix();
extern int fullconsole;
if(!hidehud || fullconsole) renderconsole(conw, conh, abovehud - FONTH/2);
pophudmatrix();
-
drawcrosshair(w, h);
-
glDisable(GL_BLEND);
}
-void cleanupgl()
-{
+void cleanupgl() {
cleanupscreenquad();
-
gle::cleanup();
}
#include "ragdoll.h"
#include "animmodel.h"
-#include "vertmodel.h"
#include "skelmodel.h"
static model *(__cdecl *modeltypes[NUMMODELTYPES])(const char *);
-static int addmodeltype(int type, model *(__cdecl *loader)(const char *))
-{
+static int addmodeltype(int type, model *(__cdecl *loader)(const char *)) {
modeltypes[type] = loader;
return type;
}
#define MODELTYPE(modeltype, modelclass) \
-static model *__loadmodel__##modelclass(const char *filename) \
-{ \
+static model *__loadmodel__##modelclass(const char *filename) { \
+ \
return new modelclass(filename); \
} \
UNUSED static int __dummy__##modelclass = addmodeltype((modeltype), __loadmodel__##modelclass);
-#include "md3.h"
#include "md5.h"
#include "iqm.h"
-MODELTYPE(MDL_MD3, md3);
MODELTYPE(MDL_MD5, md5);
MODELTYPE(MDL_IQM, iqm);
#define checkmdl if(!loadingmodel) { conoutf(CON_ERROR, "not loading a model"); return; }
-void mdlcullface(int *cullface)
-{
+void mdlcullface(int *cullface) {
checkmdl;
loadingmodel->setcullface(*cullface!=0);
}
COMMAND(mdlcullface, "i");
-void mdlcollide(int *collide)
-{
+void mdlcollide(int *collide) {
checkmdl;
loadingmodel->collide = *collide!=0;
}
COMMAND(mdlcollide, "i");
-void mdlellipsecollide(int *collide)
-{
+void mdlellipsecollide(int *collide) {
checkmdl;
loadingmodel->ellipsecollide = *collide!=0;
}
COMMAND(mdlellipsecollide, "i");
-void mdlspec(int *percent)
-{
+void mdlspec(int *percent) {
checkmdl;
float spec = 1.0f;
if(*percent>0) spec = *percent/100.0f;
COMMAND(mdlspec, "i");
-void mdlambient(int *percent)
-{
+void mdlambient(int *percent) {
checkmdl;
float ambient = 0.3f;
if(*percent>0) ambient = *percent/100.0f;
COMMAND(mdlambient, "i");
-void mdlalphatest(float *cutoff)
-{
+void mdlalphatest(float *cutoff) {
checkmdl;
loadingmodel->setalphatest(max(0.0f, min(1.0f, *cutoff)));
}
COMMAND(mdlalphatest, "f");
-void mdlalphablend(int *blend)
-{
+void mdlalphablend(int *blend) {
checkmdl;
loadingmodel->setalphablend(*blend!=0);
}
COMMAND(mdlalphablend, "i");
-void mdlalphadepth(int *depth)
-{
+void mdlalphadepth(int *depth) {
checkmdl;
loadingmodel->alphadepth = *depth!=0;
}
COMMAND(mdlalphadepth, "i");
-void mdldepthoffset(int *offset)
-{
+void mdldepthoffset(int *offset) {
checkmdl;
loadingmodel->depthoffset = *offset!=0;
}
COMMAND(mdldepthoffset, "i");
-void mdlfullbright(float *fullbright)
-{
+void mdlfullbright(float *fullbright) {
checkmdl;
loadingmodel->setfullbright(*fullbright);
}
COMMAND(mdlfullbright, "f");
-void mdlshader(char *shader)
-{
+void mdlshader(char *shader) {
checkmdl;
loadingmodel->setshader(lookupshaderbyname(shader));
}
COMMAND(mdlshader, "s");
-void mdlspin(float *yaw, float *pitch)
-{
+void mdlspin(float *yaw, float *pitch) {
checkmdl;
loadingmodel->spinyaw = *yaw;
loadingmodel->spinpitch = *pitch;
COMMAND(mdlspin, "ff");
-void mdlscale(int *percent)
-{
+void mdlscale(int *percent) {
checkmdl;
float scale = 1.0f;
if(*percent>0) scale = *percent/100.0f;
COMMAND(mdlscale, "i");
-void mdltrans(float *x, float *y, float *z)
-{
+void mdltrans(float *x, float *y, float *z) {
checkmdl;
loadingmodel->translate = vec(*x, *y, *z);
}
COMMAND(mdltrans, "fff");
-void mdlyaw(float *angle)
-{
+void mdlyaw(float *angle) {
checkmdl;
loadingmodel->offsetyaw = *angle;
}
COMMAND(mdlyaw, "f");
-void mdlpitch(float *angle)
-{
+void mdlpitch(float *angle) {
checkmdl;
loadingmodel->offsetpitch = *angle;
}
COMMAND(mdlpitch, "f");
-void mdlshadow(int *shadow)
-{
+void mdlshadow(int *shadow) {
checkmdl;
loadingmodel->shadow = *shadow!=0;
}
COMMAND(mdlshadow, "i");
-void mdlbb(float *rad, float *h, float *eyeheight)
-{
+void mdlbb(float *rad, float *h, float *eyeheight) {
checkmdl;
loadingmodel->collidexyradius = *rad;
loadingmodel->collideheight = *h;
COMMAND(mdlbb, "fff");
-void mdlextendbb(float *x, float *y, float *z)
-{
+void mdlextendbb(float *x, float *y, float *z) {
checkmdl;
loadingmodel->bbextend = vec(*x, *y, *z);
}
COMMAND(mdlextendbb, "fff");
-void mdlname()
-{
+void mdlname() {
checkmdl;
result(loadingmodel->name);
}
if(ragdoll->loaded) return;
-void rdvert(float *x, float *y, float *z, float *radius)
-{
+void rdvert(float *x, float *y, float *z, float *radius) {
checkragdoll;
ragdollskel::vert &v = ragdoll->verts.add();
v.pos = vec(*x, *y, *z);
}
COMMAND(rdvert, "ffff");
-void rdeye(int *v)
-{
+void rdeye(int *v) {
checkragdoll;
ragdoll->eye = *v;
}
COMMAND(rdeye, "i");
-void rdtri(int *v1, int *v2, int *v3)
-{
+void rdtri(int *v1, int *v2, int *v3) {
checkragdoll;
ragdollskel::tri &t = ragdoll->tris.add();
t.vert[0] = *v1;
}
COMMAND(rdtri, "iii");
-void rdjoint(int *n, int *t, int *v1, int *v2, int *v3)
-{
+void rdjoint(int *n, int *t, int *v1, int *v2, int *v3) {
checkragdoll;
if(*n < 0 || *n >= skel->numbones) return;
ragdollskel::joint &j = ragdoll->joints.add();
}
COMMAND(rdjoint, "iibbb");
-void rdlimitdist(int *v1, int *v2, float *mindist, float *maxdist)
-{
+void rdlimitdist(int *v1, int *v2, float *mindist, float *maxdist) {
checkragdoll;
ragdollskel::distlimit &d = ragdoll->distlimits.add();
d.vert[0] = *v1;
}
COMMAND(rdlimitdist, "iiff");
-void rdlimitrot(int *t1, int *t2, float *maxangle, float *qx, float *qy, float *qz, float *qw)
-{
+void rdlimitrot(int *t1, int *t2, float *maxangle, float *qx, float *qy, float *qz, float *qw) {
checkragdoll;
ragdollskel::rotlimit &r = ragdoll->rotlimits.add();
r.tri[0] = *t1;
}
COMMAND(rdlimitrot, "iifffff");
-void rdanimjoints(int *on)
-{
+void rdanimjoints(int *on) {
checkragdoll;
ragdoll->animjoints = *on!=0;
}
vector<mapmodelinfo> mapmodels;
-void mmodel(char *name)
-{
+void mmodel(char *name) {
mapmodelinfo &mmi = mapmodels.add();
copystring(mmi.name, name);
mmi.m = NULL;
}
-void mapmodelcompat(int *rad, int *h, int *tex, char *name, char *shadow)
-{
+void mapmodelcompat(int *rad, int *h, int *tex, char *name, char *shadow) {
mmodel(name);
}
-void mapmodelreset(int *n)
-{
+void mapmodelreset(int *n) {
if(!(identflags&IDF_OVERRIDDEN) && !game::allowedittoggle()) return;
mapmodels.shrink(clamp(*n, 0, mapmodels.length()));
}
hashnameset<model *> models;
vector<const char *> preloadmodels;
-void preloadmodel(const char *name)
-{
+void preloadmodel(const char *name) {
if(!name || !name[0] || models.access(name)) return;
preloadmodels.add(newstring(name));
}
-void flushpreloadedmodels(bool msg)
-{
- loopv(preloadmodels)
- {
+void flushpreloadedmodels(bool msg) {
+ loopv(preloadmodels) {
loadprogress = float(i+1)/preloadmodels.length();
model *m = loadmodel(preloadmodels[i], -1, msg);
if(!m) { if(msg) conoutf(CON_WARN, "could not load model: %s", preloadmodels[i]); }
- else
- {
+ else {
m->preloadmeshes();
}
}
loadprogress = 0;
}
-void preloadusedmapmodels(bool msg, bool bih)
-{
+void preloadusedmapmodels(bool msg, bool bih) {
vector<extentity *> &ents = entities::getents();
vector<int> mapmodels;
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
if(e.type==ET_MAPMODEL && e.attr2 >= 0 && mapmodels.find(e.attr2) < 0) mapmodels.add(e.attr2);
}
-
- loopv(mapmodels)
- {
+ loopv(mapmodels) {
loadprogress = float(i+1)/mapmodels.length();
int mmindex = mapmodels[i];
mapmodelinfo *mmi = getmminfo(mmindex);
if(!mmi) { if(msg) conoutf(CON_WARN, "could not find map model: %d", mmindex); }
else if(mmi->name[0] && !loadmodel(NULL, mmindex, msg)) { if(msg) conoutf(CON_WARN, "could not load model: %s", mmi->name); }
- else if(mmi->m)
- {
+ else if(mmi->m) {
if(bih) mmi->m->preloadBIH();
mmi->m->preloadmeshes();
}
loadprogress = 0;
}
-bool modelloaded(const char *name)
-{
+bool modelloaded(const char *name) {
return models.find(name, NULL) != NULL;
}
-model *loadmodel(const char *name, int i, bool msg)
-{
- if(!name)
- {
+model *loadmodel(const char *name, int i, bool msg) {
+ if(!name) {
if(!mapmodels.inrange(i)) return NULL;
mapmodelinfo &mmi = mapmodels[i];
if(mmi.m) return mmi.m;
model **mm = models.access(name);
model *m;
if(mm) m = *mm;
- else
- {
+ else {
if(!name[0] || loadingmodel || lightmapping > 1) return NULL;
- if(msg)
- {
+ if(msg) {
defformatstring(filename, "packages/models/%s", name);
renderprogress(loadprogress, filename);
}
- loopi(NUMMODELTYPES)
- {
+ loopi(NUMMODELTYPES) {
m = modeltypes[i](name);
if(!m) continue;
loadingmodel = m;
return m;
}
-void preloadmodelshaders(bool force)
-{
+void preloadmodelshaders() {
if(initing) return;
- enumerate(models, model *, m, m->preloadshaders(force));
+ enumerate(models, model *, m, m->preloadshaders());
}
-void clear_mdls()
-{
+void clear_mdls() {
enumerate(models, model *, m, delete m);
}
-void cleanupmodels()
-{
+void cleanupmodels() {
enumerate(models, model *, m, m->cleanup());
}
-void clearmodel(char *name)
-{
+void clearmodel(char *name) {
model **m = models.access(name);
if(!m) { conoutf(CON_WARN, "model %s is not loaded", name); return; }
loopv(mapmodels) if(mapmodels[i].m==*m) mapmodels[i].m = NULL;
COMMAND(clearmodel, "s");
-bool modeloccluded(const vec ¢er, float radius)
-{
+bool modeloccluded(const vec ¢er, float radius) {
ivec bbmin(vec(center).sub(radius)), bbmax(ivec(center).add(radius+1));
return bboccluded(bbmin, bbmax);
}
VAR(showboundingbox, 0, 0, 2);
-void render2dbox(vec &o, float x, float y, float z)
-{
+void render2dbox(vec &o, float x, float y, float z) {
gle::begin(GL_LINE_LOOP);
gle::attribf(o.x, o.y, o.z);
gle::attribf(o.x, o.y, o.z+z);
xtraverts += gle::end();
}
-void render3dbox(vec &o, float tofloor, float toceil, float xradius, float yradius)
-{
+void render3dbox(vec &o, float tofloor, float toceil, float xradius, float yradius) {
if(yradius<=0) yradius = xradius;
vec c = o;
c.sub(vec(xradius, yradius, tofloor));
render2dbox(c, 0, -ysz, h);
}
-void renderellipse(vec &o, float xradius, float yradius, float yaw)
-{
+void renderellipse(vec &o, float xradius, float yradius, float yaw) {
gle::colorf(0.5f, 0.5f, 0.5f);
gle::defvertex();
gle::begin(GL_LINE_LOOP);
- loopi(15)
- {
+ loopi(15) {
const vec2 &sc = sincos360[i*(360/15)];
gle::attrib(vec(xradius*sc.x, yradius*sc.y, 0).rotate_around_z((yaw+90)*RAD).add(o));
}
xtraverts += gle::end();
}
-struct batchedmodel
-{
+struct batchedmodel {
vec pos, color, dir;
int anim;
float yaw, pitch, transparent;
int attached;
occludequery *query;
};
-struct modelbatch
-{
+struct modelbatch {
model *m;
int flags;
vector<batchedmodel> batched;
static int numbatches = -1;
static occludequery *modelquery = NULL;
-void startmodelbatches()
-{
+void startmodelbatches() {
numbatches = 0;
modelattached.setsize(0);
}
-modelbatch &addbatchedmodel(model *m)
-{
+modelbatch &addbatchedmodel(model *m) {
modelbatch *b = NULL;
if(m->batch>=0 && m->batch<numbatches && batches[m->batch]->m==m) b = batches[m->batch];
- else
- {
- if(numbatches<batches.length())
- {
+ else {
+ if(numbatches<batches.length()) {
b = batches[numbatches];
b->batched.setsize(0);
}
return *b;
}
-void renderbatchedmodel(model *m, batchedmodel &b)
-{
+void renderbatchedmodel(model *m, batchedmodel &b) {
modelattach *a = NULL;
if(b.attached>=0) a = &modelattached[b.attached];
-
int anim = b.anim;
- if(shadowmapping)
- {
+ if(shadowmapping) {
anim |= ANIM_NOSKIN;
GLOBALPARAMF(shadowintensity, b.transparent);
}
- else
- {
+ else {
if(b.flags&MDL_FULLBRIGHT) anim |= ANIM_FULLBRIGHT;
if(b.flags&MDL_GHOST) anim |= ANIM_GHOST;
}
-
m->render(anim, b.basetime, b.basetime2, b.pos, b.yaw, b.pitch, b.d, a, b.color, b.dir, b.transparent);
}
-struct transparentmodel
-{
+struct transparentmodel {
model *m;
batchedmodel *batched;
float dist;
};
-static inline bool sorttransparentmodels(const transparentmodel &x, const transparentmodel &y)
-{
+static inline bool sorttransparentmodels(const transparentmodel &x, const transparentmodel &y) {
return x.dist < y.dist;
}
-void endmodelbatches()
-{
+void endmodelbatches() {
vector<transparentmodel> transparent;
- loopi(numbatches)
- {
+ loopi(numbatches) {
modelbatch &b = *batches[i];
if(b.batched.empty()) continue;
-
bool rendered = false;
occludequery *query = NULL;
- if(b.flags&MDL_GHOST)
- {
- loopvj(b.batched)
- {
+ if(b.flags&MDL_GHOST) {
+ loopvj(b.batched) {
batchedmodel &bm = b.batched[j];
if((bm.flags&(MDL_CULL_VFC|MDL_GHOST))!=MDL_GHOST || bm.query) continue;
if(!rendered) { b.m->startrender(); rendered = true; }
renderbatchedmodel(b.m, bm);
}
- if(rendered)
- {
+ if(rendered) {
b.m->endrender();
rendered = false;
}
}
- loopvj(b.batched)
- {
+ loopvj(b.batched) {
batchedmodel &bm = b.batched[j];
if(bm.flags&(MDL_CULL_VFC|MDL_GHOST)) continue;
- if(bm.query!=query)
- {
+ if(bm.query!=query) {
if(query) endquery(query);
query = bm.query;
if(query) startquery(query);
}
- if(bm.transparent < 1 && (!query || query->owner==bm.d) && !shadowmapping)
- {
+ if(bm.transparent < 1 && (!query || query->owner==bm.d) && !shadowmapping) {
transparentmodel &tm = transparent.add();
tm.m = b.m;
tm.batched = &bm;
if(query) endquery(query);
if(rendered) b.m->endrender();
}
- if(transparent.length())
- {
+ if(transparent.length()) {
transparent.sort(sorttransparentmodels);
model *lastmodel = NULL;
occludequery *query = NULL;
- loopv(transparent)
- {
+ loopv(transparent) {
transparentmodel &tm = transparent[i];
- if(lastmodel!=tm.m)
- {
+ if(lastmodel!=tm.m) {
if(lastmodel) lastmodel->endrender();
(lastmodel = tm.m)->startrender();
}
- if(query!=tm.batched->query)
- {
+ if(query!=tm.batched->query) {
if(query) endquery(query);
query = tm.batched->query;
if(query) startquery(query);
numbatches = -1;
}
-void startmodelquery(occludequery *query)
-{
+void startmodelquery(occludequery *query) {
modelquery = query;
}
-void endmodelquery()
-{
+void endmodelquery() {
int querybatches = 0;
- loopi(numbatches)
- {
+ loopi(numbatches) {
modelbatch &b = *batches[i];
if(b.batched.empty() || b.batched.last().query!=modelquery) continue;
querybatches++;
}
- if(querybatches<=1)
- {
+ if(querybatches<=1) {
if(!querybatches) modelquery->fragments = 0;
modelquery = NULL;
return;
}
int minattached = modelattached.length();
startquery(modelquery);
- loopi(numbatches)
- {
+ loopi(numbatches) {
modelbatch &b = *batches[i];
if(b.batched.empty() || b.batched.last().query!=modelquery) continue;
b.m->startrender();
- do
- {
+ do {
batchedmodel &bm = b.batched.pop();
if(bm.attached>=0) minattached = min(minattached, bm.attached);
renderbatchedmodel(b.m, bm);
VAR(maxmodelradiusdistance, 10, 200, 1000);
-static inline void enablecullmodelquery()
-{
+static inline void enablecullmodelquery() {
startbb();
}
-static inline void rendercullmodelquery(model *m, dynent *d, const vec ¢er, float radius)
-{
+static inline void rendercullmodelquery(model *m, dynent *d, const vec ¢er, float radius) {
if(fabs(camera1->o.x-center.x) < radius+1 &&
fabs(camera1->o.y-center.y) < radius+1 &&
- fabs(camera1->o.z-center.z) < radius+1)
- {
+ fabs(camera1->o.z-center.z) < radius+1) {
d->query = NULL;
return;
}
endquery(d->query);
}
-static inline void disablecullmodelquery()
-{
+static inline void disablecullmodelquery() {
endbb();
}
-static inline int cullmodel(model *m, const vec ¢er, float radius, int flags, dynent *d = NULL, bool shadow = false)
-{
+static inline int cullmodel(model *m, const vec ¢er, float radius, int flags, dynent *d = NULL, bool shadow = false) {
if(flags&MDL_CULL_DIST && center.dist(camera1->o)/radius>maxmodelradiusdistance) return MDL_CULL_DIST;
- if(flags&MDL_CULL_VFC)
- {
+ if(flags&MDL_CULL_VFC) {
if(shadowmapping && !isshadowmapcaster(center, radius)) return MDL_CULL_VFC;
}
- if(shadowmapping)
- {
- if(d)
- {
+ if(shadowmapping) {
+ if(d) {
if(flags&MDL_CULL_OCCLUDED && d->occluded>=OCCLUDE_PARENT) return MDL_CULL_OCCLUDED;
if(flags&MDL_CULL_QUERY && d->occluded+1>=OCCLUDE_BB && d->query && d->query->owner==d && checkquery(d->query)) return MDL_CULL_QUERY;
}
if(!addshadowmapcaster(center, radius, radius)) return MDL_CULL_VFC;
}
- else if(flags&MDL_CULL_OCCLUDED && modeloccluded(center, radius))
- {
+ else if(flags&MDL_CULL_OCCLUDED && modeloccluded(center, radius)) {
if(d) d->occluded = OCCLUDE_PARENT;
return MDL_CULL_OCCLUDED;
}
- else if(flags&MDL_CULL_QUERY && d->query && d->query->owner==d && checkquery(d->query))
- {
+ else if(flags&MDL_CULL_QUERY && d->query && d->query->owner==d && checkquery(d->query)) {
if(d->occluded<OCCLUDE_BB) d->occluded++;
return MDL_CULL_QUERY;
}
return 0;
}
-void rendermodel(entitylight *light, const char *mdl, int anim, const vec &o, float yaw, float pitch, int flags, dynent *d, modelattach *a, int basetime, int basetime2, float trans)
-{
+void rendermodel(entitylight *light, const char *mdl, int anim, const vec &o, float yaw, float pitch, int flags, dynent *d, modelattach *a, int basetime, int basetime2, float trans) {
if(shadowmapping && !(flags&(MDL_SHADOW|MDL_DYNSHADOW))) return;
model *m = loadmodel(mdl);
if(!m) return;
vec center(0, 0, 0), bbradius(0, 0, 0);
float radius = 0;
bool shadow = !shadowmap && (flags&(MDL_SHADOW|MDL_DYNSHADOW));
-
- if(flags&(MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED|MDL_CULL_QUERY|MDL_SHADOW|MDL_DYNSHADOW))
- {
- if(flags&MDL_CULL_QUERY)
- {
+ if(flags&(MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED|MDL_CULL_QUERY|MDL_SHADOW|MDL_DYNSHADOW)) {
+ if(flags&MDL_CULL_QUERY) {
if(!oqfrags || !oqdynent || !d) flags &= ~MDL_CULL_QUERY;
}
-
m->boundbox(center, bbradius);
radius = bbradius.magnitude();
- if(d && d->ragdoll)
- {
+ if(d && d->ragdoll) {
radius = max(radius, d->ragdoll->radius);
center = d->ragdoll->center;
}
- else
- {
+ else {
center.rotate_around_z(yaw*RAD);
center.add(o);
}
-
int culled = cullmodel(m, center, radius, flags, d, shadow);
- if(culled)
- {
- if(culled&(MDL_CULL_OCCLUDED|MDL_CULL_QUERY) && flags&MDL_CULL_QUERY)
- {
+ if(culled) {
+ if(culled&(MDL_CULL_OCCLUDED|MDL_CULL_QUERY) && flags&MDL_CULL_QUERY) {
enablecullmodelquery();
rendercullmodelquery(m, d, center, radius);
disablecullmodelquery();
}
return;
}
-
if(shadowmapping) flags &= ~MDL_CULL_QUERY;
}
-
if(flags&MDL_NORENDER) anim |= ANIM_NORENDER;
- else if(showboundingbox && !shadowmapping && editmode)
- {
+ else if(showboundingbox && !shadowmapping && editmode) {
notextureshader->set();
- if(d && showboundingbox==1)
- {
+ if(d && showboundingbox==1) {
render3dbox(d->o, d->eyeheight, d->aboveeye, d->radius);
renderellipse(d->o, d->xradius, d->yradius, d->yaw);
}
- else
- {
+ else {
vec center, radius;
if(showboundingbox==1) m->collisionbox(center, radius);
else m->boundbox(center, radius);
render3dbox(center, radius.z, radius.z, radius.x, radius.y);
}
}
-
vec lightcolor(1, 1, 1), lightdir(0, 0, 1);
- if(!shadowmapping)
- {
+ if(!shadowmapping) {
vec pos = o;
- if(d)
- {
+ if(d) {
d->occluded = OCCLUDE_NOTHING;
if(!light) light = &d->light;
- if(flags&MDL_LIGHT && light->millis!=lastmillis)
- {
- if(d->ragdoll)
- {
+ if(flags&MDL_LIGHT && light->millis!=lastmillis) {
+ if(d->ragdoll) {
pos = d->ragdoll->center;
pos.z += radius/2;
}
light->millis = lastmillis;
}
}
- else if(flags&MDL_LIGHT)
- {
- if(!light)
- {
+ else if(flags&MDL_LIGHT) {
+ if(!light) {
lightreaching(pos, lightcolor, lightdir, (flags&MDL_LIGHT_FAST)!=0);
dynlightreaching(pos, lightcolor, lightdir, (flags&MDL_HUD)!=0);
}
- else if(light->millis!=lastmillis)
- {
+ else if(light->millis!=lastmillis) {
lightreaching(pos, light->color, light->dir, (flags&MDL_LIGHT_FAST)!=0);
dynlightreaching(pos, light->color, light->dir, (flags&MDL_HUD)!=0);
light->millis = lastmillis;
if(light) { lightcolor = light->color; lightdir = light->dir; }
if(flags&MDL_DYNLIGHT) dynlightreaching(pos, lightcolor, lightdir, (flags&MDL_HUD)!=0);
}
-
- if(a) for(int i = 0; a[i].tag; i++)
- {
+ if(a) for(int i = 0; a[i].tag; i++) {
if(a[i].name) a[i].m = loadmodel(a[i].name);
//if(a[i].m && a[i].m->type()!=m->type()) a[i].m = NULL;
}
-
- if(numbatches>=0)
- {
+ if(numbatches>=0) {
modelbatch &mb = addbatchedmodel(m);
batchedmodel &b = mb.batched.add();
b.query = modelquery;
b.basetime2 = basetime2;
b.transparent = trans;
b.flags = flags & ~(MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED);
- if(!shadow)
- {
+ if(!shadow) {
b.flags &= ~(MDL_SHADOW|MDL_DYNSHADOW);
if(flags&MDL_CULL_VFC) b.flags |= MDL_CULL_VFC;
}
if(flags&MDL_CULL_QUERY) d->query = b.query = newquery(d);
return;
}
-
m->startrender();
-
- if(shadowmapping)
- {
+ if(shadowmapping) {
anim |= ANIM_NOSKIN;
GLOBALPARAMF(shadowintensity, trans);
}
- else
- {
+ else {
if(flags&MDL_FULLBRIGHT) anim |= ANIM_FULLBRIGHT;
if(flags&MDL_GHOST) anim |= ANIM_GHOST;
}
-
- if(flags&MDL_CULL_QUERY)
- {
+ if(flags&MDL_CULL_QUERY) {
d->query = newquery(d);
if(d->query) startquery(d->query);
}
-
m->render(anim, basetime, basetime2, o, yaw, pitch, d, a, lightcolor, lightdir, trans);
-
if(flags&MDL_CULL_QUERY && d->query) endquery(d->query);
-
m->endrender();
}
-void abovemodel(vec &o, const char *mdl)
-{
+void abovemodel(vec &o, const char *mdl) {
model *m = loadmodel(mdl);
if(!m) return;
o.z += m->above();
}
-bool matchanim(const char *name, const char *pattern)
-{
- for(;; pattern++)
- {
+bool matchanim(const char *name, const char *pattern) {
+ for(;; pattern++) {
const char *s = name;
char c;
- for(;; pattern++)
- {
+ for(;; pattern++) {
c = *pattern;
if(!c || c=='|') break;
- else if(c=='*')
- {
+ else if(c=='*') {
if(!*s || iscubespace(*s)) break;
do s++; while(*s && !iscubespace(*s));
}
return false;
}
-void findanims(const char *pattern, vector<int> &anims)
-{
+void findanims(const char *pattern, vector<int> &anims) {
loopi(sizeof(animnames)/sizeof(animnames[0])) if(matchanim(animnames[i], pattern)) anims.add(i);
}
-ICOMMAND(findanims, "s", (char *name),
-{
+ICOMMAND(findanims, "s", (char *name), {
vector<int> anims;
findanims(name, anims);
vector<char> buf;
string num;
- loopv(anims)
- {
+ loopv(anims) {
formatstring(num, "%d", anims[i]);
if(i > 0) buf.add(' ');
buf.put(num, strlen(num));
result(buf.getbuf());
});
-void loadskin(const char *dir, const char *altdir, Texture *&skin, Texture *&masks) // model skin sharing
-{
+void loadskin(const char *dir, const char *altdir, Texture *&skin, Texture *&masks) { // model skin sharing {
#define ifnoload(tex, path) if((tex = textureload(path, 0, true, false))==notexture)
#define tryload(tex, prefix, cmd, name) \
- ifnoload(tex, makerelpath(mdir, name ".jpg", prefix, cmd)) \
- { \
- ifnoload(tex, makerelpath(mdir, name ".png", prefix, cmd)) \
- { \
- ifnoload(tex, makerelpath(maltdir, name ".jpg", prefix, cmd)) \
- { \
+ ifnoload(tex, makerelpath(mdir, name ".jpg", prefix, cmd)) { \
+ \
+ ifnoload(tex, makerelpath(mdir, name ".png", prefix, cmd)) { \
+ \
+ ifnoload(tex, makerelpath(maltdir, name ".jpg", prefix, cmd)) { \
+ \
ifnoload(tex, makerelpath(maltdir, name ".png", prefix, cmd)) return; \
} \
} \
}
-
defformatstring(mdir, "packages/models/%s", dir);
defformatstring(maltdir, "packages/models/%s", altdir);
masks = notexture;
VAR(testanims, 0, 0, 1);
VAR(testpitch, -90, 0, 90);
-void renderclient(dynent *d, const char *mdlname, modelattach *attachments, int hold, int attack, int attackdelay, int lastaction, int lastpain, float fade, bool ragdoll)
-{
+void renderclient(dynent *d, const char *mdlname, modelattach *attachments, int hold, int attack, int attackdelay, int lastaction, int lastpain, float fade, bool ragdoll) {
int anim = hold ? hold : ANIM_IDLE|ANIM_LOOP;
float yaw = testanims && d==player ? 0 : d->yaw+90,
pitch = testpitch && d==player ? testpitch : d->pitch;
vec o = d->feetpos();
int basetime = 0;
if(animoverride) anim = (animoverride<0 ? ANIM_ALL : animoverride)|ANIM_LOOP;
- else if(d->state==CS_DEAD)
- {
+ else if(d->state==CS_DEAD) {
anim = ANIM_DYING|ANIM_NOPITCH;
basetime = lastpain;
- if(ragdoll)
- {
- if(!d->ragdoll || d->ragdoll->millis < basetime)
- {
+ if(ragdoll) {
+ if(!d->ragdoll || d->ragdoll->millis < basetime) {
DELETEP(d->ragdoll);
anim |= ANIM_RAGDOLL;
}
}
else if(d->state==CS_EDITING || d->state==CS_SPECTATOR) anim = ANIM_EDIT|ANIM_LOOP;
else if(d->state==CS_LAGGED) anim = ANIM_LAG|ANIM_LOOP;
- else
- {
- if(lastmillis-lastpain < 300)
- {
+ else {
+ if(lastmillis-lastpain < 300) {
anim = ANIM_PAIN;
basetime = lastpain;
}
- else if(lastpain < lastaction && (attack < 0 || (d->type != ENT_AI && lastmillis-lastaction < attackdelay)))
- {
+ else if(lastpain < lastaction && (attack < 0 || (d->type != ENT_AI && lastmillis-lastaction < attackdelay))) {
anim = attack < 0 ? -attack : attack;
basetime = lastaction;
}
-
if(d->inwater && d->physstate<=PHYS_FALL) anim |= (((game::allowmove(d) && (d->move || d->strafe)) || d->vel.z+d->falling.z>0 ? ANIM_SWIM : ANIM_SINK)|ANIM_LOOP)<<ANIM_SECONDARY;
else if(d->timeinair>100) anim |= (ANIM_JUMP|ANIM_END)<<ANIM_SECONDARY;
- else if(game::allowmove(d) && (d->move || d->strafe))
- {
+ else if(game::allowmove(d) && (d->move || d->strafe)) {
if(d->move>0) anim |= (ANIM_FORWARD|ANIM_LOOP)<<ANIM_SECONDARY;
- else if(d->strafe)
- {
+ else if(d->strafe) {
if(d->move<0) anim |= ((d->strafe>0 ? ANIM_RIGHT : ANIM_LEFT)|ANIM_REVERSE|ANIM_LOOP)<<ANIM_SECONDARY;
else anim |= ((d->strafe>0 ? ANIM_LEFT : ANIM_RIGHT)|ANIM_LOOP)<<ANIM_SECONDARY;
}
else if(d->move<0) anim |= (ANIM_BACKWARD|ANIM_LOOP)<<ANIM_SECONDARY;
}
-
if((anim&ANIM_INDEX)==ANIM_IDLE && (anim>>ANIM_SECONDARY)&ANIM_INDEX) anim >>= ANIM_SECONDARY;
}
if(d->ragdoll && (!ragdoll || (anim&ANIM_INDEX)!=ANIM_DYING)) DELETEP(d->ragdoll);
rendermodel(NULL, mdlname, anim, o, yaw, pitch, flags, d, attachments, basetime, 0, fade);
}
-void setbbfrommodel(dynent *d, const char *mdl)
-{
+void setbbfrommodel(dynent *d, const char *mdl) {
model *m = loadmodel(mdl);
if(!m) return;
vec center, radius;
d->radius = d->collidetype==COLLIDE_OBB ? sqrtf(d->xradius*d->xradius + d->yradius*d->yradius) : max(d->xradius, d->yradius);
d->eyeheight = (center.z-radius.z) + radius.z*2*m->eyeheight;
d->aboveeye = radius.z*2*(1.0f-m->eyeheight);
- if (d->aboveeye + d->eyeheight <= 0.5f)
- {
+ if (d->aboveeye + d->eyeheight <= 0.5f) {
float zrad = (0.5f - (d->aboveeye + d->eyeheight)) / 2;
d->aboveeye += zrad;
d->eyeheight += zrad;
static int lastemitframe = 0, emitoffset = 0;
static bool canemit = false, regenemitters = false, canstep = false;
-static bool canemitparticles()
-{
+static bool canemitparticles() {
return canemit || emitoffset;
}
VAR(replayparticles, 0, 1, 1);
VARN(seedparticles, seedmillis, 0, 3000, 10000);
-struct particleemitter
-{
+struct particleemitter {
extentity *ent;
vec bbmin, bbmax;
vec center;
float radius;
ivec cullmin, cullmax;
int maxfade, lastemit, lastcull;
-
particleemitter(extentity *ent)
- : ent(ent), bbmin(ent->o), bbmax(ent->o), maxfade(-1), lastemit(0), lastcull(0)
- {}
-
- void finalize()
- {
+ : ent(ent), bbmin(ent->o), bbmax(ent->o), maxfade(-1), lastemit(0), lastcull(0) {
+ }
+ void finalize() {
center = vec(bbmin).add(bbmax).mul(0.5f);
radius = bbmin.dist(bbmax)/2;
cullmin = ivec(int(floor(bbmin.x)), int(floor(bbmin.y)), int(floor(bbmin.z)));
cullmax = ivec(int(ceil(bbmax.x)), int(ceil(bbmax.y)), int(ceil(bbmax.z)));
}
-
- void extendbb(const vec &o, float size = 0)
- {
+ void extendbb(const vec &o, float size = 0) {
bbmin.x = min(bbmin.x, o.x - size);
bbmin.y = min(bbmin.y, o.y - size);
bbmin.z = min(bbmin.z, o.z - size);
bbmax.y = max(bbmax.y, o.y + size);
bbmax.z = max(bbmax.z, o.z + size);
}
-
- void extendbb(float z, float size = 0)
- {
+ void extendbb(float z, float size = 0) {
bbmin.z = min(bbmin.z, z - size);
bbmax.z = max(bbmax.z, z + size);
}
static vector<particleemitter> emitters;
static particleemitter *seedemitter = NULL;
-void clearparticleemitters()
-{
+void clearparticleemitters() {
emitters.setsize(0);
regenemitters = true;
}
-void addparticleemitters()
-{
+void addparticleemitters() {
emitters.setsize(0);
const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
if(e.type != ET_PARTICLES) continue;
emitters.add(particleemitter(&e));
regenemitters = false;
}
-enum
-{
+enum {
PT_PART = 0,
PT_TAPE,
PT_TRAIL,
PT_TEXTICON,
PT_METER,
PT_METERVS,
- PT_FIREBALL,
- PT_LIGHTNING,
PT_FLARE,
-
PT_MOD = 1<<8,
PT_RND4 = 1<<9,
PT_LERP = 1<<10, // use very sparingly - order of blending issues
PT_FLIP = PT_HFLIP | PT_VFLIP | PT_ROT
};
-const char *partnames[] = { "part", "tape", "trail", "text", "texticon", "meter", "metervs", "fireball", "lightning", "flare" };
+const char *partnames[] = { "part", "tape", "trail", "text", "texticon", "meter", "metervs", "flare" };
-struct particle
-{
+struct particle {
vec o, d;
int gravity, fade, millis;
bvec color;
uchar flags;
float size;
- union
- {
+ union {
const char *text;
float val;
physent *owner;
- struct
- {
+ struct {
uchar color2[3];
uchar progress;
};
};
};
-struct partvert
-{
+struct partvert {
vec pos;
bvec4 color;
vec2 tc;
#define COLLIDERADIUS 8.0f
#define COLLIDEERROR 1.0f
-struct partrenderer
-{
+struct partrenderer {
Texture *tex;
const char *texname;
int texclamp;
uint type;
int collide;
string info;
-
partrenderer(const char *texname, int texclamp, int type, int collide = 0)
- : tex(NULL), texname(texname), texclamp(texclamp), type(type), collide(collide)
- {
+ : tex(NULL), texname(texname), texclamp(texclamp), type(type), collide(collide) {
}
partrenderer(int type, int collide = 0)
- : tex(NULL), texname(NULL), texclamp(0), type(type), collide(collide)
- {
+ : tex(NULL), texname(NULL), texclamp(0), type(type), collide(collide) {
}
- virtual ~partrenderer()
- {
+ virtual ~partrenderer() {
}
-
virtual void init(int n) { }
virtual void reset() = 0;
virtual void resettracked(physent *owner) { }
virtual void render() = 0;
virtual bool haswork() = 0;
virtual void cleanup() {}
-
- virtual void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
- {
+ virtual void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity) {
}
-
//blend = 0 => remove it
- void calc(particle *p, int &blend, int &ts, vec &o, vec &d, bool step = true)
- {
+ void calc(particle *p, int &blend, int &ts, vec &o, vec &d, bool step = true) {
o = p->o;
d = p->d;
if(type&PT_TRACK && p->owner) game::particletrack(p->owner, o, d);
- if(p->fade <= 5)
- {
+ if(p->fade <= 5) {
ts = 1;
blend = 255;
}
- else
- {
+ else {
ts = lastmillis-p->millis;
blend = max(255 - (ts<<8)/p->fade, 0);
- if(p->gravity)
- {
+ if(p->gravity) {
if(ts > p->fade) ts = p->fade;
float t = ts;
o.add(vec(d).mul(t/5000.0f));
o.z -= t*t/(2.0f * 5000.0f * p->gravity);
}
- if(collide && o.z < p->val && step)
- {
- if(collide >= 0)
- {
+ if(collide && o.z < p->val && step) {
+ if(collide >= 0) {
vec surface;
float floorz = rayfloor(vec(o.x, o.y, p->val), surface, RAY_CLIPMAT, COLLIDERADIUS);
float collidez = floorz<0 ? o.z-COLLIDERADIUS : p->val - floorz;
if(o.z >= collidez+COLLIDEERROR)
p->val = collidez+COLLIDEERROR;
- else
- {
+ else {
adddecal(collide, vec(o.x, o.y, collidez), vec(p->o).sub(o).normalize(), 2*p->size, p->color, type&PT_RND4 ? (p->flags>>5)&3 : 0);
blend = 0;
}
}
};
-struct listparticle : particle
-{
+struct listparticle : particle {
listparticle *next;
};
VARP(outlinemeters, 0, 0, 1);
-struct listrenderer : partrenderer
-{
+struct listrenderer : partrenderer {
static listparticle *parempty;
listparticle *list;
-
listrenderer(const char *texname, int texclamp, int type, int collide = 0)
- : partrenderer(texname, texclamp, type, collide), list(NULL)
- {
+ : partrenderer(texname, texclamp, type, collide), list(NULL) {
}
listrenderer(int type, int collide = 0)
- : partrenderer(type, collide), list(NULL)
- {
+ : partrenderer(type, collide), list(NULL) {
}
-
- virtual ~listrenderer()
- {
+ virtual ~listrenderer() {
}
-
- virtual void killpart(listparticle *p)
- {
+ virtual void killpart(listparticle *p) {
}
-
- void reset()
- {
+ void reset() {
if(!list) return;
listparticle *p = list;
- for(;;)
- {
+ for(;;) {
killpart(p);
if(p->next) p = p->next;
else break;
parempty = list;
list = NULL;
}
-
- void resettracked(physent *owner)
- {
+ void resettracked(physent *owner) {
if(!(type&PT_TRACK)) return;
- for(listparticle **prev = &list, *cur = list; cur; cur = *prev)
- {
- if(!owner || cur->owner==owner)
- {
+ for(listparticle **prev = &list, *cur = list; cur; cur = *prev) {
+ if(!owner || cur->owner==owner) {
*prev = cur->next;
cur->next = parempty;
parempty = cur;
else prev = &cur->next;
}
}
-
- particle *addpart(const vec &o, const vec &d, int fade, int color, float size, int gravity)
- {
- if(!parempty)
- {
+ particle *addpart(const vec &o, const vec &d, int fade, int color, float size, int gravity) {
+ if(!parempty) {
listparticle *ps = new listparticle[256];
loopi(255) ps[i].next = &ps[i+1];
ps[255].next = parempty;
p->flags = 0;
return p;
}
-
- int count()
- {
+ int count() {
int num = 0;
listparticle *lp;
for(lp = list; lp; lp = lp->next) num++;
return num;
}
-
- bool haswork()
- {
+ bool haswork() {
return (list != NULL);
}
-
virtual void startrender() = 0;
virtual void endrender() = 0;
virtual void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts) = 0;
-
- void render()
- {
+ void render() {
startrender();
- if(texname)
- {
+ if(texname) {
if(!tex) tex = textureload(texname, texclamp);
glBindTexture(GL_TEXTURE_2D, tex->id);
}
-
- for(listparticle **prev = &list, *p = list; p; p = *prev)
- {
+ for(listparticle **prev = &list, *p = list; p; p = *prev) {
vec o, d;
int blend, ts;
calc(p, blend, ts, o, d, canstep);
- if(blend > 0)
- {
+ if(blend > 0) {
renderpart(p, o, d, blend, ts);
-
- if(p->fade > 5 || !canstep)
- {
+ if(p->fade > 5 || !canstep) {
prev = &p->next;
continue;
}
killpart(p);
parempty = p;
}
-
endrender();
}
};
listparticle *listrenderer::parempty = NULL;
-struct meterrenderer : listrenderer
-{
+struct meterrenderer : listrenderer {
meterrenderer(int type)
- : listrenderer(type|PT_NOTEX|PT_LERP)
- {}
-
- void startrender()
- {
+ : listrenderer(type|PT_NOTEX|PT_LERP) {
+ }
+ void startrender() {
glDisable(GL_BLEND);
gle::defvertex();
}
-
- void endrender()
- {
+ void endrender() {
glEnable(GL_BLEND);
}
-
- void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
- {
+ void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts) {
int basetype = type&0xFF;
float scale = FONTH*p->size/80.0f, right = 8, left = p->progress/100.0f*right;
matrix4x3 m(camright, vec(camup).neg(), vec(camdir).neg(), o);
m.scale(scale);
m.translate(-right/2.0f, 0, 0);
-
- if(outlinemeters)
- {
+ if(outlinemeters) {
gle::colorf(0, 0.8f, 0);
gle::begin(GL_TRIANGLE_STRIP);
- loopk(10)
- {
+ loopk(10) {
const vec2 &sc = sincos360[k*(180/(10-1))];
float c = (0.5f + 0.1f)*sc.y, s = 0.5f - (0.5f + 0.1f)*sc.x;
gle::attrib(m.transform(vec2(-c, s)));
}
gle::end();
}
-
if(basetype==PT_METERVS) gle::colorub(p->color2[0], p->color2[1], p->color2[2]);
else gle::colorf(0, 0, 0);
gle::begin(GL_TRIANGLE_STRIP);
- loopk(10)
- {
+ loopk(10) {
const vec2 &sc = sincos360[k*(180/(10-1))];
float c = 0.5f*sc.y, s = 0.5f - 0.5f*sc.x;
gle::attrib(m.transform(vec2(left + c, s)));
gle::attrib(m.transform(vec2(right + c, s)));
}
gle::end();
-
- if(outlinemeters)
- {
+ if(outlinemeters) {
gle::colorf(0, 0.8f, 0);
gle::begin(GL_TRIANGLE_FAN);
- loopk(10)
- {
+ loopk(10) {
const vec2 &sc = sincos360[k*(180/(10-1))];
float c = (0.5f + 0.1f)*sc.y, s = 0.5f - (0.5f + 0.1f)*sc.x;
gle::attrib(m.transform(vec2(left + c, s)));
}
gle::end();
}
-
gle::color(p->color);
gle::begin(GL_TRIANGLE_STRIP);
- loopk(10)
- {
+ loopk(10) {
const vec2 &sc = sincos360[k*(180/(10-1))];
float c = 0.5f*sc.y, s = 0.5f - 0.5f*sc.x;
gle::attrib(m.transform(vec2(-c, s)));
};
static meterrenderer meters(PT_METER), metervs(PT_METERVS);
-struct textrenderer : listrenderer
-{
+struct textrenderer : listrenderer {
textrenderer(int type)
- : listrenderer(type)
- {}
-
- void startrender()
- {
+ : listrenderer(type) {
}
-
- void endrender()
- {
+ void startrender() {
}
-
- void killpart(listparticle *p)
- {
+ void endrender() {
+ }
+ void killpart(listparticle *p) {
if(p->text && p->flags&1) delete[] p->text;
}
-
- void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
- {
+ void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts) {
float scale = p->size/80.0f, xoff = -(text_width(p->text) + ((p->flags>>1)&7)*FONTH)/2, yoff = 0;
-
matrix4x3 m(camright, vec(camup).neg(), vec(camdir).neg(), o);
m.scale(scale);
m.translate(xoff, yoff, 50);
-
textmatrix = &m;
draw_text(p->text, 0, 0, p->color.r, p->color.g, p->color.b, blend);
textmatrix = NULL;
};
static textrenderer texts(PT_TEXT|PT_LERP);
-struct texticonrenderer : listrenderer
-{
+struct texticonrenderer : listrenderer {
texticonrenderer(const char *texname, int type)
- : listrenderer(texname, 3, type)
- {}
-
- void startrender()
- {
+ : listrenderer(texname, 3, type) {
+ }
+ void startrender() {
gle::defvertex();
gle::deftexcoord0();
gle::defcolor(4, GL_UNSIGNED_BYTE);
gle::begin(GL_QUADS);
}
-
- void endrender()
- {
+ void endrender() {
gle::end();
}
-
- void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
- {
+ void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts) {
float scale = p->size/80.0f, xoff = p->val, yoff = 0;
-
matrix4x3 m(camright, vec(camup).neg(), vec(camdir).neg(), o);
m.scale(scale);
m.translate(xoff, yoff, 50);
-
float tx = 0.25f*(p->flags&3), ty = 0.25f*((p->flags>>2)&3);
-
gle::attrib(m.transform(vec2(0, 0)));
gle::attrib(tx, ty);
gle::attrib(p->color, blend);
static texticonrenderer texticons("packages/hud/items.png", PT_TEXTICON|PT_LERP);
template<int T>
-static inline void modifyblend(const vec &o, int &blend)
-{
+static inline void modifyblend(const vec &o, int &blend) {
blend = min(blend<<2, 255);
}
template<>
-inline void modifyblend<PT_TAPE>(const vec &o, int &blend)
-{
+inline void modifyblend<PT_TAPE>(const vec &o, int &blend) {
}
template<int T>
-static inline void genpos(const vec &o, const vec &d, float size, int grav, int ts, partvert *vs)
-{
+static inline void genpos(const vec &o, const vec &d, float size, int grav, int ts, partvert *vs) {
vec udir = vec(camup).sub(camright).mul(size);
vec vdir = vec(camup).add(camright).mul(size);
vs[0].pos = vec(o.x + udir.x, o.y + udir.y, o.z + udir.z);
}
template<>
-inline void genpos<PT_TAPE>(const vec &o, const vec &d, float size, int ts, int grav, partvert *vs)
-{
+inline void genpos<PT_TAPE>(const vec &o, const vec &d, float size, int ts, int grav, partvert *vs) {
vec dir1 = d, dir2 = d, c;
dir1.sub(o);
dir2.sub(camera1->o);
}
template<>
-inline void genpos<PT_TRAIL>(const vec &o, const vec &d, float size, int ts, int grav, partvert *vs)
-{
+inline void genpos<PT_TRAIL>(const vec &o, const vec &d, float size, int ts, int grav, partvert *vs) {
vec e = d;
if(grav) e.z -= float(ts)/grav;
e.div(-75.0f).add(o);
}
template<int T>
-static inline void genrotpos(const vec &o, const vec &d, float size, int grav, int ts, partvert *vs, int rot)
-{
+static inline void genrotpos(const vec &o, const vec &d, float size, int grav, int ts, partvert *vs, int rot) {
genpos<T>(o, d, size, grav, ts, vs);
}
vec( 1, -1, 0).rotate_around_z(n*2*M_PI/32.0f), \
vec(-1, -1, 0).rotate_around_z(n*2*M_PI/32.0f) \
}
-static const vec rotcoeffs[32][4] =
-{
+static const vec rotcoeffs[32][4] = {
ROTCOEFFS(0), ROTCOEFFS(1), ROTCOEFFS(2), ROTCOEFFS(3), ROTCOEFFS(4), ROTCOEFFS(5), ROTCOEFFS(6), ROTCOEFFS(7),
ROTCOEFFS(8), ROTCOEFFS(9), ROTCOEFFS(10), ROTCOEFFS(11), ROTCOEFFS(12), ROTCOEFFS(13), ROTCOEFFS(14), ROTCOEFFS(15),
ROTCOEFFS(16), ROTCOEFFS(17), ROTCOEFFS(18), ROTCOEFFS(19), ROTCOEFFS(20), ROTCOEFFS(21), ROTCOEFFS(22), ROTCOEFFS(7),
};
template<>
-inline void genrotpos<PT_PART>(const vec &o, const vec &d, float size, int grav, int ts, partvert *vs, int rot)
-{
+inline void genrotpos<PT_PART>(const vec &o, const vec &d, float size, int grav, int ts, partvert *vs, int rot) {
const vec *coeffs = rotcoeffs[rot];
(vs[0].pos = o).add(vec(camright).mul(coeffs[0].x*size)).add(vec(camup).mul(coeffs[0].y*size));
(vs[1].pos = o).add(vec(camright).mul(coeffs[1].x*size)).add(vec(camup).mul(coeffs[1].y*size));
}
template<int T>
-static inline void seedpos(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int grav)
-{
- if(grav)
- {
+static inline void seedpos(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int grav) {
+ if(grav) {
vec end(o);
float t = fade;
end.add(vec(d).mul(t/5000.0f));
end.z -= t*t/(2.0f * 5000.0f * grav);
pe.extendbb(end, size);
-
float tpeak = d.z*grav;
if(tpeak > 0 && tpeak < fade) pe.extendbb(o.z + 1.5f*d.z*tpeak/5000.0f, size);
}
}
template<>
-inline void seedpos<PT_TAPE>(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int grav)
-{
+inline void seedpos<PT_TAPE>(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int grav) {
pe.extendbb(d, size);
}
template<>
-inline void seedpos<PT_TRAIL>(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int grav)
-{
+inline void seedpos<PT_TRAIL>(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int grav) {
vec e = d;
if(grav) e.z -= float(fade)/grav;
e.div(-75.0f).add(o);
}
template<int T>
-struct varenderer : partrenderer
-{
+struct varenderer : partrenderer {
partvert *verts;
particle *parts;
int maxparts, numparts, lastupdate, rndmask;
GLuint vbo;
-
varenderer(const char *texname, int type, int collide = 0)
: partrenderer(texname, 3, type, collide),
- verts(NULL), parts(NULL), maxparts(0), numparts(0), lastupdate(-1), rndmask(0), vbo(0)
- {
+ verts(NULL), parts(NULL), maxparts(0), numparts(0), lastupdate(-1), rndmask(0), vbo(0) {
if(type & PT_HFLIP) rndmask |= 0x01;
if(type & PT_VFLIP) rndmask |= 0x02;
if(type & PT_ROT) rndmask |= 0x1F<<2;
if(type & PT_RND4) rndmask |= 0x03<<5;
}
-
- void cleanup()
- {
+ void cleanup() {
if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; }
}
-
- void init(int n)
- {
+ void init(int n) {
DELETEA(parts);
DELETEA(verts);
parts = new particle[n];
numparts = 0;
lastupdate = -1;
}
-
- void reset()
- {
+ void reset() {
numparts = 0;
lastupdate = -1;
}
-
- void resettracked(physent *owner)
- {
+ void resettracked(physent *owner) {
if(!(type&PT_TRACK)) return;
- loopi(numparts)
- {
+ loopi(numparts) {
particle *p = parts+i;
if(!owner || (p->owner == owner)) p->fade = -1;
}
lastupdate = -1;
}
-
- int count()
- {
+ int count() {
return numparts;
}
-
- bool haswork()
- {
+ bool haswork() {
return (numparts > 0);
}
-
- particle *addpart(const vec &o, const vec &d, int fade, int color, float size, int gravity)
- {
+ particle *addpart(const vec &o, const vec &d, int fade, int color, float size, int gravity) {
particle *p = parts + (numparts < maxparts ? numparts++ : rnd(maxparts)); //next free slot, or kill a random kitten
p->o = o;
p->d = d;
lastupdate = -1;
return p;
}
-
- void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
- {
+ void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity) {
pe.maxfade = max(pe.maxfade, fade);
size *= SQRT2;
pe.extendbb(o, size);
-
seedpos<T>(pe, o, d, fade, size, gravity);
if(!gravity) return;
-
vec end(o);
float t = fade;
end.add(vec(d).mul(t/5000.0f));
end.z -= t*t/(2.0f * 5000.0f * gravity);
pe.extendbb(end, size);
-
float tpeak = d.z*gravity;
if(tpeak > 0 && tpeak < fade) pe.extendbb(o.z + 1.5f*d.z*tpeak/5000.0f, size);
}
-
- void genverts(particle *p, partvert *vs, bool regen)
- {
+ void genverts(particle *p, partvert *vs, bool regen) {
vec o, d;
int blend, ts;
-
calc(p, blend, ts, o, d);
if(blend <= 1 || p->fade <= 5) p->fade = -1; //mark to remove on next pass (i.e. after render)
-
modifyblend<T>(o, blend);
-
- if(regen)
- {
+ if(regen) {
p->flags &= ~0x80;
-
- #define SETTEXCOORDS(u1c, u2c, v1c, v2c, body) \
- { \
+ #define SETTEXCOORDS(u1c, u2c, v1c, v2c, body) { \
+ \
float u1 = u1c, u2 = u2c, v1 = v1c, v2 = v2c; \
body; \
vs[0].tc = vec2(u1, v1); \
vs[2].tc = vec2(u2, v2); \
vs[3].tc = vec2(u1, v2); \
}
- if(type&PT_RND4)
- {
+ if(type&PT_RND4) {
float tx = 0.5f*((p->flags>>5)&1), ty = 0.5f*((p->flags>>6)&1);
- SETTEXCOORDS(tx, tx + 0.5f, ty, ty + 0.5f,
- {
+ SETTEXCOORDS(tx, tx + 0.5f, ty, ty + 0.5f, {
if(p->flags&0x01) swap(u1, u2);
if(p->flags&0x02) swap(v1, v2);
});
}
- else if(type&PT_ICON)
- {
+ else if(type&PT_ICON) {
float tx = 0.25f*(p->flags&3), ty = 0.25f*((p->flags>>2)&3);
SETTEXCOORDS(tx, tx + 0.25f, ty, ty + 0.25f, {});
}
else SETTEXCOORDS(0, 1, 0, 1, {});
-
#define SETCOLOR(r, g, b, a) \
do { \
bvec4 col(r, g, b, a); \
}
else if(type&PT_MOD) SETMODCOLOR;
else loopi(4) vs[i].color.a = blend;
-
if(type&PT_ROT) genrotpos<T>(o, d, p->size, ts, p->gravity, vs, (p->flags>>2)&0x1F);
else genpos<T>(o, d, p->size, ts, p->gravity, vs);
}
-
- void genverts()
- {
- loopi(numparts)
- {
+ void genverts() {
+ loopi(numparts) {
particle *p = &parts[i];
partvert *vs = &verts[i*4];
- if(p->fade < 0)
- {
- do
- {
+ if(p->fade < 0) {
+ do {
--numparts;
if(numparts <= i) return;
}
else genverts(p, vs, (p->flags&0x80)!=0);
}
}
-
- void update()
- {
+ void update() {
if(lastmillis == lastupdate && vbo) return;
lastupdate = lastmillis;
-
genverts();
-
if(!vbo) glGenBuffers_(1, &vbo);
gle::bindvbo(vbo);
glBufferData_(GL_ARRAY_BUFFER, maxparts*4*sizeof(partvert), NULL, GL_STREAM_DRAW);
glBufferSubData_(GL_ARRAY_BUFFER, 0, numparts*4*sizeof(partvert), verts);
gle::clearvbo();
}
-
- void render()
- {
+ void render() {
if(!tex) tex = textureload(texname, texclamp);
glBindTexture(GL_TEXTURE_2D, tex->id);
-
gle::bindvbo(vbo);
const partvert *ptr = 0;
gle::vertexpointer(sizeof(partvert), ptr->pos.v);
gle::enabletexcoord0();
gle::enablecolor();
gle::enablequads();
-
gle::drawquads(0, numparts);
-
gle::disablequads();
gle::disablevertex();
gle::disabletexcoord0();
gle::clearvbo();
}
};
+
typedef varenderer<PT_PART> quadrenderer;
typedef varenderer<PT_TAPE> taperenderer;
typedef varenderer<PT_TRAIL> trailrenderer;
-#include "explosion.h"
-#include "lightning.h"
-
-struct softquadrenderer : quadrenderer
-{
+struct softquadrenderer : quadrenderer {
softquadrenderer(const char *texname, int type, int collide = 0)
- : quadrenderer(texname, type|PT_SOFT, collide)
- {
+ : quadrenderer(texname, type|PT_SOFT, collide) {
}
};
-static partrenderer *parts[] =
-{
+static partrenderer *parts[] = {
new quadrenderer("<grey>packages/particles/blood.png", PT_PART|PT_FLIP|PT_MOD|PT_RND4, DECAL_BLOOD), // blood spats (note: rgb is inverted)
new trailrenderer("packages/particles/base.png", PT_TRAIL|PT_LERP), // water, entity
new quadrenderer("<grey>packages/particles/smoke.png", PT_PART|PT_FLIP|PT_LERP), // smoke
new quadrenderer("<grey>packages/particles/steam.png", PT_PART|PT_FLIP), // steam
new quadrenderer("<grey>packages/particles/flames.png", PT_PART|PT_HFLIP|PT_RND4|PT_GLARE), // flame on - no flipping please, they have orientation
- new quadrenderer("packages/particles/ball1.png", PT_PART|PT_FEW|PT_GLARE), // fireball1
- new quadrenderer("packages/particles/ball2.png", PT_PART|PT_FEW|PT_GLARE), // fireball2
- new quadrenderer("packages/particles/ball3.png", PT_PART|PT_FEW|PT_GLARE), // fireball3
new taperenderer("packages/particles/flare.png", PT_TAPE|PT_GLARE), // streak
- &lightnings, // lightning
- &fireballs, // explosion fireball
- &bluefireballs, // bluish explosion fireball
new quadrenderer("packages/particles/spark.png", PT_PART|PT_FLIP|PT_GLARE), // sparks
new quadrenderer("packages/particles/base.png", PT_PART|PT_FLIP|PT_GLARE), // edit mode entities
new quadrenderer("<grey>packages/particles/snow.png", PT_PART|PT_FLIP|PT_RND4, -1), // colliding snow
VARFP(maxparticles, 10, 4000, 40000, initparticles());
VARFP(fewparticles, 10, 100, 40000, initparticles());
-void initparticles()
-{
+void initparticles() {
if(!particleshader) particleshader = lookupshaderbyname("particle");
if(!particlenotextureshader) particlenotextureshader = lookupshaderbyname("particlenotexture");
loopi(sizeof(parts)/sizeof(parts[0])) parts[i]->init(parts[i]->type&PT_FEW ? min(fewparticles, maxparticles) : maxparticles);
}
-void clearparticles()
-{
+void clearparticles() {
loopi(sizeof(parts)/sizeof(parts[0])) parts[i]->reset();
clearparticleemitters();
}
-void cleanupparticles()
-{
+void cleanupparticles() {
loopi(sizeof(parts)/sizeof(parts[0])) parts[i]->cleanup();
}
-void removetrackedparticles(physent *owner)
-{
+void removetrackedparticles(physent *owner) {
loopi(sizeof(parts)/sizeof(parts[0])) parts[i]->resettracked(owner);
}
-void renderparticles(bool mainpass)
-{
+void renderparticles(bool mainpass) {
canstep = mainpass;
-
- loopi(sizeof(parts)/sizeof(parts[0]))
- {
+ loopi(sizeof(parts)/sizeof(parts[0])) {
parts[i]->update();
}
-
bool rendered = false;
uint lastflags = PT_LERP|PT_SHADER,
flagmask = PT_LERP|PT_MOD|PT_SHADER|PT_NOTEX;
-
- loopi(sizeof(parts)/sizeof(parts[0]))
- {
+ loopi(sizeof(parts)/sizeof(parts[0])) {
partrenderer *p = parts[i];
if(!(p->type&PT_GLARE)) continue;
if(!p->haswork()) continue;
-
- if(!rendered)
- {
+ if(!rendered) {
rendered = true;
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
GLOBALPARAMF(colorscale, 1, 1, 1, 1);
}
-
uint flags = p->type & flagmask, changedbits = (flags ^ lastflags);
- if(changedbits)
- {
- if(changedbits&(PT_LERP|PT_MOD))
- {
+ if(changedbits) {
+ if(changedbits&(PT_LERP|PT_MOD)) {
if(flags&PT_LERP) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
else if(flags&PT_MOD) glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
else glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
- if(!(flags&PT_SHADER))
- {
- if(changedbits&(PT_SOFT|PT_SHADER|PT_NOTEX|PT_LERP))
- {
- if(flags&PT_SOFT)
- {
+ if(!(flags&PT_SHADER)) {
+ if(changedbits&(PT_SOFT|PT_SHADER|PT_NOTEX|PT_LERP)) {
+ if(flags&PT_SOFT) {
SETSHADER(particlesoft);
}
else if(flags&PT_NOTEX) particlenotextureshader->set();
}
p->render();
}
-
- if(rendered)
- {
+ if(rendered) {
if(lastflags&(PT_LERP|PT_MOD)) glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
static int addedparticles = 0;
-static inline particle *newparticle(const vec &o, const vec &d, int fade, int type, int color, float size, int gravity = 0)
-{
+static inline particle *newparticle(const vec &o, const vec &d, int fade, int type, int color, float size, int gravity = 0) {
static particle dummy;
- if(seedemitter)
- {
+ if(seedemitter) {
parts[type]->seedemitter(*seedemitter, o, d, fade, size, gravity);
return &dummy;
}
VARP(maxparticledistance, 256, 1024, 4096);
-static void splash(int type, int color, int radius, int num, int fade, const vec &p, float size, int gravity)
-{
+static void splash(int type, int color, int radius, int num, int fade, const vec &p, float size, int gravity) {
if(camera1->o.dist(p) > maxparticledistance && !seedemitter) return;
float collidez = parts[type]->collide ? p.z - raycube(p, vec(0, 0, -1), COLLIDERADIUS, RAY_CLIPMAT) + (parts[type]->collide >= 0 ? COLLIDEERROR : 0) : -1;
int fmin = 1;
int fmax = fade*3;
- loopi(num)
- {
+ loopi(num) {
int x, y, z;
- do
- {
+ do {
x = rnd(radius*2)-radius;
y = rnd(radius*2)-radius;
z = rnd(radius*2)-radius;
}
}
-static void regularsplash(int type, int color, int radius, int num, int fade, const vec &p, float size, int gravity, int delay = 0)
-{
+static void regularsplash(int type, int color, int radius, int num, int fade, const vec &p, float size, int gravity, int delay = 0) {
if(!canemitparticles() || (delay > 0 && rnd(delay) != 0)) return;
splash(type, color, radius, num, fade, p, size, gravity);
}
-bool canaddparticles()
-{
+bool canaddparticles() {
return !renderedgame && !shadowmapping && !minimized;
}
-void regular_particle_splash(int type, int num, int fade, const vec &p, int color, float size, int radius, int gravity, int delay)
-{
+void regular_particle_splash(int type, int num, int fade, const vec &p, int color, float size, int radius, int gravity, int delay) {
if(!canaddparticles()) return;
regularsplash(type, color, radius, num, fade, p, size, gravity, delay);
}
-void particle_splash(int type, int num, int fade, const vec &p, int color, float size, int radius, int gravity)
-{
+void particle_splash(int type, int num, int fade, const vec &p, int color, float size, int radius, int gravity) {
if(!canaddparticles()) return;
splash(type, color, radius, num, fade, p, size, gravity);
}
VARP(maxtrail, 1, 500, 10000);
-void particle_trail(int type, int fade, const vec &s, const vec &e, int color, float size, int gravity)
-{
+void particle_trail(int type, int fade, const vec &s, const vec &e, int color, float size, int gravity) {
if(!canaddparticles()) return;
vec v;
float d = e.dist(s, v);
int steps = clamp(int(d*2), 1, maxtrail);
v.div(steps);
vec p = s;
- loopi(steps)
- {
+ loopi(steps) {
p.add(v);
vec tmp = vec(float(rnd(11)-5), float(rnd(11)-5), float(rnd(11)-5));
newparticle(p, tmp, rnd(fade)+fade, type, color, size, gravity);
VARP(particletext, 0, 1, 1);
VARP(maxparticletextdistance, 0, 128, 10000);
-void particle_text(const vec &s, const char *t, int type, int fade, int color, float size, int gravity, int icons)
-{
+void particle_text(const vec &s, const char *t, int type, int fade, int color, float size, int gravity, int icons) {
if(!canaddparticles()) return;
if(!particletext || camera1->o.dist(s) > maxparticletextdistance) return;
particle *p = newparticle(s, vec(0, 0, 1), fade, type, color, size, gravity);
p->flags = icons<<1;
}
-void particle_textcopy(const vec &s, const char *t, int type, int fade, int color, float size, int gravity)
-{
+void particle_textcopy(const vec &s, const char *t, int type, int fade, int color, float size, int gravity) {
if(!canaddparticles()) return;
if(!particletext || camera1->o.dist(s) > maxparticletextdistance) return;
particle *p = newparticle(s, vec(0, 0, 1), fade, type, color, size, gravity);
p->flags = 1;
}
-void particle_texticon(const vec &s, int ix, int iy, float offset, int type, int fade, int color, float size, int gravity)
-{
+void particle_texticon(const vec &s, int ix, int iy, float offset, int type, int fade, int color, float size, int gravity) {
if(!canaddparticles()) return;
if(!particletext || camera1->o.dist(s) > maxparticletextdistance) return;
particle *p = newparticle(s, vec(0, 0, 1), fade, type, color, size, gravity);
p->val = offset;
}
-void particle_icon(const vec &s, int ix, int iy, int type, int fade, int color, float size, int gravity)
-{
+void particle_icon(const vec &s, int ix, int iy, int type, int fade, int color, float size, int gravity) {
if(!canaddparticles()) return;
particle *p = newparticle(s, vec(0, 0, 1), fade, type, color, size, gravity);
p->flags |= ix | (iy<<2);
}
-void particle_meter(const vec &s, float val, int type, int fade, int color, int color2, float size)
-{
+void particle_meter(const vec &s, float val, int type, int fade, int color, int color2, float size) {
if(!canaddparticles()) return;
particle *p = newparticle(s, vec(0, 0, 1), fade, type, color, size);
p->color2[0] = color2>>16;
p->progress = clamp(int(val*100), 0, 100);
}
-void particle_flare(const vec &p, const vec &dest, int fade, int type, int color, float size, physent *owner)
-{
+void particle_flare(const vec &p, const vec &dest, int fade, int type, int color, float size, physent *owner) {
if(!canaddparticles()) return;
newparticle(p, dest, fade, type, color, size)->owner = owner;
}
-void particle_fireball(const vec &dest, float maxsize, int type, int fade, int color, float size)
-{
- if(!canaddparticles()) return;
- float growth = maxsize - size;
- if(fade < 0) fade = int(growth*20);
- newparticle(dest, vec(0, 0, 1), fade, type, color, size)->val = growth;
-}
-
//dir = 0..6 where 0=up
-static inline vec offsetvec(vec o, int dir, int dist)
-{
+static inline vec offsetvec(vec o, int dir, int dist) {
vec v = vec(o);
v[(2+dir)%3] += (dir>2)?(-dist):dist;
return v;
}
//converts a 16bit color to 24bit
-static inline int colorfromattr(int attr)
-{
+static inline int colour_from_attribute(int attr) {
return (((attr&0xF)<<4) | ((attr&0xF0)<<8) | ((attr&0xF00)<<12)) + 0x0F0F0F;
}
* 24..26 flat plane
* +32 to inverse direction
*/
-void regularshape(int type, int radius, int color, int dir, int num, int fade, const vec &p, float size, int gravity, int vel = 200)
-{
+void regularshape(int type, int radius, int color, int dir, int num, int fade, const vec &p, float size, int gravity, int vel = 200) {
if(!canemitparticles()) return;
-
int basetype = parts[type]->type&0xFF;
- bool flare = (basetype == PT_TAPE) || (basetype == PT_LIGHTNING),
+ bool flare = (basetype == PT_TAPE),
inv = (dir&0x20)!=0, taper = (dir&0x40)!=0 && !seedemitter;
dir &= 0x1F;
- loopi(num)
- {
+ loopi(num) {
vec to, from;
- if(dir < 12)
- {
+ if(dir < 12) {
const vec2 &sc = sincos360[rnd(360)];
to[dir%3] = sc.y*radius;
to[(dir+1)%3] = sc.x*radius;
to.add(p);
if(dir < 3) //circle
from = p;
- else if(dir < 6) //cylinder
- {
+ else if(dir < 6) { //cylinder {
from = to;
to[(dir+2)%3] += radius;
from[(dir+2)%3] -= radius;
}
- else //cone
- {
+ else { //cone {
from = p;
to[(dir+2)%3] += (dir < 9)?radius:(-radius);
}
}
- else if(dir < 15) //plane
- {
+ else if(dir < 15) { //plane {
to[dir%3] = float(rnd(radius<<4)-(radius<<3))/8.0;
to[(dir+1)%3] = float(rnd(radius<<4)-(radius<<3))/8.0;
to[(dir+2)%3] = radius;
from = to;
from[(dir+2)%3] -= 2*radius;
}
- else if(dir < 21) //line
- {
- if(dir < 18)
- {
+ else if(dir < 21) { //line {
+ if(dir < 18) {
to[dir%3] = float(rnd(radius<<4)-(radius<<3))/8.0;
to[(dir+1)%3] = 0.0;
}
- else
- {
+ else {
to[dir%3] = 0.0;
to[(dir+1)%3] = float(rnd(radius<<4)-(radius<<3))/8.0;
}
from = to;
to[(dir+2)%3] += radius;
}
- else if(dir < 24) //sphere
- {
+ else if(dir < 24) { //sphere {
to = vec(2*M_PI*float(rnd(1000))/1000.0, M_PI*float(rnd(1000)-500)/1000.0).mul(radius);
to.add(p);
from = p;
}
- else if(dir < 27) // flat plane
- {
+ else if(dir < 27) { // flat plane {
to[dir%3] = float(rndscale(2*radius)-radius);
to[(dir+1)%3] = float(rndscale(2*radius)-radius);
to[(dir+2)%3] = 0.0;
from = to;
}
else from = to = p;
-
if(inv) swap(from, to);
-
- if(taper)
- {
+ if(taper) {
float dist = clamp(from.dist2(camera1->o)/maxparticledistance, 0.0f, 1.0f);
- if(dist > 0.2f)
- {
+ if(dist > 0.2f) {
dist = 1 - (dist - 0.2f)/0.8f;
if(rnd(0x10000) > dist*dist*0xFFFF) continue;
}
}
-
if(flare)
newparticle(from, to, rnd(fade*3)+1, type, color, size, gravity);
- else
- {
+ else {
vec d = vec(to).sub(from).rescale(vel); //velocity
particle *n = newparticle(from, d, rnd(fade*3)+1, type, color, size, gravity);
if(parts[type]->collide)
}
}
-static void regularflame(int type, const vec &p, float radius, float height, int color, int density = 3, float scale = 2.0f, float speed = 200.0f, float fade = 600.0f, int gravity = -15)
-{
+static void regularflame(int type, const vec &p, float radius, float height, int color, int density = 3, float scale = 2.0f, float speed = 200.0f, float fade = 600.0f, int gravity = -15) {
if(!canemitparticles()) return;
-
float size = scale * min(radius, height);
vec v(0, 0, min(1.0f, height)*speed);
- loopi(density)
- {
+ loopi(density) {
vec s = p;
s.x += rndscale(radius*2.0f)-radius;
s.y += rndscale(radius*2.0f)-radius;
}
}
-void regular_particle_flame(int type, const vec &p, float radius, float height, int color, int density, float scale, float speed, float fade, int gravity)
-{
+void regular_particle_flame(int type, const vec &p, float radius, float height, int color, int density, float scale, float speed, float fade, int gravity) {
if(!canaddparticles()) return;
regularflame(type, p, radius, height, color, density, scale, speed, fade, gravity);
}
-static void makeparticles(entity &e)
-{
- switch(e.attr1)
- {
- case 0: //fire and smoke - <radius> <height> <rgb> - 0 values default to compat for old maps
- {
- //regularsplash(PART_FIREBALL1, 0xFFC8C8, 150, 1, 40, e.o, 4.8f);
- //regularsplash(PART_SMOKE, 0x897661, 50, 1, 200, vec(e.o.x, e.o.y, e.o.z+3.0f), 2.4f, -20, 3);
+static void makeparticles(entity &e) {
+ switch(e.attr1) {
+ case 0: { //fire and smoke - <radius> <height> <rgb> - 0 values default to compat for old maps {
float radius = e.attr2 ? float(e.attr2)/100.0f : 1.5f,
height = e.attr3 ? float(e.attr3)/100.0f : radius/3;
- regularflame(PART_FLAME, e.o, radius, height, e.attr4 ? colorfromattr(e.attr4) : 0x903020, 3, 2.0f);
+ regularflame(PART_FLAME, e.o, radius, height, e.attr4 ? colour_from_attribute(e.attr4) : 0x903020, 3, 2.0f);
regularflame(PART_SMOKE, vec(e.o.x, e.o.y, e.o.z + 4.0f*min(radius, height)), radius, height, 0x303020, 1, 4.0f, 100.0f, 2000.0f, -20);
break;
}
case 1: //steam vent - <dir>
regularsplash(PART_STEAM, 0x897661, 50, 1, 200, offsetvec(e.o, e.attr2, rnd(10)), 2.4f, -20);
break;
- case 2: //water fountain - <dir>
- {
+ case 2: { //water fountain - <dir> {
int color;
- if(e.attr3 > 0) color = colorfromattr(e.attr3);
- else
- {
- int mat = clamp(-e.attr3, 0, 3);
- color = 0xff7700;
- }
+ if(e.attr3 > 0) color = colour_from_attribute(e.attr3);
+ else color = 0xff7700;
regularsplash(PART_WATER, color, 150, 4, 200, offsetvec(e.o, e.attr2, rnd(10)), 0.6f, 2);
break;
}
- case 3: //fire ball - <size> <rgb>
- newparticle(e.o, vec(0, 0, 1), 1, PART_EXPLOSION, colorfromattr(e.attr3), 4.0f)->val = 1+e.attr2;
- break;
- case 4: //tape - <dir> <length> <rgb>
- case 7: //lightning
case 9: //steam
+ case 4: //tape - <dir> <length> <rgb>
case 10: //water
- case 13: //snow
- {
- static const int typemap[] = { PART_STREAK, -1, -1, PART_LIGHTNING, -1, PART_STEAM, PART_WATER, -1, -1, PART_SNOW };
- static const float sizemap[] = { 0.28f, 0.0f, 0.0f, 1.0f, 0.0f, 2.4f, 0.60f, 0.0f, 0.0f, 0.5f };
+ case 13: { //snow {
+ static const int typemap[] = { PART_STREAK, -1, -1, -1, -1, PART_STEAM, PART_WATER, -1, -1, PART_SNOW };
+ static const float sizemap[] = { 0.28f, 0.0f, 0.0f, 0.0f, 0.0f, 2.4f, 0.60f, 0.0f, 0.0f, 0.5f };
static const int gravmap[] = { 0, 0, 0, 0, 0, -20, 2, 0, 0, 20 };
int type = typemap[e.attr1-4];
float size = sizemap[e.attr1-4];
int gravity = gravmap[e.attr1-4];
- if(e.attr2 >= 256) regularshape(type, max(1+e.attr3, 1), colorfromattr(e.attr4), e.attr2-256, 5, e.attr5 > 0 ? min(int(e.attr5), 10000) : 200, e.o, size, gravity);
- else newparticle(e.o, offsetvec(e.o, e.attr2, max(1+e.attr3, 0)), 1, type, colorfromattr(e.attr4), size, gravity);
+ if(e.attr2 >= 256) regularshape(type, max(1+e.attr3, 1), colour_from_attribute(e.attr4), e.attr2-256, 5, e.attr5 > 0 ? min(int(e.attr5), 10000) : 200, e.o, size, gravity);
+ else newparticle(e.o, offsetvec(e.o, e.attr2, max(1+e.attr3, 0)), 1, type, colour_from_attribute(e.attr4), size, gravity);
break;
}
case 5: //meter, metervs - <percent> <rgb> <rgb2>
- case 6:
- {
- particle *p = newparticle(e.o, vec(0, 0, 1), 1, e.attr1==5 ? PART_METER : PART_METER_VS, colorfromattr(e.attr3), 2.0f);
- int color2 = colorfromattr(e.attr4);
+ case 6: {
+ particle *p = newparticle(e.o, vec(0, 0, 1), 1, e.attr1==5 ? PART_METER : PART_METER_VS, colour_from_attribute(e.attr3), 2.0f);
+ int color2 = colour_from_attribute(e.attr4);
p->color2[0] = color2>>16;
p->color2[1] = (color2>>8)&0xFF;
p->color2[2] = color2&0xFF;
break;
}
case 11: // flame <radius> <height> <rgb> - radius=100, height=100 is the classic size
- regularflame(PART_FLAME, e.o, float(e.attr2)/100.0f, float(e.attr3)/100.0f, colorfromattr(e.attr4), 3, 2.0f);
+ regularflame(PART_FLAME, e.o, float(e.attr2)/100.0f, float(e.attr3)/100.0f, colour_from_attribute(e.attr4), 3, 2.0f);
break;
case 12: // smoke plume <radius> <height> <rgb>
- regularflame(PART_SMOKE, e.o, float(e.attr2)/100.0f, float(e.attr3)/100.0f, colorfromattr(e.attr4), 1, 4.0f, 100.0f, 2000.0f, -20);
+ regularflame(PART_SMOKE, e.o, float(e.attr2)/100.0f, float(e.attr3)/100.0f, colour_from_attribute(e.attr4), 1, 4.0f, 100.0f, 2000.0f, -20);
break;
case 32: //lens flares - plain/sparkle/sun/sparklesun <red> <green> <blue>
case 33:
case 35:
break;
default:
- if(!editmode)
- {
+ if(!editmode) {
defformatstring(ds, "particles %d?", e.attr1);
particle_textcopy(e.o, ds, PART_TEXT, 1, 0x6496FF, 2.0f);
}
}
}
-bool printparticles(extentity &e, char *buf, int len)
-{
- switch(e.attr1)
- {
+bool printparticles(extentity &e, char *buf, int len) {
+ switch(e.attr1) {
case 0: case 4: case 7: case 8: case 9: case 10: case 11: case 12: case 13:
nformatstring(buf, len, "%s %d %d %d 0x%.3hX %d", entities::entname(e.type), e.attr1, e.attr2, e.attr3, e.attr4, e.attr5);
return true;
return false;
}
-void seedparticles()
-{
+void seedparticles() {
renderprogress(0, "seeding particles");
addparticleemitters();
canemit = true;
- loopv(emitters)
- {
+ loopv(emitters) {
particleemitter &pe = emitters[i];
extentity &e = *pe.ent;
seedemitter = &pe;
}
}
-void updateparticles()
-{
+void updateparticles() {
if(regenemitters) addparticleemitters();
-
if(minimized) { canemit = false; return; }
-
- if(lastmillis - lastemitframe >= emitmillis)
- {
+ if(lastmillis - lastemitframe >= emitmillis) {
canemit = true;
lastemitframe = lastmillis - (lastmillis%emitmillis);
}
else canemit = false;
-
- if(!editmode || showparticles)
- {
+ if(!editmode || showparticles) {
int emitted = 0, replayed = 0;
addedparticles = 0;
- loopv(emitters)
- {
+ loopv(emitters) {
particleemitter &pe = emitters[i];
extentity &e = *pe.ent;
if(e.o.dist(camera1->o) > maxparticledistance) { pe.lastemit = lastmillis; continue; }
makeparticles(e);
emitted++;
- if(replayparticles && pe.maxfade > 5 && pe.lastcull > pe.lastemit)
- {
- for(emitoffset = max(pe.lastemit + emitmillis - lastmillis, -pe.maxfade); emitoffset < 0; emitoffset += emitmillis)
- {
+ if(replayparticles && pe.maxfade > 5 && pe.lastcull > pe.lastemit) {
+ for(emitoffset = max(pe.lastemit + emitmillis - lastmillis, -pe.maxfade); emitoffset < 0; emitoffset += emitmillis) {
makeparticles(e);
replayed++;
}
pe.lastemit = lastmillis;
}
}
- if(editmode) // show sparkly thingies for map entities in edit mode
- {
+ if(editmode) { // show sparkly thingies for map entities in edit mode {
const vector<extentity *> &ents = entities::getents();
// note: order matters in this case as particles of the same type are drawn in the reverse order that they are added
- loopv(entgroup)
- {
+ loopv(entgroup) {
entity &e = *ents[entgroup[i]];
particle_textcopy(e.o, entname(e), PART_TEXT, 1, 0xFF4B19, 2.0f);
}
- loopv(ents)
- {
+ loopv(ents) {
entity &e = *ents[i];
if(e.type==ET_EMPTY) continue;
particle_textcopy(e.o, entname(e), PART_TEXT, 1, 0x1EC850, 2.0f);
extern int rtsharefb, rtscissor, blurtile;
-struct rendertarget
-{
+struct rendertarget {
int texw, texh, vieww, viewh;
GLenum colorfmt, depthfmt;
GLuint rendertex, renderfb, renderdb, blurtex, blurfb, blurdb;
float blursigma;
float blurweights[MAXBLURRADIUS+1], bluroffsets[MAXBLURRADIUS+1];
float bluryweights[MAXBLURRADIUS+1], bluryoffsets[MAXBLURRADIUS+1];
-
float scissorx1, scissory1, scissorx2, scissory2;
#define BLURTILES 32
#define BLURTILEMASK (0xFFFFFFFFU>>(32-BLURTILES))
uint blurtiles[BLURTILES+1];
-
bool initialized;
-
- rendertarget() : texw(0), texh(0), vieww(0), viewh(0), colorfmt(GL_FALSE), depthfmt(GL_FALSE), rendertex(0), renderfb(0), renderdb(0), blurtex(0), blurfb(0), blurdb(0), blursize(0), blurysize(0), blursigma(0), initialized(false)
- {
+ rendertarget() : texw(0), texh(0), vieww(0), viewh(0), colorfmt(GL_FALSE), depthfmt(GL_FALSE), rendertex(0), renderfb(0), renderdb(0), blurtex(0), blurfb(0), blurdb(0), blursize(0), blurysize(0), blursigma(0), initialized(false) {
}
-
virtual ~rendertarget() {}
-
- virtual GLenum attachment() const
- {
+ virtual GLenum attachment() const {
return GL_COLOR_ATTACHMENT0;
}
-
- virtual const GLenum *colorformats() const
- {
+ virtual const GLenum *colorformats() const {
static const GLenum colorfmts[] = { GL_RGB, GL_RGB8, GL_FALSE };
return colorfmts;
}
-
- virtual const GLenum *depthformats() const
- {
+ virtual const GLenum *depthformats() const {
static const GLenum depthfmts[] = { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_FALSE };
return depthfmts;
}
-
virtual bool depthtest() const { return true; }
-
- void cleanup(bool fullclean = false)
- {
+ void cleanup(bool fullclean = false) {
if(renderfb) { glDeleteFramebuffers_(1, &renderfb); renderfb = 0; }
if(renderdb) { glDeleteRenderbuffers_(1, &renderdb); renderdb = 0; }
if(rendertex) { glDeleteTextures(1, &rendertex); rendertex = 0; }
texw = texh = 0;
cleanupblur();
-
if(fullclean) colorfmt = depthfmt = GL_FALSE;
}
-
- void cleanupblur()
- {
+ void cleanupblur() {
if(blurfb) { glDeleteFramebuffers_(1, &blurfb); blurfb = 0; }
if(blurtex) { glDeleteTextures(1, &blurtex); blurtex = 0; }
if(blurdb) { glDeleteRenderbuffers_(1, &blurdb); blurdb = 0; }
blursize = blurysize = 0;
blursigma = 0.0f;
}
-
- void setupblur()
- {
+ void setupblur() {
if(!blurtex) glGenTextures(1, &blurtex);
createtexture(blurtex, texw, texh, NULL, 3, 1, colorfmt);
-
if(!swaptexs() || rtsharefb) return;
if(!blurfb) glGenFramebuffers_(1, &blurfb);
glBindFramebuffer_(GL_FRAMEBUFFER, blurfb);
glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, blurtex, 0);
- if(depthtest())
- {
+ if(depthtest()) {
if(!blurdb) glGenRenderbuffers_(1, &blurdb);
glGenRenderbuffers_(1, &blurdb);
glBindRenderbuffer_(GL_RENDERBUFFER, blurdb);
}
glBindFramebuffer_(GL_FRAMEBUFFER, 0);
}
-
- void setup(int w, int h)
- {
+ void setup(int w, int h) {
if(!renderfb) glGenFramebuffers_(1, &renderfb);
glBindFramebuffer_(GL_FRAMEBUFFER, renderfb);
if(!rendertex) glGenTextures(1, &rendertex);
-
GLenum attach = attachment();
- if(attach == GL_DEPTH_ATTACHMENT)
- {
+ if(attach == GL_DEPTH_ATTACHMENT) {
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
-
const GLenum *colorfmts = colorformats();
int find = 0;
- do
- {
+ do {
createtexture(rendertex, w, h, NULL, 3, filter() ? 1 : 0, colorfmt ? colorfmt : colorfmts[find]);
glFramebufferTexture2D_(GL_FRAMEBUFFER, attach, GL_TEXTURE_2D, rendertex, 0);
if(glCheckFramebufferStatus_(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_COMPLETE) break;
}
while(!colorfmt && colorfmts[++find]);
if(!colorfmt) colorfmt = colorfmts[find];
-
- if(attach != GL_DEPTH_ATTACHMENT && depthtest())
- {
+ if(attach != GL_DEPTH_ATTACHMENT && depthtest()) {
if(!renderdb) { glGenRenderbuffers_(1, &renderdb); depthfmt = GL_FALSE; }
if(!depthfmt) glBindRenderbuffer_(GL_RENDERBUFFER, renderdb);
const GLenum *depthfmts = depthformats();
find = 0;
- do
- {
+ do {
if(!depthfmt) glRenderbufferStorage_(GL_RENDERBUFFER, depthfmts[find], w, h);
glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderdb);
if(glCheckFramebufferStatus_(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_COMPLETE) break;
while(!depthfmt && depthfmts[++find]);
if(!depthfmt) depthfmt = depthfmts[find];
}
-
glBindFramebuffer_(GL_FRAMEBUFFER, 0);
-
texw = w;
texh = h;
initialized = false;
}
-
- bool addblurtiles(float x1, float y1, float x2, float y2, float blurmargin = 0)
- {
+ bool addblurtiles(float x1, float y1, float x2, float y2, float blurmargin = 0) {
if(x1 >= 1 || y1 >= 1 || x2 <= -1 || y2 <= -1) return false;
-
scissorx1 = min(scissorx1, max(x1, -1.0f));
scissory1 = min(scissory1, max(y1, -1.0f));
scissorx2 = max(scissorx2, min(x2, 1.0f));
scissory2 = max(scissory2, min(y2, 1.0f));
-
float blurerror = 2.0f*float(2*blursize + blurmargin);
int tx1 = max(0, min(BLURTILES - 1, int((x1-blurerror/vieww + 1)/2 * BLURTILES))),
ty1 = max(0, min(BLURTILES - 1, int((y1-blurerror/viewh + 1)/2 * BLURTILES))),
tx2 = max(0, min(BLURTILES - 1, int((x2+blurerror/vieww + 1)/2 * BLURTILES))),
ty2 = max(0, min(BLURTILES - 1, int((y2+blurerror/viewh + 1)/2 * BLURTILES)));
-
uint mask = (BLURTILEMASK>>(BLURTILES - (tx2+1))) & (BLURTILEMASK<<tx1);
for(int y = ty1; y <= ty2; y++) blurtiles[y] |= mask;
return true;
}
-
- bool checkblurtiles(float x1, float y1, float x2, float y2, float blurmargin = 0)
- {
+ bool checkblurtiles(float x1, float y1, float x2, float y2, float blurmargin = 0) {
float blurerror = 2.0f*float(2*blursize + blurmargin);
if(x2+blurerror/vieww < scissorx1 || y2+blurerror/viewh < scissory1 ||
x1-blurerror/vieww > scissorx2 || y1-blurerror/viewh > scissory2)
return false;
-
if(!blurtile) return true;
-
int tx1 = max(0, min(BLURTILES - 1, int((x1 + 1)/2 * BLURTILES))),
ty1 = max(0, min(BLURTILES - 1, int((y1 + 1)/2 * BLURTILES))),
tx2 = max(0, min(BLURTILES - 1, int((x2 + 1)/2 * BLURTILES))),
ty2 = max(0, min(BLURTILES - 1, int((y2 + 1)/2 * BLURTILES)));
-
uint mask = (BLURTILEMASK>>(BLURTILES - (tx2+1))) & (BLURTILEMASK<<tx1);
for(int y = ty1; y <= ty2; y++) if(blurtiles[y] & mask) return true;
-
return false;
}
-
- void rendertiles()
- {
+ void rendertiles() {
float wscale = vieww/float(texw), hscale = viewh/float(texh);
- if(blurtile && scissorx1 < scissorx2 && scissory1 < scissory2)
- {
+ if(blurtile && scissorx1 < scissorx2 && scissory1 < scissory2) {
uint tiles[sizeof(blurtiles)/sizeof(uint)];
memcpy(tiles, blurtiles, sizeof(blurtiles));
-
LOCALPARAMF(screentexcoord0, wscale*0.5f, hscale*0.5f, wscale*0.5f, hscale*0.5f);
gle::defvertex(2);
gle::begin(GL_QUADS);
float tsz = 1.0f/BLURTILES;
- loop(y, BLURTILES+1)
- {
+ loop(y, BLURTILES+1) {
uint mask = tiles[y];
int x = 0;
- while(mask)
- {
+ while(mask) {
while(!(mask&0xFF)) { mask >>= 8; x += 8; }
while(!(mask&1)) { mask >>= 1; x++; }
int xstart = x;
}
gle::end();
}
- else
- {
+ else {
screenquad(wscale, hscale);
}
}
-
- void blur(int wantsblursize, float wantsblursigma, int wantsblurysize, int x, int y, int w, int h, bool scissor)
- {
+ void blur(int wantsblursize, float wantsblursigma, int wantsblurysize, int x, int y, int w, int h, bool scissor) {
if(!blurtex) setupblur();
- if(blursize!=wantsblursize || blurysize != wantsblurysize || (wantsblursize && blursigma!=wantsblursigma))
- {
+ if(blursize!=wantsblursize || blurysize != wantsblurysize || (wantsblursize && blursigma!=wantsblursigma)) {
setupblurkernel(wantsblursize, wantsblursigma, blurweights, bluroffsets);
if(wantsblurysize != wantsblursize) setupblurkernel(wantsblurysize, wantsblursigma, bluryweights, bluryoffsets);
blursize = wantsblursize;
blursigma = wantsblursigma;
blurysize = wantsblurysize;
}
-
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
-
- if(scissor)
- {
+ if(scissor) {
glScissor(x, y, w, h);
glEnable(GL_SCISSOR_TEST);
}
-
- loopi(2)
- {
+ loopi(2) {
if(i && blurysize != blursize) setblurshader(i, texh, blurysize, bluryweights, bluryoffsets);
else setblurshader(i, i ? texh : texw, blursize, blurweights, bluroffsets);
-
if(!swaptexs() || rtsharefb) glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, i ? rendertex : blurtex, 0);
else glBindFramebuffer_(GL_FRAMEBUFFER, i ? renderfb : blurfb);
glBindTexture(GL_TEXTURE_2D, i ? blurtex : rendertex);
-
rendertiles();
}
-
if(scissor) glDisable(GL_SCISSOR_TEST);
-
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
-
virtual bool swaptexs() const { return false; }
-
virtual bool dorender() { return true; }
-
virtual bool shouldrender() { return true; }
-
- virtual void doblur(int blursize, float blursigma, int blurysize)
- {
+ virtual void doblur(int blursize, float blursigma, int blurysize) {
int sx, sy, sw, sh;
bool scissoring = rtscissor && scissorblur(sx, sy, sw, sh) && sw > 0 && sh > 0;
if(!scissoring) { sx = sy = 0; sw = vieww; sh = viewh; }
blur(blursize, blursigma, blurysize, sx, sy, sw, sh, scissoring);
}
-
- virtual bool scissorrender(int &x, int &y, int &w, int &h)
- {
- if(scissorx1 >= scissorx2 || scissory1 >= scissory2)
- {
- if(vieww < texw || viewh < texh)
- {
+ virtual bool scissorrender(int &x, int &y, int &w, int &h) {
+ if(scissorx1 >= scissorx2 || scissory1 >= scissory2) {
+ if(vieww < texw || viewh < texh) {
x = y = 0;
w = vieww;
h = viewh;
h = min(int(ceil((scissory2+1)/2*viewh)) + 2*blursize, viewh) - y;
return true;
}
-
- virtual bool scissorblur(int &x, int &y, int &w, int &h)
- {
- if(scissorx1 >= scissorx2 || scissory1 >= scissory2)
- {
- if(vieww < texw || viewh < texh)
- {
+ virtual bool scissorblur(int &x, int &y, int &w, int &h) {
+ if(scissorx1 >= scissorx2 || scissory1 >= scissory2) {
+ if(vieww < texw || viewh < texh) {
x = y = 0;
w = vieww;
h = viewh;
h = min(int(ceil((scissory2+1)/2*viewh)), viewh) - y;
return true;
}
-
virtual void doclear() {}
-
virtual bool screenrect() const { return false; }
virtual bool filter() const { return true; }
-
- void render(int w, int h, int blursize = 0, float blursigma = 0, int blurysize = 0)
- {
+ void render(int w, int h, int blursize = 0, float blursigma = 0, int blurysize = 0) {
w = min(w, hwtexsize);
h = min(h, hwtexsize);
- if(screenrect())
- {
+ if(screenrect()) {
if(w > screenw) w = screenw;
if(h > screenh) h = screenh;
}
vieww = w;
viewh = h;
if(w!=texw || h!=texh || (swaptexs() && !rtsharefb ? !blurfb : blurfb)) cleanup();
-
- if(!filter())
- {
+ if(!filter()) {
if(blurtex) cleanupblur();
blursize = blurysize = 0;
}
-
if(!rendertex) setup(w, h);
-
scissorx2 = scissory2 = -1;
scissorx1 = scissory1 = 1;
memset(blurtiles, 0, sizeof(blurtiles));
-
if(!shouldrender()) return;
-
if(blursize && !blurtex) setupblur();
- if(swaptexs() && blursize)
- {
+ if(swaptexs() && blursize) {
swap(rendertex, blurtex);
- if(!rtsharefb)
- {
+ if(!rtsharefb) {
swap(renderfb, blurfb);
swap(renderdb, blurdb);
}
if(swaptexs() && blursize && rtsharefb)
glFramebufferTexture2D_(GL_FRAMEBUFFER, attachment(), GL_TEXTURE_2D, rendertex, 0);
glViewport(0, 0, vieww, viewh);
-
doclear();
-
int sx, sy, sw, sh;
bool scissoring = rtscissor && scissorrender(sx, sy, sw, sh) && sw > 0 && sh > 0;
- if(scissoring)
- {
+ if(scissoring) {
glScissor(sx, sy, sw, sh);
glEnable(GL_SCISSOR_TEST);
}
- else
- {
+ else {
sx = sy = 0;
sw = vieww;
sh = viewh;
}
-
if(!depthtest()) glDisable(GL_DEPTH_TEST);
-
bool succeeded = dorender();
-
if(!depthtest()) glEnable(GL_DEPTH_TEST);
-
if(scissoring) glDisable(GL_SCISSOR_TEST);
-
- if(succeeded)
- {
+ if(succeeded) {
initialized = true;
-
if(blursize) doblur(blursize, blursigma, blurysize ? blurysize : blursize);
}
-
glBindFramebuffer_(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screenw, screenh);
}
font *curfont = NULL;
int curfonttex = 0;
-void newfont(char *name, char *tex, int *defaultw, int *defaulth)
-{
+void newfont(char *name, char *tex, int *defaultw, int *defaulth) {
font *f = &fonts[name];
if(!f->name) f->name = newstring(name);
f->texs.shrink(0);
f->defaultw = *defaultw;
f->defaulth = *defaulth;
f->scale = f->defaulth;
-
fontdef = f;
fontdeftex = 0;
}
-void fontoffset(char *c)
-{
+void fontoffset(char *c) {
if(!fontdef) return;
-
fontdef->charoffset = c[0];
}
-void fontscale(int *scale)
-{
+void fontscale(int *scale) {
if(!fontdef) return;
-
fontdef->scale = *scale > 0 ? *scale : fontdef->defaulth;
}
-void fonttex(char *s)
-{
+void fonttex(char *s) {
if(!fontdef) return;
-
Texture *t = textureload(s);
loopv(fontdef->texs) if(fontdef->texs[i] == t) { fontdeftex = i; return; }
fontdeftex = fontdef->texs.length();
fontdef->texs.add(t);
}
-void fontchar(int *x, int *y, int *w, int *h, int *offsetx, int *offsety, int *advance)
-{
+void fontchar(int *x, int *y, int *w, int *h, int *offsetx, int *offsety, int *advance) {
if(!fontdef) return;
-
font::charinfo &c = fontdef->chars.add();
c.x = *x;
c.y = *y;
c.tex = fontdeftex;
}
-void fontskip(int *n)
-{
+void fontskip(int *n) {
if(!fontdef) return;
- loopi(max(*n, 1))
- {
+ loopi(max(*n, 1)) {
font::charinfo &c = fontdef->chars.add();
c.x = c.y = c.w = c.h = c.offsetx = c.offsety = c.advance = c.tex = 0;
}
COMMAND(fontchar, "iiiiiii");
COMMAND(fontskip, "i");
-void fontalias(const char *dst, const char *src)
-{
+void fontalias(const char *dst, const char *src) {
font *s = fonts.access(src);
if(!s) return;
font *d = &fonts[dst];
d->defaultw = s->defaultw;
d->defaulth = s->defaulth;
d->scale = s->scale;
-
fontdef = d;
fontdeftex = d->texs.length()-1;
}
COMMAND(fontalias, "ss");
-bool setfont(const char *name)
-{
+bool setfont(const char *name) {
font *f = fonts.access(name);
if(!f) return false;
curfont = f;
static vector<font *> fontstack;
-void pushfont()
-{
+void pushfont() {
fontstack.add(curfont);
}
-bool popfont()
-{
+bool popfont() {
if(fontstack.empty()) return false;
curfont = fontstack.pop();
return true;
}
-void gettextres(int &w, int &h)
-{
- if(w < MINRESW || h < MINRESH)
- {
- if(MINRESW > w*MINRESH/h)
- {
+void gettextres(int &w, int &h) {
+ if(w < MINRESW || h < MINRESH) {
+ if(MINRESW > w*MINRESH/h) {
h = h*MINRESW/w;
w = MINRESW;
}
- else
- {
+ else {
w = w*MINRESH/h;
h = MINRESH;
}
}
}
-float text_widthf(const char *str)
-{
+float text_widthf(const char *str) {
float width, height;
text_boundsf(str, width, height);
return width;
#define FONTTAB (4*FONTW)
#define TEXTTAB(x) ((int((x)/FONTTAB)+1.0f)*FONTTAB)
-void tabify(const char *str, int *numtabs)
-{
+void tabify(const char *str, int *numtabs) {
int tw = max(*numtabs, 0)*FONTTAB-1, tabs = 0;
for(float w = text_widthf(str); w <= tw; w = TEXTTAB(w)) ++tabs;
int len = strlen(str);
COMMAND(tabify, "si");
-void draw_textf(const char *fstr, int left, int top, ...)
-{
+void draw_textf(const char *fstr, int left, int top, ...) {
defvformatstring(str, top, fstr);
draw_text(str, left, top);
}
const matrix4x3 *textmatrix = NULL;
-static float draw_char(Texture *&tex, int c, float x, float y, float scale)
-{
+static float draw_char(Texture *&tex, int c, float x, float y, float scale) {
font::charinfo &info = curfont->chars[c-curfont->charoffset];
- if(tex != curfont->texs[info.tex])
- {
+ if(tex != curfont->texs[info.tex]) {
xtraverts += gle::end();
tex = curfont->texs[info.tex];
glBindTexture(GL_TEXTURE_2D, tex->id);
}
-
float x1 = x + scale*info.offsetx,
y1 = y + scale*info.offsety,
x2 = x + scale*(info.offsetx + info.w),
ty1 = info.y / float(tex->ys),
tx2 = (info.x + info.w) / float(tex->xs),
ty2 = (info.y + info.h) / float(tex->ys);
-
- if(textmatrix)
- {
+ if(textmatrix) {
gle::attrib(textmatrix->transform(vec2(x1, y1))); gle::attribf(tx1, ty1);
gle::attrib(textmatrix->transform(vec2(x2, y1))); gle::attribf(tx2, ty1);
gle::attrib(textmatrix->transform(vec2(x2, y2))); gle::attribf(tx2, ty2);
gle::attrib(textmatrix->transform(vec2(x1, y2))); gle::attribf(tx1, ty2);
}
- else
- {
+ else {
gle::attribf(x1, y1); gle::attribf(tx1, ty1);
gle::attribf(x2, y1); gle::attribf(tx2, ty1);
gle::attribf(x2, y2); gle::attribf(tx2, ty2);
gle::attribf(x1, y2); gle::attribf(tx1, ty2);
}
-
return scale*info.advance;
}
//stack[sp] is current color index
-static void text_color(char c, char *stack, int size, int &sp, bvec color, int a)
-{
- if(c=='s') // save color
- {
+static void text_color(char c, char *stack, int size, int &sp, bvec color, int a) {
+ if(c=='s') { // save color {
c = stack[sp];
if(sp<size-1) stack[++sp] = c;
- }
- else
- {
+ } else {
xtraverts += gle::end();
if(c=='r') { if(sp > 0) --sp; c = stack[sp]; } // restore color
else stack[sp] = c;
- switch(c)
- {
+ switch(c) {
case '0': color = bvec( 64, 255, 128); break; // green: player talk
case '1': color = bvec( 96, 160, 255); break; // blue: "echo" command
case '2': color = bvec(255, 192, 64); break; // yellow: gameplay messages
#define TEXTSKELETON \
float y = 0, x = 0, scale = curfont->scale/float(curfont->defaulth);\
int i;\
- for(i = 0; str[i]; i++)\
- {\
+ for(i = 0; str[i]; i++) { \
TEXTINDEX(i)\
int c = uchar(str[i]);\
- if(c=='\t') { x = TEXTTAB(x); TEXTWHITE(i) }\
- else if(c==' ') { x += scale*curfont->defaultw; TEXTWHITE(i) }\
+ if(c=='\t') { x = TEXTTAB(x); TEXTWHITE(i) }\
+ else if(c==' ') { x += scale*curfont->defaultw; TEXTWHITE(i) }\
else if(c=='\n') { TEXTLINE(i) x = 0; y += FONTH; }\
else if(c=='\f') { if(str[i+1]) { i++; TEXTCOLOR(i) }}\
- else if(curfont->chars.inrange(c-curfont->charoffset))\
- {\
+ else if(curfont->chars.inrange(c-curfont->charoffset)) {\
float cw = scale*curfont->chars[c-curfont->charoffset].advance;\
if(cw <= 0) continue;\
- if(maxwidth != -1)\
- {\
+ if(maxwidth != -1) {\
int j = i;\
float w = cw;\
- for(; str[i+1]; i++)\
- {\
+ for(; str[i+1]; i++) {\
+ \
int c = uchar(str[i+1]);\
if(c=='\f') { if(str[i+2]) i++; continue; }\
if(i-j > 16) break;\
if(x + w > maxwidth && j!=0) { TEXTLINE(j-1) x = 0; y += FONTH; }\
TEXTWORD\
}\
- else\
- { TEXTCHAR(i) }\
+ else{ \
+ TEXTCHAR(i) }\
}\
}
//all the chars are guaranteed to be either drawable or color commands
#define TEXTWORDSKELETON \
- for(; j <= i; j++)\
- {\
+ for(; j <= i; j++){ \
+ \
TEXTINDEX(j)\
int c = uchar(str[j]);\
if(c=='\f') { if(str[j+1]) { j++; TEXTCOLOR(j) }}\
#define TEXTEND(cursor) if(cursor >= i) { do { TEXTINDEX(cursor); } while(0); }
-int text_visible(const char *str, float hitx, float hity, int maxwidth)
-{
+int text_visible(const char *str, float hitx, float hity, int maxwidth) {
#define TEXTINDEX(idx)
#define TEXTWHITE(idx) if(y+FONTH > hity && x >= hitx) return idx;
#define TEXTLINE(idx) if(y+FONTH > hity) return idx;
}
//inverse of text_visible
-void text_posf(const char *str, int cursor, float &cx, float &cy, int maxwidth)
-{
+void text_posf(const char *str, int cursor, float &cx, float &cy, int maxwidth) {
#define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; break; }
#define TEXTWHITE(idx)
#define TEXTLINE(idx)
#undef TEXTWORD
}
-void text_boundsf(const char *str, float &width, float &height, int maxwidth)
-{
+void text_boundsf(const char *str, float &width, float &height, int maxwidth) {
#define TEXTINDEX(idx)
#define TEXTWHITE(idx)
#define TEXTLINE(idx) if(x > width) width = x;
#undef TEXTWORD
}
-void draw_text(const char *str, int left, int top, int r, int g, int b, int a, int cursor, int maxwidth)
-{
+void draw_text(const char *str, int left, int top, int r, int g, int b, int a, int cursor, int maxwidth) {
#define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; }
#define TEXTWHITE(idx)
#define TEXTLINE(idx)
TEXTSKELETON
TEXTEND(cursor)
xtraverts += gle::end();
- if(cursor >= 0 && (totalmillis/250)&1)
- {
+ if(cursor >= 0 && (totalmillis/250)&1) {
gle::color(color, a);
if(maxwidth != -1 && cx >= maxwidth) { cx = 0; cy += FONTH; }
draw_char(tex, '_', left+cx, top+cy, scale);
#undef TEXTWORD
}
-void reloadfonts()
-{
+void reloadfonts() {
enumerate(fonts, font, f,
loopv(f.texs) if(!reloadtexture(*f.texs[i])) fatal("failed to reload font texture");
);
#include "engine.h"
-static inline void drawtris(GLsizei numindices, const GLvoid *indices, ushort minvert, ushort maxvert)
-{
+static inline void drawtris(GLsizei numindices, const GLvoid *indices, ushort minvert, ushort maxvert) {
glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices);
glde++;
}
-static inline void drawvatris(vtxarray *va, GLsizei numindices, const GLvoid *indices)
-{
+static inline void drawvatris(vtxarray *va, GLsizei numindices, const GLvoid *indices) {
drawtris(numindices, indices, va->minvert, va->maxvert);
}
vtxarray *visibleva;
-int isvisiblesphere(float rad, const vec &cv)
-{
+int isvisiblesphere(float rad, const vec &cv) {
int v = VFC_FULL_VISIBLE;
float dist;
-
- loopi(5)
- {
+ loopi(5) {
dist = vfcP[i].dist(cv);
if(dist < -rad) return VFC_NOT_VISIBLE;
if(dist < rad) v = VFC_PART_VISIBLE;
}
-
if(dist > -rad) v = VFC_PART_VISIBLE;
-
return v;
}
-static inline int ishiddencube(const ivec &o, int size)
-{
+static inline int ishiddencube(const ivec &o, int size) {
loopi(5) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true;
return false;
}
-int isvisiblecube(const ivec &o, int size)
-{
+int isvisiblecube(const ivec &o, int size) {
int v = VFC_FULL_VISIBLE;
float dist;
-
- loopi(5)
- {
+ loopi(5) {
dist = o.dist(vfcP[i]);
if(dist < -vfcDfar[i]*size) return VFC_NOT_VISIBLE;
if(dist < -vfcDnear[i]*size) v = VFC_PART_VISIBLE;
}
-
if(dist > -vfcDfar[4]*size) v = VFC_PART_VISIBLE;
-
return v;
}
-float vadist(vtxarray *va, const vec &p)
-{
+float vadist(vtxarray *va, const vec &p) {
return p.dist_to_bb(va->bbmin, va->bbmax);
}
static vtxarray *vasort[VASORTSIZE];
-void addvisibleva(vtxarray *va)
-{
+void addvisibleva(vtxarray *va) {
float dist = vadist(va, camera1->o);
va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
-
int hash = clamp(int(dist*VASORTSIZE/worldsize), 0, VASORTSIZE-1);
vtxarray **prev = &vasort[hash], *cur = vasort[hash];
-
- while(cur && va->distance >= cur->distance)
- {
+ while(cur && va->distance >= cur->distance) {
prev = &cur->next;
cur = cur->next;
}
-
va->next = *prev;
*prev = va;
}
-void sortvisiblevas()
-{
+void sortvisiblevas() {
visibleva = NULL;
vtxarray **last = &visibleva;
- loopi(VASORTSIZE) if(vasort[i])
- {
+ loopi(VASORTSIZE) if(vasort[i]) {
vtxarray *va = vasort[i];
*last = va;
while(va->next) va = va->next;
}
}
-void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false)
-{
- loopv(vas)
- {
+void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false) {
+ loopv(vas) {
vtxarray &v = *vas[i];
int prevvfc = resetocclude ? (int) VFC_NOT_VISIBLE : (int) v.curvfc;
v.curvfc = isvisiblecube(v.o, v.size);
- if(v.curvfc!=VFC_NOT_VISIBLE)
- {
+ if(v.curvfc!=VFC_NOT_VISIBLE) {
addvisibleva(&v);
if(v.children.length()) findvisiblevas(v.children, prevvfc>=VFC_NOT_VISIBLE);
- if(prevvfc>=VFC_NOT_VISIBLE)
- {
+ if(prevvfc>=VFC_NOT_VISIBLE) {
v.occluded = !v.texs ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
v.query = NULL;
}
}
}
-void calcvfcD()
-{
- loopi(5)
- {
+void calcvfcD() {
+ loopi(5) {
plane &p = vfcP[i];
vfcDnear[i] = vfcDfar[i] = 0;
loopk(3) if(p[k] > 0) vfcDfar[i] += p[k];
}
}
-void setvfcP(float z, const vec &bbmin, const vec &bbmax)
-{
+void setvfcP(float z, const vec &bbmin, const vec &bbmax) {
vec4 px = camprojmatrix.rowx(), py = camprojmatrix.rowy(), pz = camprojmatrix.rowz(), pw = camprojmatrix.roww();
vfcP[0] = plane(vec4(pw).mul(-bbmin.x).add(px)).normalize(); // left plane
vfcP[1] = plane(vec4(pw).mul(bbmax.x).sub(px)).normalize(); // right plane
vfcP[3] = plane(vec4(pw).mul(bbmax.y).sub(py)).normalize(); // top plane
vfcP[4] = plane(vec4(pw).add(pz)).normalize(); // near/far planes
if(z >= 0) loopi(5) vfcP[i].reflectz(z);
-
calcvfcD();
}
plane oldvfcP[5];
-void savevfcP()
-{
+void savevfcP() {
memcpy(oldvfcP, vfcP, sizeof(vfcP));
}
-void restorevfcP()
-{
+void restorevfcP() {
memcpy(vfcP, oldvfcP, sizeof(vfcP));
calcvfcD();
}
-void visiblecubes(bool cull)
-{
+void visiblecubes(bool cull) {
memclear(vasort);
-
- if(cull)
- {
+ if(cull) {
setvfcP();
findvisiblevas(varoot);
sortvisiblevas();
}
- else
- {
+ else {
memclear(vfcP);
memclear(vfcDnear);
memclear(vfcDfar);
visibleva = NULL;
- loopv(valist)
- {
+ loopv(valist) {
vtxarray *va = valist[i];
va->distance = 0;
va->curvfc = VFC_FULL_VISIBLE;
}
}
-static inline bool insideva(const vtxarray *va, const vec &v, int margin = 2)
-{
+static inline bool insideva(const vtxarray *va, const vec &v, int margin = 2) {
int size = va->size + margin;
return v.x>=va->o.x-margin && v.y>=va->o.y-margin && v.z>=va->o.z-margin &&
v.x<=va->o.x+size && v.y<=va->o.y+size && v.z<=va->o.z+size;
#define MAXQUERY 2048
#define MAXQUERYFRAMES 2
-struct queryframe
-{
+struct queryframe {
int cur, max;
occludequery queries[MAXQUERY];
-
queryframe() : cur(0), max(0) {}
-
void flip() { loopi(cur) queries[i].owner = NULL; cur = 0; }
-
- occludequery *newquery(void *owner)
- {
- if(cur >= max)
- {
+ occludequery *newquery(void *owner) {
+ if(cur >= max) {
if(max >= MAXQUERY) return NULL;
glGenQueries_(1, &queries[max++].id);
}
query->fragments = -1;
return query;
}
-
void reset() { loopi(max) queries[i].owner = NULL; }
-
- void cleanup()
- {
- loopi(max)
- {
+ void cleanup() {
+ loopi(max) {
glDeleteQueries_(1, &queries[i].id);
queries[i].owner = NULL;
}
static queryframe queryframes[MAXQUERYFRAMES];
static uint flipquery = 0;
-int getnumqueries()
-{
+int getnumqueries() {
return queryframes[flipquery].cur;
}
-void flipqueries()
-{
+void flipqueries() {
flipquery = (flipquery + 1) % MAXQUERYFRAMES;
queryframes[flipquery].flip();
}
-occludequery *newquery(void *owner)
-{
+occludequery *newquery(void *owner) {
return queryframes[flipquery].newquery(owner);
}
-void resetqueries()
-{
+void resetqueries() {
loopi(MAXQUERYFRAMES) queryframes[i].reset();
}
-void clearqueries()
-{
+void clearqueries() {
loopi(MAXQUERYFRAMES) queryframes[i].cleanup();
}
VAR(oqfrags, 0, 8, 64);
VAR(oqwait, 0, 1, 1);
-void startquery(occludequery *query)
-{
+void startquery(occludequery *query) {
glBeginQuery_(GL_SAMPLES_PASSED, query->id);
}
-void endquery(occludequery *query)
-{
+void endquery(occludequery *query) {
glEndQuery_(GL_SAMPLES_PASSED);
}
-bool checkquery(occludequery *query, bool nowait)
-{
+bool checkquery(occludequery *query, bool nowait) {
GLuint fragments;
if(query->fragments >= 0) fragments = query->fragments;
- else
- {
- if(nowait || !oqwait)
- {
+ else {
+ if(nowait || !oqwait) {
GLint avail;
glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail);
if(!avail) return false;
static GLuint bbvbo = 0, bbebo = 0;
-static void setupbb()
-{
- if(!bbvbo)
- {
+static void setupbb() {
+ if(!bbvbo) {
glGenBuffers_(1, &bbvbo);
gle::bindvbo(bbvbo);
vec verts[8];
glBufferData_(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
gle::clearvbo();
}
- if(!bbebo)
- {
+ if(!bbebo) {
glGenBuffers_(1, &bbebo);
gle::bindebo(bbebo);
GLushort tris[3*2*6];
}
}
-static void cleanupbb()
-{
+static void cleanupbb() {
if(bbvbo) { glDeleteBuffers_(1, &bbvbo); bbvbo = 0; }
if(bbebo) { glDeleteBuffers_(1, &bbebo); bbebo = 0; }
}
-void startbb(bool mask)
-{
+void startbb(bool mask) {
setupbb();
gle::bindvbo(bbvbo);
gle::bindebo(bbebo);
gle::vertexpointer(sizeof(vec), (const vec *)0);
gle::enablevertex();
SETSHADER(bbquery);
- if(mask)
- {
+ if(mask) {
glDepthMask(GL_FALSE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
}
}
-void endbb(bool mask)
-{
+void endbb(bool mask) {
gle::disablevertex();
gle::clearvbo();
gle::clearebo();
- if(mask)
- {
+ if(mask) {
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
}
-void drawbb(const ivec &bo, const ivec &br)
-{
+void drawbb(const ivec &bo, const ivec &br) {
LOCALPARAMF(bborigin, bo.x, bo.y, bo.z);
LOCALPARAMF(bbsize, br.x, br.y, br.z);
glDrawRangeElements_(GL_TRIANGLES, 0, 8-1, 3*2*6, GL_UNSIGNED_SHORT, (ushort *)0);
static octaentities *visiblemms, **lastvisiblemms;
-static inline bool insideoe(const octaentities *oe, const vec &v, int margin = 1)
-{
+static inline bool insideoe(const octaentities *oe, const vec &v, int margin = 1) {
return v.x>=oe->bbmin.x-margin && v.y>=oe->bbmin.y-margin && v.z>=oe->bbmin.z-margin &&
v.x<=oe->bbmax.x+margin && v.y<=oe->bbmax.y+margin && v.z<=oe->bbmax.z+margin;
}
-void findvisiblemms(const vector<extentity *> &ents, bool doquery)
-{
+void findvisiblemms(const vector<extentity *> &ents, bool doquery) {
visiblemms = NULL;
lastvisiblemms = &visiblemms;
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(va->mapmodels.empty() || va->occluded >= OCCLUDE_BB) continue;
- loopv(va->mapmodels)
- {
+ loopv(va->mapmodels) {
octaentities *oe = va->mapmodels[i];
-
bool occluded = doquery && oe->query && oe->query->owner == oe && checkquery(oe->query);
- if(occluded)
- {
+ if(occluded) {
oe->distance = -1;
-
oe->next = NULL;
*lastvisiblemms = oe;
lastvisiblemms = &oe->next;
}
- else
- {
+ else {
int visible = 0;
- loopv(oe->mapmodels)
- {
+ loopv(oe->mapmodels) {
extentity &e = *ents[oe->mapmodels[i]];
if(e.flags&EF_NOVIS) continue;
e.flags |= EF_RENDER;
++visible;
}
if(!visible) continue;
-
oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size));
-
octaentities **prev = &visiblemms, *cur = visiblemms;
- while(cur && cur->distance >= 0 && oe->distance > cur->distance)
- {
+ while(cur && cur->distance >= 0 && oe->distance > cur->distance) {
prev = &cur->next;
cur = cur->next;
}
-
if(*prev == NULL) lastvisiblemms = &oe->next;
oe->next = *prev;
*prev = oe;
VAR(oqmm, 0, 4, 8);
-void rendermapmodel(extentity &e)
-{
+void rendermapmodel(extentity &e) {
int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0;
mapmodelinfo *mmi = getmminfo(e.attr2);
if(mmi) rendermodel(&e.light, mmi->name, anim, e.o, e.attr1, 0, MDL_CULL_VFC | MDL_CULL_DIST | MDL_DYNLIGHT, NULL, NULL, basetime);
}
-void rendermapmodels()
-{
+void rendermapmodels() {
static int skipoq = 0;
bool doquery = !drawtex && oqfrags && oqmm;
const vector<extentity *> &ents = entities::getents();
findvisiblemms(ents, doquery);
-
startmodelbatches();
- for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0)
- {
+ for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0) {
bool rendered = false;
- loopv(oe->mapmodels)
- {
+ loopv(oe->mapmodels) {
extentity &e = *ents[oe->mapmodels[i]];
if(!(e.flags&EF_RENDER)) continue;
- if(!rendered)
- {
+ if(!rendered) {
rendered = true;
oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? newquery(oe) : NULL;
if(oe->query) startmodelquery(oe->query);
if(rendered && oe->query) endmodelquery();
}
endmodelbatches();
-
bool queried = true;
- for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0)
- {
+ for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0) {
oe->query = doquery && !insideoe(oe, camera1->o) ? newquery(oe) : NULL;
if(!oe->query) continue;
- if(queried)
- {
+ if(queried) {
startbb();
queried = false;
}
drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin));
endquery(oe->query);
}
- if(!queried)
- {
+ if(!queried) {
endbb();
}
}
-static inline bool bbinsideva(const ivec &bo, const ivec &br, vtxarray *va)
-{
+static inline bool bbinsideva(const ivec &bo, const ivec &br, vtxarray *va) {
return bo.x >= va->bbmin.x && bo.y >= va->bbmin.y && bo.z >= va->bbmin.z &&
br.x <= va->bbmax.x && br.y <= va->bbmax.y && br.z <= va->bbmax.z;
}
-static inline bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size)
-{
- loopoctabox(o, size, bo, br)
- {
+static inline bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size) {
+ loopoctabox(o, size, bo, br) {
ivec co(i, o, size);
- if(c[i].ext && c[i].ext->va)
- {
+ if(c[i].ext && c[i].ext->va) {
vtxarray *va = c[i].ext->va;
if(va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va)) continue;
}
return true;
}
-bool bboccluded(const ivec &bo, const ivec &br)
-{
+bool bboccluded(const ivec &bo, const ivec &br) {
int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z);
if(diff&~((1<<worldscale)-1)) return false;
int scale = worldscale-1;
if(diff&(1<<scale)) return bboccluded(bo, br, worldroot, ivec(0, 0, 0), 1<<scale);
cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)];
- if(c->ext && c->ext->va)
- {
+ if(c->ext && c->ext->va) {
vtxarray *va = c->ext->va;
if(va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va)) return true;
}
scale--;
- while(c->children && !(diff&(1<<scale)))
- {
+ while(c->children && !(diff&(1<<scale))) {
c = &c->children[octastep(bo.x, bo.y, bo.z, scale)];
- if(c->ext && c->ext->va)
- {
+ if(c->ext && c->ext->va) {
vtxarray *va = c->ext->va;
if(va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va)) return true;
}
HVARP(outlinecolour, 0, 0, 0xFFFFFF);
VAR(dtoutline, 0, 1, 1);
-void renderoutline()
-{
+void renderoutline() {
notextureshader->set();
-
gle::enablevertex();
-
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gle::color(vec::hexcolor(outlinecolour));
-
enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
-
if(!dtoutline) glDisable(GL_DEPTH_TEST);
-
vtxarray *prev = NULL;
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(va->occluded >= OCCLUDE_BB) continue;
if(!va->alphaback && !va->alphafront && (!va->texs || va->occluded >= OCCLUDE_GEOM)) continue;
-
- if(!prev || va->vbuf != prev->vbuf)
- {
+ if(!prev || va->vbuf != prev->vbuf) {
gle::bindvbo(va->vbuf);
gle::bindebo(va->ebuf);
const vertex *ptr = 0;
gle::vertexpointer(sizeof(vertex), ptr->pos.v);
}
-
- if(va->texs && va->occluded < OCCLUDE_GEOM)
- {
+ if(va->texs && va->occluded < OCCLUDE_GEOM) {
drawvatris(va, 3*va->tris, va->edata);
xtravertsva += va->verts;
}
- if(va->alphatris)
- {
+ if(va->alphatris) {
drawvatris(va, 3*va->alphatris, &va->edata[3*(va->tris + va->blendtris)]);
xtravertsva += 3*va->alphatris;
}
-
prev = va;
}
-
if(!dtoutline) glEnable(GL_DEPTH_TEST);
-
disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
-
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
gle::clearvbo();
gle::clearebo();
gle::disablevertex();
}
-void rendershadowmapreceivers()
-{
+void rendershadowmapreceivers() {
SETSHADER(shadowmapreceiver);
-
gle::enablevertex();
-
glCullFace(GL_FRONT);
glDepthMask(GL_FALSE);
glDepthFunc(GL_GREATER);
-
extern int ati_minmax_bug;
if(!ati_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
-
glEnable(GL_BLEND);
glBlendEquation_(GL_MAX);
glBlendFunc(GL_ONE, GL_ONE);
-
vtxarray *prev = NULL;
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->texs || !isshadowmapreceiver(va)) continue;
-
- if(!prev || va->vbuf != prev->vbuf)
- {
+ if(!prev || va->vbuf != prev->vbuf) {
gle::bindvbo(va->vbuf);
gle::bindebo(va->ebuf);
const vertex *ptr = 0;
gle::vertexpointer(sizeof(vertex), ptr->pos.v);
}
-
drawvatris(va, 3*va->tris, va->edata);
xtravertsva += va->verts;
-
prev = va;
}
-
glDisable(GL_BLEND);
glBlendEquation_(GL_FUNC_ADD);
-
glCullFace(GL_BACK);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
-
if(!ati_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
gle::clearvbo();
gle::clearebo();
gle::disablevertex();
VAR(zpass, 0, 1, 1);
VAR(envpass, 0, 1, 1);
-struct renderstate
-{
+struct renderstate {
bool colormask, depthmask, blending;
int alphaing;
GLuint vbuf;
int texgendim;
int visibledynlights;
uint dynlightmask;
-
- renderstate() : colormask(true), depthmask(true), blending(false), alphaing(0), vbuf(0), vattribs(false), vquery(false), colorscale(1, 1, 1), alphascale(0), slot(NULL), texgenslot(NULL), vslot(NULL), texgenvslot(NULL), texgenscroll(0, 0), texgendim(-1), visibledynlights(0), dynlightmask(0)
- {
+ renderstate() : colormask(true), depthmask(true), blending(false), alphaing(0), vbuf(0), vattribs(false), vquery(false), colorscale(1, 1, 1), alphascale(0), slot(NULL), texgenslot(NULL), vslot(NULL), texgenvslot(NULL), texgenscroll(0, 0), texgendim(-1), visibledynlights(0), dynlightmask(0) {
loopk(8) textures[k] = 0;
}
};
-static inline void disablevbuf(renderstate &cur)
-{
+static inline void disablevbuf(renderstate &cur) {
gle::clearvbo();
gle::clearebo();
cur.vbuf = 0;
}
-static inline void enablevquery(renderstate &cur)
-{
+static inline void enablevquery(renderstate &cur) {
if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); }
startbb(false);
cur.vquery = true;
}
-static inline void disablevquery(renderstate &cur)
-{
+static inline void disablevquery(renderstate &cur) {
endbb(false);
cur.vquery = false;
}
-static void renderquery(renderstate &cur, occludequery *query, vtxarray *va, bool full = true)
-{
+static void renderquery(renderstate &cur, occludequery *query, vtxarray *va, bool full = true) {
if(!cur.vquery) enablevquery(cur);
-
startquery(query);
-
if(full) drawbb(ivec(va->bbmin).sub(1), ivec(va->bbmax).sub(va->bbmin).add(2));
else drawbb(va->geommin, ivec(va->geommax).sub(va->geommin));
-
endquery(query);
}
-enum
-{
+enum {
RENDERPASS_LIGHTMAP = 0,
RENDERPASS_Z,
RENDERPASS_LIGHTMAP_BLEND
};
-struct geombatch
-{
+struct geombatch {
const elementset &es;
VSlot &vslot;
ushort *edata;
vtxarray *va;
int next, batch;
-
geombatch(const elementset &es, ushort *edata, vtxarray *va)
: es(es), vslot(lookupvslot(es.texture)), edata(edata), va(va),
- next(-1), batch(-1)
- {}
-
- int compare(const geombatch &b) const
- {
+ next(-1), batch(-1) {
+ }
+ int compare(const geombatch &b) const {
if(va->vbuf < b.va->vbuf) return -1;
if(va->vbuf > b.va->vbuf) return 1;
if(va->dynlightmask < b.va->dynlightmask) return -1;
static vector<geombatch> geombatches;
static int firstbatch = -1, numbatches = 0;
-static void mergetexs(renderstate &cur, vtxarray *va, elementset *texs = NULL, int numtexs = 0, ushort *edata = NULL)
-{
- if(!texs)
- {
+static void mergetexs(renderstate &cur, vtxarray *va, elementset *texs = NULL, int numtexs = 0, ushort *edata = NULL) {
+ if(!texs) {
texs = va->eslist;
numtexs = va->texs;
edata = va->edata;
- if(cur.alphaing)
- {
+ if(cur.alphaing) {
texs += va->texs + va->blends;
edata += 3*(va->tris + va->blendtris);
numtexs = va->alphaback;
if(cur.alphaing > 1) numtexs += va->alphafront;
}
}
-
- if(firstbatch < 0)
- {
+ if(firstbatch < 0) {
firstbatch = geombatches.length();
numbatches = numtexs;
- loopi(numtexs-1)
- {
+ loopi(numtexs-1) {
geombatches.add(geombatch(texs[i], edata, va)).next = i+1;
edata += texs[i].length[1];
}
geombatches.add(geombatch(texs[numtexs-1], edata, va));
return;
}
-
int prevbatch = -1, curbatch = firstbatch, curtex = 0;
- do
- {
+ do {
geombatch &b = geombatches.add(geombatch(texs[curtex], edata, va));
edata += texs[curtex].length[1];
int dir = -1;
- while(curbatch >= 0)
- {
+ while(curbatch >= 0) {
dir = b.compare(geombatches[curbatch]);
if(dir <= 0) break;
prevbatch = curbatch;
curbatch = geombatches[curbatch].next;
}
- if(!dir)
- {
+ if(!dir) {
int last = curbatch, next;
- for(;;)
- {
+ for(;;) {
next = geombatches[last].batch;
if(next < 0) break;
last = next;
}
- if(last==curbatch)
- {
+ if(last==curbatch) {
b.batch = curbatch;
b.next = geombatches[curbatch].next;
if(prevbatch < 0) firstbatch = geombatches.length()-1;
else geombatches[prevbatch].next = geombatches.length()-1;
curbatch = geombatches.length()-1;
}
- else
- {
+ else {
b.batch = next;
geombatches[last].batch = geombatches.length()-1;
}
}
- else
- {
+ else {
numbatches++;
b.next = curbatch;
if(prevbatch < 0) firstbatch = geombatches.length()-1;
while(++curtex < numtexs);
}
-static inline void enablevattribs(renderstate &cur, bool all = true)
-{
+static inline void enablevattribs(renderstate &cur, bool all = true) {
gle::enablevertex();
- if(all)
- {
+ if(all) {
gle::enabletexcoord0();
gle::enabletexcoord1();
gle::enablenormal();
cur.vattribs = true;
}
-static inline void disablevattribs(renderstate &cur, bool all = true)
-{
+static inline void disablevattribs(renderstate &cur, bool all = true) {
gle::disablevertex();
- if(all)
- {
+ if(all) {
gle::disabletexcoord0();
gle::disabletexcoord1();
gle::disablenormal();
cur.vattribs = false;
}
-static void changevbuf(renderstate &cur, int pass, vtxarray *va)
-{
+static void changevbuf(renderstate &cur, int pass, vtxarray *va) {
gle::bindvbo(va->vbuf);
gle::bindebo(va->ebuf);
cur.vbuf = va->vbuf;
-
vertex *vdata = (vertex *)0;
gle::vertexpointer(sizeof(vertex), vdata->pos.v);
-
- if(pass==RENDERPASS_LIGHTMAP)
- {
+ if(pass==RENDERPASS_LIGHTMAP) {
gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE);
gle::texcoord0pointer(sizeof(vertex), vdata->tc.v);
gle::texcoord1pointer(sizeof(vertex), vdata->lm.v, GL_SHORT);
}
}
-static void changebatchtmus(renderstate &cur, int pass, geombatch &b)
-{
+static void changebatchtmus(renderstate &cur, int pass, geombatch &b) {
bool changed = false;
extern bool brightengeom;
extern int fullbright;
int lmid = brightengeom && (b.es.lmid < LMID_RESERVED || (fullbright && editmode)) ? (int) LMID_BRIGHT : (int) b.es.lmid;
- if(cur.textures[1]!=lightmaptexs[lmid].id)
- {
+ if(cur.textures[1]!=lightmaptexs[lmid].id) {
glActiveTexture_(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, cur.textures[1] = lightmaptexs[lmid].id);
changed = true;
}
int tmu = 2;
- if(b.vslot.slot->shader->type&SHADER_NORMALSLMS)
- {
- if(cur.textures[tmu]!=lightmaptexs[lmid+1].id)
- {
+ if(b.vslot.slot->shader->type&SHADER_NORMALSLMS) {
+ if(cur.textures[tmu]!=lightmaptexs[lmid+1].id) {
glActiveTexture_(GL_TEXTURE0+tmu);
glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = lightmaptexs[lmid+1].id);
changed = true;
}
tmu++;
}
-
if(changed) glActiveTexture_(GL_TEXTURE0);
-
- if(cur.dynlightmask != b.va->dynlightmask)
- {
+ if(cur.dynlightmask != b.va->dynlightmask) {
cur.visibledynlights = setdynlights(b.va);
cur.dynlightmask = b.va->dynlightmask;
}
}
-static void changeslottmus(renderstate &cur, int pass, Slot &slot, VSlot &vslot)
-{
- if(pass==RENDERPASS_LIGHTMAP)
- {
+static void changeslottmus(renderstate &cur, int pass, Slot &slot, VSlot &vslot) {
+ if(pass==RENDERPASS_LIGHTMAP) {
GLuint diffusetex = slot.sts.empty() ? notexture->id : slot.sts[0].t->id;
if(cur.textures[0]!=diffusetex)
glBindTexture(GL_TEXTURE_2D, cur.textures[0] = diffusetex);
}
-
- if(cur.alphaing)
- {
+ if(cur.alphaing) {
float alpha = cur.alphaing > 1 ? vslot.alphafront : vslot.alphaback;
- if(cur.colorscale != vslot.colorscale || cur.alphascale != alpha)
- {
+ if(cur.colorscale != vslot.colorscale || cur.alphascale != alpha) {
cur.colorscale = vslot.colorscale;
cur.alphascale = alpha;
GLOBALPARAMF(colorparams, 2*alpha*vslot.colorscale.x, 2*alpha*vslot.colorscale.y, 2*alpha*vslot.colorscale.z, alpha);
}
}
- else if(cur.colorscale != vslot.colorscale)
- {
+ else if(cur.colorscale != vslot.colorscale) {
cur.colorscale = vslot.colorscale;
GLOBALPARAMF(colorparams, 2*vslot.colorscale.x, 2*vslot.colorscale.y, 2*vslot.colorscale.z, 1);
}
int tmu = 2;
if(slot.shader->type&SHADER_NORMALSLMS) tmu++;
- loopvj(slot.sts)
- {
+ loopvj(slot.sts) {
Slot::Tex &t = slot.sts[j];
if(t.type==TEX_DIFFUSE || t.combined>=0) continue;
- if(cur.textures[tmu]!=t.t->id)
- {
+ if(cur.textures[tmu]!=t.t->id) {
glActiveTexture_(GL_TEXTURE0+tmu);
glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = t.t->id);
}
if(++tmu >= 8) break;
}
glActiveTexture_(GL_TEXTURE0);
-
cur.slot = &slot;
cur.vslot = &vslot;
}
-static void changeshader(renderstate &cur, Shader *s, Slot &slot, VSlot &vslot, bool shadowed)
-{
- if(!cur.blending && !cur.alphaing)
- {
+static void changeshader(renderstate &cur, Shader *s, Slot &slot, VSlot &vslot, bool shadowed) {
+ if(!cur.blending && !cur.alphaing) {
if(shadowed) s->setvariant(cur.visibledynlights, 3, slot, vslot);
else s->setvariant(cur.visibledynlights, 2, slot, vslot);
}
else s->setvariant(cur.visibledynlights-1, 0, slot, vslot);
}
-static void changetexgen(renderstate &cur, int dim, Slot &slot, VSlot &vslot)
-{
- if(cur.texgenslot != &slot || cur.texgenvslot != &vslot)
- {
+static void changetexgen(renderstate &cur, int dim, Slot &slot, VSlot &vslot) {
+ if(cur.texgenslot != &slot || cur.texgenvslot != &vslot) {
Texture *curtex = !cur.texgenslot || cur.texgenslot->sts.empty() ? notexture : cur.texgenslot->sts[0].t,
*tex = slot.sts.empty() ? notexture : slot.sts[0].t;
if(!cur.texgenvslot || slot.sts.empty() ||
(curtex->xs != tex->xs || curtex->ys != tex->ys ||
cur.texgenvslot->rotation != vslot.rotation || cur.texgenvslot->scale != vslot.scale ||
- cur.texgenvslot->offset != vslot.offset || cur.texgenvslot->scroll != vslot.scroll))
- {
+ cur.texgenvslot->offset != vslot.offset || cur.texgenvslot->scroll != vslot.scroll)) {
const texrotation &r = texrotations[vslot.rotation];
float xs = r.flipx ? -tex->xs : tex->xs,
ys = r.flipy ? -tex->ys : tex->ys;
if(r.swapxy) swap(scroll.x, scroll.y);
scroll.x *= lastmillis*tex->xs/xs;
scroll.y *= lastmillis*tex->ys/ys;
- if(cur.texgenscroll != scroll)
- {
+ if(cur.texgenscroll != scroll) {
cur.texgenscroll = scroll;
cur.texgendim = -1;
}
cur.texgenslot = &slot;
cur.texgenvslot = &vslot;
}
-
if(cur.texgendim == dim) return;
GLOBALPARAM(texgenscroll, cur.texgenscroll);
cur.texgendim = dim;
}
-static void renderbatch(renderstate &cur, int pass, geombatch &b)
-{
+static void renderbatch(renderstate &cur, int pass, geombatch &b) {
geombatch *shadowed = NULL;
int rendered = -1;
- for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch])
- {
+ for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch]) {
ushort len = curbatch->es.length[curbatch->va->shadowed ? 0 : 1];
- if(len)
- {
- if(rendered < 0)
- {
+ if(len) {
+ if(rendered < 0) {
changeshader(cur, b.vslot.slot->shader, *b.vslot.slot, b.vslot, false);
rendered = 0;
gbatches++;
if(curbatch->es.length[1] > len && !shadowed) shadowed = curbatch;
if(curbatch->batch < 0) break;
}
- if(shadowed) for(geombatch *curbatch = shadowed;; curbatch = &geombatches[curbatch->batch])
- {
- if(curbatch->va->shadowed && curbatch->es.length[1] > curbatch->es.length[0])
- {
- if(rendered < 1)
- {
+ if(shadowed) for(geombatch *curbatch = shadowed;; curbatch = &geombatches[curbatch->batch]) {
+ if(curbatch->va->shadowed && curbatch->es.length[1] > curbatch->es.length[0]) {
+ if(rendered < 1) {
changeshader(cur, b.vslot.slot->shader, *b.vslot.slot, b.vslot, true);
rendered = 1;
gbatches++;
}
}
-static void resetbatches()
-{
+static void resetbatches() {
geombatches.setsize(0);
firstbatch = -1;
numbatches = 0;
}
-static void renderbatches(renderstate &cur, int pass)
-{
+static void renderbatches(renderstate &cur, int pass) {
cur.slot = NULL;
cur.vslot = NULL;
int curbatch = firstbatch;
- if(curbatch >= 0)
- {
- if(cur.alphaing)
- {
+ if(curbatch >= 0) {
+ if(cur.alphaing) {
if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); }
}
else if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, cur.alphaing ? GL_FALSE : GL_TRUE); }
- if(!cur.vattribs)
- {
+ if(!cur.vattribs) {
if(cur.vquery) disablevquery(cur);
enablevattribs(cur);
}
}
- while(curbatch >= 0)
- {
+ while(curbatch >= 0) {
geombatch &b = geombatches[curbatch];
curbatch = b.next;
-
if(cur.vbuf != b.va->vbuf) changevbuf(cur, pass, b.va);
- if(cur.vslot != &b.vslot)
- {
+ if(cur.vslot != &b.vslot) {
changeslottmus(cur, pass, *b.vslot.slot, b.vslot);
if(cur.texgendim != b.es.dim || (cur.texgendim <= 2 && cur.texgenvslot != &b.vslot)) changetexgen(cur, b.es.dim, *b.vslot.slot, b.vslot);
}
else if(cur.texgendim != b.es.dim) changetexgen(cur, b.es.dim, *b.vslot.slot, b.vslot);
if(pass == RENDERPASS_LIGHTMAP) changebatchtmus(cur, pass, b);
-
renderbatch(cur, pass, b);
}
-
resetbatches();
}
-void renderzpass(renderstate &cur, vtxarray *va)
-{
- if(!cur.vattribs)
- {
+void renderzpass(renderstate &cur, vtxarray *va) {
+ if(!cur.vattribs) {
if(cur.vquery) disablevquery(cur);
enablevattribs(cur, false);
}
if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
int firsttex = 0, numtris = va->tris;
ushort *edata = va->edata;
- if(cur.alphaing)
- {
+ if(cur.alphaing) {
firsttex += va->texs + va->blends;
edata += 3*(va->tris + va->blendtris);
numtris = va->alphatris;
#define startvaquery(va, flush) \
do { \
- if(va->query) \
- { \
+ if(va->query) { \
+ \
flush; \
startquery(va->query); \
} \
#define endvaquery(va, flush) \
do { \
- if(va->query) \
- { \
+ if(va->query) { \
+ \
flush; \
endquery(va->query); \
} \
VAR(batchgeom, 0, 1, 1);
-void renderva(renderstate &cur, vtxarray *va, int pass = RENDERPASS_LIGHTMAP, bool doquery = false)
-{
- switch(pass)
- {
+void renderva(renderstate &cur, vtxarray *va, int pass = RENDERPASS_LIGHTMAP, bool doquery = false) {
+ switch(pass) {
case RENDERPASS_LIGHTMAP:
if(!cur.alphaing) vverts += va->verts;
va->shadowed = false;
va->dynlightmask = 0;
- if(!drawtex && !cur.alphaing)
- {
+ if(!drawtex && !cur.alphaing) {
va->shadowed = isshadowmapreceiver(va);
calcdynlightmask(va);
}
if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
else if(!batchgeom && geombatches.length()) renderbatches(cur, pass);
break;
-
- case RENDERPASS_LIGHTMAP_BLEND:
- {
+ case RENDERPASS_LIGHTMAP_BLEND: {
if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); });
mergetexs(cur, va, &va->eslist[va->texs], va->blends, va->edata + 3*va->tris);
if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); });
else if(!batchgeom && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
break;
}
-
case RENDERPASS_Z:
if(doquery) startvaquery(va, );
renderzpass(cur, va);
}
}
-void cleanupva()
-{
+void cleanupva() {
clearvas(worldroot);
clearqueries();
cleanupbb();
}
-void setupgeom(renderstate &cur)
-{
+void setupgeom(renderstate &cur) {
GLOBALPARAMF(colorparams, 2, 2, 2, 1);
GLOBALPARAM(camera, camera1->o);
GLOBALPARAMF(ambient, ambientcolor.x/255.0f, ambientcolor.y/255.0f, ambientcolor.z/255.0f);
GLOBALPARAMF(millis, lastmillis/1000.0f);
-
glActiveTexture_(GL_TEXTURE0);
}
-void cleanupgeom(renderstate &cur)
-{
+void cleanupgeom(renderstate &cur) {
if(cur.vattribs) disablevattribs(cur);
if(cur.vbuf) disablevbuf(cur);
}
VAR(oqgeom, 0, 1, 1);
-void rendergeom(void)
-{
+void rendergeom(void) {
bool mainpass = !drawtex,
doOQ = oqfrags && oqgeom && mainpass,
doZP = doOQ && zpass,
doSM = shadowmap && !drawtex;
renderstate cur;
- if(mainpass)
- {
+ if(mainpass) {
flipqueries();
vtris = vverts = 0;
}
- if(!doZP)
- {
+ if(!doZP) {
if(shadowmap && mainpass) rendershadowmap();
setupgeom(cur);
if(doSM) pushshadowmap();
}
-
finddynlights();
-
resetbatches();
-
int blends = 0;
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->texs) continue;
- if(doOQ && (zpass || va->distance > oqdist) && !insideva(va, camera1->o))
- {
- if(va->parent && va->parent->occluded >= OCCLUDE_BB)
- {
+ if(doOQ && (zpass || va->distance > oqdist) && !insideva(va, camera1->o)) {
+ if(va->parent && va->parent->occluded >= OCCLUDE_BB) {
va->query = NULL;
va->occluded = OCCLUDE_PARENT;
continue;
va->query = newquery(va);
if((!va->query && zpass) || !va->occluded)
va->occluded = OCCLUDE_NOTHING;
- if(va->occluded >= OCCLUDE_GEOM)
- {
- if(va->query)
- {
+ if(va->occluded >= OCCLUDE_GEOM) {
+ if(va->query) {
if(!zpass && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
if(cur.vattribs) disablevattribs(cur, !doZP);
if(cur.vbuf) disablevbuf(cur);
continue;
}
}
- else
- {
+ else {
va->query = NULL;
va->occluded = OCCLUDE_NOTHING;
}
-
if(!doZP) blends += va->blends;
renderva(cur, va, doZP ? RENDERPASS_Z : RENDERPASS_LIGHTMAP, doOQ);
}
-
if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
-
if(cur.vquery) disablevquery(cur);
if(cur.vattribs) disablevattribs(cur, !doZP);
if(cur.vbuf) disablevbuf(cur);
-
if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
-
bool multipassing = false;
-
- if(doZP)
- {
+ if(doZP) {
glFlush();
-
if(shadowmap && mainpass) rendershadowmap();
setupgeom(cur);
if(doSM) pushshadowmap();
-
if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); }
cur.texgendim = -1;
-
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue;
blends += va->blends;
renderva(cur, va, RENDERPASS_LIGHTMAP);
}
if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->texs || va->occluded < OCCLUDE_GEOM) continue;
else if((va->parent && va->parent->occluded >= OCCLUDE_BB) ||
- (va->query && checkquery(va->query)))
- {
+ (va->query && checkquery(va->query))) {
va->occluded = OCCLUDE_BB;
continue;
}
-
blends += va->blends;
renderva(cur, va, RENDERPASS_LIGHTMAP);
}
if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
}
-
- if(blends)
- {
+ if(blends) {
if(cur.vbuf) disablevbuf(cur);
-
if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); }
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-
cur.texgendim = -1;
cur.blending = true;
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->blends) continue;
if(va->occluded >= OCCLUDE_GEOM) continue;
renderva(cur, va, RENDERPASS_LIGHTMAP_BLEND);
}
if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
cur.blending = false;
-
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
}
-
- if(doSM) popshadowmap();
-
if(cur.vattribs) disablevattribs(cur);
-
if(multipassing) glDepthFunc(GL_LESS);
-
cleanupgeom(cur);
}
-void renderalphageom(void)
-{
+void renderalphageom(void) {
static vector<vtxarray *> alphavas;
alphavas.setsize(0);
bool hasback = false;
- for(vtxarray *va = visibleva; va; va = va->next)
- {
+ for(vtxarray *va = visibleva; va; va = va->next) {
if(!va->alphatris) continue;
if(va->occluded >= OCCLUDE_BB) continue;
alphavas.add(va);
if(va->alphabacktris) hasback = true;
}
if(alphavas.empty()) return;
-
resetbatches();
-
renderstate cur;
cur.alphaing = 1;
-
- loop(front, 2) if(front || hasback)
- {
+ loop(front, 2) if(front || hasback) {
cur.alphaing = front+1;
if(!front) glCullFace(GL_FRONT);
cur.vbuf = 0;
if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); }
cur.colormask = true;
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-
if(cur.vattribs) disablevattribs(cur, false);
if(cur.vbuf) disablevbuf(cur);
-
setupgeom(cur);
-
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
cur.alphascale = -1;
loopv(alphavas) if(front || alphavas[i]->alphabacktris) renderva(cur, alphavas[i], RENDERPASS_LIGHTMAP);
if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
-
cleanupgeom(cur);
-
if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
glDisable(GL_BLEND);
glDepthFunc(GL_LESS);
if(!front) glCullFace(GL_BACK);
}
-
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
static FILE *logfile = NULL;
-void closelogfile()
-{
- if(logfile)
- {
+void closelogfile() {
+ if(logfile) {
fclose(logfile);
logfile = NULL;
}
}
-FILE *getlogfile()
-{
+FILE *getlogfile() {
return logfile ? logfile : stdout;
}
-void setlogfile(const char *fname)
-{
+void setlogfile(const char *fname) {
closelogfile();
- if(fname && fname[0])
- {
+ if(fname && fname[0]) {
fname = findfile(fname, "w");
if(fname) logfile = fopen(fname, "w");
}
if(f) setvbuf(f, NULL, _IOLBF, BUFSIZ);
}
-void logoutf(const char *fmt, ...)
-{
+void logoutf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
logoutfv(fmt, args);
}
-static void writelog(FILE *file, const char *buf)
-{
+static void writelog(FILE *file, const char *buf) {
static uchar ubuf[512];
size_t len = strlen(buf), carry = 0;
- while(carry < len)
- {
+ while(carry < len) {
size_t numu = encodeutf8(ubuf, sizeof(ubuf)-1, &((const uchar *)buf)[carry], len - carry, &carry);
if(carry >= len) ubuf[numu++] = '\n';
fwrite(ubuf, 1, numu, file);
}
}
-static void writelogv(FILE *file, const char *fmt, va_list args)
-{
+static void writelogv(FILE *file, const char *fmt, va_list args) {
static char buf[LOGSTRLEN];
vformatstring(buf, fmt, args, sizeof(buf));
writelog(file, buf);
}
#ifdef STANDALONE
-void fatal(const char *fmt, ...)
-{
+void fatal(const char *fmt, ...) {
void cleanupserver();
cleanupserver();
defvformatstring(msg,fmt,fmt);
exit(EXIT_FAILURE);
}
-void conoutfv(int type, const char *fmt, va_list args)
-{
+void conoutfv(int type, const char *fmt, va_list args) {
logoutfv(fmt, args);
}
#endif
enum { ST_EMPTY, ST_LOCAL, ST_TCPIP };
-struct client // server side version of "dynent" type
-{
+struct client { // server side version of "dynent" type {
int type;
int num;
ENetPeer *peer;
bool hasnonlocalclients() { return nonlocalclients!=0; }
bool haslocalclients() { return localclients!=0; }
-client &addclient(int type)
-{
+client &addclient(int type) {
client *c = NULL;
- loopv(clients) if(clients[i]->type==ST_EMPTY)
- {
+ loopv(clients) if(clients[i]->type==ST_EMPTY) {
c = clients[i];
break;
}
- if(!c)
- {
+ if(!c) {
c = new client;
c->num = clients.length();
clients.add(c);
}
c->info = server::newclientinfo();
c->type = type;
- switch(type)
- {
+ switch(type) {
case ST_TCPIP: nonlocalclients++; break;
case ST_LOCAL: localclients++; break;
}
return *c;
}
-void delclient(client *c)
-{
+void delclient(client *c) {
if(!c) return;
- switch(c->type)
- {
+ switch(c->type) {
case ST_TCPIP: nonlocalclients--; if(c->peer) c->peer->data = NULL; break;
case ST_LOCAL: localclients--; break;
case ST_EMPTY: return;
}
c->type = ST_EMPTY;
c->peer = NULL;
- if(c->info)
- {
+ if(c->info) {
server::deleteclientinfo(c->info);
c->info = NULL;
}
}
-void cleanupserver()
-{
+void cleanupserver() {
if(serverhost) enet_host_destroy(serverhost);
serverhost = NULL;
-
if(pongsock != ENET_SOCKET_NULL) enet_socket_destroy(pongsock);
if(lansock != ENET_SOCKET_NULL) enet_socket_destroy(lansock);
pongsock = lansock = ENET_SOCKET_NULL;
int getnumclients() { return clients.length(); }
uint getclientip(int n) { return clients.inrange(n) && clients[n]->type==ST_TCPIP ? clients[n]->peer->address.host : 0; }
-void sendpacket(int n, int chan, ENetPacket *packet, int exclude)
-{
- if(n<0)
- {
+void sendpacket(int n, int chan, ENetPacket *packet, int exclude) {
+ if(n<0) {
server::recordpacket(chan, packet->data, packet->dataLength);
loopv(clients) if(i!=exclude && server::allowbroadcast(i)) sendpacket(i, chan, packet);
return;
}
- switch(clients[n]->type)
- {
- case ST_TCPIP:
- {
+ switch(clients[n]->type) {
+ case ST_TCPIP: {
enet_peer_send(clients[n]->peer, chan, packet);
break;
}
}
}
-ENetPacket *sendf(int cn, int chan, const char *format, ...)
-{
+ENetPacket *sendf(int cn, int chan, const char *format, ...) {
int exclude = -1;
bool reliable = false;
if(*format=='r') { reliable = true; ++format; }
packetbuf p(MAXTRANS, reliable ? ENET_PACKET_FLAG_RELIABLE : 0);
va_list args;
va_start(args, format);
- while(*format) switch(*format++)
- {
+ while(*format) switch(*format++) {
case 'x':
exclude = va_arg(args, int);
break;
-
- case 'v':
- {
+ case 'v': {
int n = va_arg(args, int);
int *v = va_arg(args, int *);
loopi(n) putint(p, v[i]);
break;
}
-
- case 'i':
- {
+ case 'i': {
int n = isdigit(*format) ? *format++-'0' : 1;
loopi(n) putint(p, va_arg(args, int));
break;
}
- case 'f':
- {
+ case 'f': {
int n = isdigit(*format) ? *format++-'0' : 1;
loopi(n) putfloat(p, (float)va_arg(args, double));
break;
}
case 's': sendstring(va_arg(args, const char *), p); break;
- case 'm':
- {
+ case 'm': {
int n = va_arg(args, int);
p.put(va_arg(args, uchar *), n);
break;
return packet->referenceCount > 0 ? packet : NULL;
}
-ENetPacket *sendfile(int cn, int chan, stream *file, const char *format, ...)
-{
- if(cn < 0)
- {
+ENetPacket *sendfile(int cn, int chan, stream *file, const char *format, ...) {
+ if(cn < 0) {
#ifdef STANDALONE
return NULL;
#endif
}
else if(!clients.inrange(cn)) return NULL;
-
int len = (int)min(file->size(), stream::offset(INT_MAX));
if(len <= 0 || len > 16<<20) return NULL;
-
packetbuf p(MAXTRANS+len, ENET_PACKET_FLAG_RELIABLE);
va_list args;
va_start(args, format);
- while(*format) switch(*format++)
- {
- case 'i':
- {
+ while(*format) switch(*format++) {
+ case 'i': {
int n = isdigit(*format) ? *format++-'0' : 1;
loopi(n) putint(p, va_arg(args, int));
break;
case 'l': putint(p, len); break;
}
va_end(args);
-
file->seek(0, SEEK_SET);
file->read(p.subbuf(len).buf, len);
-
ENetPacket *packet = p.finalize();
if(cn >= 0) sendpacket(cn, chan, packet, -1);
#ifndef STANDALONE
return packet->referenceCount > 0 ? packet : NULL;
}
-const char *disconnectreason(int reason)
-{
- switch(reason)
- {
+const char *disconnectreason(int reason) {
+ switch(reason) {
case DISC_EOP: return "end of packet";
case DISC_LOCAL: return "server is in local mode";
case DISC_KICK: return "kicked/banned";
}
}
-void disconnect_client(int n, int reason)
-{
+void disconnect_client(int n, int reason) {
if(!clients.inrange(n) || clients[n]->type!=ST_TCPIP) return;
enet_peer_disconnect(clients[n]->peer, reason);
server::clientdisconnect(n);
server::sendservmsg(s);
}
-void kicknonlocalclients(int reason)
-{
+void kicknonlocalclients(int reason) {
loopv(clients) if(clients[i]->type==ST_TCPIP) disconnect_client(i, reason);
}
-void process(ENetPacket *packet, int sender, int chan) // sender may be -1
-{
+void process(ENetPacket *packet, int sender, int chan) { // sender may be -1 {
packetbuf p(packet);
server::parsepacket(sender, chan, p);
if(p.overread()) { disconnect_client(sender, DISC_EOP); return; }
}
-void localclienttoserver(int chan, ENetPacket *packet)
-{
+void localclienttoserver(int chan, ENetPacket *packet) {
client *c = NULL;
loopv(clients) if(clients[i]->type==ST_LOCAL) { c = clients[i]; break; }
if(c) process(packet, c->num, chan);
}
#ifdef STANDALONE
-bool resolverwait(const char *name, ENetAddress *address)
-{
+bool resolverwait(const char *name, ENetAddress *address) {
return enet_address_set_host(address, name) >= 0;
}
-int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &remoteaddress)
-{
+int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &remoteaddress) {
return enet_socket_connect(sock, &remoteaddress);
}
#endif
int masteroutpos = 0, masterinpos = 0;
VARN(updatemaster, allowupdatemaster, 0, 1, 1);
-void disconnectmaster()
-{
- if(mastersock != ENET_SOCKET_NULL)
- {
+void disconnectmaster() {
+ if(mastersock != ENET_SOCKET_NULL) {
server::masterdisconnected();
enet_socket_destroy(mastersock);
mastersock = ENET_SOCKET_NULL;
}
-
masterout.setsize(0);
masterin.setsize(0);
masteroutpos = masterinpos = 0;
-
masteraddress.host = ENET_HOST_ANY;
masteraddress.port = ENET_PORT_ANY;
-
lastupdatemaster = masterconnecting = masterconnected = 0;
}
SVARF(mastername, server::defaultmaster(), disconnectmaster());
VARF(masterport, 1, server::masterport(), 0xFFFF, disconnectmaster());
-ENetSocket connectmaster(bool wait)
-{
+ENetSocket connectmaster(bool wait) {
if(!mastername[0]) return ENET_SOCKET_NULL;
- if(masteraddress.host == ENET_HOST_ANY)
- {
+ if(masteraddress.host == ENET_HOST_ANY) {
if(isdedicatedserver()) logoutf("looking up %s...", mastername);
masteraddress.port = masterport;
if(!resolverwait(mastername, &masteraddress)) return ENET_SOCKET_NULL;
}
ENetSocket sock = enet_socket_create(ENET_SOCKET_TYPE_STREAM);
- if(sock == ENET_SOCKET_NULL)
- {
+ if(sock == ENET_SOCKET_NULL) {
if(isdedicatedserver()) logoutf("could not open master server socket");
return ENET_SOCKET_NULL;
}
- if(wait || serveraddress.host == ENET_HOST_ANY || !enet_socket_bind(sock, &serveraddress))
- {
+ if(wait || serveraddress.host == ENET_HOST_ANY || !enet_socket_bind(sock, &serveraddress)) {
enet_socket_set_option(sock, ENET_SOCKOPT_NONBLOCK, 1);
- if(wait)
- {
+ if(wait) {
if(!connectwithtimeout(sock, mastername, masteraddress)) return sock;
}
else if(!enet_socket_connect(sock, &masteraddress)) return sock;
return ENET_SOCKET_NULL;
}
-bool requestmaster(const char *req)
-{
- if(mastersock == ENET_SOCKET_NULL)
- {
+bool requestmaster(const char *req) {
+ if(mastersock == ENET_SOCKET_NULL) {
mastersock = connectmaster(false);
if(mastersock == ENET_SOCKET_NULL) return false;
lastconnectmaster = masterconnecting = totalmillis ? totalmillis : 1;
}
-
if(masterout.length() >= 4096) return false;
-
masterout.put(req, strlen(req));
return true;
}
-bool requestmasterf(const char *fmt, ...)
-{
+bool requestmasterf(const char *fmt, ...) {
defvformatstring(req, fmt, fmt);
return requestmaster(req);
}
-void processmasterinput()
-{
+void processmasterinput() {
if(masterinpos >= masterin.length()) return;
-
char *input = &masterin[masterinpos], *end = (char *)memchr(input, '\n', masterin.length() - masterinpos);
- while(end)
- {
+ while(end) {
*end = '\0';
-
const char *args = input;
while(args < end && !iscubespace(*args)) args++;
int cmdlen = args - input;
while(args < end && iscubespace(*args)) args++;
-
if(matchstring(input, cmdlen, "failreg"))
conoutf(CON_ERROR, "master server registration failed: %s", args);
else if(matchstring(input, cmdlen, "succreg"))
conoutf("master server registration succeeded");
- else server::processmasterinput(input, cmdlen, args);
-
+ else server::processmasterinput(input, cmdlen);
end++;
masterinpos = end - masterin.getbuf();
input = end;
end = (char *)memchr(input, '\n', masterin.length() - masterinpos);
}
-
- if(masterinpos >= masterin.length())
- {
+ if(masterinpos >= masterin.length()) {
masterin.setsize(0);
masterinpos = 0;
}
}
-void flushmasteroutput()
-{
- if(masterconnecting && totalmillis - masterconnecting >= 60000)
- {
+void flushmasteroutput() {
+ if(masterconnecting && totalmillis - masterconnecting >= 60000) {
logoutf("could not connect to master server");
disconnectmaster();
}
if(masterout.empty() || !masterconnected) return;
-
ENetBuffer buf;
buf.data = &masterout[masteroutpos];
buf.dataLength = masterout.length() - masteroutpos;
int sent = enet_socket_send(mastersock, NULL, &buf, 1);
- if(sent >= 0)
- {
+ if(sent >= 0) {
masteroutpos += sent;
- if(masteroutpos >= masterout.length())
- {
+ if(masteroutpos >= masterout.length()) {
masterout.setsize(0);
masteroutpos = 0;
}
else disconnectmaster();
}
-void flushmasterinput()
-{
+void flushmasterinput() {
if(masterin.length() >= masterin.capacity())
masterin.reserve(4096);
-
ENetBuffer buf;
buf.data = masterin.getbuf() + masterin.length();
buf.dataLength = masterin.capacity() - masterin.length();
int recv = enet_socket_receive(mastersock, NULL, &buf, 1);
- if(recv > 0)
- {
+ if(recv > 0) {
masterin.advance(recv);
processmasterinput();
}
static ENetAddress pongaddr;
-void sendserverinforeply(ucharbuf &p)
-{
+void sendserverinforeply(ucharbuf &p) {
ENetBuffer buf;
buf.data = p.buf;
buf.dataLength = p.length();
#define MAXPINGDATA 32
-void checkserversockets() // reply all server info requests
-{
+void checkserversockets() { // reply all server info requests {
static ENetSocketSet readset, writeset;
ENET_SOCKETSET_EMPTY(readset);
ENET_SOCKETSET_EMPTY(writeset);
ENetSocket maxsock = pongsock;
ENET_SOCKETSET_ADD(readset, pongsock);
- if(mastersock != ENET_SOCKET_NULL)
- {
+ if(mastersock != ENET_SOCKET_NULL) {
maxsock = max(maxsock, mastersock);
ENET_SOCKETSET_ADD(readset, mastersock);
if(!masterconnected) ENET_SOCKETSET_ADD(writeset, mastersock);
}
- if(lansock != ENET_SOCKET_NULL)
- {
+ if(lansock != ENET_SOCKET_NULL) {
maxsock = max(maxsock, lansock);
ENET_SOCKETSET_ADD(readset, lansock);
}
if(enet_socketset_select(maxsock, &readset, &writeset, 0) <= 0) return;
-
ENetBuffer buf;
uchar pong[MAXTRANS];
- loopi(2)
- {
+ loopi(2) {
ENetSocket sock = i ? lansock : pongsock;
if(sock == ENET_SOCKET_NULL || !ENET_SOCKETSET_CHECK(readset, sock)) continue;
-
buf.data = pong;
buf.dataLength = sizeof(pong);
int len = enet_socket_receive(sock, &pongaddr, &buf, 1);
p.len += len;
server::serverinforeply(req, p);
}
-
- if(mastersock != ENET_SOCKET_NULL)
- {
- if(!masterconnected)
- {
- if(ENET_SOCKETSET_CHECK(readset, mastersock) || ENET_SOCKETSET_CHECK(writeset, mastersock))
- {
+ if(mastersock != ENET_SOCKET_NULL) {
+ if(!masterconnected) {
+ if(ENET_SOCKETSET_CHECK(readset, mastersock) || ENET_SOCKETSET_CHECK(writeset, mastersock)) {
int error = 0;
- if(enet_socket_get_option(mastersock, ENET_SOCKOPT_ERROR, &error) < 0 || error)
- {
+ if(enet_socket_get_option(mastersock, ENET_SOCKOPT_ERROR, &error) < 0 || error) {
logoutf("could not connect to master server");
disconnectmaster();
}
- else
- {
+ else {
masterconnecting = 0;
masterconnected = totalmillis ? totalmillis : 1;
server::masterconnected();
int curtime = 0, lastmillis = 0, elapsedtime = 0, totalmillis = 0;
#endif
-void updatemasterserver()
-{
+void updatemasterserver() {
if(!masterconnected && lastconnectmaster && totalmillis-lastconnectmaster <= 5*60*1000) return;
if(mastername[0] && allowupdatemaster) requestmasterf("regserv %d\n", serverport);
lastupdatemaster = totalmillis ? totalmillis : 1;
uint totalsecs = 0;
-void updatetime()
-{
+void updatetime() {
static int lastsec = 0;
- if(totalmillis - lastsec >= 1000)
- {
+ if(totalmillis - lastsec >= 1000) {
int cursecs = (totalmillis - lastsec) / 1000;
totalsecs += cursecs;
lastsec += cursecs * 1000;
}
}
-void serverslice(bool dedicated, uint timeout) // main server update, called from main loop in sp, or from below in dedicated server
-{
- if(!serverhost)
- {
+void serverslice(bool dedicated, uint timeout) { // main server update, called from main loop in sp, or from below in dedicated server {
+ if(!serverhost) {
server::serverupdate();
server::sendpackets();
return;
}
-
// below is network only
-
- if(dedicated)
- {
+ if(dedicated) {
int millis = (int)enet_time_get();
elapsedtime = millis - totalmillis;
static int timeerr = 0;
updatetime();
}
server::serverupdate();
-
flushmasteroutput();
checkserversockets();
-
if(!lastupdatemaster || totalmillis-lastupdatemaster>60*60*1000) // send alive signal to masterserver every hour of uptime
updatemasterserver();
-
- if(totalmillis-laststatus>60*1000) // display bandwidth stats, useful for server ops
- {
+ if(totalmillis-laststatus>60*1000) { // display bandwidth stats, useful for server ops {
laststatus = totalmillis;
if(nonlocalclients || serverhost->totalSentData || serverhost->totalReceivedData) logoutf("status: %d remote clients, %.1f send, %.1f rec (K/sec)", nonlocalclients, serverhost->totalSentData/60.0f/1024, serverhost->totalReceivedData/60.0f/1024);
serverhost->totalSentData = serverhost->totalReceivedData = 0;
}
-
ENetEvent event;
bool serviced = false;
- while(!serviced)
- {
- if(enet_host_check_events(serverhost, &event) <= 0)
- {
+ while(!serviced) {
+ if(enet_host_check_events(serverhost, &event) <= 0) {
if(enet_host_service(serverhost, &event, timeout) <= 0) break;
serviced = true;
}
- switch(event.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- {
+ switch(event.type) {
+ case ENET_EVENT_TYPE_CONNECT: {
client &c = addclient(ST_TCPIP);
c.peer = event.peer;
c.peer->data = &c;
if(reason) disconnect_client(c.num, reason);
break;
}
- case ENET_EVENT_TYPE_RECEIVE:
- {
+ case ENET_EVENT_TYPE_RECEIVE: {
client *c = (client *)event.peer->data;
if(c) process(event.packet, c->num, event.channelID);
if(event.packet->referenceCount==0) enet_packet_destroy(event.packet);
break;
}
- case ENET_EVENT_TYPE_DISCONNECT:
- {
+ case ENET_EVENT_TYPE_DISCONNECT: {
client *c = (client *)event.peer->data;
if(!c) break;
logoutf("disconnected client (%s)", c->hostname);
if(server::sendpackets()) enet_host_flush(serverhost);
}
-void flushserver(bool force)
-{
+void flushserver(bool force) {
if(server::sendpackets(force) && serverhost) enet_host_flush(serverhost);
}
#ifndef STANDALONE
-void localdisconnect(bool cleanup)
-{
+void localdisconnect(bool cleanup) {
bool disconnected = false;
- loopv(clients) if(clients[i]->type==ST_LOCAL)
- {
+ loopv(clients) if(clients[i]->type==ST_LOCAL) {
server::localdisconnect(i);
delclient(clients[i]);
disconnected = true;
mainmenu = 1;
}
-void localconnect()
-{
+void localconnect() {
if(initing) return;
client &c = addclient(ST_LOCAL);
copystring(c.hostname, "local");
}
#endif
-void logoutfv(const char *fmt, va_list args)
-{
+void logoutfv(const char *fmt, va_list args) {
FILE *f = getlogfile();
if(f) writelogv(f, fmt, args);
}
bool isdedicatedserver() { return dedicatedserver; }
-void rundedicatedserver()
-{
+void rundedicatedserver() {
dedicatedserver = true;
logoutf("dedicated server started, waiting for clients...");
for(;;) serverslice(true, 5);
dedicatedserver = false;
}
-bool servererror(bool dedicated, const char *desc)
-{
+bool servererror(bool dedicated, const char *desc) {
+ (void) dedicated;
#ifndef STANDALONE
- if(!dedicated)
- {
+ if(!dedicated) {
conoutf(CON_ERROR, "%s", desc);
cleanupserver();
}
return false;
}
-bool setuplistenserver(bool dedicated)
-{
+bool setuplistenserver(bool dedicated) {
ENetAddress address = { ENET_HOST_ANY, enet_uint16(serverport <= 0 ? server::serverport() : serverport) };
- if(*serverip)
- {
+ if(*serverip) {
if(enet_address_set_host(&address, serverip)<0) conoutf(CON_WARN, "WARNING: server ip not resolved");
else serveraddress.host = address.host;
}
serverhost->duplicatePeers = maxdupclients ? maxdupclients : MAXCLIENTS;
address.port = server::serverinfoport(serverport > 0 ? serverport : -1);
pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
- if(pongsock != ENET_SOCKET_NULL && enet_socket_bind(pongsock, &address) < 0)
- {
+ if(pongsock != ENET_SOCKET_NULL && enet_socket_bind(pongsock, &address) < 0) {
enet_socket_destroy(pongsock);
pongsock = ENET_SOCKET_NULL;
}
else enet_socket_set_option(pongsock, ENET_SOCKOPT_NONBLOCK, 1);
address.port = server::laninfoport();
lansock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
- if(lansock != ENET_SOCKET_NULL && (enet_socket_set_option(lansock, ENET_SOCKOPT_REUSEADDR, 1) < 0 || enet_socket_bind(lansock, &address) < 0))
- {
+ if(lansock != ENET_SOCKET_NULL && (enet_socket_set_option(lansock, ENET_SOCKOPT_REUSEADDR, 1) < 0 || enet_socket_bind(lansock, &address) < 0)) {
enet_socket_destroy(lansock);
lansock = ENET_SOCKET_NULL;
}
return true;
}
-void initserver(bool listen, bool dedicated)
-{
+void initserver(bool listen, bool dedicated) {
execfile("server-init.cfg", false);
-
if(listen) setuplistenserver(dedicated);
-
server::serverinit();
-
- if(listen)
- {
+ if(listen) {
dedicatedserver = dedicated;
updatemasterserver();
if(dedicated) rundedicatedserver(); // never returns
}
#ifndef STANDALONE
-void startlistenserver(int *usemaster)
-{
+void startlistenserver(int *usemaster) {
if(serverhost) { conoutf(CON_ERROR, "listen server is already running"); return; }
-
allowupdatemaster = *usemaster>0 ? 1 : 0;
-
if(!setuplistenserver(false)) return;
-
updatemasterserver();
-
conoutf("listen server started for %d clients%s", maxclients, allowupdatemaster ? " and listed with master server" : "");
}
COMMAND(startlistenserver, "i");
-void stoplistenserver()
-{
+void stoplistenserver() {
if(!serverhost) { conoutf(CON_ERROR, "listen server is not running"); return; }
-
kicknonlocalclients();
enet_host_flush(serverhost);
cleanupserver();
-
conoutf("listen server stopped");
}
COMMAND(stoplistenserver, "");
#endif
-bool serveroption(char *opt)
-{
- switch(opt[1])
- {
+bool serveroption(char *opt) {
+ switch(opt[1]) {
case 'u': setvar("serveruprate", atoi(opt+2)); return true;
case 'c': setvar("maxclients", atoi(opt+2)); return true;
case 'i': setsvar("serverip", opt+2); return true;
vector<const char *> gameargs;
#ifdef STANDALONE
-int main(int argc, char **argv)
-{
+int main(int argc, char **argv) {
setlogfile(NULL);
if(enet_initialize()<0) fatal("Unable to initialise network module");
atexit(enet_deinitialize);
#define PROTOCOL_VERSION 260 // bump when protocol changes, dpulicate
-struct resolverthread
-{
+struct resolverthread {
SDL_Thread *thread;
const char *query;
int starttime;
};
-struct resolverresult
-{
+struct resolverresult {
const char *query;
ENetAddress address;
};
#define RESOLVERTHREADS 2
#define RESOLVERLIMIT 3000
-int resolverloop(void * data)
-{
+int resolverloop(void * data) {
resolverthread *rt = (resolverthread *)data;
SDL_LockMutex(resolvermutex);
SDL_Thread *thread = rt->thread;
SDL_UnlockMutex(resolvermutex);
if(!thread || SDL_GetThreadID(thread) != SDL_ThreadID())
return 0;
- while(thread == rt->thread)
- {
+ while(thread == rt->thread) {
SDL_LockMutex(resolvermutex);
while(resolverqueries.empty()) SDL_CondWait(querycond, resolvermutex);
rt->query = resolverqueries.pop();
rt->starttime = totalmillis;
SDL_UnlockMutex(resolvermutex);
-
ENetAddress address = { ENET_HOST_ANY, ENET_PORT_ANY };
enet_address_set_host(&address, rt->query);
-
SDL_LockMutex(resolvermutex);
- if(rt->query && thread == rt->thread)
- {
+ if(rt->query && thread == rt->thread) {
resolverresult &rr = resolverresults.add();
rr.query = rt->query;
rr.address = address;
return 0;
}
-void resolverinit()
-{
+void resolverinit() {
resolvermutex = SDL_CreateMutex();
querycond = SDL_CreateCond();
resultcond = SDL_CreateCond();
-
SDL_LockMutex(resolvermutex);
- loopi(RESOLVERTHREADS)
- {
+ loopi(RESOLVERTHREADS) {
resolverthread &rt = resolverthreads.add();
rt.query = NULL;
rt.starttime = 0;
SDL_UnlockMutex(resolvermutex);
}
-void resolverstop(resolverthread &rt)
-{
+void resolverstop(resolverthread &rt) {
SDL_LockMutex(resolvermutex);
- if(rt.query)
- {
+ if(rt.query) {
#if SDL_VERSION_ATLEAST(2, 0, 2)
SDL_DetachThread(rt.thread);
#endif
SDL_UnlockMutex(resolvermutex);
}
-void resolverclear()
-{
+void resolverclear() {
if(resolverthreads.empty()) return;
-
SDL_LockMutex(resolvermutex);
resolverqueries.shrink(0);
resolverresults.shrink(0);
- loopv(resolverthreads)
- {
+ loopv(resolverthreads) {
resolverthread &rt = resolverthreads[i];
resolverstop(rt);
}
SDL_UnlockMutex(resolvermutex);
}
-void resolverquery(const char *name)
-{
+void resolverquery(const char *name) {
if(resolverthreads.empty()) resolverinit();
-
SDL_LockMutex(resolvermutex);
resolverqueries.add(name);
SDL_CondSignal(querycond);
SDL_UnlockMutex(resolvermutex);
}
-bool resolvercheck(const char **name, ENetAddress *address)
-{
+bool resolvercheck(const char **name, ENetAddress *address) {
bool resolved = false;
SDL_LockMutex(resolvermutex);
- if(!resolverresults.empty())
- {
+ if(!resolverresults.empty()) {
resolverresult &rr = resolverresults.pop();
*name = rr.query;
address->host = rr.address.host;
resolved = true;
}
- else loopv(resolverthreads)
- {
+ else loopv(resolverthreads) {
resolverthread &rt = resolverthreads[i];
- if(rt.query && totalmillis - rt.starttime > RESOLVERLIMIT)
- {
+ if(rt.query && totalmillis - rt.starttime > RESOLVERLIMIT) {
resolverstop(rt);
*name = rt.query;
resolved = true;
return resolved;
}
-bool resolverwait(const char *name, ENetAddress *address)
-{
+bool resolverwait(const char *name, ENetAddress *address) {
if(resolverthreads.empty()) resolverinit();
-
defformatstring(text, "resolving %s... (esc to abort)", name);
renderprogress(0, text);
-
SDL_LockMutex(resolvermutex);
resolverqueries.add(name);
SDL_CondSignal(querycond);
int starttime = SDL_GetTicks(), timeout = 0;
bool resolved = false;
- for(;;)
- {
+ for(;;) {
SDL_CondWaitTimeout(resultcond, resolvermutex, 250);
- loopv(resolverresults) if(resolverresults[i].query == name)
- {
+ loopv(resolverresults) if(resolverresults[i].query == name) {
address->host = resolverresults[i].address.host;
resolverresults.remove(i);
resolved = true;
break;
}
if(resolved) break;
-
timeout = SDL_GetTicks() - starttime;
renderprogress(min(float(timeout)/RESOLVERLIMIT, 1.0f), text);
if(interceptkey(SDLK_ESCAPE)) timeout = RESOLVERLIMIT + 1;
if(timeout > RESOLVERLIMIT) break;
}
- if(!resolved && timeout > RESOLVERLIMIT)
- {
- loopv(resolverthreads)
- {
+ if(!resolved && timeout > RESOLVERLIMIT) {
+ loopv(resolverthreads) {
resolverthread &rt = resolverthreads[i];
if(rt.query == name) { resolverstop(rt); break; }
}
#define CONNLIMIT 20000
-int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &address)
-{
+int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &address) {
defformatstring(text, "connecting to %s... (esc to abort)", hostname);
renderprogress(0, text);
-
ENetSocketSet readset, writeset;
- if(!enet_socket_connect(sock, &address)) for(int starttime = SDL_GetTicks(), timeout = 0; timeout <= CONNLIMIT;)
- {
+ if(!enet_socket_connect(sock, &address)) for(int starttime = SDL_GetTicks(), timeout = 0; timeout <= CONNLIMIT;) {
ENET_SOCKETSET_EMPTY(readset);
ENET_SOCKETSET_EMPTY(writeset);
ENET_SOCKETSET_ADD(readset, sock);
ENET_SOCKETSET_ADD(writeset, sock);
int result = enet_socketset_select(sock, &readset, &writeset, 250);
if(result < 0) break;
- else if(result > 0)
- {
- if(ENET_SOCKETSET_CHECK(readset, sock) || ENET_SOCKETSET_CHECK(writeset, sock))
- {
+ else if(result > 0) {
+ if(ENET_SOCKETSET_CHECK(readset, sock) || ENET_SOCKETSET_CHECK(writeset, sock)) {
int error = 0;
if(enet_socket_get_option(sock, ENET_SOCKOPT_ERROR, &error) < 0 || error) break;
return 0;
renderprogress(min(float(timeout)/CONNLIMIT, 1.0f), text);
if(interceptkey(SDLK_ESCAPE)) break;
}
-
return -1;
}
-struct pingattempts
-{
+struct pingattempts {
enum { MAXATTEMPTS = 2 };
-
int offset, attempts[MAXATTEMPTS];
-
pingattempts() : offset(0) { clearattempts(); }
-
void clearattempts() { memset(attempts, 0, sizeof(attempts)); }
-
void setoffset() { offset = 1 + rnd(0xFFFFFF); }
-
- int encodeping(int millis)
- {
+ int encodeping(int millis) {
millis += offset;
return millis ? millis : 1;
}
-
- int decodeping(int val)
- {
+ int decodeping(int val) {
return val - offset;
}
-
- int addattempt(int millis)
- {
+ int addattempt(int millis) {
int val = encodeping(millis);
loopk(MAXATTEMPTS-1) attempts[k+1] = attempts[k];
attempts[0] = val;
return val;
}
-
- bool checkattempt(int val, bool del = true)
- {
- if(val) loopk(MAXATTEMPTS) if(attempts[k] == val)
- {
+ bool checkattempt(int val, bool del = true) {
+ if(val) loopk(MAXATTEMPTS) if(attempts[k] == val) {
if(del) attempts[k] = 0;
return true;
}
enum { UNRESOLVED = 0, RESOLVING, RESOLVED };
-struct serverinfo : pingattempts
-{
- enum
- {
+struct serverinfo : pingattempts {
+ enum {
WAITING = INT_MAX,
-
MAXPINGS = 3
};
-
string name, map, sdesc;
int port, numplayers, resolved, ping, lastping, nextping;
int pings[MAXPINGS];
ENetAddress address;
bool keep;
const char *password;
-
serverinfo()
- : port(-1), numplayers(0), resolved(UNRESOLVED), keep(false), password(NULL)
- {
+ : port(-1), numplayers(0), resolved(UNRESOLVED), keep(false), password(NULL) {
name[0] = map[0] = sdesc[0] = '\0';
clearpings();
setoffset();
}
-
- ~serverinfo()
- {
+ ~serverinfo() {
DELETEA(password);
}
-
- void clearpings()
- {
+ void clearpings() {
ping = WAITING;
loopk(MAXPINGS) pings[k] = WAITING;
nextping = 0;
lastping = -1;
clearattempts();
}
-
- void cleanup()
- {
+ void cleanup() {
clearpings();
attr.setsize(0);
numplayers = 0;
}
-
- void reset()
- {
+ void reset() {
lastping = -1;
}
-
- void checkdecay(int decay)
- {
+ void checkdecay(int decay) {
if(lastping >= 0 && totalmillis - lastping >= decay)
cleanup();
if(lastping < 0) lastping = totalmillis;
}
-
- void calcping()
- {
+ void calcping() {
int numpings = 0, totalpings = 0;
loopk(MAXPINGS) if(pings[k] != WAITING) { totalpings += pings[k]; numpings++; }
ping = numpings ? totalpings/numpings : WAITING;
}
-
- void addping(int rtt, int millis)
- {
+ void addping(int rtt, int millis) {
if(millis >= lastping) lastping = -1;
pings[nextping] = rtt;
nextping = (nextping+1)%MAXPINGS;
calcping();
}
-
- static bool compare(serverinfo *a, serverinfo *b)
- {
+ static bool compare(serverinfo *a, serverinfo *b) {
bool ac = (a->attr.length() != 0) && (a->attr[0]==PROTOCOL_VERSION);
bool bc = (b->attr.length() != 0) && (b->attr[0]==PROTOCOL_VERSION);
if(ac > bc) return true;
ENetSocket pingsock = ENET_SOCKET_NULL;
int lastinfo = 0;
-static serverinfo *newserver(const char *name, int port, uint ip = ENET_HOST_ANY)
-{
+static serverinfo *newserver(const char *name, int port, uint ip = ENET_HOST_ANY) {
serverinfo *si = new serverinfo;
si->address.host = ip;
si->address.port = server::serverinfoport(port);
if(ip!=ENET_HOST_ANY) si->resolved = RESOLVED;
-
si->port = port;
if(name) copystring(si->name, name);
- else if(ip==ENET_HOST_ANY || enet_address_get_host_ip(&si->address, si->name, sizeof(si->name)) < 0)
- {
+ else if(ip==ENET_HOST_ANY || enet_address_get_host_ip(&si->address, si->name, sizeof(si->name)) < 0) {
delete si;
return NULL;
-
}
-
servers.add(si);
-
return si;
}
-void addserver(const char *name, int port, const char *password, bool keep)
-{
+void addserver(const char *name, int port, const char *password, bool keep) {
if(port <= 0) port = server::serverport();
- loopv(servers)
- {
+ loopv(servers) {
serverinfo *s = servers[i];
if(strcmp(s->name, name) || s->port != port) continue;
- if(password && (!s->password || strcmp(s->password, password)))
- {
+ if(password && (!s->password || strcmp(s->password, password))) {
DELETEA(s->password);
s->password = newstring(password);
}
pingattempts lanpings;
-template<size_t N> static inline void buildping(ENetBuffer &buf, uchar (&ping)[N], pingattempts &a)
-{
+template<size_t N> static inline void buildping(ENetBuffer &buf, uchar (&ping)[N], pingattempts &a) {
ucharbuf p(ping, N);
putint(p, a.addattempt(totalmillis));
buf.data = ping;
buf.dataLength = p.length();
}
-void pingservers()
-{
- if(pingsock == ENET_SOCKET_NULL)
- {
+void pingservers() {
+ if(pingsock == ENET_SOCKET_NULL) {
pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
- if(pingsock == ENET_SOCKET_NULL)
- {
+ if(pingsock == ENET_SOCKET_NULL) {
lastinfo = totalmillis;
return;
}
enet_socket_set_option(pingsock, ENET_SOCKOPT_NONBLOCK, 1);
enet_socket_set_option(pingsock, ENET_SOCKOPT_BROADCAST, 1);
-
lanpings.setoffset();
}
-
ENetBuffer buf;
uchar ping[MAXTRANS];
-
static int lastping = 0;
if(lastping >= servers.length()) lastping = 0;
- loopi(maxservpings ? min(servers.length(), maxservpings) : servers.length())
- {
+ loopi(maxservpings ? min(servers.length(), maxservpings) : servers.length()) {
serverinfo &si = *servers[lastping];
if(++lastping >= servers.length()) lastping = 0;
if(si.address.host == ENET_HOST_ANY) continue;
buildping(buf, ping, si);
enet_socket_send(pingsock, &si.address, &buf, 1);
-
si.checkdecay(servpingdecay);
}
- if(searchlan)
- {
+ if(searchlan) {
ENetAddress address;
address.host = ENET_HOST_BROADCAST;
address.port = server::laninfoport();
lastinfo = totalmillis;
}
-void checkresolver()
-{
+void checkresolver() {
int resolving = 0;
- loopv(servers)
- {
+ loopv(servers) {
serverinfo &si = *servers[i];
if(si.resolved == RESOLVED) continue;
- if(si.address.host == ENET_HOST_ANY)
- {
+ if(si.address.host == ENET_HOST_ANY) {
if(si.resolved == UNRESOLVED) { si.resolved = RESOLVING; resolverquery(si.name); }
resolving++;
}
}
if(!resolving) return;
-
const char *name = NULL;
- for(;;)
- {
+ for(;;) {
ENetAddress addr = { ENET_HOST_ANY, ENET_PORT_ANY };
if(!resolvercheck(&name, &addr)) break;
- loopv(servers)
- {
+ loopv(servers) {
serverinfo &si = *servers[i];
- if(name == si.name)
- {
+ if(name == si.name) {
si.resolved = RESOLVED;
si.address.host = addr.host;
break;
static int lastreset = 0;
-void checkpings()
-{
+void checkpings() {
if(pingsock==ENET_SOCKET_NULL) return;
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
ENetBuffer buf;
char text[MAXTRANS];
buf.data = ping;
buf.dataLength = sizeof(ping);
- while(enet_socket_wait(pingsock, &events, 0) >= 0 && events)
- {
+ while(enet_socket_wait(pingsock, &events, 0) >= 0 && events) {
int len = enet_socket_receive(pingsock, &addr, &buf, 1);
if(len <= 0) return;
ucharbuf p(ping, len);
int millis = getint(p);
serverinfo *si = NULL;
loopv(servers) if(addr.host == servers[i]->address.host && addr.port == servers[i]->address.port) { si = servers[i]; break; }
- if(si)
- {
+ if(si) {
if(!si->checkattempt(millis)) continue;
millis = si->decodeping(millis);
}
else if(!searchlan || !lanpings.checkattempt(millis, false)) continue;
- else
- {
+ else {
si = newserver(NULL, server::serverport(addr.port), addr.host);
millis = lanpings.decodeping(millis);
}
}
}
-void sortservers()
-{
+void sortservers() {
servers.sort(serverinfo::compare);
}
COMMAND(sortservers, "");
VARP(autosortservers, 0, 1, 1);
VARP(autoupdateservers, 0, 1, 1);
-void refreshservers()
-{
+void refreshservers() {
static int lastrefresh = 0;
if(lastrefresh==totalmillis) return;
- if(totalmillis - lastrefresh > 1000)
- {
+ if(totalmillis - lastrefresh > 1000) {
loopv(servers) servers[i]->reset();
lastreset = totalmillis;
}
lastrefresh = totalmillis;
-
checkresolver();
checkpings();
if(totalmillis - lastinfo >= servpingrate/(maxservpings ? max(1, (servers.length() + maxservpings - 1) / maxservpings) : 1)) pingservers();
serverinfo *selectedserver = NULL;
-const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax)
-{
+const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax) {
refreshservers();
- if(servers.empty())
- {
+ if(servers.empty()) {
if(header) execute(header);
return NULL;
}
serverinfo *sc = NULL;
- for(int start = 0; start < servers.length();)
- {
+ for(int start = 0; start < servers.length();) {
if(start > 0) cgui->tab();
if(header) execute(header);
int end = servers.length();
cgui->pushlist();
- loopi(10)
- {
+ loopi(10) {
if(!game::serverinfostartcolumn(cgui, i)) break;
- for(int j = start; j < end; j++)
- {
+ for(int j = start; j < end; j++) {
if(!i && j+1 - start >= pagemin && (j+1 - start >= pagemax || cgui->shouldtab())) { end = j; break; }
serverinfo &si = *servers[j];
const char *sdesc = si.sdesc;
return "connectselected";
}
-void connectselected()
-{
+void connectselected() {
if(!selectedserver) return;
connectserv(selectedserver->name, selectedserver->port, selectedserver->password);
selectedserver = NULL;
COMMAND(connectselected, "");
-void clearservers(bool full = false)
-{
+void clearservers(bool full = false) {
resolverclear();
if(full) servers.deletecontents();
else loopvrev(servers) if(!servers[i]->keep) delete servers.remove(i);
#define RETRIEVELIMIT 20000
-void retrieveservers(vector<char> &data)
-{
+void retrieveservers(vector<char> &data) {
ENetSocket sock = connectmaster(true);
if(sock == ENET_SOCKET_NULL) return;
-
extern char *mastername;
defformatstring(text, "retrieving servers from %s... (esc to abort)", mastername);
renderprogress(0, text);
-
int starttime = SDL_GetTicks(), timeout = 0;
const char *req = "list\n";
int reqlen = strlen(req);
ENetBuffer buf;
- while(reqlen > 0)
- {
+ while(reqlen > 0) {
enet_uint32 events = ENET_SOCKET_WAIT_SEND;
- if(enet_socket_wait(sock, &events, 250) >= 0 && events)
- {
+ if(enet_socket_wait(sock, &events, 250) >= 0 && events) {
buf.data = (void *)req;
buf.dataLength = reqlen;
int sent = enet_socket_send(sock, NULL, &buf, 1);
if(interceptkey(SDLK_ESCAPE)) timeout = RETRIEVELIMIT + 1;
if(timeout > RETRIEVELIMIT) break;
}
-
- if(reqlen <= 0) for(;;)
- {
+ if(reqlen <= 0) for(;;) {
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
- if(enet_socket_wait(sock, &events, 250) >= 0 && events)
- {
+ if(enet_socket_wait(sock, &events, 250) >= 0 && events) {
if(data.length() >= data.capacity()) data.reserve(4096);
buf.data = data.getbuf() + data.length();
buf.dataLength = data.capacity() - data.length();
if(interceptkey(SDLK_ESCAPE)) timeout = RETRIEVELIMIT + 1;
if(timeout > RETRIEVELIMIT) break;
}
-
if(data.length()) data.add('\0');
enet_socket_destroy(sock);
}
bool updatedservers = false;
-void updatefrommaster()
-{
+void updatefrommaster() {
vector<char> data;
retrieveservers(data);
if(data.empty()) conoutf(CON_ERROR, "master server not replying");
- else
- {
+ else {
clearservers();
char *line = data.getbuf();
- while(char *end = (char *)memchr(line, '\n', data.length() - (line - data.getbuf())))
- {
+ while(char *end = (char *)memchr(line, '\n', data.length() - (line - data.getbuf()))) {
*end = '\0';
-
const char *args = line;
while(args < end && !iscubespace(*args)) args++;
int cmdlen = args - line;
while(args < end && iscubespace(*args)) args++;
-
- if(matchstring(line, cmdlen, "addserver"))
- {
+ if(matchstring(line, cmdlen, "addserver")) {
string ip;
int port;
if(sscanf(args, "%100s %d", ip, &port) == 2) addserver(ip, port);
}
else if(matchstring(line, cmdlen, "echo")) conoutf("\f1%s", args);
-
line = end + 1;
}
}
updatedservers = true;
}
-void initservers()
-{
+void initservers() {
selectedserver = NULL;
if(autoupdateservers && !updatedservers) updatefrommaster();
}
COMMAND(updatefrommaster, "");
COMMAND(initservers, "");
-void writeservercfg()
-{
+void writeservercfg() {
if(!game::savedservers()) return;
stream *f = openutf8file(path(game::savedservers(), true), "w");
if(!f) return;
int kept = 0;
- loopv(servers)
- {
+ loopv(servers) {
serverinfo *s = servers[i];
- if(s->keep)
- {
+ if(s->keep) {
if(!kept) f->printf("// servers that should never be cleared from the server list\n\n");
if(s->password) f->printf("keepserver %s %d %s\n", escapeid(s->name), s->port, escapestring(s->password));
else f->printf("keepserver %s %d\n", escapeid(s->name), s->port);
}
if(kept) f->printf("\n");
f->printf("// servers connected to are added here automatically\n\n");
- loopv(servers)
- {
+ loopv(servers) {
serverinfo *s = servers[i];
- if(!s->keep)
- {
+ if(!s->keep) {
if(s->password) f->printf("addserver %s %d %s\n", escapeid(s->name), s->port, escapestring(s->password));
else f->printf("addserver %s %d\n", escapeid(s->name), s->port);
}
VAR(maxfsuniforms, 1, 0, 0);
VAR(maxvaryings, 1, 0, 0);
-void loadshaders()
-{
+void loadshaders() {
standardshaders = true;
execfile("data/glsl.cfg");
standardshaders = false;
-
nullshader = lookupshaderbyname("null");
hudshader = lookupshaderbyname("hud");
hudnotextureshader = lookupshaderbyname("hudnotexture");
stdworldshader = lookupshaderbyname("stdworld");
if(!nullshader || !hudshader || !hudnotextureshader || !stdworldshader) fatal("cannot find shader definitions");
-
dummyslot.shader = stdworldshader;
-
textureshader = lookupshaderbyname("texture");
notextureshader = lookupshaderbyname("notexture");
nocolorshader = lookupshaderbyname("nocolor");
-
nullshader->set();
-
loadedshaders = true;
}
-Shader *lookupshaderbyname(const char *name)
-{
+Shader *lookupshaderbyname(const char *name) {
Shader *s = shaders.access(name);
return s && s->loaded() ? s : NULL;
}
-Shader *generateshader(const char *name, const char *fmt, ...)
-{
+Shader *generateshader(const char *name, const char *fmt, ...) {
if(!loadedshaders) return NULL;
Shader *s = name ? lookupshaderbyname(name) : NULL;
- if(!s)
- {
+ if(!s) {
defvformatstring(cmd, fmt, fmt);
bool wasstandard = standardshaders;
standardshaders = true;
return s;
}
-static void showglslinfo(GLenum type, GLuint obj, const char *name, const char **parts = NULL, int numparts = 0)
-{
+static void showglslinfo(GLenum type, GLuint obj, const char *name, const char **parts = NULL, int numparts = 0) {
GLint length = 0;
if(type) glGetShaderiv_(obj, GL_INFO_LOG_LENGTH, &length);
else glGetProgramiv_(obj, GL_INFO_LOG_LENGTH, &length);
- if(length > 1)
- {
+ if(length > 1) {
conoutf(CON_ERROR, "GLSL ERROR (%s:%s)", type == GL_VERTEX_SHADER ? "VS" : (type == GL_FRAGMENT_SHADER ? "FS" : "PROG"), name);
FILE *l = getlogfile();
- if(l)
- {
+ if(l) {
GLchar *log = new GLchar[length];
if(type) glGetShaderInfoLog_(obj, length, &length, log);
else glGetProgramInfoLog_(obj, length, &length, log);
fprintf(l, "%s\n", log);
bool partlines = log[0] != '0';
int line = 0;
- loopi(numparts)
- {
+ loopi(numparts) {
const char *part = parts[i];
int startline = line;
- while(*part)
- {
+ while(*part) {
const char *next = strchr(part, '\n');
if(++line > 1000) goto done;
if(partlines) fprintf(l, "%d(%d): ", i, line - startline); else fprintf(l, "%d: ", line);
}
}
-static void compileglslshader(GLenum type, GLuint &obj, const char *def, const char *name, bool msg = true)
-{
+static void compileglslshader(GLenum type, GLuint &obj, const char *def, const char *name, bool msg = true) {
const char *source = def + strspn(def, " \t\r\n");
const char *parts[16];
int numparts = 0;
- static const struct { int version; const char * const header; } glslversions[] =
- {
- { 330, "#version 330\n" },
- { 150, "#version 150\n" },
- { 130, "#version 130\n" },
- { 120, "#version 120\n" }
+ static const struct { int version; const char * const header; } glslversions[] = {
+ {
+ 330, "#version 330\n" }, {
+ 150, "#version 150\n" }, {
+ 130, "#version 130\n" }, {
+ 120, "#version 120\n" }
};
- loopi(sizeof(glslversions)/sizeof(glslversions[0])) if(glslversion >= glslversions[i].version)
- {
+ loopi(sizeof(glslversions)/sizeof(glslversions[0])) if(glslversion >= glslversions[i].version) {
parts[numparts++] = glslversions[i].header;
break;
}
- if(glslversion >= 130)
- {
+ if(glslversion >= 130) {
if(type == GL_VERTEX_SHADER) parts[numparts++] =
"#define attribute in\n"
"#define varying out\n";
- else if(type == GL_FRAGMENT_SHADER)
- {
+ else if(type == GL_FRAGMENT_SHADER) {
parts[numparts++] = "#define varying in\n";
if(glslversion < 150) parts[numparts++] = "precision highp float;\n";
if(glversion >= 300) parts[numparts++] =
"#define textureCube(sampler, coords) texture(sampler, coords)\n";
}
parts[numparts++] = source;
-
obj = glCreateShader_(type);
glShaderSource_(obj, numparts, (const GLchar **)parts, NULL);
glCompileShader_(obj);
GLint success;
glGetShaderiv_(obj, GL_COMPILE_STATUS, &success);
- if(!success)
- {
+ if(!success) {
if(msg) showglslinfo(type, obj, name, parts, numparts);
glDeleteShader_(obj);
obj = 0;
}
}
-static void bindglsluniform(Shader &s, UniformLoc &u)
-{
+static void bindglsluniform(Shader &s, UniformLoc &u) {
u.loc = glGetUniformLocation_(s.program, u.name);
if(!u.blockname || !hasUBO) return;
GLuint bidx = glGetUniformBlockIndex_(s.program, u.blockname);
GLuint uidx = GL_INVALID_INDEX;
glGetUniformIndices_(s.program, 1, &u.name, &uidx);
- if(bidx != GL_INVALID_INDEX && uidx != GL_INVALID_INDEX)
- {
+ if(bidx != GL_INVALID_INDEX && uidx != GL_INVALID_INDEX) {
GLint sizeval = 0, offsetval = 0, strideval = 0;
glGetActiveUniformBlockiv_(s.program, bidx, GL_UNIFORM_BLOCK_DATA_SIZE, &sizeval);
if(sizeval <= 0) return;
glGetActiveUniformsiv_(s.program, 1, &uidx, GL_UNIFORM_OFFSET, &offsetval);
- if(u.stride > 0)
- {
+ if(u.stride > 0) {
glGetActiveUniformsiv_(s.program, 1, &uidx, GL_UNIFORM_ARRAY_STRIDE, &strideval);
if(strideval > u.stride) return;
}
}
}
-static void linkglslprogram(Shader &s, bool msg = true)
-{
+static void linkglslprogram(Shader &s, bool msg = true) {
s.program = s.vsobj && s.psobj ? glCreateProgram_() : 0;
GLint success = 0;
- if(s.program)
- {
+ if(s.program) {
glAttachShader_(s.program, s.vsobj);
glAttachShader_(s.program, s.psobj);
uint attribs = 0;
- loopv(s.attriblocs)
- {
+ loopv(s.attriblocs) {
AttribLoc &a = s.attriblocs[i];
glBindAttribLocation_(s.program, a.loc, a.name);
attribs |= 1<<a.loc;
}
loopi(gle::MAXATTRIBS) if(!(attribs&(1<<i))) glBindAttribLocation_(s.program, i, gle::attribnames[i]);
- if(glversion >= 300)
- {
+ if(glversion >= 300) {
glBindFragDataLocation_(s.program, 0, "cube2_FragColor");
}
glLinkProgram_(s.program);
glGetProgramiv_(s.program, GL_LINK_STATUS, &success);
}
- if(success)
- {
+ if(success) {
glUseProgram_(s.program);
- loopi(8)
- {
+ loopi(8) {
static const char * const texnames[8] = { "tex0", "tex1", "tex2", "tex3", "tex4", "tex5", "tex6", "tex7" };
GLint loc = glGetUniformLocation_(s.program, texnames[i]);
if(loc != -1) glUniform1i_(loc, i);
}
- loopv(s.defaultparams)
- {
+ loopv(s.defaultparams) {
SlotShaderParamState ¶m = s.defaultparams[i];
param.loc = glGetUniformLocation_(s.program, param.name);
}
loopv(s.uniformlocs) bindglsluniform(s, s.uniformlocs[i]);
glUseProgram_(0);
}
- else if(s.program)
- {
+ else if(s.program) {
if(msg) showglslinfo(GL_FALSE, s.program, s.name);
glDeleteProgram_(s.program);
s.program = 0;
}
}
-int getlocalparam(const char *name)
-{
+int getlocalparam(const char *name) {
return localparams.access(name, int(localparams.numelems));
}
-static int addlocalparam(Shader &s, const char *name, int loc, int size, GLenum format)
-{
+static int addlocalparam(Shader &s, const char *name, int loc, int size, GLenum format) {
int idx = getlocalparam(name);
- if(idx >= s.localparamremap.length())
- {
+ if(idx >= s.localparamremap.length()) {
int n = idx + 1 - s.localparamremap.length();
memset(s.localparamremap.pad(n), 0xFF, n);
}
s.localparamremap[idx] = s.localparams.length();
-
LocalShaderParamState &l = s.localparams.add();
l.name = name;
l.loc = loc;
return idx;
}
-GlobalShaderParamState *getglobalparam(const char *name)
-{
+GlobalShaderParamState *getglobalparam(const char *name) {
GlobalShaderParamState *param = globalparams.access(name);
- if(!param)
- {
+ if(!param) {
param = &globalparams[name];
param->name = name;
memset(param->buf, -1, sizeof(param->buf));
return param;
}
-static GlobalShaderParamUse *addglobalparam(Shader &s, GlobalShaderParamState *param, int loc, int size, GLenum format)
-{
+static GlobalShaderParamUse *addglobalparam(Shader &s, GlobalShaderParamState *param, int loc, int size, GLenum format) {
GlobalShaderParamUse &g = s.globalparams.add();
g.param = param;
g.version = -2;
return &g;
}
-static void setglsluniformformat(Shader &s, const char *name, GLenum format, int size)
-{
- switch(format)
- {
+static void setglsluniformformat(Shader &s, const char *name, GLenum format, int size) {
+ switch(format) {
case GL_FLOAT:
case GL_FLOAT_VEC2:
case GL_FLOAT_VEC3:
return;
}
if(!strncmp(name, "gl_", 3)) return;
-
int loc = glGetUniformLocation_(s.program, name);
if(loc < 0) return;
- loopvj(s.defaultparams) if(s.defaultparams[j].loc == loc)
- {
+ loopvj(s.defaultparams) if(s.defaultparams[j].loc == loc) {
s.defaultparams[j].format = format;
return;
}
loopvj(s.uniformlocs) if(s.uniformlocs[j].loc == loc) return;
loopvj(s.globalparams) if(s.globalparams[j].loc == loc) return;
loopvj(s.localparams) if(s.localparams[j].loc == loc) return;
-
name = getshaderparamname(name);
GlobalShaderParamState *param = globalparams.access(name);
if(param) addglobalparam(s, param, loc, size, format);
else addlocalparam(s, name, loc, size, format);
}
-static void allocglslactiveuniforms(Shader &s)
-{
+static void allocglslactiveuniforms(Shader &s) {
GLint numactive = 0;
glGetProgramiv_(s.program, GL_ACTIVE_UNIFORMS, &numactive);
string name;
- loopi(numactive)
- {
+ loopi(numactive) {
GLsizei namelen = 0;
GLint size = 0;
GLenum format = GL_FLOAT_VEC4;
}
}
-void Shader::allocparams(Slot *slot)
-{
- if(slot)
- {
-#define UNIFORMTEX(name, tmu) \
- { \
+void Shader::allocparams(Slot *slot) {
+ if(slot) {
+#define UNIFORMTEX(name, tmu) { \
+ \
loc = glGetUniformLocation_(program, name); \
int val = tmu; \
if(loc != -1) glUniform1i_(loc, val); \
}
int loc, tmu = 2;
- if(type & SHADER_NORMALSLMS)
- {
+ if(type & SHADER_NORMALSLMS) {
UNIFORMTEX("lmcolor", 1);
UNIFORMTEX("lmdir", 2);
tmu++;
else UNIFORMTEX("lightmap", 1);
UNIFORMTEX("shadowmap", 7);
int stex = 0;
- loopv(slot->sts)
- {
+ loopv(slot->sts) {
Slot::Tex &t = slot->sts[i];
- switch(t.type)
- {
+ switch(t.type) {
case TEX_DIFFUSE: UNIFORMTEX("diffusemap", 0); break;
case TEX_NORMAL: UNIFORMTEX("normalmap", tmu++); break;
case TEX_DECAL: UNIFORMTEX("decal", tmu++); break;
case TEX_SPEC: if(t.combined<0) UNIFORMTEX("specmap", tmu++); break;
case TEX_DEPTH: if(t.combined<0) UNIFORMTEX("depthmap", tmu++); break;
case TEX_ALPHA: if(t.combined<0) UNIFORMTEX("alphamap", tmu++); break;
- case TEX_UNKNOWN:
- {
+ case TEX_UNKNOWN: {
defformatstring(sname, "stex%d", stex++);
UNIFORMTEX(sname, tmu++);
break;
int GlobalShaderParamState::nextversion = 0;
-void GlobalShaderParamState::resetversions()
-{
- enumerate(shaders, Shader, s,
- {
- loopv(s.globalparams)
- {
+void GlobalShaderParamState::resetversions() {
+ enumerate(shaders, Shader, s, {
+ loopv(s.globalparams) {
GlobalShaderParamUse &u = s.globalparams[i];
if(u.version != u.param->version) u.version = -2;
}
});
nextversion = 0;
enumerate(globalparams, GlobalShaderParamState, g, { g.version = ++nextversion; });
- enumerate(shaders, Shader, s,
- {
- loopv(s.globalparams)
- {
+ enumerate(shaders, Shader, s, {
+ loopv(s.globalparams) {
GlobalShaderParamUse &u = s.globalparams[i];
if(u.version >= 0) u.version = u.param->version;
}
});
}
-static inline void setslotparam(SlotShaderParamState &l, const float *val)
-{
- switch(l.format)
- {
+static inline void setslotparam(SlotShaderParamState &l, const float *val) {
+ switch(l.format) {
case GL_BOOL:
case GL_FLOAT: glUniform1fv_(l.loc, 1, val); break;
case GL_BOOL_VEC2:
} while(0)
#define SETSLOTPARAMS(slotparams) \
- loopv(slotparams) \
- { \
+ loopv(slotparams) { \
+ \
SlotShaderParam &p = slotparams[i]; \
if(!defaultparams.inrange(p.loc)) continue; \
SlotShaderParamState &l = defaultparams[p.loc]; \
SETSLOTPARAM(l, unimask, p.loc, p.val); \
}
#define SETDEFAULTPARAMS \
- loopv(defaultparams) \
- { \
+ loopv(defaultparams) { \
+ \
SlotShaderParamState &l = defaultparams[i]; \
SETSLOTPARAM(l, unimask, i, l.val); \
}
-void Shader::setslotparams(Slot &slot)
-{
+void Shader::setslotparams(Slot &slot) {
uint unimask = 0;
SETSLOTPARAMS(slot.params)
SETDEFAULTPARAMS
}
-void Shader::setslotparams(Slot &slot, VSlot &vslot)
-{
+void Shader::setslotparams(Slot &slot, VSlot &vslot) {
uint unimask = 0;
- if(vslot.slot == &slot)
- {
+ if(vslot.slot == &slot) {
SETSLOTPARAMS(vslot.params)
SETSLOTPARAMS(slot.params)
SETDEFAULTPARAMS
}
- else
- {
+ else {
SETSLOTPARAMS(slot.params)
SETDEFAULTPARAMS
}
}
-void Shader::bindprograms()
-{
+void Shader::bindprograms() {
if(this == lastshader || type&(SHADER_DEFERRED|SHADER_INVALID)) return;
glUseProgram_(program);
lastshader = this;
}
-bool Shader::compile()
-{
+bool Shader::compile() {
if(!vsstr) vsobj = !reusevs || reusevs->invalid() ? 0 : reusevs->vsobj;
else compileglslshader(GL_VERTEX_SHADER, vsobj, vsstr, name, !variantshader);
if(!psstr) psobj = !reuseps || reuseps->invalid() ? 0 : reuseps->psobj;
return program!=0;
}
-void Shader::cleanup(bool invalid)
-{
+void Shader::cleanup(bool invalid) {
detailshader = NULL;
used = false;
if(vsobj) { if(!reusevs) glDeleteShader_(vsobj); vsobj = 0; }
localparams.setsize(0);
localparamremap.setsize(0);
globalparams.setsize(0);
- if(standard || invalid)
- {
+ if(standard || invalid) {
type = SHADER_INVALID;
DELETEA(vsstr);
DELETEA(psstr);
bool Shader::isnull(const Shader *s) { return !s; }
-static void genattriblocs(Shader &s, const char *vs, const char *ps, Shader *reusevs, Shader *reuseps)
-{
+static void genattriblocs(Shader &s, const char *vs, const char *ps, Shader *reusevs, Shader *reuseps) {
static int len = strlen("//:attrib");
string name;
int loc;
if(reusevs) s.attriblocs = reusevs->attriblocs;
- else while((vs = strstr(vs, "//:attrib")))
- {
+ else while((vs = strstr(vs, "//:attrib"))) {
if(sscanf(vs, "//:attrib %100s %d", name, &loc) == 2)
s.attriblocs.add(AttribLoc(getshaderparamname(name), loc));
vs += len;
}
}
-static void genuniformlocs(Shader &s, const char *vs, const char *ps, Shader *reusevs, Shader *reuseps)
-{
+static void genuniformlocs(Shader &s, const char *vs, const char *ps, Shader *reusevs, Shader *reuseps) {
static int len = strlen("//:uniform");
string name, blockname;
int binding, stride;
if(reusevs) s.uniformlocs = reusevs->uniformlocs;
- else while((vs = strstr(vs, "//:uniform")))
- {
+ else while((vs = strstr(vs, "//:uniform"))) {
int numargs = sscanf(vs, "//:uniform %100s %100s %d %d", name, blockname, &binding, &stride);
if(numargs >= 3) s.uniformlocs.add(UniformLoc(getshaderparamname(name), getshaderparamname(blockname), binding, numargs >= 4 ? stride : 0));
else if(numargs >= 1) s.uniformlocs.add(UniformLoc(getshaderparamname(name)));
}
}
-Shader *newshader(int type, const char *name, const char *vs, const char *ps, Shader *variant = NULL, int row = 0)
-{
- if(Shader::lastshader)
- {
+Shader *newshader(int type, const char *name, const char *vs, const char *ps, Shader *variant = NULL, int row = 0) {
+ if(Shader::lastshader) {
glUseProgram_(0);
Shader::lastshader = NULL;
}
-
Shader *exists = shaders.access(name);
char *rname = exists ? exists->name : newstring(name);
Shader &s = shaders[rname];
s.standard = standardshaders;
if(forceshaders) s.forced = true;
s.reusevs = s.reuseps = NULL;
- if(variant)
- {
+ if(variant) {
int row = 0, col = 0;
- if(!vs[0] || sscanf(vs, "%d , %d", &row, &col) >= 1)
- {
+ if(!vs[0] || sscanf(vs, "%d , %d", &row, &col) >= 1) {
DELETEA(s.vsstr);
s.reusevs = !vs[0] ? variant : variant->getvariant(col, row);
}
row = col = 0;
- if(!ps[0] || sscanf(ps, "%d , %d", &row, &col) >= 1)
- {
+ if(!ps[0] || sscanf(ps, "%d , %d", &row, &col) >= 1) {
DELETEA(s.psstr);
s.reuseps = !ps[0] ? variant : variant->getvariant(col, row);
}
s.uniformlocs.setsize(0);
genattriblocs(s, vs, ps, s.reusevs, s.reuseps);
genuniformlocs(s, vs, ps, s.reusevs, s.reuseps);
- if(!s.compile())
- {
+ if(!s.compile()) {
s.cleanup(true);
if(variant) shaders.remove(rname);
return NULL;
return &s;
}
-void setupshaders()
-{
+void setupshaders() {
GLint val;
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &val);
maxvsuniforms = val/4;
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &val);
maxfsuniforms = val/4;
- if(glversion < 300)
- {
+ if(glversion < 300) {
glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &val);
maxvaryings = val;
}
-
standardshaders = true;
nullshader = newshader(0, "<init>null",
"attribute vec4 vvertex;\n"
" gl_FragColor = color;\n"
"}\n");
standardshaders = false;
-
if(!nullshader || !hudshader || !hudnotextureshader) fatal("failed to setup shaders");
-
dummyslot.shader = nullshader;
}
-static const char *findglslmain(const char *s)
-{
+static const char *findglslmain(const char *s) {
const char *main = strstr(s, "main");
if(!main) return NULL;
for(; main >= s; main--) switch(*main) { case '\r': case '\n': case ';': return main + 1; }
return s;
}
-static void gengenericvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0)
-{
+static void gengenericvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0) {
int rowoffset = 0;
bool vschanged = false, pschanged = false;
vector<char> vsv, psv;
vsv.put(vs, strlen(vs)+1);
psv.put(ps, strlen(ps)+1);
-
static const int len = strlen("//:variant"), olen = strlen("override");
- for(char *vspragma = vsv.getbuf();; vschanged = true)
- {
+ for(char *vspragma = vsv.getbuf();; vschanged = true) {
vspragma = strstr(vspragma, "//:variant");
if(!vspragma) break;
if(sscanf(vspragma + len, "row %d", &rowoffset) == 1) continue;
memset(vspragma, ' ', len);
vspragma += len;
- if(!strncmp(vspragma, "override", olen))
- {
+ if(!strncmp(vspragma, "override", olen)) {
memset(vspragma, ' ', olen);
vspragma += olen;
char *end = vspragma + strcspn(vspragma, "\n\r");
memset(end, ' ', endlen);
}
}
- for(char *pspragma = psv.getbuf();; pschanged = true)
- {
+ for(char *pspragma = psv.getbuf();; pschanged = true) {
pspragma = strstr(pspragma, "//:variant");
if(!pspragma) break;
if(sscanf(pspragma + len, "row %d", &rowoffset) == 1) continue;
memset(pspragma, ' ', len);
pspragma += len;
- if(!strncmp(pspragma, "override", olen))
- {
+ if(!strncmp(pspragma, "override", olen)) {
memset(pspragma, ' ', olen);
pspragma += olen;
char *end = pspragma + strcspn(pspragma, "\n\r");
bool minimizedynlighttcusage() { return glversion < 300 && maxvaryings < 48; }
-static void gendynlightvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0)
-{
+static void gendynlightvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0) {
int numlights = minimizedynlighttcusage() ? 1 : MAXDYNLIGHTS;
-
const char *vspragma = strstr(vs, "//:dynlight"), *pspragma = strstr(ps, "//:dynlight");
if(!vspragma || !pspragma) return;
-
string pslight;
vspragma += strcspn(vspragma, "\n");
if(*vspragma) vspragma++;
-
if(sscanf(pspragma, "//:dynlight %100s", pslight)!=1) return;
-
pspragma += strcspn(pspragma, "\n");
if(*pspragma) pspragma++;
-
const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps);
if(vsmain > vspragma) vsmain = vs;
if(psmain > pspragma) psmain = ps;
-
vector<char> vsdl, psdl;
- loopi(MAXDYNLIGHTS)
- {
+ loopi(MAXDYNLIGHTS) {
vsdl.setsize(0);
psdl.setsize(0);
if(vsmain >= vs) vsdl.put(vs, vsmain - vs);
if(psmain >= ps) psdl.put(ps, psmain - ps);
-
defformatstring(pos, "uniform vec4 dynlightpos[%d];\n", i+1);
vsdl.put(pos, strlen(pos));
psdl.put(pos, strlen(pos));
defformatstring(color, "uniform vec3 dynlightcolor[%d];\n", i+1);
psdl.put(color, strlen(color));
-
- loopk(min(i+1, numlights))
- {
+ loopk(min(i+1, numlights)) {
defformatstring(dir, "%sdynlight%ddir%s", !k ? "varying vec3 " : " ", k, k==i || k+1==numlights ? ";\n" : ",");
vsdl.put(dir, strlen(dir));
psdl.put(dir, strlen(dir));
}
-
vsdl.put(vsmain, vspragma-vsmain);
psdl.put(psmain, pspragma-psmain);
-
- loopk(i+1)
- {
+ loopk(i+1) {
defformatstring(tc,
k<numlights ?
"dynlight%ddir = vvertex.xyz*dynlightpos[%d].w + dynlightpos[%d].xyz;\n" :
k, k, k);
if(k < numlights) vsdl.put(tc, strlen(tc));
else psdl.put(tc, strlen(tc));
-
defformatstring(dl,
"%s.rgb += dynlightcolor[%d] * (1.0 - clamp(dot(dynlight%ddir, dynlight%ddir), 0.0, 1.0));\n",
pslight, k, k, k);
psdl.put(dl, strlen(dl));
}
-
vsdl.put(vspragma, strlen(vspragma)+1);
psdl.put(pspragma, strlen(pspragma)+1);
-
defformatstring(name, "<dynlight %d>%s", i+1, sname);
Shader *variant = newshader(s.type, name, vsdl.getbuf(), psdl.getbuf(), &s, row);
if(!variant) return;
}
}
-static void genshadowmapvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 1)
-{
+static void genshadowmapvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 1) {
const char *vspragma = strstr(vs, "//:shadowmap"), *pspragma = strstr(ps, "//:shadowmap");
if(!vspragma || !pspragma) return;
-
string pslight;
vspragma += strcspn(vspragma, "\n");
if(*vspragma) vspragma++;
-
if(sscanf(pspragma, "//:shadowmap %100s", pslight)!=1) return;
-
pspragma += strcspn(pspragma, "\n");
if(*pspragma) pspragma++;
-
const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps);
if(vsmain > vspragma) vsmain = vs;
if(psmain > pspragma) psmain = ps;
-
vector<char> vssm, pssm;
if(vsmain >= vs) vssm.put(vs, vsmain - vs);
if(psmain >= ps) pssm.put(ps, psmain - ps);
-
const char *vsdecl =
"uniform mat4 shadowmapproject;\n"
"varying vec3 shadowmaptc;\n";
vssm.put(vsdecl, strlen(vsdecl));
-
const char *psdecl =
"uniform sampler2D shadowmap;\n"
"uniform vec4 shadowmapambient;\n"
"varying vec3 shadowmaptc;\n";
pssm.put(psdecl, strlen(psdecl));
-
vssm.put(vsmain, vspragma-vsmain);
pssm.put(psmain, pspragma-psmain);
-
extern int smoothshadowmappeel;
const char *tcgen =
"shadowmaptc = vec3(shadowmapproject * vvertex);\n";
"vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n"
"vec2 smdiff = clamp(smvals.xz - shadowmaptc.zz*smvals.y, 0.0, 1.0);\n"
"float shadowed = clamp((smdiff.x > 0.0 ? smvals.w : 0.0) - 8.0*smdiff.y, 0.0, 1.0);\n" :
-
"vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n"
"float smtest = shadowmaptc.z*smvals.y;\n"
"float shadowed = smtest < smvals.x && smtest > smvals.z ? smvals.w : 0.0;\n";
"%s.rgb -= shadowed*clamp(%s.rgb - shadowmapambient.rgb, 0.0, 1.0);\n",
pslight, pslight);
pssm.put(smlight, strlen(smlight));
-
vssm.put(vspragma, strlen(vspragma)+1);
pssm.put(pspragma, strlen(pspragma)+1);
-
defformatstring(name, "<shadowmap>%s", sname);
Shader *variant = newshader(s.type, name, vssm.getbuf(), pssm.getbuf(), &s, row);
if(!variant) return;
-
if(strstr(vs, "//:dynlight")) gendynlightvariant(s, name, vssm.getbuf(), pssm.getbuf(), row);
}
-static void genuniformdefs(vector<char> &vsbuf, vector<char> &psbuf, const char *vs, const char *ps, Shader *variant = NULL)
-{
+static void genuniformdefs(vector<char> &vsbuf, vector<char> &psbuf, const char *vs, const char *ps, Shader *variant = NULL) {
if(variant ? variant->defaultparams.empty() : slotparams.empty()) return;
const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps);
if(!vsmain || !psmain) return;
vsbuf.put(vs, vsmain - vs);
psbuf.put(ps, psmain - ps);
- if(variant) loopv(variant->defaultparams)
- {
+ if(variant) loopv(variant->defaultparams) {
defformatstring(uni, "\nuniform vec4 %s;\n", variant->defaultparams[i].name);
vsbuf.put(uni, strlen(uni));
psbuf.put(uni, strlen(uni));
}
- else loopv(slotparams)
- {
+ else loopv(slotparams) {
defformatstring(uni, "\nuniform vec4 %s;\n", slotparams[i].name);
vsbuf.put(uni, strlen(uni));
psbuf.put(uni, strlen(uni));
VAR(defershaders, 0, 1, 1);
-void defershader(int *type, const char *name, const char *contents)
-{
+void defershader(int *type, const char *name, const char *contents) {
Shader *exists = shaders.access(name);
if(exists && !exists->invalid()) return;
if(!defershaders) { execute(contents); return; }
s.standard = standardshaders;
}
-void Shader::force()
-{
+void Shader::force() {
if(!deferred() || !defer) return;
-
char *cmd = defer;
defer = NULL;
bool wasstandard = standardshaders, wasforcing = forceshaders;
forceshaders = wasforcing;
standardshaders = wasstandard;
delete[] cmd;
-
- if(deferred())
- {
+ if(deferred()) {
DELETEA(defer);
type = SHADER_INVALID;
}
}
-void fixshaderdetail()
-{
+void fixshaderdetail() {
// must null out separately because fixdetailshader can recursively set it
enumerate(shaders, Shader, s, { if(!s.forced) s.detailshader = NULL; });
enumerate(shaders, Shader, s, { if(s.forced) s.fixdetailshader(); });
linkslotshaders();
}
-int Shader::uniformlocversion()
-{
+int Shader::uniformlocversion() {
static int version = 0;
if(++version >= 0) return version;
version = 0;
VARFP(shaderdetail, 0, MAXSHADERDETAIL, MAXSHADERDETAIL, fixshaderdetail());
-void Shader::fixdetailshader(bool shouldforce, bool recurse)
-{
+void Shader::fixdetailshader(bool shouldforce, bool recurse) {
Shader *alt = this;
detailshader = NULL;
- do
- {
+ do {
Shader *cur = shaderdetail < MAXSHADERDETAIL ? alt->fastshader[shaderdetail] : alt;
if(cur->deferred() && shouldforce) cur->force();
- if(!cur->invalid())
- {
+ if(!cur->invalid()) {
if(cur->deferred()) break;
detailshader = cur;
break;
}
alt = alt->altshader;
} while(alt && alt!=this);
-
if(recurse && detailshader) loopv(detailshader->variants) detailshader->variants[i]->fixdetailshader(shouldforce, false);
}
-Shader *useshaderbyname(const char *name)
-{
+Shader *useshaderbyname(const char *name) {
Shader *s = shaders.access(name);
if(!s) return NULL;
if(!s->detailshader) s->fixdetailshader();
return s;
}
-void shader(int *type, char *name, char *vs, char *ps)
-{
+void shader(int *type, char *name, char *vs, char *ps) {
if(lookupshaderbyname(name)) return;
-
defformatstring(info, "shader %s", name);
renderprogress(loadprogress, info);
-
vector<char> vsbuf, psbuf, vsbak, psbak;
#define GENSHADER(cond, body) \
- if(cond) \
- { \
+ if(cond) { \
+ \
if(vsbuf.length()) { vsbak.setsize(0); vsbak.put(vs, strlen(vs)+1); vs = vsbak.getbuf(); vsbuf.setsize(0); } \
if(psbuf.length()) { psbak.setsize(0); psbak.put(ps, strlen(ps)+1); ps = psbak.getbuf(); psbuf.setsize(0); } \
body; \
}
GENSHADER(slotparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps));
Shader *s = newshader(*type, name, vs, ps);
- if(s)
- {
+ if(s) {
if(strstr(vs, "//:shadowmap")) genshadowmapvariant(*s, s->name, vs, ps);
if(strstr(vs, "//:dynlight")) gendynlightvariant(*s, s->name, vs, ps);
}
slotparams.shrink(0);
}
-void variantshader(int *type, char *name, int *row, char *vs, char *ps)
-{
- if(*row < 0)
- {
+void variantshader(int *type, char *name, int *row, char *vs, char *ps) {
+ if(*row < 0) {
shader(type, name, vs, ps);
return;
}
else if(*row >= MAXVARIANTROWS) return;
-
Shader *s = lookupshaderbyname(name);
if(!s) return;
-
defformatstring(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name);
//defformatstring(info, "shader %s", varname);
//renderprogress(loadprogress, info);
vector<char> vsbuf, psbuf, vsbak, psbak;
GENSHADER(s->defaultparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps, s));
Shader *v = newshader(*type, varname, vs, ps, s, *row);
- if(v)
- {
+ if(v) {
if(strstr(vs, "//:dynlight")) gendynlightvariant(*s, varname, vs, ps, *row);
if(strstr(ps, "//:variant") || strstr(vs, "//:variant")) gengenericvariant(*s, varname, vs, ps, *row);
}
}
-void setshader(char *name)
-{
+void setshader(char *name) {
slotparams.shrink(0);
Shader *s = shaders.access(name);
- if(!s)
- {
+ if(!s) {
conoutf(CON_ERROR, "no such shader: %s", name);
}
else slotshader = s;
}
-void resetslotshader()
-{
+void resetslotshader() {
slotshader = NULL;
slotparams.shrink(0);
}
-void setslotshader(Slot &s)
-{
+void setslotshader(Slot &s) {
s.shader = slotshader;
- if(!s.shader)
- {
+ if(!s.shader) {
s.shader = stdworldshader;
return;
}
loopv(slotparams) s.params.add(slotparams[i]);
}
-static void linkslotshaderparams(vector<SlotShaderParam> ¶ms, Shader *sh, bool load)
-{
- if(sh) loopv(params)
- {
+static void linkslotshaderparams(vector<SlotShaderParam> ¶ms, Shader *sh, bool load) {
+ if(sh) loopv(params) {
int loc = -1;
SlotShaderParam ¶m = params[i];
- loopv(sh->defaultparams)
- {
+ loopv(sh->defaultparams) {
SlotShaderParamState &dparam = sh->defaultparams[i];
- if(dparam.name==param.name)
- {
+ if(dparam.name==param.name) {
if(memcmp(param.val, dparam.val, sizeof(param.val))) loc = i;
break;
}
else if(load) loopv(params) params[i].loc = -1;
}
-void linkslotshader(Slot &s, bool load)
-{
+void linkslotshader(Slot &s, bool load) {
if(!s.shader) return;
-
if(load && !s.shader->detailshader) s.shader->fixdetailshader();
-
linkslotshaderparams(s.params, s.shader->detailshader, load);
}
-void linkvslotshader(VSlot &s, bool load)
-{
+void linkvslotshader(VSlot &s, bool load) {
if(!s.slot->shader) return;
-
Shader *sh = s.slot->shader->detailshader;
linkslotshaderparams(s.params, sh, load);
-
if(!sh) return;
}
-void altshader(char *origname, char *altname)
-{
+void altshader(char *origname, char *altname) {
Shader *orig = shaders.access(origname), *alt = shaders.access(altname);
if(!orig || !alt) return;
orig->altshader = alt;
orig->fixdetailshader(false);
}
-void fastshader(char *nice, char *fast, int *detail)
-{
+void fastshader(char *nice, char *fast, int *detail) {
Shader *ns = shaders.access(nice), *fs = shaders.access(fast);
if(!ns || !fs) return;
loopi(min(*detail+1, MAXSHADERDETAIL)) ns->fastshader[i] = fs;
static hashset<const char *> shaderparamnames(256);
-const char *getshaderparamname(const char *name, bool insert)
-{
+const char *getshaderparamname(const char *name, bool insert) {
const char *exists = shaderparamnames.find(name, NULL);
if(exists || !insert) return exists;
return shaderparamnames.add(newstring(name));
}
-void addslotparam(const char *name, float x, float y, float z, float w)
-{
+void addslotparam(const char *name, float x, float y, float z, float w) {
if(name) name = getshaderparamname(name);
- loopv(slotparams)
- {
+ loopv(slotparams) {
SlotShaderParam ¶m = slotparams[i];
- if(param.name==name)
- {
+ if(param.name==name) {
param.val[0] = x;
param.val[1] = y;
param.val[2] = z;
ICOMMAND(setshaderparam, "sffff", (char *name, float *x, float *y, float *z, float *w), addslotparam(name, *x, *y, *z, *w));
ICOMMAND(defuniformparam, "sffff", (char *name, float *x, float *y, float *z, float *w), addslotparam(name, *x, *y, *z, *w));
-void cleanupshaders()
-{
+void cleanupshaders() {
loadedshaders = false;
nullshader = hudshader = hudnotextureshader = textureshader = notextureshader = nocolorshader = stdworldshader = NULL;
enumerate(shaders, Shader, s, s.cleanup());
glUseProgram_(0);
}
-void reloadshaders()
-{
+void reloadshaders() {
identflags &= ~IDF_PERSIST;
loadshaders();
identflags |= IDF_PERSIST;
linkslotshaders();
- enumerate(shaders, Shader, s,
- {
- if(!s.standard && !(s.type&(SHADER_DEFERRED|SHADER_INVALID)) && !s.variantshader)
- {
+ enumerate(shaders, Shader, s, {
+ if(!s.standard && !(s.type&(SHADER_DEFERRED|SHADER_INVALID)) && !s.variantshader) {
defformatstring(info, "shader %s", s.name);
renderprogress(0.0, info);
if(!s.compile()) s.cleanup(true);
- loopv(s.variants)
- {
+ loopv(s.variants) {
Shader *v = s.variants[i];
if((v->reusevs && v->reusevs->invalid()) ||
(v->reuseps && v->reuseps->invalid()) ||
});
}
-void setupblurkernel(int radius, float sigma, float *weights, float *offsets)
-{
+void setupblurkernel(int radius, float sigma, float *weights, float *offsets) {
if(radius<1 || radius>MAXBLURRADIUS) return;
sigma *= 2*radius;
float total = 1.0f/sigma;
offsets[0] = 0;
// rely on bilinear filtering to sample 2 pixels at once
// transforms a*X + b*Y into (u+v)*[X*u/(u+v) + Y*(1 - u/(u+v))]
- loopi(radius)
- {
+ loopi(radius) {
float weight1 = exp(-((2*i)*(2*i)) / (2*sigma*sigma)) / sigma,
weight2 = exp(-((2*i+1)*(2*i+1)) / (2*sigma*sigma)) / sigma,
scale = weight1 + weight2,
for(int i = radius+1; i <= MAXBLURRADIUS; i++) weights[i] = offsets[i] = 0;
}
-void setblurshader(int pass, int size, int radius, float *weights, float *offsets)
-{
+void setblurshader(int pass, int size, int radius, float *weights, float *offsets) {
if(radius<1 || radius>MAXBLURRADIUS) return;
static Shader *blurshader[7][2] = { { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL } };
Shader *&s = blurshader[radius-1][pass];
- if(!s)
- {
+ if(!s) {
defformatstring(name, "blur%c%d", 'x'+pass, radius);
s = lookupshaderbyname(name);
}
VARFP(fpshadowmap, 0, 0, 1, cleanshadowmap());
VARFP(shadowmapprecision, 0, 0, 1, cleanshadowmap());
bvec shadowmapambientcolor(0, 0, 0);
-HVARFR(shadowmapambient, 0, 0, 0xFFFFFF,
-{
+HVARFR(shadowmapambient, 0, 0, 0xFFFFFF, {
if(shadowmapambient <= 255) shadowmapambient |= (shadowmapambient<<8) | (shadowmapambient<<16);
shadowmapambientcolor = bvec((shadowmapambient>>16)&0xFF, (shadowmapambient>>8)&0xFF, shadowmapambient&0xFF);
});
VAR(shadowmapcasters, 1, 0, 0);
float shadowmapmaxz = 0;
-void setshadowdir(int angle)
-{
+void setshadowdir(int angle) {
shadowdir = vec(0, SHADOWSKEW, 1);
shadowdir.rotate_around_z(angle*RAD);
}
VARFR(shadowmapangle, 0, 0, 360, setshadowdir(shadowmapangle));
-void guessshadowdir()
-{
+void guessshadowdir() {
if(shadowmapangle) return;
- vec dir;
- {
+ vec dir; {
vec lightpos(0, 0, 0), casterpos(0, 0, 0);
int numlights = 0, numcasters = 0;
const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
- switch(e.type)
- {
+ switch(e.type) {
case ET_LIGHT:
if(!e.attr1) { lightpos.add(e.o); numlights++; }
break;
-
case ET_MAPMODEL:
casterpos.add(e.o);
numcasters++;
break;
-
default:
if(e.type<ET_GAMESPECIFIC) break;
casterpos.add(e.o);
VAR(smdepthpeel, 0, 1, 1);
VAR(smoothshadowmappeel, 1, 0, 0);
-static struct shadowmaptexture : rendertarget
-{
- const GLenum *colorformats() const
- {
+static struct shadowmaptexture : rendertarget {
+ const GLenum *colorformats() const {
static const GLenum rgbafmts[] = { GL_RGBA16F, GL_RGBA16, GL_RGBA, GL_RGBA8, GL_FALSE };
return &rgbafmts[fpshadowmap && hasTF ? 0 : (shadowmapprecision ? 1 : 2)];
}
-
bool swaptexs() const { return true; }
-
- bool scissorblur(int &x, int &y, int &w, int &h)
- {
+ bool scissorblur(int &x, int &y, int &w, int &h) {
x = max(int(floor((scissorx1+1)/2*vieww)) - 2*blursize, 2);
y = max(int(floor((scissory1+1)/2*viewh)) - 2*blursize, 2);
w = min(int(ceil((scissorx2+1)/2*vieww)) + 2*blursize, vieww-2) - x;
h = min(int(ceil((scissory2+1)/2*viewh)) + 2*blursize, viewh-2) - y;
return true;
}
-
- bool scissorrender(int &x, int &y, int &w, int &h)
- {
+ bool scissorrender(int &x, int &y, int &w, int &h) {
x = y = 2;
w = vieww - 2*2;
h = viewh - 2*2;
return true;
}
-
- void doclear()
- {
+ void doclear() {
glClearColor(0, 0, 0, 0);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
-
- bool dorender()
- {
+ bool dorender() {
vec skewdir(shadowdir);
skewdir.rotate_around_z(-camera1->yaw*RAD);
-
vec dir;
vecfromyawpitch(camera1->yaw, camera1->pitch, 1, 0, dir);
dir.z = 0;
dir.mul(shadowmapradius);
-
vec dirx, diry;
vecfromyawpitch(camera1->yaw, 0, 0, 1, dirx);
vecfromyawpitch(camera1->yaw, 0, 1, 0, diry);
shadowoffset.x = -fmod(dirx.dot(camera1->o) - skewdir.x*camera1->o.z, 2.0f*shadowmapradius/vieww);
shadowoffset.y = -fmod(diry.dot(camera1->o) - skewdir.y*camera1->o.z, 2.0f*shadowmapradius/viewh);
-
shadowmatrix.ortho(-shadowmapradius, shadowmapradius, -shadowmapradius, shadowmapradius, -shadowmapdist, shadowmapdist);
shadowmatrix.mul(matrix3(vec(1, 0, 0), vec(0, 1, 0), vec(skewdir.x, skewdir.y, 1)));
shadowmatrix.translate(skewdir.x*shadowmapheight + shadowoffset.x, skewdir.y*shadowmapheight + shadowoffset.y + dir.magnitude(), -shadowmapheight);
shadowmatrix.rotate_around_z((camera1->yaw+180)*-RAD);
shadowmatrix.translate(vec(camera1->o).neg());
GLOBALPARAM(shadowmatrix, shadowmatrix);
-
shadowfocus = camera1->o;
shadowfocus.add(dir);
shadowfocus.add(vec(shadowdir).mul(shadowmapheight));
shadowfocus.add(dirx.mul(shadowoffset.x));
shadowfocus.add(diry.mul(shadowoffset.y));
-
gle::colorf(0, 0, 0);
-
GLOBALPARAMF(shadowmapbias, -shadowmapbias/float(shadowmapdist), 1 - (shadowmapbias + (smoothshadowmappeel ? 0 : shadowmappeelbias))/float(shadowmapdist));
-
shadowmapcasters = 0;
shadowmapmaxz = shadowfocus.z - shadowmapdist;
shadowmapping = true;
rendergame();
shadowmapping = false;
shadowmapmaxz = min(shadowmapmaxz, shadowfocus.z);
-
- if(shadowmapcasters && smdepthpeel)
- {
+ if(shadowmapcasters && smdepthpeel) {
int sx, sy, sw, sh;
bool scissoring = rtscissor && scissorblur(sx, sy, sw, sh) && sw > 0 && sh > 0;
if(scissoring) glScissor(sx, sy, sw, sh);
if(!rtscissor || scissoring) rendershadowmapreceivers();
}
-
return shadowmapcasters>0;
}
} shadowmaptex;
-void cleanshadowmap()
-{
+void cleanshadowmap() {
shadowmaptex.cleanup(true);
}
-void calcshadowmapbb(const vec &o, float xyrad, float zrad, float &x1, float &y1, float &x2, float &y2)
-{
+void calcshadowmapbb(const vec &o, float xyrad, float zrad, float &x1, float &y1, float &x2, float &y2) {
vec skewdir(shadowdir);
skewdir.rotate_around_z(-camera1->yaw*RAD);
-
vec ro(o);
ro.sub(camera1->o);
ro.rotate_around_z(-(camera1->yaw+180)*RAD);
ro.x += ro.z * skewdir.x + shadowoffset.x;
ro.y += ro.z * skewdir.y + shadowmapradius * cosf(camera1->pitch*RAD) + shadowoffset.y;
-
vec high(ro), low(ro);
high.x += zrad * skewdir.x;
high.y += zrad * skewdir.y;
low.x -= zrad * skewdir.x;
low.y -= zrad * skewdir.y;
-
x1 = (min(high.x, low.x) - xyrad) / shadowmapradius;
y1 = (min(high.y, low.y) - xyrad) / shadowmapradius;
x2 = (max(high.x, low.x) + xyrad) / shadowmapradius;
y2 = (max(high.y, low.y) + xyrad) / shadowmapradius;
}
-bool addshadowmapcaster(const vec &o, float xyrad, float zrad)
-{
+bool addshadowmapcaster(const vec &o, float xyrad, float zrad) {
if(o.z + zrad <= shadowfocus.z - shadowmapdist || o.z - zrad >= shadowfocus.z) return false;
-
shadowmapmaxz = max(shadowmapmaxz, o.z + zrad);
-
float x1, y1, x2, y2;
calcshadowmapbb(o, xyrad, zrad, x1, y1, x2, y2);
-
if(!shadowmaptex.addblurtiles(x1, y1, x2, y2, 2)) return false;
-
shadowmapcasters++;
return true;
}
-bool isshadowmapreceiver(vtxarray *va)
-{
+bool isshadowmapreceiver(vtxarray *va) {
if(!shadowmap || !shadowmapcasters) return false;
-
if(va->shadowmapmax.z <= shadowfocus.z - shadowmapdist || va->shadowmapmin.z >= shadowmapmaxz) return false;
-
float xyrad = SQRT2*0.5f*max(va->shadowmapmax.x-va->shadowmapmin.x, va->shadowmapmax.y-va->shadowmapmin.y),
zrad = 0.5f*(va->shadowmapmax.z-va->shadowmapmin.z),
x1, y1, x2, y2;
if(xyrad<0 || zrad<0) return false;
-
vec center = vec(va->shadowmapmin).add(vec(va->shadowmapmax)).mul(0.5f);
calcshadowmapbb(center, xyrad, zrad, x1, y1, x2, y2);
-
return shadowmaptex.checkblurtiles(x1, y1, x2, y2, 2);
#if 0
#endif
}
-bool isshadowmapcaster(const vec &o, float rad)
-{
+bool isshadowmapcaster(const vec &o, float rad) {
// cheaper inexact test
float dz = o.z - shadowfocus.z;
float cx = shadowfocus.x + dz*shadowdir.x, cy = shadowfocus.y + dz*shadowdir.y;
return true;
}
-void pushshadowmap()
-{
+void pushshadowmap() {
if(!shadowmap || !shadowmaptex.rendertex) return;
-
glActiveTexture_(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, shadowmaptex.rendertex);
-
matrix4 m = shadowmatrix;
m.projective(-1, 1-shadowmapbias/float(shadowmapdist));
GLOBALPARAM(shadowmapproject, m);
-
glActiveTexture_(GL_TEXTURE0);
-
float r, g, b;
- if(!shadowmapambient)
- {
+ if(!shadowmapambient) {
r = max(25.0f, 2.0f*ambientcolor[0]);
g = max(25.0f, 2.0f*ambientcolor[1]);
b = max(25.0f, 2.0f*ambientcolor[2]);
GLOBALPARAMF(shadowmapambient, r/255.0f, g/255.0f, b/255.0f);
}
-void popshadowmap()
-{
- if(!shadowmap || !shadowmaptex.rendertex) return;
-}
-
-void rendershadowmap()
-{
+void rendershadowmap() {
if(!shadowmap) return;
-
shadowmaptex.render(1<<shadowmapsize, 1<<shadowmapsize, blurshadowmap, blursmsigma/100.0f);
}
#define BONEMASK_END 0xFFFF
#define BONEMASK_BONE 0x7FFF
-struct skelmodel : animmodel
-{
+struct skelmodel : animmodel {
struct vert { vec pos, norm; vec2 tc; int blend, interpindex; };
struct vvert { vec pos; vec2 tc; };
struct vvertn : vvert { vec norm; };
struct vvertbumpw : vvertbump, vvertw {};
struct bumpvert { quat tangent; };
struct tri { ushort vert[3]; };
-
- struct blendcombo
- {
+ struct blendcombo {
int uses, interpindex;
float weights[4];
uchar bones[4], interpbones[4];
-
- blendcombo() : uses(1)
- {
+ blendcombo() : uses(1) {
}
-
- bool operator==(const blendcombo &c) const
- {
+ bool operator==(const blendcombo &c) const {
loopk(4) if(bones[k] != c.bones[k]) return false;
loopk(4) if(weights[k] != c.weights[k]) return false;
return true;
}
-
- int size() const
- {
+ int size() const {
int i = 1;
while(i < 4 && weights[i]) i++;
return i;
}
-
- static bool sortcmp(const blendcombo &x, const blendcombo &y)
- {
- loopi(4)
- {
- if(x.weights[i])
- {
+ static bool sortcmp(const blendcombo &x, const blendcombo &y) {
+ loopi(4) {
+ if(x.weights[i]) {
if(!y.weights[i]) return true;
}
else if(y.weights[i]) return false;
}
return false;
}
-
- int addweight(int sorted, float weight, int bone)
- {
+ int addweight(int sorted, float weight, int bone) {
if(weight <= 1e-3f) return sorted;
- loopk(sorted) if(weight > weights[k])
- {
- for(int l = min(sorted-1, 2); l >= k; l--)
- {
+ loopk(sorted) if(weight > weights[k]) {
+ for(int l = min(sorted-1, 2); l >= k; l--) {
weights[l+1] = weights[l];
bones[l+1] = bones[l];
}
bones[sorted] = bone;
return sorted+1;
}
-
- void finalize(int sorted)
- {
+ void finalize(int sorted) {
loopj(4-sorted) { weights[sorted+j] = 0; bones[sorted+j] = 0; }
if(sorted <= 0) return;
float total = 0;
total = 1.0f/total;
loopj(sorted) weights[j] *= total;
}
-
- void serialize(vvertw &v)
- {
- if(interpindex >= 0)
- {
+ void serialize(vvertw &v) {
+ if(interpindex >= 0) {
v.weights[0] = 255;
loopk(3) v.weights[k+1] = 0;
v.bones[0] = 2*interpindex;
loopk(3) v.bones[k+1] = v.bones[0];
}
- else
- {
+ else {
int total = 0;
loopk(4) total += (v.weights[k] = uchar(0.5f + weights[k]*255));
- while(total > 255)
- {
+ while(total > 255) {
loopk(4) if(v.weights[k] > 0 && total > 255) { v.weights[k]--; total--; }
}
- while(total < 255)
- {
+ while(total < 255) {
loopk(4) if(v.weights[k] < 255 && total < 255) { v.weights[k]++; total++; }
}
loopk(4) v.bones[k] = 2*interpbones[k];
}
};
-
- struct animcacheentry
- {
+ struct animcacheentry {
animstate as[MAXANIMPARTS];
float pitch;
int millis;
uchar *partmask;
ragdolldata *ragdoll;
-
- animcacheentry() : ragdoll(NULL)
- {
+ animcacheentry() : ragdoll(NULL) {
loopk(MAXANIMPARTS) as[k].cur.fr1 = as[k].prev.fr1 = -1;
}
-
- bool operator==(const animcacheentry &c) const
- {
+ bool operator==(const animcacheentry &c) const {
loopi(MAXANIMPARTS) if(as[i]!=c.as[i]) return false;
return pitch==c.pitch && partmask==c.partmask && ragdoll==c.ragdoll && (!ragdoll || min(millis, c.millis) >= ragdoll->lastmove);
}
};
-
- struct vbocacheentry : animcacheentry
- {
+ struct vbocacheentry : animcacheentry {
GLuint vbuf;
int owner;
-
vbocacheentry() : vbuf(0), owner(-1) {}
};
-
- struct skelcacheentry : animcacheentry
- {
+ struct skelcacheentry : animcacheentry {
dualquat *bdata;
int version;
bool dirty;
-
skelcacheentry() : bdata(NULL), version(-1), dirty(false) {}
-
- void nextversion()
- {
+ void nextversion() {
version = Shader::uniformlocversion();
dirty = true;
}
};
-
- struct blendcacheentry : skelcacheentry
- {
+ struct blendcacheentry : skelcacheentry {
int owner;
-
blendcacheentry() : owner(-1) {}
};
-
struct skelmeshgroup;
-
- struct skelmesh : mesh
- {
+ struct skelmesh : mesh {
vert *verts;
bumpvert *bumpverts;
tri *tris;
int numverts, numtris, maxweights;
-
int voffset, eoffset, elen;
ushort minvert, maxvert;
-
- skelmesh() : verts(NULL), bumpverts(NULL), tris(NULL), numverts(0), numtris(0), maxweights(0)
- {
+ skelmesh() : verts(NULL), bumpverts(NULL), tris(NULL), numverts(0), numtris(0), maxweights(0) {
}
-
- virtual ~skelmesh()
- {
+ virtual ~skelmesh() {
DELETEA(verts);
DELETEA(bumpverts);
DELETEA(tris);
}
-
- int addblendcombo(const blendcombo &c)
- {
+ int addblendcombo(const blendcombo &c) {
maxweights = max(maxweights, c.size());
return ((skelmeshgroup *)group)->addblendcombo(c);
}
-
- void smoothnorms(float limit = 0, bool areaweight = true)
- {
+ void smoothnorms(float limit = 0, bool areaweight = true) {
mesh::smoothnorms(verts, numverts, tris, numtris, limit, areaweight);
}
-
- void buildnorms(bool areaweight = true)
- {
+ void buildnorms(bool areaweight = true) {
mesh::buildnorms(verts, numverts, tris, numtris, areaweight);
}
-
- void calctangents(bool areaweight = true)
- {
+ void calctangents(bool areaweight = true) {
if(bumpverts) return;
bumpverts = new bumpvert[numverts];
mesh::calctangents(bumpverts, verts, verts, numverts, tris, numtris, areaweight);
}
-
- void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m)
- {
- loopj(numverts)
- {
+ void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) {
+ loopj(numverts) {
vec v = m.transform(verts[j].pos);
- loopi(3)
- {
+ loopi(3) {
bbmin[i] = min(bbmin[i], v[i]);
bbmax[i] = max(bbmax[i], v[i]);
}
}
}
-
- void genBIH(BIH::mesh &m)
- {
+ void genBIH(BIH::mesh &m) {
m.tris = (const BIH::tri *)tris;
m.numtris = numtris;
m.pos = (const uchar *)&verts->pos;
m.tc = (const uchar *)&verts->tc;
m.tcstride = sizeof(vert);
}
-
- static inline void assignvert(vvertn &vv, int j, vert &v, blendcombo &c)
- {
+ static inline void assignvert(vvertn &vv, int j, vert &v, blendcombo &c) {
vv.pos = v.pos;
vv.norm = v.norm;
vv.tc = v.tc;
}
-
- inline void assignvert(vvertbump &vv, int j, vert &v, blendcombo &c)
- {
+ inline void assignvert(vvertbump &vv, int j, vert &v, blendcombo &c) {
vv.pos = v.pos;
vv.tc = v.tc;
vv.tangent = bumpverts[j].tangent;
}
-
- static inline void assignvert(vvertnw &vv, int j, vert &v, blendcombo &c)
- {
+ static inline void assignvert(vvertnw &vv, int j, vert &v, blendcombo &c) {
vv.pos = v.pos;
vv.norm = v.norm;
vv.tc = v.tc;
c.serialize(vv);
}
-
- inline void assignvert(vvertbumpw &vv, int j, vert &v, blendcombo &c)
- {
+ inline void assignvert(vvertbumpw &vv, int j, vert &v, blendcombo &c) {
vv.pos = v.pos;
vv.tc = v.tc;
vv.tangent = bumpverts[j].tangent;
c.serialize(vv);
}
-
template<class T>
- int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts)
- {
+ int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts) {
voffset = offset;
eoffset = idxs.length();
- loopi(numverts)
- {
+ loopi(numverts) {
vert &v = verts[i];
assignvert(vverts.add(), i, v, ((skelmeshgroup *)group)->blendcombos[v.blend]);
}
maxvert = voffset + numverts-1;
return numverts;
}
-
template<class T>
- int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts, int *htdata, int htlen)
- {
+ int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts, int *htdata, int htlen) {
voffset = offset;
eoffset = idxs.length();
minvert = 0xFFFF;
- loopi(numtris)
- {
+ loopi(numtris) {
tri &t = tris[i];
- loopj(3)
- {
+ loopj(3) {
int index = t.vert[j];
vert &v = verts[index];
T vv;
assignvert(vv, index, v, ((skelmeshgroup *)group)->blendcombos[v.blend]);
int htidx = hthash(v.pos)&(htlen-1);
- loopk(htlen)
- {
+ loopk(htlen) {
int &vidx = htdata[(htidx+k)&(htlen-1)];
if(vidx < 0) { vidx = idxs.add(ushort(vverts.length())); vverts.add(vv); break; }
else if(!memcmp(&vverts[vidx], &vv, sizeof(vv))) { minvert = min(minvert, idxs.add(ushort(vidx))); break; }
maxvert = max(minvert, ushort(vverts.length()-1));
return vverts.length()-voffset;
}
-
- int genvbo(vector<ushort> &idxs, int offset)
- {
+ int genvbo(vector<ushort> &idxs, int offset) {
loopi(numverts) verts[i].interpindex = ((skelmeshgroup *)group)->remapblend(verts[i].blend);
-
voffset = offset;
eoffset = idxs.length();
- loopi(numtris)
- {
+ loopi(numtris) {
tri &t = tris[i];
loopj(3) idxs.add(voffset+t.vert[j]);
}
elen = idxs.length()-eoffset;
return numverts;
}
-
template<class T>
- static inline void fillvert(T &vv, int j, vert &v)
- {
+ static inline void fillvert(T &vv, int j, vert &v) {
vv.tc = v.tc;
}
-
template<class T>
- void fillverts(T *vdata)
- {
+ void fillverts(T *vdata) {
vdata += voffset;
loopi(numverts) fillvert(vdata[i], i, verts[i]);
}
-
- void interpverts(const dualquat * RESTRICT bdata1, const dualquat * RESTRICT bdata2, bool tangents, void * RESTRICT vdata, skin &s)
- {
+ void interpverts(const dualquat * RESTRICT bdata1, const dualquat * RESTRICT bdata2, bool tangents, void * RESTRICT vdata, skin &s) {
const int blendoffset = ((skelmeshgroup *)group)->skel->numgpubones;
bdata2 -= blendoffset;
-
#define IPLOOP(type, dosetup, dotransform) \
- loopi(numverts) \
- { \
+ loopi(numverts) { \
+ \
const vert &src = verts[i]; \
type &dst = ((type * RESTRICT)vdata)[i]; \
dosetup; \
dst.pos = b.transform(src.pos); \
dotransform; \
}
-
- if(tangents)
- {
- IPLOOP(vvertbump, bumpvert &bsrc = bumpverts[i],
- {
+ if(tangents) {
+ IPLOOP(vvertbump, bumpvert &bsrc = bumpverts[i], {
quat q = b.transform(bsrc.tangent);
fixqtangent(q, bsrc.tangent.w);
dst.tangent = q;
});
}
- else
- {
- IPLOOP(vvertn, ,
- {
+ else {
+ IPLOOP(vvertn, , {
dst.norm = b.transformnormal(src.norm);
});
}
-
#undef IPLOOP
}
-
- void setshader(Shader *s)
- {
+ void setshader(Shader *s) {
skelmeshgroup *g = (skelmeshgroup *)group;
if(!g->skel->usegpuskel) s->set();
else s->setvariant(min(maxweights, g->vweights)-1, 0);
}
-
- void render(const animstate *as, skin &s, vbocacheentry &vc)
- {
+ void render(const animstate *as, skin &s, vbocacheentry &vc) {
if(!Shader::lastshader) return;
glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_SHORT, &((skelmeshgroup *)group)->edata[eoffset]);
glde++;
}
};
-
- struct tag
- {
+ struct tag {
char *name;
int bone;
matrix4x3 matrix;
-
tag() : name(NULL) {}
~tag() { DELETEA(name); }
};
-
- struct skelanimspec
- {
+ struct skelanimspec {
char *name;
int frame, range;
-
skelanimspec() : name(NULL), frame(0), range(0) {}
- ~skelanimspec()
- {
+ ~skelanimspec() {
DELETEA(name);
}
};
-
- struct boneinfo
- {
+ struct boneinfo {
const char *name;
int parent, children, next, group, scheduled, interpindex, interpparent, ragdollindex, correctindex;
float pitchscale, pitchoffset, pitchmin, pitchmax;
dualquat base, invbase;
-
boneinfo() : name(NULL), parent(-1), children(-1), next(-1), group(INT_MAX), scheduled(-1), interpindex(-1), interpparent(-1), ragdollindex(-1), correctindex(-1), pitchscale(0), pitchoffset(0), pitchmin(0), pitchmax(0) {}
- ~boneinfo()
- {
+ ~boneinfo() {
DELETEA(name);
}
};
-
- struct antipode
- {
+ struct antipode {
int parent, child;
-
antipode(int parent, int child) : parent(parent), child(child) {}
};
-
- struct pitchdep
- {
+ struct pitchdep {
int bone, parent;
dualquat pose;
};
-
- struct pitchtarget
- {
+ struct pitchtarget {
int bone, frame, corrects, deps;
float pitchmin, pitchmax, deviated;
dualquat pose;
};
-
- struct pitchcorrect
- {
+ struct pitchcorrect {
int bone, target, parent;
float pitchmin, pitchmax, pitchscale, pitchangle, pitchtotal;
-
pitchcorrect() : parent(-1), pitchangle(0), pitchtotal(0) {}
};
-
- struct skeleton
- {
+ struct skeleton {
char *name;
int shared;
vector<skelmeshgroup *> users;
vector<pitchdep> pitchdeps;
vector<pitchtarget> pitchtargets;
vector<pitchcorrect> pitchcorrects;
-
bool usegpuskel;
vector<skelcacheentry> skelcache;
hashtable<GLuint, int> blendoffsets;
-
- skeleton() : name(NULL), shared(0), bones(NULL), numbones(0), numinterpbones(0), numgpubones(0), numframes(0), framebones(NULL), ragdoll(NULL), usegpuskel(false), blendoffsets(32)
- {
+ skeleton() : name(NULL), shared(0), bones(NULL), numbones(0), numinterpbones(0), numgpubones(0), numframes(0), framebones(NULL), ragdoll(NULL), usegpuskel(false), blendoffsets(32) {
}
-
- ~skeleton()
- {
+ ~skeleton() {
DELETEA(name);
DELETEA(bones);
DELETEA(framebones);
DELETEP(ragdoll);
- loopv(skelcache)
- {
+ loopv(skelcache) {
DELETEA(skelcache[i].bdata);
}
}
-
- skelanimspec *findskelanim(const char *name, char sep = '\0')
- {
+ skelanimspec *findskelanim(const char *name, char sep = '\0') {
int len = sep ? strlen(name) : 0;
- loopv(skelanims)
- {
- if(skelanims[i].name)
- {
- if(sep)
- {
+ loopv(skelanims) {
+ if(skelanims[i].name) {
+ if(sep) {
const char *end = strchr(skelanims[i].name, ':');
if(end && end - skelanims[i].name == len && !memcmp(name, skelanims[i].name, len)) return &skelanims[i];
}
}
return NULL;
}
-
- skelanimspec &addskelanim(const char *name)
- {
+ skelanimspec &addskelanim(const char *name) {
skelanimspec &sa = skelanims.add();
sa.name = name ? newstring(name) : NULL;
return sa;
}
-
- int findbone(const char *name)
- {
+ int findbone(const char *name) {
loopi(numbones) if(bones[i].name && !strcmp(bones[i].name, name)) return i;
return -1;
}
-
- int findtag(const char *name)
- {
+ int findtag(const char *name) {
loopv(tags) if(!strcmp(tags[i].name, name)) return i;
return -1;
}
-
- bool addtag(const char *name, int bone, const matrix4x3 &matrix)
- {
+ bool addtag(const char *name, int bone, const matrix4x3 &matrix) {
int idx = findtag(name);
- if(idx >= 0)
- {
+ if(idx >= 0) {
if(!testtags) return false;
tag &t = tags[idx];
t.bone = bone;
t.matrix = matrix;
}
- else
- {
+ else {
tag &t = tags.add();
t.name = newstring(name);
t.bone = bone;
}
return true;
}
-
- void calcantipodes()
- {
+ void calcantipodes() {
antipodes.shrink(0);
vector<int> schedule;
- loopi(numbones)
- {
- if(bones[i].group >= numbones)
- {
+ loopi(numbones) {
+ if(bones[i].group >= numbones) {
bones[i].scheduled = schedule.length();
schedule.add(i);
}
else bones[i].scheduled = -1;
}
- loopv(schedule)
- {
+ loopv(schedule) {
int bone = schedule[i];
const boneinfo &info = bones[bone];
- loopj(numbones) if(abs(bones[j].group) == bone && bones[j].scheduled < 0)
- {
+ loopj(numbones) if(abs(bones[j].group) == bone && bones[j].scheduled < 0) {
antipodes.add(antipode(info.interpindex, bones[j].interpindex));
bones[j].scheduled = schedule.length();
schedule.add(j);
}
- if(i + 1 == schedule.length())
- {
+ if(i + 1 == schedule.length()) {
int conflict = INT_MAX;
loopj(numbones) if(bones[j].group < numbones && bones[j].scheduled < 0) conflict = min(conflict, abs(bones[j].group));
- if(conflict < numbones)
- {
+ if(conflict < numbones) {
bones[conflict].scheduled = schedule.length();
schedule.add(conflict);
}
}
}
}
-
- void remapbones()
- {
- loopi(numbones)
- {
+ void remapbones() {
+ loopi(numbones) {
boneinfo &info = bones[i];
info.interpindex = -1;
info.ragdollindex = -1;
}
numgpubones = 0;
- loopv(users)
- {
+ loopv(users) {
skelmeshgroup *group = users[i];
- loopvj(group->blendcombos)
- {
+ loopvj(group->blendcombos) {
blendcombo &c = group->blendcombos[j];
- loopk(4)
- {
+ loopk(4) {
if(!c.weights[k]) { c.interpbones[k] = k > 0 ? c.interpbones[k-1] : 0; continue; }
boneinfo &info = bones[c.bones[k]];
if(info.interpindex < 0) info.interpindex = numgpubones++;
c.interpbones[k] = info.interpindex;
if(info.group < 0) continue;
- loopl(4)
- {
+ loopl(4) {
if(!c.weights[l]) break;
if(l == k) continue;
int parent = c.bones[l];
}
}
numinterpbones = numgpubones;
- loopv(tags)
- {
+ loopv(tags) {
boneinfo &info = bones[tags[i].bone];
if(info.interpindex < 0) info.interpindex = numinterpbones++;
}
- if(ragdoll)
- {
- loopv(ragdoll->joints)
- {
+ if(ragdoll) {
+ loopv(ragdoll->joints) {
boneinfo &info = bones[ragdoll->joints[i].bone];
if(info.interpindex < 0) info.interpindex = numinterpbones++;
info.ragdollindex = i;
}
}
- loopi(numbones)
- {
+ loopi(numbones) {
boneinfo &info = bones[i];
if(info.interpindex < 0) continue;
for(int parent = info.parent; parent >= 0 && bones[parent].interpindex < 0; parent = bones[parent].parent)
bones[parent].interpindex = numinterpbones++;
}
- loopi(numbones)
- {
+ loopi(numbones) {
boneinfo &info = bones[i];
if(info.interpindex < 0) continue;
info.interpparent = info.parent >= 0 ? bones[info.parent].interpindex : -1;
}
- if(ragdoll)
- {
- loopi(numbones)
- {
+ if(ragdoll) {
+ loopi(numbones) {
boneinfo &info = bones[i];
if(info.interpindex < 0 || info.ragdollindex >= 0) continue;
- for(int parent = info.parent; parent >= 0; parent = bones[parent].parent)
- {
+ for(int parent = info.parent; parent >= 0; parent = bones[parent].parent) {
if(bones[parent].ragdollindex >= 0) { ragdoll->addreljoint(i, bones[parent].ragdollindex); break; }
}
}
calcantipodes();
}
-
- void addpitchdep(int bone, int frame)
- {
- for(; bone >= 0; bone = bones[bone].parent)
- {
+ void addpitchdep(int bone, int frame) {
+ for(; bone >= 0; bone = bones[bone].parent) {
int pos = pitchdeps.length();
- loopvj(pitchdeps) if(bone <= pitchdeps[j].bone)
- {
+ loopvj(pitchdeps) if(bone <= pitchdeps[j].bone) {
if(bone == pitchdeps[j].bone) goto nextbone;
pos = j;
break;
- }
- {
+ } {
pitchdep d;
d.bone = bone;
d.parent = -1;
nextbone:;
}
}
-
- int findpitchdep(int bone)
- {
+ int findpitchdep(int bone) {
loopv(pitchdeps) if(bone <= pitchdeps[i].bone) return bone == pitchdeps[i].bone ? i : -1;
return -1;
}
-
- int findpitchcorrect(int bone)
- {
+ int findpitchcorrect(int bone) {
loopv(pitchcorrects) if(bone <= pitchcorrects[i].bone) return bone == pitchcorrects[i].bone ? i : -1;
return -1;
}
-
- void initpitchdeps()
- {
+ void initpitchdeps() {
pitchdeps.setsize(0);
if(pitchtargets.empty()) return;
- loopv(pitchtargets)
- {
+ loopv(pitchtargets) {
pitchtarget &t = pitchtargets[i];
t.deps = -1;
addpitchdep(t.bone, t.frame);
}
- loopv(pitchdeps)
- {
+ loopv(pitchdeps) {
pitchdep &d = pitchdeps[i];
int parent = bones[d.bone].parent;
- if(parent >= 0)
- {
+ if(parent >= 0) {
int j = findpitchdep(parent);
- if(j >= 0)
- {
+ if(j >= 0) {
d.parent = j;
d.pose.mul(pitchdeps[j].pose, dualquat(d.pose));
}
}
}
- loopv(pitchtargets)
- {
+ loopv(pitchtargets) {
pitchtarget &t = pitchtargets[i];
int j = findpitchdep(t.bone);
- if(j >= 0)
- {
+ if(j >= 0) {
t.deps = j;
t.pose = pitchdeps[j].pose;
}
t.corrects = -1;
- for(int parent = t.bone; parent >= 0; parent = bones[parent].parent)
- {
+ for(int parent = t.bone; parent >= 0; parent = bones[parent].parent) {
t.corrects = findpitchcorrect(parent);
if(t.corrects >= 0) break;
}
}
- loopv(pitchcorrects)
- {
+ loopv(pitchcorrects) {
pitchcorrect &c = pitchcorrects[i];
bones[c.bone].correctindex = i;
c.parent = -1;
- for(int parent = c.bone;;)
- {
+ for(int parent = c.bone;;) {
parent = bones[parent].parent;
if(parent < 0) break;
c.parent = findpitchcorrect(parent);
}
}
}
-
- void optimize()
- {
+ void optimize() {
cleanup();
if(ragdoll) ragdoll->setup();
remapbones();
initpitchdeps();
}
-
- void expandbonemask(uchar *expansion, int bone, int val)
- {
+ void expandbonemask(uchar *expansion, int bone, int val) {
expansion[bone] = val;
bone = bones[bone].children;
while(bone>=0) { expandbonemask(expansion, bone, val); bone = bones[bone].next; }
}
-
- void applybonemask(ushort *mask, uchar *partmask, int partindex)
- {
+ void applybonemask(ushort *mask, uchar *partmask, int partindex) {
if(!mask || *mask==BONEMASK_END) return;
uchar *expansion = new uchar[numbones];
memset(expansion, *mask&BONEMASK_NOT ? 1 : 0, numbones);
- while(*mask!=BONEMASK_END)
- {
+ while(*mask!=BONEMASK_END) {
expandbonemask(expansion, *mask&BONEMASK_BONE, *mask&BONEMASK_NOT ? 0 : 1);
mask++;
}
loopi(numbones) if(expansion[i]) partmask[i] = partindex;
delete[] expansion;
}
-
- void linkchildren()
- {
- loopi(numbones)
- {
+ void linkchildren() {
+ loopi(numbones) {
boneinfo &b = bones[i];
b.children = -1;
if(b.parent<0) b.next = -1;
- else
- {
+ else {
b.next = bones[b.parent].children;
bones[b.parent].children = i;
}
}
}
-
int availgpubones() const { return min(maxvsuniforms - reservevpparams - 10, maxskelanimdata) / 2; }
bool gpuaccelerate() const { return numframes && gpuskel && numgpubones<=availgpubones(); }
-
- float calcdeviation(const vec &axis, const vec &forward, const dualquat &pose1, const dualquat &pose2)
- {
+ float calcdeviation(const vec &axis, const vec &forward, const dualquat &pose1, const dualquat &pose2) {
vec forward1 = pose1.transformnormal(forward).project(axis).normalize(),
forward2 = pose2.transformnormal(forward).project(axis).normalize(),
daxis = vec().cross(forward1, forward2);
if(daxis.dot(axis) < 0) dy = -dy;
return atan2f(dy, dx)/RAD;
}
-
- void calcpitchcorrects(float pitch, const vec &axis, const vec &forward)
- {
- loopv(pitchtargets)
- {
+ void calcpitchcorrects(float pitch, const vec &axis, const vec &forward) {
+ loopv(pitchtargets) {
pitchtarget &t = pitchtargets[i];
t.deviated = calcdeviation(axis, forward, t.pose, pitchdeps[t.deps].pose);
}
- loopv(pitchcorrects)
- {
+ loopv(pitchcorrects) {
pitchcorrect &c = pitchcorrects[i];
c.pitchangle = c.pitchtotal = 0;
}
- loopvj(pitchtargets)
- {
+ loopvj(pitchtargets) {
pitchtarget &t = pitchtargets[j];
float tpitch = pitch - t.deviated;
for(int parent = t.corrects; parent >= 0; parent = pitchcorrects[parent].parent)
tpitch -= pitchcorrects[parent].pitchangle;
if(t.pitchmin || t.pitchmax) tpitch = clamp(tpitch, t.pitchmin, t.pitchmax);
- loopv(pitchcorrects)
- {
+ loopv(pitchcorrects) {
pitchcorrect &c = pitchcorrects[i];
if(c.target != j) continue;
float total = c.parent >= 0 ? pitchcorrects[c.parent].pitchtotal : 0,
avail = tpitch - total,
used = tpitch*c.pitchscale;
- if(c.pitchmin || c.pitchmax)
- {
+ if(c.pitchmin || c.pitchmax) {
if(used < 0) used = clamp(c.pitchmin, used, 0.0f);
else used = clamp(c.pitchmax, 0.0f, used);
}
}
}
}
-
#define INTERPBONE(bone) \
const animstate &s = as[partmask[bone]]; \
const framedata &f = partframes[partmask[bone]]; \
dualquat d; \
(d = f.fr1[bone]).mul((1-s.cur.t)*s.interp); \
d.accumulate(f.fr2[bone], s.cur.t*s.interp); \
- if(s.interp<1) \
- { \
+ if(s.interp<1) { \
+ \
d.accumulate(f.pfr1[bone], (1-s.prev.t)*(1-s.interp)); \
d.accumulate(f.pfr2[bone], s.prev.t*(1-s.interp)); \
}
-
- void interpbones(const animstate *as, float pitch, const vec &axis, const vec &forward, int numanimparts, const uchar *partmask, skelcacheentry &sc)
- {
+ void interpbones(const animstate *as, float pitch, const vec &axis, const vec &forward, int numanimparts, const uchar *partmask, skelcacheentry &sc) {
if(!sc.bdata) sc.bdata = new dualquat[numinterpbones];
sc.nextversion();
- struct framedata
- {
+ struct framedata {
const dualquat *fr1, *fr2, *pfr1, *pfr2;
} partframes[MAXANIMPARTS];
- loopi(numanimparts)
- {
+ loopi(numanimparts) {
partframes[i].fr1 = &framebones[as[i].cur.fr1*numbones];
partframes[i].fr2 = &framebones[as[i].cur.fr2*numbones];
- if(as[i].interp<1)
- {
+ if(as[i].interp<1) {
partframes[i].pfr1 = &framebones[as[i].prev.fr1*numbones];
partframes[i].pfr2 = &framebones[as[i].prev.fr2*numbones];
}
}
- loopv(pitchdeps)
- {
+ loopv(pitchdeps) {
pitchdep &p = pitchdeps[i];
INTERPBONE(p.bone);
d.normalize();
else p.pose = d;
}
calcpitchcorrects(pitch, axis, forward);
- loopi(numbones) if(bones[i].interpindex>=0)
- {
+ loopi(numbones) if(bones[i].interpindex>=0) {
INTERPBONE(i);
const boneinfo &b = bones[i];
d.normalize();
}
loopv(antipodes) sc.bdata[antipodes[i].child].fixantipodal(sc.bdata[antipodes[i].parent]);
}
-
- void initragdoll(ragdolldata &d, skelcacheentry &sc, part *p)
- {
+ void initragdoll(ragdolldata &d, skelcacheentry &sc, part *p) {
const dualquat *bdata = sc.bdata;
- loopv(ragdoll->joints)
- {
+ loopv(ragdoll->joints) {
const ragdollskel::joint &j = ragdoll->joints[i];
const boneinfo &b = bones[j.bone];
const dualquat &q = bdata[b.interpindex];
- loopk(3) if(j.vert[k] >= 0)
- {
+ loopk(3) if(j.vert[k] >= 0) {
ragdollskel::vert &v = ragdoll->verts[j.vert[k]];
ragdolldata::vert &dv = d.verts[j.vert[k]];
dv.pos.add(q.transform(v.pos).mul(v.weight));
}
}
- if(ragdoll->animjoints) loopv(ragdoll->joints)
- {
+ if(ragdoll->animjoints) loopv(ragdoll->joints) {
const ragdollskel::joint &j = ragdoll->joints[i];
const boneinfo &b = bones[j.bone];
const dualquat &q = bdata[b.interpindex];
d.calcanimjoint(i, matrix4x3(q));
}
- loopv(ragdoll->verts)
- {
+ loopv(ragdoll->verts) {
ragdolldata::vert &dv = d.verts[i];
matrixstack[matrixpos].transform(vec(dv.pos).add(p->translate).mul(p->model->scale), dv.pos);
}
- loopv(ragdoll->reljoints)
- {
+ loopv(ragdoll->reljoints) {
const ragdollskel::reljoint &r = ragdoll->reljoints[i];
const ragdollskel::joint &j = ragdoll->joints[r.parent];
const boneinfo &br = bones[r.bone], &bj = bones[j.bone];
d.reljoints[i].mul(dualquat(bdata[bj.interpindex]).invert(), bdata[br.interpindex]);
}
}
-
- void genragdollbones(ragdolldata &d, skelcacheentry &sc, part *p)
- {
+ void genragdollbones(ragdolldata &d, skelcacheentry &sc, part *p) {
if(!sc.bdata) sc.bdata = new dualquat[numinterpbones];
sc.nextversion();
- loopv(ragdoll->joints)
- {
+ loopv(ragdoll->joints) {
const ragdollskel::joint &j = ragdoll->joints[i];
const boneinfo &b = bones[j.bone];
vec pos(0, 0, 0);
m.mul(d.tris[j.tri], pos, d.animjoints ? d.animjoints[i] : j.orient);
sc.bdata[b.interpindex] = dualquat(m);
}
- loopv(ragdoll->reljoints)
- {
+ loopv(ragdoll->reljoints) {
const ragdollskel::reljoint &r = ragdoll->reljoints[i];
const ragdollskel::joint &j = ragdoll->joints[r.parent];
const boneinfo &br = bones[r.bone], &bj = bones[j.bone];
}
loopv(antipodes) sc.bdata[antipodes[i].child].fixantipodal(sc.bdata[antipodes[i].parent]);
}
-
- void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n)
- {
+ void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n) {
matrix4x3 t;
t.mul(bones[tags[i].bone].base, tags[i].matrix);
t.posttranslate(p->translate, p->model->scale);
n.mul(m, t);
}
-
- void calctags(part *p, skelcacheentry *sc = NULL)
- {
- loopv(p->links)
- {
+ void calctags(part *p, skelcacheentry *sc = NULL) {
+ loopv(p->links) {
linkedpart &l = p->links[i];
tag &t = tags[l.tag];
dualquat q;
l.matrix = m;
}
}
-
- void cleanup(bool full = true)
- {
- loopv(skelcache)
- {
+ void cleanup(bool full = true) {
+ loopv(skelcache) {
skelcacheentry &sc = skelcache[i];
loopj(MAXANIMPARTS) sc.as[j].cur.fr1 = -1;
DELETEA(sc.bdata);
blendoffsets.clear();
if(full) loopv(users) users[i]->cleanup();
}
-
bool canpreload() { return !numframes || gpuaccelerate(); }
-
- void preload()
- {
+ void preload() {
if(!numframes) return;
- if(skelcache.empty())
- {
+ if(skelcache.empty()) {
usegpuskel = gpuaccelerate();
}
}
-
- skelcacheentry &checkskelcache(part *p, const animstate *as, float pitch, const vec &axis, const vec &forward, ragdolldata *rdata)
- {
- if(skelcache.empty())
- {
+ skelcacheentry &checkskelcache(part *p, const animstate *as, float pitch, const vec &axis, const vec &forward, ragdolldata *rdata) {
+ if(skelcache.empty()) {
usegpuskel = gpuaccelerate();
}
-
int numanimparts = ((skelpart *)as->owner)->numanimparts;
uchar *partmask = ((skelpart *)as->owner)->partmask;
skelcacheentry *sc = NULL;
bool match = false;
- loopv(skelcache)
- {
+ loopv(skelcache) {
skelcacheentry &c = skelcache[i];
loopj(numanimparts) if(c.as[j]!=as[j]) goto mismatch;
if(c.pitch != pitch || c.partmask != partmask || c.ragdoll != rdata || (rdata && c.millis < rdata->lastmove)) goto mismatch;
if(c.millis < lastmillis) { sc = &c; break; }
}
if(!sc) sc = &skelcache.add();
- if(!match)
- {
+ if(!match) {
loopi(numanimparts) sc->as[i] = as[i];
sc->pitch = pitch;
sc->partmask = partmask;
sc->millis = lastmillis;
return *sc;
}
-
- int getblendoffset(UniformLoc &u)
- {
+ int getblendoffset(UniformLoc &u) {
int &offset = blendoffsets.access(Shader::lastshader->program, -1);
- if(offset < 0)
- {
+ if(offset < 0) {
defformatstring(offsetname, "%s[%d]", u.name, 2*numgpubones);
offset = glGetUniformLocation_(Shader::lastshader->program, offsetname);
}
return offset;
}
-
- void setglslbones(UniformLoc &u, skelcacheentry &sc, skelcacheentry &bc, int count)
- {
+ void setglslbones(UniformLoc &u, skelcacheentry &sc, skelcacheentry &bc, int count) {
if(u.version == bc.version && u.data == bc.bdata) return;
glUniform4fv_(u.loc, 2*numgpubones, sc.bdata[0].real.v);
- if(count > 0)
- {
+ if(count > 0) {
int offset = getblendoffset(u);
if(offset >= 0) glUniform4fv_(offset, 2*count, bc.bdata[0].real.v);
}
u.version = bc.version;
u.data = bc.bdata;
}
-
- void setgpubones(skelcacheentry &sc, blendcacheentry *bc, int count)
- {
+ void setgpubones(skelcacheentry &sc, blendcacheentry *bc, int count) {
if(!Shader::lastshader) return;
if(Shader::lastshader->uniformlocs.length() < 1) return;
UniformLoc &u = Shader::lastshader->uniformlocs[0];
setglslbones(u, sc, bc ? *bc : sc, count);
}
-
- bool shouldcleanup() const
- {
+ bool shouldcleanup() const {
return numframes && (skelcache.empty() || gpuaccelerate()!=usegpuskel);
}
};
-
- struct skelmeshgroup : meshgroup
- {
+ struct skelmeshgroup : meshgroup {
skeleton *skel;
-
vector<blendcombo> blendcombos;
int numblends[4];
-
static const int MAXBLENDCACHE = 16;
blendcacheentry blendcache[MAXBLENDCACHE];
-
static const int MAXVBOCACHE = 16;
vbocacheentry vbocache[MAXVBOCACHE];
-
ushort *edata;
GLuint ebuf;
bool vtangents;
int vlen, vertsize, vblends, vweights;
uchar *vdata;
-
- skelmeshgroup() : skel(NULL), edata(NULL), ebuf(0), vtangents(false), vlen(0), vertsize(0), vblends(0), vweights(0), vdata(NULL)
- {
+ skelmeshgroup() : skel(NULL), edata(NULL), ebuf(0), vtangents(false), vlen(0), vertsize(0), vblends(0), vweights(0), vdata(NULL) {
memset(numblends, 0, sizeof(numblends));
}
-
- virtual ~skelmeshgroup()
- {
- if(skel)
- {
+ virtual ~skelmeshgroup() {
+ if(skel) {
if(skel->shared) skel->users.removeobj(this);
else DELETEP(skel);
}
if(ebuf) glDeleteBuffers_(1, &ebuf);
- loopi(MAXBLENDCACHE)
- {
+ loopi(MAXBLENDCACHE) {
DELETEA(blendcache[i].bdata);
}
- loopi(MAXVBOCACHE)
- {
+ loopi(MAXVBOCACHE) {
if(vbocache[i].vbuf) glDeleteBuffers_(1, &vbocache[i].vbuf);
}
DELETEA(vdata);
}
-
- void shareskeleton(char *name)
- {
- if(!name)
- {
+ void shareskeleton(char *name) {
+ if(!name) {
skel = new skeleton;
skel->users.add(this);
return;
}
-
static hashnameset<skeleton *> skeletons;
if(skeletons.access(name)) skel = skeletons[name];
- else
- {
+ else {
skel = new skeleton;
skel->name = newstring(name);
skeletons.add(skel);
skel->users.add(this);
skel->shared++;
}
-
- int findtag(const char *name)
- {
+ int findtag(const char *name) {
return skel->findtag(name);
}
-
void *animkey() { return skel; }
int totalframes() const { return max(skel->numframes, 1); }
-
virtual skelanimspec *loadanim(const char *filename) { (void) filename; return NULL; }
-
- void genvbo(bool tangents, vbocacheentry &vc)
- {
+ void genvbo(bool tangents, vbocacheentry &vc) {
if(!vc.vbuf) glGenBuffers_(1, &vc.vbuf);
if(ebuf) return;
-
vector<ushort> idxs;
-
if(tangents) loopv(meshes) ((skelmesh *)meshes[i])->calctangents();
-
vtangents = tangents;
vlen = 0;
vblends = 0;
- if(skel->numframes && !skel->usegpuskel)
- {
+ if(skel->numframes && !skel->usegpuskel) {
vweights = 1;
- loopv(blendcombos)
- {
+ loopv(blendcombos) {
blendcombo &c = blendcombos[i];
c.interpindex = c.weights[1] ? skel->numgpubones + vblends++ : -1;
}
-
vertsize = tangents ? sizeof(vvertbump) : sizeof(vvertn);
loopv(meshes) vlen += ((skelmesh *)meshes[i])->genvbo(idxs, vlen);
DELETEA(vdata);
else FILLVDATA(vvertn);
#undef FILLVDATA
}
- else
- {
- if(skel->numframes)
- {
+ else {
+ if(skel->numframes) {
vweights = 4;
int availbones = skel->availgpubones() - skel->numgpubones;
while(vweights > 1 && availbones >= numblends[vweights-1]) availbones -= numblends[--vweights];
- loopv(blendcombos)
- {
+ loopv(blendcombos) {
blendcombo &c = blendcombos[i];
c.interpindex = c.size() > vweights ? skel->numgpubones + vblends++ : -1;
}
}
- else
- {
+ else {
vweights = 0;
loopv(blendcombos) blendcombos[i].interpindex = -1;
}
-
gle::bindvbo(vc.vbuf);
#define GENVBO(type, args) do { \
vertsize = sizeof(type); \
} while(0)
#define GENVBOANIM(type) GENVBO(type, (idxs, vlen, vverts))
#define GENVBOSTAT(type) GENVBO(type, (idxs, vlen, vverts, htdata, htlen))
- if(skel->numframes)
- {
+ if(skel->numframes) {
if(tangents) GENVBOANIM(vvertbumpw);
else GENVBOANIM(vvertnw);
}
- else
- {
+ else {
int numverts = 0, htlen = 128;
loopv(meshes) numverts += ((skelmesh *)meshes[i])->numverts;
while(htlen < numverts) htlen *= 2;
#undef GENVBOSTAT
gle::clearvbo();
}
-
glGenBuffers_(1, &ebuf);
gle::bindebo(ebuf);
glBufferData_(GL_ELEMENT_ARRAY_BUFFER, idxs.length()*sizeof(ushort), idxs.getbuf(), GL_STATIC_DRAW);
gle::clearebo();
}
-
- void bindvbo(const animstate *as, vbocacheentry &vc, skelcacheentry *sc = NULL, blendcacheentry *bc = NULL)
- {
+ void bindvbo(const animstate *as, vbocacheentry &vc, skelcacheentry *sc = NULL, blendcacheentry *bc = NULL) {
vvert *vverts = 0;
bindpos(ebuf, vc.vbuf, &vverts->pos, vertsize);
- if(as->cur.anim&ANIM_NOSKIN)
- {
+ if(as->cur.anim&ANIM_NOSKIN) {
if(enabletc) disabletc();
if(enablenormals) disablenormals();
if(enabletangents) disabletangents();
}
- else
- {
- if(vtangents)
- {
+ else {
+ if(vtangents) {
if(enablenormals) disablenormals();
vvertbump *vvertbumps = 0;
bindtangents(&vvertbumps->tangent, vertsize);
}
- else
- {
+ else {
if(enabletangents) disabletangents();
vvertn *vvertns = 0;
bindnormals(&vvertns->norm, vertsize);
}
-
bindtc(&vverts->tc, vertsize);
}
- if(!sc || !skel->usegpuskel)
- {
+ if(!sc || !skel->usegpuskel) {
if(enablebones) disablebones();
}
- else
- {
- if(vtangents)
- {
+ else {
+ if(vtangents) {
vvertbumpw *vvertbumpws = 0;
bindbones(vvertbumpws->weights, vvertbumpws->bones, vertsize);
}
- else
- {
+ else {
vvertnw *vvertnws = 0;
bindbones(vvertnws->weights, vvertnws->bones, vertsize);
}
}
}
-
- void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n)
- {
+ void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n) {
skel->concattagtransform(p, i, m, n);
}
-
- int addblendcombo(const blendcombo &c)
- {
- loopv(blendcombos) if(blendcombos[i]==c)
- {
+ int addblendcombo(const blendcombo &c) {
+ loopv(blendcombos) if(blendcombos[i]==c) {
blendcombos[i].uses += c.uses;
return i;
}
blendcombo &a = blendcombos.add(c);
return a.interpindex = blendcombos.length()-1;
}
-
- void sortblendcombos()
- {
+ void sortblendcombos() {
blendcombos.sort(blendcombo::sortcmp);
int *remap = new int[blendcombos.length()];
loopv(blendcombos) remap[blendcombos[i].interpindex] = i;
- loopv(meshes)
- {
+ loopv(meshes) {
skelmesh *m = (skelmesh *)meshes[i];
- loopj(m->numverts)
- {
+ loopj(m->numverts) {
vert &v = m->verts[j];
v.blend = remap[v.blend];
}
}
delete[] remap;
}
-
- int remapblend(int blend)
- {
+ int remapblend(int blend) {
const blendcombo &c = blendcombos[blend];
return c.weights[1] ? c.interpindex : c.interpbones[0];
}
-
- static inline void blendbones(dualquat &d, const dualquat *bdata, const blendcombo &c)
- {
+ static inline void blendbones(dualquat &d, const dualquat *bdata, const blendcombo &c) {
d = bdata[c.interpbones[0]];
d.mul(c.weights[0]);
d.accumulate(bdata[c.interpbones[1]], c.weights[1]);
- if(c.weights[2])
- {
+ if(c.weights[2]) {
d.accumulate(bdata[c.interpbones[2]], c.weights[2]);
if(c.weights[3]) d.accumulate(bdata[c.interpbones[3]], c.weights[3]);
}
}
-
- void blendbones(const skelcacheentry &sc, blendcacheentry &bc)
- {
+ void blendbones(const skelcacheentry &sc, blendcacheentry &bc) {
bc.nextversion();
if(!bc.bdata) bc.bdata = new dualquat[vblends];
dualquat *dst = bc.bdata - skel->numgpubones;
bool normalize = !skel->usegpuskel || vweights<=1;
- loopv(blendcombos)
- {
+ loopv(blendcombos) {
const blendcombo &c = blendcombos[i];
if(c.interpindex<0) break;
dualquat &d = dst[c.interpindex];
if(normalize) d.normalize();
}
}
-
- void cleanup()
- {
- loopi(MAXBLENDCACHE)
- {
+ void cleanup() {
+ loopi(MAXBLENDCACHE) {
blendcacheentry &c = blendcache[i];
DELETEA(c.bdata);
c.owner = -1;
}
- loopi(MAXVBOCACHE)
- {
+ loopi(MAXVBOCACHE) {
vbocacheentry &c = vbocache[i];
if(c.vbuf) { glDeleteBuffers_(1, &c.vbuf); c.vbuf = 0; }
c.owner = -1;
if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; }
if(skel) skel->cleanup(false);
}
-
#define SEARCHCACHE(cachesize, cacheentry, cache, reusecheck) \
- loopi(cachesize) \
- { \
+ loopi(cachesize) { \
+ \
cacheentry &c = cache[i]; \
- if(c.owner==owner) \
- { \
+ if(c.owner==owner) { \
+ \
if(c==sc) return c; \
else c.owner = -1; \
break; \
} \
} \
- loopi(cachesize-1) \
- { \
+ loopi(cachesize-1) { \
+ \
cacheentry &c = cache[i]; \
if(reusecheck c.owner < 0 || c.millis < lastmillis) \
return c; \
} \
return cache[cachesize-1];
-
- vbocacheentry &checkvbocache(skelcacheentry &sc, int owner)
- {
+ vbocacheentry &checkvbocache(skelcacheentry &sc, int owner) {
SEARCHCACHE(MAXVBOCACHE, vbocacheentry, vbocache, !c.vbuf || );
}
-
- blendcacheentry &checkblendcache(skelcacheentry &sc, int owner)
- {
+ blendcacheentry &checkblendcache(skelcacheentry &sc, int owner) {
SEARCHCACHE(MAXBLENDCACHE, blendcacheentry, blendcache, )
}
-
- void preload(part *p)
- {
+ void preload(part *p) {
if(!skel->canpreload()) return;
bool tangents = false;
loopv(p->skins) if(p->skins[i].tangents()) tangents = true;
skel->preload();
if(!vbocache->vbuf) genvbo(tangents, *vbocache);
}
-
- void render(const animstate *as, float pitch, const vec &axis, const vec &forward, dynent *d, part *p)
- {
+ void render(const animstate *as, float pitch, const vec &axis, const vec &forward, dynent *d, part *p) {
bool tangents = false;
loopv(p->skins) if(p->skins[i].tangents()) tangents = true;
if(skel->shouldcleanup()) { skel->cleanup(); disablevbo(); }
else if(tangents!=vtangents) { cleanup(); disablevbo(); }
-
- if(!skel->numframes)
- {
- if(!(as->cur.anim&ANIM_NORENDER))
- {
+ if(!skel->numframes) {
+ if(!(as->cur.anim&ANIM_NORENDER)) {
if(!vbocache->vbuf) genvbo(tangents, *vbocache);
bindvbo(as, *vbocache);
- loopv(meshes)
- {
+ loopv(meshes) {
skelmesh *m = (skelmesh *)meshes[i];
p->skins[i].bind(m, as);
m->render(as, p->skins[i], *vbocache);
skel->calctags(p);
return;
}
-
skelcacheentry &sc = skel->checkskelcache(p, as, pitch, axis, forward, as->cur.anim&ANIM_RAGDOLL || !d || !d->ragdoll || d->ragdoll->skel != skel->ragdoll ? NULL : d->ragdoll);
- if(!(as->cur.anim&ANIM_NORENDER))
- {
+ if(!(as->cur.anim&ANIM_NORENDER)) {
int owner = &sc-&skel->skelcache[0];
vbocacheentry &vc = skel->usegpuskel ? *vbocache : checkvbocache(sc, owner);
vc.millis = lastmillis;
if(!vc.vbuf) genvbo(tangents, vc);
blendcacheentry *bc = NULL;
- if(vblends)
- {
+ if(vblends) {
bc = &checkblendcache(sc, owner);
bc->millis = lastmillis;
- if(bc->owner!=owner)
- {
+ if(bc->owner!=owner) {
bc->owner = owner;
*(animcacheentry *)bc = sc;
blendbones(sc, *bc);
}
}
- if(!skel->usegpuskel && vc.owner!=owner)
- {
+ if(!skel->usegpuskel && vc.owner!=owner) {
vc.owner = owner;
(animcacheentry &)vc = sc;
- loopv(meshes)
- {
+ loopv(meshes) {
skelmesh &m = *(skelmesh *)meshes[i];
m.interpverts(sc.bdata, bc ? bc->bdata : NULL, tangents, vdata + m.voffset*vertsize, p->skins[i]);
}
gle::bindvbo(vc.vbuf);
glBufferData_(GL_ARRAY_BUFFER, vlen*vertsize, vdata, GL_STREAM_DRAW);
}
-
bindvbo(as, vc, &sc, bc);
- loopv(meshes)
- {
+ loopv(meshes) {
skelmesh *m = (skelmesh *)meshes[i];
p->skins[i].bind(m, as);
if(skel->usegpuskel) skel->setgpubones(sc, bc, vblends);
m->render(as, p->skins[i], vc);
}
}
-
skel->calctags(p, &sc);
-
- if(as->cur.anim&ANIM_RAGDOLL && skel->ragdoll && !d->ragdoll)
- {
+ if(as->cur.anim&ANIM_RAGDOLL && skel->ragdoll && !d->ragdoll) {
d->ragdoll = new ragdolldata(skel->ragdoll, p->model->scale);
skel->initragdoll(*d->ragdoll, sc, p);
d->ragdoll->init(d);
}
}
};
-
- struct animpartmask
- {
+ struct animpartmask {
animpartmask *next;
int numbones;
uchar bones[1];
};
-
- struct skelpart : part
- {
+ struct skelpart : part {
animpartmask *buildingpartmask;
-
uchar *partmask;
-
- skelpart(animmodel *model, int index = 0) : part(model, index), buildingpartmask(NULL), partmask(NULL)
- {
+ skelpart(animmodel *model, int index = 0) : part(model, index), buildingpartmask(NULL), partmask(NULL) {
}
-
- virtual ~skelpart()
- {
+ virtual ~skelpart() {
DELETEA(buildingpartmask);
}
-
- uchar *sharepartmask(animpartmask *o)
- {
+ uchar *sharepartmask(animpartmask *o) {
static animpartmask *partmasks = NULL;
animpartmask *p = partmasks;
- for(; p; p = p->next) if(p->numbones==o->numbones && !memcmp(p->bones, o->bones, p->numbones))
- {
+ for(; p; p = p->next) if(p->numbones==o->numbones && !memcmp(p->bones, o->bones, p->numbones)) {
delete[] (uchar *)o;
return p->bones;
}
-
o->next = p;
partmasks = o;
return o->bones;
}
-
- animpartmask *newpartmask()
- {
+ animpartmask *newpartmask() {
animpartmask *p = (animpartmask *)new uchar[sizeof(animpartmask) + ((skelmeshgroup *)meshes)->skel->numbones-1];
p->numbones = ((skelmeshgroup *)meshes)->skel->numbones;
memset(p->bones, 0, p->numbones);
return p;
}
-
- void initanimparts()
- {
+ void initanimparts() {
DELETEA(buildingpartmask);
buildingpartmask = newpartmask();
}
-
- bool addanimpart(ushort *bonemask)
- {
+ bool addanimpart(ushort *bonemask) {
if(!buildingpartmask || numanimparts>=MAXANIMPARTS) return false;
((skelmeshgroup *)meshes)->skel->applybonemask(bonemask, buildingpartmask->bones, numanimparts);
numanimparts++;
return true;
}
-
- void endanimparts()
- {
- if(buildingpartmask)
- {
+ void endanimparts() {
+ if(buildingpartmask) {
partmask = sharepartmask(buildingpartmask);
buildingpartmask = NULL;
}
-
((skelmeshgroup *)meshes)->skel->optimize();
}
-
- void loaded()
- {
+ void loaded() {
endanimparts();
part::loaded();
}
};
-
- skelmodel(const char *name) : animmodel(name)
- {
+ skelmodel(const char *name) : animmodel(name) {
}
-
- int linktype(animmodel *m) const
- {
+ int linktype(animmodel *m) const {
return type()==m->type() &&
((skelmeshgroup *)parts[0]->meshes)->skel == ((skelmeshgroup *)m->parts[0]->meshes)->skel ?
LINK_REUSE :
LINK_TAG;
}
-
bool skeletal() const { return true; }
-
- skelpart &addpart()
- {
+ skelpart &addpart() {
flushpart();
skelpart *p = new skelpart(this, parts.length());
parts.add(p);
}
};
-struct skeladjustment
-{
+struct skeladjustment {
float yaw, pitch, roll;
vec translate;
-
skeladjustment(float yaw, float pitch, float roll, const vec &translate) : yaw(yaw), pitch(pitch), roll(roll), translate(translate) {}
-
- void adjust(dualquat &dq)
- {
+ void adjust(dualquat &dq) {
if(yaw) dq.mulorient(quat(vec(0, 0, 1), yaw*RAD));
if(pitch) dq.mulorient(quat(vec(0, -1, 0), pitch*RAD));
if(roll) dq.mulorient(quat(vec(-1, 0, 0), roll*RAD));
}
};
-template<class MDL> struct skelloader : modelloader<MDL, skelmodel>
-{
+template<class MDL> struct skelloader : modelloader<MDL, skelmodel> {
static vector<skeladjustment> adjustments;
-
skelloader(const char *name) : modelloader<MDL, skelmodel>(name) {}
-
- void flushpart()
- {
+ void flushpart() {
adjustments.setsize(0);
}
};
template<class MDL> vector<skeladjustment> skelloader<MDL>::adjustments;
-template<class MDL> struct skelcommands : modelcommands<MDL, struct MDL::skelmesh>
-{
+template<class MDL> struct skelcommands : modelcommands<MDL, struct MDL::skelmesh> {
typedef modelcommands<MDL, struct MDL::skelmesh> commands;
typedef struct MDL::skeleton skeleton;
typedef struct MDL::skelmeshgroup meshgroup;
typedef struct MDL::pitchdep pitchdep;
typedef struct MDL::pitchtarget pitchtarget;
typedef struct MDL::pitchcorrect pitchcorrect;
-
- static void loadpart(char *meshfile, char *skelname, float *smooth)
- {
+ static void loadpart(char *meshfile, char *skelname, float *smooth) {
if(!MDL::loading) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
defformatstring(filename, "%s/%s", MDL::dir, meshfile);
part &mdl = MDL::loading->addpart();
mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
mdl.meshes = MDL::loading->sharemeshes(path(filename), skelname[0] ? skelname : NULL, double(*smooth > 0 ? cos(clamp(*smooth, 0.0f, 180.0f)*RAD) : 2));
if(!mdl.meshes) conoutf(CON_ERROR, "could not load %s", filename);
- else
- {
+ else {
mdl.initanimparts();
mdl.initskins();
}
}
-
- static void settag(char *name, char *tagname, float *tx, float *ty, float *tz, float *rx, float *ry, float *rz)
- {
+ static void settag(char *name, char *tagname, float *tx, float *ty, float *tz, float *rx, float *ry, float *rz) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
part &mdl = *(part *)MDL::loading->parts.last();
int i = mdl.meshes ? ((meshgroup *)mdl.meshes)->skel->findbone(name) : -1;
- if(i >= 0)
- {
+ if(i >= 0) {
float cx = *rx ? cosf(*rx/2*RAD) : 1, sx = *rx ? sinf(*rx/2*RAD) : 0,
cy = *ry ? cosf(*ry/2*RAD) : 1, sy = *ry ? sinf(*ry/2*RAD) : 0,
cz = *rz ? cosf(*rz/2*RAD) : 1, sz = *rz ? sinf(*rz/2*RAD) : 0;
}
conoutf(CON_ERROR, "could not find bone %s for tag %s", name, tagname);
}
-
- static void setpitch(char *name, float *pitchscale, float *pitchoffset, float *pitchmin, float *pitchmax)
- {
+ static void setpitch(char *name, float *pitchscale, float *pitchoffset, float *pitchmin, float *pitchmax) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
part &mdl = *(part *)MDL::loading->parts.last();
-
- if(name[0])
- {
+ if(name[0]) {
int i = mdl.meshes ? ((meshgroup *)mdl.meshes)->skel->findbone(name) : -1;
- if(i>=0)
- {
+ if(i>=0) {
boneinfo &b = ((meshgroup *)mdl.meshes)->skel->bones[i];
b.pitchscale = *pitchscale;
b.pitchoffset = *pitchoffset;
- if(*pitchmin || *pitchmax)
- {
+ if(*pitchmin || *pitchmax) {
b.pitchmin = *pitchmin;
b.pitchmax = *pitchmax;
}
- else
- {
+ else {
b.pitchmin = -360*fabs(b.pitchscale) + b.pitchoffset;
b.pitchmax = 360*fabs(b.pitchscale) + b.pitchoffset;
}
conoutf(CON_ERROR, "could not find bone %s to pitch", name);
return;
}
-
mdl.pitchscale = *pitchscale;
mdl.pitchoffset = *pitchoffset;
- if(*pitchmin || *pitchmax)
- {
+ if(*pitchmin || *pitchmax) {
mdl.pitchmin = *pitchmin;
mdl.pitchmax = *pitchmax;
}
- else
- {
+ else {
mdl.pitchmin = -360*fabs(mdl.pitchscale) + mdl.pitchoffset;
mdl.pitchmax = 360*fabs(mdl.pitchscale) + mdl.pitchoffset;
}
}
-
- static void setpitchtarget(char *name, char *animfile, int *frameoffset, float *pitchmin, float *pitchmax)
- {
+ static void setpitchtarget(char *name, char *animfile, int *frameoffset, float *pitchmin, float *pitchmax) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
part &mdl = *(part *)MDL::loading->parts.last();
if(!mdl.meshes) return;
if(!sa) { conoutf(CON_ERROR, "could not load %s anim file %s", MDL::formatname(), filename); return; }
skeleton *skel = ((meshgroup *)mdl.meshes)->skel;
int bone = skel ? skel->findbone(name) : -1;
- if(bone < 0)
- {
+ if(bone < 0) {
conoutf(CON_ERROR, "could not find bone %s to pitch target", name);
return;
}
t.pitchmin = *pitchmin;
t.pitchmax = *pitchmax;
}
-
- static void setpitchcorrect(char *name, char *targetname, float *scale, float *pitchmin, float *pitchmax)
- {
+ static void setpitchcorrect(char *name, char *targetname, float *scale, float *pitchmin, float *pitchmax) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
part &mdl = *(part *)MDL::loading->parts.last();
if(!mdl.meshes) return;
skeleton *skel = ((meshgroup *)mdl.meshes)->skel;
int bone = skel ? skel->findbone(name) : -1;
- if(bone < 0)
- {
+ if(bone < 0) {
conoutf(CON_ERROR, "could not find bone %s to pitch correct", name);
return;
}
if(skel->findpitchcorrect(bone) >= 0) return;
int targetbone = skel->findbone(targetname), target = -1;
if(targetbone >= 0) loopv(skel->pitchtargets) if(skel->pitchtargets[i].bone == targetbone) { target = i; break; }
- if(target < 0)
- {
+ if(target < 0) {
conoutf(CON_ERROR, "could not find pitch target %s to pitch correct %s", targetname, name);
return;
}
loopv(skel->pitchcorrects) if(bone <= skel->pitchcorrects[i].bone) { pos = i; break; }
skel->pitchcorrects.insert(pos, c);
}
-
- static void setanim(char *anim, char *animfile, float *speed, int *priority, int *startoffset, int *endoffset)
- {
+ static void setanim(char *anim, char *animfile, float *speed, int *priority, int *startoffset, int *endoffset) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
-
vector<int> anims;
findanims(anim, anims);
if(anims.empty()) conoutf(CON_ERROR, "could not find animation %s", anim);
- else
- {
+ else {
part *p = (part *)MDL::loading->parts.last();
if(!p->meshes) return;
defformatstring(filename, "%s/%s", MDL::dir, animfile);
animspec *sa = ((meshgroup *)p->meshes)->loadanim(path(filename));
if(!sa) conoutf(CON_ERROR, "could not load %s anim file %s", MDL::formatname(), filename);
- else loopv(anims)
- {
+ else loopv(anims) {
int start = sa->frame, end = sa->range;
if(*startoffset > 0) start += min(*startoffset, end-1);
else if(*startoffset < 0) start += max(end + *startoffset, 0);
}
}
}
-
- static void setanimpart(char *maskstr)
- {
+ static void setanimpart(char *maskstr) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
-
part *p = (part *)MDL::loading->parts.last();
-
vector<char *> bonestrs;
explodelist(maskstr, bonestrs);
vector<ushort> bonemask;
- loopv(bonestrs)
- {
+ loopv(bonestrs) {
char *bonestr = bonestrs[i];
int bone = p->meshes ? ((meshgroup *)p->meshes)->skel->findbone(bonestr[0]=='!' ? bonestr+1 : bonestr) : -1;
if(bone<0) { conoutf(CON_ERROR, "could not find bone %s for anim part mask [%s]", bonestr, maskstr); bonestrs.deletearrays(); return; }
bonestrs.deletearrays();
bonemask.sort();
if(bonemask.length()) bonemask.add(BONEMASK_END);
-
if(!p->addanimpart(bonemask.getbuf())) conoutf(CON_ERROR, "too many animation parts");
}
-
- static void setadjust(char *name, float *yaw, float *pitch, float *roll, float *tx, float *ty, float *tz)
- {
+ static void setadjust(char *name, float *yaw, float *pitch, float *roll, float *tx, float *ty, float *tz) {
if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
part &mdl = *(part *)MDL::loading->parts.last();
-
if(!name[0]) return;
int i = mdl.meshes ? ((meshgroup *)mdl.meshes)->skel->findbone(name) : -1;
if(i < 0) { conoutf(CON_ERROR, "could not find bone %s to adjust", name); return; }
while(!MDL::adjustments.inrange(i)) MDL::adjustments.add(skeladjustment(0, 0, 0, vec(0, 0, 0)));
MDL::adjustments[i] = skeladjustment(*yaw, *pitch, *roll, vec(*tx/4, *ty/4, *tz/4));
}
-
- skelcommands()
- {
+ skelcommands() {
if(MDL::multiparted()) this->modelcommand(loadpart, "load", "ssf");
this->modelcommand(settag, "tag", "ssffffff");
this->modelcommand(setpitch, "pitch", "sffff");
this->modelcommand(setpitchtarget, "pitchtarget", "ssiff");
this->modelcommand(setpitchcorrect, "pitchcorrect", "ssfff");
- if(MDL::animated())
- {
+ if(MDL::animated()) {
this->modelcommand(setanim, "anim", "ssfiii");
this->modelcommand(setanimpart, "animpart", "s");
this->modelcommand(setadjust, "adjust", "sffffff");
bool nosound = true;
-struct soundsample
-{
+struct soundsample {
char *name;
Mix_Chunk *chunk;
-
soundsample() : name(NULL), chunk(NULL) {}
~soundsample() { DELETEA(name); }
-
void cleanup() { if(chunk) { Mix_FreeChunk(chunk); chunk = NULL; } }
bool load(bool msg = false);
};
-struct soundslot
-{
+struct soundslot {
soundsample *sample;
int volume;
};
-struct soundconfig
-{
+struct soundconfig {
int slots, numslots;
int maxuses;
-
- bool hasslot(const soundslot *p, const vector<soundslot> &v) const
- {
+ bool hasslot(const soundslot *p, const vector<soundslot> &v) const {
return p >= v.getbuf() + slots && p < v.getbuf() + slots+numslots && slots+numslots < v.length();
}
-
- int chooseslot(int flags) const
- {
+ int chooseslot(int flags) const {
if(flags&SND_NO_ALT || numslots <= 1) return slots;
if(flags&SND_USE_ALT) return slots + 1 + rnd(numslots - 1);
return slots + rnd(numslots);
}
};
-struct soundchannel
-{
+struct soundchannel {
int id;
bool inuse;
vec loc;
extentity *ent;
int radius, volume, pan, flags;
bool dirty;
-
soundchannel(int id) : id(id) { reset(); }
-
bool hasloc() const { return loc.x >= -1e15f; }
void clearloc() { loc = vec(-1e16f, -1e16f, -1e16f); }
-
- void reset()
- {
+ void reset() {
inuse = false;
clearloc();
slot = NULL;
vector<soundchannel> channels;
int maxchannels = 0;
-soundchannel &newchannel(int n, soundslot *slot, const vec *loc = NULL, extentity *ent = NULL, int flags = 0, int radius = 0)
-{
- if(ent)
- {
+soundchannel &newchannel(int n, soundslot *slot, const vec *loc = NULL, extentity *ent = NULL, int flags = 0, int radius = 0) {
+ if(ent) {
loc = &ent->o;
ent->flags |= EF_SOUND;
}
return chan;
}
-void freechannel(int n)
-{
+void freechannel(int n) {
if(!channels.inrange(n) || !channels[n].inuse) return;
soundchannel &chan = channels[n];
chan.inuse = false;
if(chan.ent) chan.ent->flags &= ~EF_SOUND;
}
-void syncchannel(soundchannel &chan)
-{
+void syncchannel(soundchannel &chan) {
if(!chan.dirty) return;
if(!Mix_FadingChannel(chan.id)) Mix_Volume(chan.id, chan.volume);
Mix_SetPanning(chan.id, 255-chan.pan, chan.pan);
chan.dirty = false;
}
-void stopchannels()
-{
- loopv(channels)
- {
+void stopchannels() {
+ loopv(channels) {
soundchannel &chan = channels[i];
if(!chan.inuse) continue;
Mix_HaltChannel(i);
void setmusicvol(int musicvol);
extern int musicvol;
static int curvol = 0;
-VARFP(soundvol, 0, 255, 255,
-{
+VARFP(soundvol, 0, 255, 255, {
if(!soundvol) { stopchannels(); setmusicvol(0); }
else if(!curvol) setmusicvol(musicvol);
curvol = soundvol;
SDL_RWops *musicrw = NULL;
stream *musicstream = NULL;
-void setmusicvol(int musicvol)
-{
+void setmusicvol(int musicvol) {
if(nosound) return;
if(music) Mix_VolumeMusic((musicvol*MIX_MAX_VOLUME)/255);
}
-void stopmusic()
-{
+void stopmusic() {
if(nosound) return;
DELETEA(musicfile);
DELETEA(musicdonecmd);
- if(music)
- {
+ if(music) {
Mix_HaltMusic();
Mix_FreeMusic(music);
music = NULL;
VARF(soundfreq, 0, MIX_DEFAULT_FREQUENCY, 48000, initwarning("sound configuration", INIT_RESET, CHANGE_SOUND));
VARF(soundbufferlen, 128, 1024, 4096, initwarning("sound configuration", INIT_RESET, CHANGE_SOUND));
-bool initaudio()
-{
+bool initaudio() {
static string fallback = "";
static bool initfallback = true;
static bool restorefallback = false;
- if(initfallback)
- {
+ if(initfallback) {
initfallback = false;
if(char *env = SDL_getenv("SDL_AUDIODRIVER")) copystring(fallback, env);
}
- if(!fallback[0] && audiodriver[0])
- {
+ if(!fallback[0] && audiodriver[0]) {
vector<char*> drivers;
explodelist(audiodriver, drivers);
- loopv(drivers)
- {
+ loopv(drivers) {
restorefallback = true;
SDL_setenv("SDL_AUDIODRIVER", drivers[i], 1);
- if(SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0)
- {
+ if(SDL_InitSubSystem(SDL_INIT_AUDIO) >= 0) {
drivers.deletearrays();
return true;
}
}
drivers.deletearrays();
}
- if(restorefallback)
- {
+ if(restorefallback) {
restorefallback = false;
unsetenv("SDL_AUDIODRIVER");
}
return false;
}
-void initsound()
-{
+void initsound() {
SDL_version version;
SDL_GetVersion(&version);
- if(version.major == 2 && version.minor == 0 && version.patch == 6)
- {
+ if(version.major == 2 && version.minor == 0 && version.patch == 6) {
nosound = true;
if(usesound) conoutf(CON_ERROR, "audio is broken in SDL 2.0.6");
return;
}
-
- if(shouldinitaudio)
- {
+ if(shouldinitaudio) {
shouldinitaudio = false;
if(SDL_WasInit(SDL_INIT_AUDIO)) SDL_QuitSubSystem(SDL_INIT_AUDIO);
- if(!usesound || !initaudio())
- {
+ if(!usesound || !initaudio()) {
nosound = true;
return;
}
}
-
- if(Mix_OpenAudio(soundfreq, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0)
- {
+ if(Mix_OpenAudio(soundfreq, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) {
nosound = true;
conoutf(CON_ERROR, "sound init failed (SDL_mixer): %s", Mix_GetError());
return;
nosound = false;
}
-void musicdone()
-{
+void musicdone() {
if(music) { Mix_HaltMusic(); Mix_FreeMusic(music); music = NULL; }
if(musicrw) { SDL_FreeRW(musicrw); musicrw = NULL; }
DELETEP(musicstream);
delete[] cmd;
}
-Mix_Music *loadmusic(const char *name)
-{
+Mix_Music *loadmusic(const char *name) {
if(!musicstream) musicstream = openzipfile(name, "rb");
- if(musicstream)
- {
+ if(musicstream) {
if(!musicrw) musicrw = musicstream->rwops();
if(!musicrw) DELETEP(musicstream);
}
if(musicrw) music = Mix_LoadMUSType_RW(musicrw, MUS_NONE, 0);
else music = Mix_LoadMUS(findfile(name, "rb"));
- if(!music)
- {
+ if(!music) {
if(musicrw) { SDL_FreeRW(musicrw); musicrw = NULL; }
DELETEP(musicstream);
}
return music;
}
-void startmusic(char *name, char *cmd)
-{
+void startmusic(char *name, char *cmd) {
if(nosound) return;
stopmusic();
- if(soundvol && musicvol && *name)
- {
+ if(soundvol && musicvol && *name) {
defformatstring(file, "packages/%s", name);
path(file);
- if(loadmusic(file))
- {
+ if(loadmusic(file)) {
DELETEA(musicfile);
DELETEA(musicdonecmd);
musicfile = newstring(file);
Mix_VolumeMusic((musicvol*MIX_MAX_VOLUME)/255);
intret(1);
}
- else
- {
+ else {
conoutf(CON_ERROR, "could not play music: %s", file);
intret(0);
}
COMMANDN(music, startmusic, "ss");
-static Mix_Chunk *loadwav(const char *name)
-{
+static Mix_Chunk *loadwav(const char *name) {
Mix_Chunk *c = NULL;
stream *z = openzipfile(name, "rb");
- if(z)
- {
+ if(z) {
SDL_RWops *rw = z->rwops();
- if(rw)
- {
+ if(rw) {
c = Mix_LoadWAV_RW(rw, 0);
SDL_FreeRW(rw);
}
return c;
}
-template<class T> static void scalewav(T* dst, T* src, size_t len, int scale)
-{
+template<class T> static void scalewav(T* dst, T* src, size_t len, int scale) {
len /= sizeof(T);
const T* end = src + len;
- if(scale==2) for(; src < end; src++, dst += scale)
- {
+ if(scale==2) for(; src < end; src++, dst += scale) {
T s = src[0];
dst[0] = s;
dst[1] = s;
}
- else if(scale==4) for(; src < end; src++, dst += scale)
- {
+ else if(scale==4) for(; src < end; src++, dst += scale) {
T s = src[0];
dst[0] = s;
dst[1] = s;
dst[2] = s;
dst[3] = s;
}
- else for(; src < end; src++)
- {
+ else for(; src < end; src++) {
T s = src[0];
loopi(scale) *dst++ = s;
}
}
-static Mix_Chunk *loadwavscaled(const char *name)
-{
+static Mix_Chunk *loadwavscaled(const char *name) {
int mixerfreq = 0;
Uint16 mixerformat = 0;
int mixerchannels = 0;
if(!Mix_QuerySpec(&mixerfreq, &mixerformat, &mixerchannels)) return NULL;
-
SDL_AudioSpec spec;
Uint8 *audiobuf = NULL;
Uint32 audiolen = 0;
stream *z = openzipfile(name, "rb");
- if(z)
- {
+ if(z) {
SDL_RWops *rw = z->rwops();
- if(rw)
- {
+ if(rw) {
SDL_LoadWAV_RW(rw, 0, &spec, &audiobuf, &audiolen);
SDL_FreeRW(rw);
}
if(!audiobuf) return NULL;
int samplesize = ((spec.format&0xFF)/8) * spec.channels;
int scale = mixerfreq / spec.freq;
- if(scale >= 2)
- {
+ if(scale >= 2) {
Uint8 *scalebuf = (Uint8*)SDL_malloc(audiolen * scale);
- if(scalebuf)
- {
- switch(samplesize)
- {
+ if(scalebuf) {
+ switch(samplesize) {
case 1: scalewav((uchar*)scalebuf, (uchar*)audiobuf, audiolen, scale); break;
case 2: scalewav((ushort*)scalebuf, (ushort*)audiobuf, audiolen, scale); break;
case 4: scalewav((uint*)scalebuf, (uint*)audiobuf, audiolen, scale); break;
case 8: scalewav((ullong*)scalebuf, (ullong*)audiobuf, audiolen, scale); break;
default: SDL_free(scalebuf); scalebuf = NULL; break;
}
- if(scalebuf)
- {
+ if(scalebuf) {
SDL_free(audiobuf);
audiobuf = scalebuf;
audiolen *= scale;
}
}
}
- if(spec.freq != mixerfreq || spec.format != mixerformat || spec.channels != mixerchannels)
- {
+ if(spec.freq != mixerfreq || spec.format != mixerformat || spec.channels != mixerchannels) {
SDL_AudioCVT cvt;
- if(SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq, mixerformat, mixerchannels, mixerfreq) < 0)
- {
+ if(SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq, mixerformat, mixerchannels, mixerfreq) < 0) {
SDL_free(audiobuf);
return NULL;
}
- if(cvt.filters[0])
- {
+ if(cvt.filters[0]) {
cvt.len = audiolen & ~(samplesize-1);
cvt.buf = (Uint8*)SDL_malloc(cvt.len * cvt.len_mult);
if(!cvt.buf) { SDL_free(audiobuf); return NULL; }
VARFP(fixwav, 0, 1, 1, initwarning("sound configuration", INIT_LOAD, CHANGE_SOUND));
-bool soundsample::load(bool msg)
-{
+bool soundsample::load(bool msg) {
if(chunk) return true;
if(!name[0]) return false;
-
static const char * const exts[] = { "", ".wav", ".ogg" };
string filename;
- loopi(sizeof(exts)/sizeof(exts[0]))
- {
+ loopi(sizeof(exts)/sizeof(exts[0])) {
formatstring(filename, "packages/sounds/%s%s", name, exts[i]);
if(msg && !i) renderprogress(0, filename);
path(filename);
- if(fixwav)
- {
+ if(fixwav) {
size_t len = strlen(filename);
- if(len >= 4 && !strcasecmp(filename + len - 4, ".wav"))
- {
+ if(len >= 4 && !strcasecmp(filename + len - 4, ".wav")) {
chunk = loadwavscaled(filename);
if(chunk) return true;
}
chunk = loadwav(filename);
if(chunk) return true;
}
-
conoutf(CON_ERROR, "failed to load sample: packages/sounds/%s", name);
return false;
}
static hashnameset<soundsample> samples;
-static void cleanupsamples()
-{
+static void cleanupsamples() {
enumerate(samples, soundsample, s, s.cleanup());
}
-static struct soundtype
-{
+static struct soundtype {
vector<soundslot> slots;
vector<soundconfig> configs;
-
- int findsound(const char *name, int vol)
- {
- loopv(configs)
- {
+ int findsound(const char *name, int vol) {
+ loopv(configs) {
soundconfig &s = configs[i];
- loopj(s.numslots)
- {
+ loopj(s.numslots) {
soundslot &c = slots[s.slots+j];
if(!strcmp(c.sample->name, name) && (!vol || c.volume==vol)) return i;
}
}
return -1;
}
-
- int addslot(const char *name, int vol)
- {
+ int addslot(const char *name, int vol) {
soundsample *s = samples.access(name);
- if(!s)
- {
+ if(!s) {
char *n = newstring(name);
s = &samples[n];
s->name = n;
int oldlen = slots.length();
soundslot &slot = slots.add();
// soundslots.add() may relocate slot pointers
- if(slots.getbuf() != oldslots) loopv(channels)
- {
+ if(slots.getbuf() != oldslots) loopv(channels) {
soundchannel &chan = channels[i];
if(chan.inuse && chan.slot >= oldslots && chan.slot < &oldslots[oldlen])
chan.slot = &slots[chan.slot - oldslots];
slot.volume = vol ? vol : 100;
return oldlen;
}
-
- int addsound(const char *name, int vol, int maxuses = 0)
- {
+ int addsound(const char *name, int vol, int maxuses = 0) {
soundconfig &s = configs.add();
s.slots = addslot(name, vol);
s.numslots = 1;
s.maxuses = maxuses;
return configs.length()-1;
}
-
- void addalt(const char *name, int vol)
- {
+ void addalt(const char *name, int vol) {
if(configs.empty()) return;
addslot(name, vol);
configs.last().numslots++;
}
-
- void clear()
- {
+ void clear() {
slots.setsize(0);
configs.setsize(0);
}
-
- void reset()
- {
- loopv(channels)
- {
+ void reset() {
+ loopv(channels) {
soundchannel &chan = channels[i];
- if(chan.inuse && slots.inbuf(chan.slot))
- {
+ if(chan.inuse && slots.inbuf(chan.slot)) {
Mix_HaltChannel(i);
freechannel(i);
}
}
clear();
}
-
- void preloadsound(int n)
- {
+ void preloadsound(int n) {
if(nosound || !configs.inrange(n)) return;
soundconfig &config = configs[n];
loopk(config.numslots) slots[config.slots+k].sample->load(true);
}
-
- bool playing(const soundchannel &chan, const soundconfig &config) const
- {
+ bool playing(const soundchannel &chan, const soundconfig &config) const {
return chan.inuse && config.hasslot(chan.slot, slots);
}
} gamesounds, mapsounds;
ICOMMAND(numsounds, "", (), intret(gamesounds.configs.length()));
ICOMMAND(nummapsounds, "", (), intret(mapsounds.configs.length()));
-void soundreset()
-{
+void soundreset() {
gamesounds.reset();
}
COMMAND(soundreset, "");
-void mapsoundreset()
-{
+void mapsoundreset() {
mapsounds.reset();
}
COMMAND(mapsoundreset, "");
-void resetchannels()
-{
+void resetchannels() {
loopv(channels) if(channels[i].inuse) freechannel(i);
channels.shrink(0);
}
-void clear_sound()
-{
+void clear_sound() {
if(nosound) return;
stopmusic();
-
cleanupsamples();
gamesounds.clear();
mapsounds.clear();
resetchannels();
}
-void stopmapsounds()
-{
- loopv(channels) if(channels[i].inuse && channels[i].ent)
- {
+void stopmapsounds() {
+ loopv(channels) if(channels[i].inuse && channels[i].ent) {
Mix_HaltChannel(i);
freechannel(i);
}
}
-void clearmapsounds()
-{
+void clearmapsounds() {
stopmapsounds();
mapsounds.clear();
}
-void stopmapsound(extentity *e)
-{
- loopv(channels)
- {
+void stopmapsound(extentity *e) {
+ loopv(channels) {
soundchannel &chan = channels[i];
- if(chan.inuse && chan.ent == e)
- {
+ if(chan.inuse && chan.ent == e) {
Mix_HaltChannel(i);
freechannel(i);
}
}
}
-void checkmapsounds()
-{
+void checkmapsounds() {
const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
if(e.type!=ET_SOUND) continue;
- if(camera1->o.dist(e.o) < e.attr2)
- {
+ if(camera1->o.dist(e.o) < e.attr2) {
if(!(e.flags&EF_SOUND)) playsound(e.attr1, NULL, &e, SND_MAP, -1);
}
else if(e.flags&EF_SOUND) stopmapsound(&e);
VAR(stereo, 0, 1, 1);
-bool updatechannel(soundchannel &chan)
-{
+bool updatechannel(soundchannel &chan) {
if(!chan.slot) return false;
int vol = soundvol, pan = 255/2;
- if(chan.hasloc())
- {
+ if(chan.hasloc()) {
vec v;
float dist = chan.loc.dist(camera1->o, v);
int rad = 0;
- if(chan.ent)
- {
+ if(chan.ent) {
rad = chan.ent->attr2;
- if(chan.ent->attr3)
- {
+ if(chan.ent->attr3) {
rad -= chan.ent->attr3;
dist -= chan.ent->attr3;
}
}
else if(chan.radius > 0) rad = chan.radius;
if(rad > 0) vol -= int(clamp(dist/rad, 0.0f, 1.0f)*soundvol); // simple mono distance attenuation
- if(stereo && (v.x != 0 || v.y != 0) && dist>0)
- {
+ if(stereo && (v.x != 0 || v.y != 0) && dist>0) {
v.rotate_around_z(-camera1->yaw*RAD);
pan = int(255.9f*(0.5f - 0.5f*v.x/v.magnitude2())); // range is from 0 (left) to 255 (right)
}
return true;
}
-void reclaimchannels()
-{
- loopv(channels)
- {
+void reclaimchannels() {
+ loopv(channels) {
soundchannel &chan = channels[i];
if(chan.inuse && !Mix_Playing(i)) freechannel(i);
}
}
-void syncchannels()
-{
- loopv(channels)
- {
+void syncchannels() {
+ loopv(channels) {
soundchannel &chan = channels[i];
if(chan.inuse && chan.hasloc() && updatechannel(chan)) syncchannel(chan);
}
VARP(minimizedsounds, 0, 0, 1);
-void updatesounds()
-{
+void updatesounds() {
if(nosound) return;
if(minimized && !minimizedsounds) stopsounds();
- else
- {
+ else {
reclaimchannels();
if(mainmenu) stopmapsounds();
else checkmapsounds();
syncchannels();
}
- if(music)
- {
+ if(music) {
if(!Mix_PlayingMusic()) musicdone();
else if(Mix_PausedMusic()) Mix_ResumeMusic();
}
VARP(maxsoundsatonce, 0, 7, 100);
-void preloadsound(int n)
-{
+void preloadsound(int n) {
gamesounds.preloadsound(n);
}
-void preloadmapsound(int n)
-{
+void preloadmapsound(int n) {
mapsounds.preloadsound(n);
}
-void preloadmapsounds()
-{
+void preloadmapsounds() {
const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
if(e.type==ET_SOUND) mapsounds.preloadsound(e.attr1);
}
}
-int playsound(int n, const vec *loc, extentity *ent, int flags, int loops, int fade, int chanid, int radius, int expire)
-{
+int playsound(int n, const vec *loc, extentity *ent, int flags, int loops, int fade, int chanid, int radius, int expire) {
if(nosound || !soundvol || (minimized && !minimizedsounds)) return -1;
-
soundtype &sounds = ent || flags&SND_MAP ? mapsounds : gamesounds;
if(!sounds.configs.inrange(n)) { conoutf(CON_WARN, "unregistered sound: %d", n); return -1; }
soundconfig &config = sounds.configs[n];
-
- if(loc)
- {
+ if(loc) {
// cull sounds that are unlikely to be heard
int maxrad = game::maxsoundradius(n);
if(radius <= 0 || maxrad < radius) radius = maxrad;
- if(camera1->o.dist(*loc) > 1.5f*radius)
- {
- if(channels.inrange(chanid) && sounds.playing(channels[chanid], config))
- {
+ if(camera1->o.dist(*loc) > 1.5f*radius) {
+ if(channels.inrange(chanid) && sounds.playing(channels[chanid], config)) {
Mix_HaltChannel(chanid);
freechannel(chanid);
}
return -1;
}
}
-
- if(chanid < 0)
- {
- if(config.maxuses)
- {
+ if(chanid < 0) {
+ if(config.maxuses) {
int uses = 0;
loopv(channels) if(sounds.playing(channels[i], config) && ++uses >= config.maxuses) return -1;
}
-
// avoid bursts of sounds with heavy packetloss and in sp
static int soundsatonce = 0, lastsoundmillis = 0;
if(totalmillis == lastsoundmillis) soundsatonce++; else soundsatonce = 1;
lastsoundmillis = totalmillis;
if(maxsoundsatonce && soundsatonce > maxsoundsatonce) return -1;
}
-
- if(channels.inrange(chanid))
- {
+ if(channels.inrange(chanid)) {
soundchannel &chan = channels[chanid];
- if(sounds.playing(chan, config))
- {
+ if(sounds.playing(chan, config)) {
if(loc) chan.loc = *loc;
else if(chan.hasloc()) chan.clearloc();
return chanid;
}
}
if(fade < 0) return -1;
-
soundslot &slot = sounds.slots[config.chooseslot(flags)];
if(!slot.sample->chunk && !slot.sample->load()) return -1;
-
chanid = -1;
loopv(channels) if(!channels[i].inuse) { chanid = i; break; }
if(chanid < 0 && channels.length() < maxchannels) chanid = channels.length();
if(chanid < 0) loopv(channels) if(!channels[i].volume) { chanid = i; break; }
if(chanid < 0) return -1;
-
soundchannel &chan = newchannel(chanid, &slot, loc, ent, flags, radius);
updatechannel(chan);
int playing = -1;
- if(fade)
- {
+ if(fade) {
Mix_Volume(chanid, chan.volume);
playing = expire >= 0 ? Mix_FadeInChannelTimed(chanid, slot.sample->chunk, loops, fade, expire) : Mix_FadeInChannel(chanid, slot.sample->chunk, loops, fade);
}
return playing;
}
-void stopsounds()
-{
- loopv(channels) if(channels[i].inuse)
- {
+void stopsounds() {
+ loopv(channels) if(channels[i].inuse) {
Mix_HaltChannel(i);
freechannel(i);
}
}
-bool stopsound(int n, int chanid, int fade)
-{
+bool stopsound(int n, int chanid, int fade) {
if(!gamesounds.configs.inrange(n) || !channels.inrange(chanid) || !channels[chanid].inuse || !gamesounds.playing(channels[chanid], gamesounds.configs[n])) return false;
- if(!fade || !Mix_FadeOutChannel(chanid, fade))
- {
+ if(!fade || !Mix_FadeOutChannel(chanid, fade)) {
Mix_HaltChannel(chanid);
freechannel(chanid);
}
return true;
}
-int playsoundname(const char *s, const vec *loc, int vol, int flags, int loops, int fade, int chanid, int radius, int expire)
-{
+int playsoundname(const char *s, const vec *loc, int vol, int flags, int loops, int fade, int chanid, int radius, int expire) {
if(!vol) vol = 100;
int id = gamesounds.findsound(s, vol);
if(id < 0) id = gamesounds.addsound(s, vol);
ICOMMAND(sound, "i", (int *n), playsound(*n));
-void resetsound()
-{
+void resetsound() {
clearchanges(CHANGE_SOUND);
- if(!nosound)
- {
+ if(!nosound) {
cleanupsamples();
- if(music)
- {
+ if(music) {
Mix_HaltMusic();
Mix_FreeMusic(music);
}
}
initsound();
resetchannels();
- if(nosound)
- {
+ if(nosound) {
DELETEA(musicfile);
DELETEA(musicdonecmd);
music = NULL;
cleanupsamples();
return;
}
- if(music && loadmusic(musicfile))
- {
+ if(music && loadmusic(musicfile)) {
Mix_PlayMusic(music, musicdonecmd ? 0 : -1);
Mix_VolumeMusic((musicvol*MIX_MAX_VOLUME)/255);
}
- else
- {
+ else {
DELETEA(musicfile);
DELETEA(musicdonecmd);
}
-struct editline
-{
+struct editline {
enum { CHUNKSIZE = 256 };
-
char *text;
int len, maxlen;
-
editline() : text(NULL), len(0), maxlen(0) {}
- editline(const char *init) : text(NULL), len(0), maxlen(0)
- {
+ editline(const char *init) : text(NULL), len(0), maxlen(0) {
set(init);
}
-
bool empty() { return len <= 0; }
-
- void clear()
- {
+ void clear() {
DELETEA(text);
len = maxlen = 0;
}
-
- bool grow(int total, const char *fmt = "", ...)
- {
+ bool grow(int total, const char *fmt = "", ...) {
if(total + 1 <= maxlen) return false;
maxlen = (total + CHUNKSIZE) - total%CHUNKSIZE;
char *newtext = new char[maxlen];
- if(fmt)
- {
+ if(fmt) {
va_list args;
va_start(args, fmt);
vformatstring(newtext, fmt, args, maxlen);
text = newtext;
return true;
}
-
- void set(const char *str, int slen = -1)
- {
- if(slen < 0)
- {
+ void set(const char *str, int slen = -1) {
+ if(slen < 0) {
slen = strlen(str);
if(!grow(slen, "%s", str)) memcpy(text, str, slen + 1);
}
- else
- {
+ else {
grow(slen);
memcpy(text, str, slen);
text[slen] = '\0';
}
len = slen;
}
-
- void prepend(const char *str)
- {
+ void prepend(const char *str) {
int slen = strlen(str);
- if(!grow(slen + len, "%s%s", str, text ? text : ""))
- {
+ if(!grow(slen + len, "%s%s", str, text ? text : "")) {
memmove(&text[slen], text, len + 1);
memcpy(text, str, slen + 1);
}
len += slen;
}
-
- void append(const char *str)
- {
+ void append(const char *str) {
int slen = strlen(str);
if(!grow(len + slen, "%s%s", text ? text : "", str)) memcpy(&text[len], str, slen + 1);
len += slen;
}
-
- bool read(stream *f, int chop = -1)
- {
+ bool read(stream *f, int chop = -1) {
if(chop < 0) chop = INT_MAX; else chop++;
set("");
- while(len + 1 < chop && f->getline(&text[len], min(maxlen, chop) - len))
- {
+ while(len + 1 < chop && f->getline(&text[len], min(maxlen, chop) - len)) {
len += strlen(&text[len]);
- if(len > 0 && text[len-1] == '\n')
- {
+ if(len > 0 && text[len-1] == '\n') {
text[--len] = '\0';
return true;
}
if(len + 1 >= maxlen && len + 1 < chop) grow(len + CHUNKSIZE, "%s", text);
}
- if(len + 1 >= chop)
- {
+ if(len + 1 >= chop) {
char buf[CHUNKSIZE];
- while(f->getline(buf, sizeof(buf)))
- {
+ while(f->getline(buf, sizeof(buf))) {
int blen = strlen(buf);
if(blen > 0 && buf[blen-1] == '\n') return true;
}
}
return len > 0;
}
-
- void del(int start, int count)
- {
+ void del(int start, int count) {
if(!text) return;
if(start < 0) { count += start; start = 0; }
if(count <= 0 || start >= len) return;
memmove(&text[start], &text[start+count], len + 1 - (start + count));
len -= count;
}
-
- void chop(int newlen)
- {
+ void chop(int newlen) {
if(!text) return;
len = clamp(newlen, 0, len);
text[len] = '\0';
}
-
- void insert(char *str, int start, int count = 0)
- {
+ void insert(char *str, int start, int count = 0) {
if(count <= 0) count = strlen(str);
start = clamp(start, 0, len);
grow(len + count, "%s", text ? text : "");
memcpy(&text[start], str, count);
len += count;
}
-
- void combinelines(vector<editline> &src)
- {
+ void combinelines(vector<editline> &src) {
if(src.empty()) set("");
- else loopv(src)
- {
+ else loopv(src) {
if(i) append("\n");
if(!i) set(src[i].text, src[i].len);
else insert(src[i].text, len, src[i].len);
}
};
-struct editor
-{
+struct editor {
int mode; //editor mode - 1= keep while focused, 2= keep while used in gui, 3= keep forever (i.e. until mode changes)
bool active, rendered;
const char *name;
const char *filename;
-
int cx, cy; // cursor position - ensured to be valid after a region() or currentline()
int mx, my; // selection mark, mx=-1 if following cursor - avoid direct access, instead use region()
int maxx, maxy; // maxy=-1 if unlimited lines, 1 if single line editor
-
int scrolly; // vertical scroll offset
-
bool linewrap;
int pixelwidth; // required for up/down/hit/draw/bounds
int pixelheight; // -1 for variable sized, i.e. from bounds()
-
vector<editline> lines; // MUST always contain at least one line!
-
editor(const char *name, int mode, const char *initval) :
mode(mode), active(true), rendered(false), name(newstring(name)), filename(NULL),
- cx(0), cy(0), mx(-1), maxx(-1), maxy(-1), scrolly(0), linewrap(false), pixelwidth(-1), pixelheight(-1)
- {
+ cx(0), cy(0), mx(-1), maxx(-1), maxy(-1), scrolly(0), linewrap(false), pixelwidth(-1), pixelheight(-1) {
//printf("editor %08x '%s'\n", this, name);
lines.add().set(initval ? initval : "");
}
-
- ~editor()
- {
+ ~editor() {
//printf("~editor %08x '%s'\n", this, name);
DELETEA(name);
DELETEA(filename);
clear(NULL);
}
-
- void clear(const char *init = "")
- {
+ void clear(const char *init = "") {
cx = cy = 0;
mark(false);
loopv(lines) lines[i].clear();
lines.shrink(0);
if(init) lines.add().set(init);
}
-
- void setfile(const char *fname)
- {
+ void setfile(const char *fname) {
DELETEA(filename);
if(fname) filename = newstring(fname);
}
-
- void load()
- {
+ void load() {
if(!filename) return;
clear(NULL);
stream *file = openutf8file(filename, "r");
- if(file)
- {
+ if(file) {
while(lines.add().read(file, maxx) && (maxy < 0 || lines.length() <= maxy));
lines.pop().clear();
delete file;
}
if(lines.empty()) lines.add().set("");
}
-
- void save()
- {
+ void save() {
if(!filename) return;
stream *file = openutf8file(filename, "w");
if(!file) return;
loopv(lines) file->putline(lines[i].text);
delete file;
}
-
- void mark(bool enable)
- {
+ void mark(bool enable) {
mx = (enable) ? cx : -1;
my = cy;
}
-
- void selectall()
- {
+ void selectall() {
mx = my = INT_MAX;
cx = cy = 0;
}
-
// constrain results to within buffer - s=start, e=end, return true if a selection range
// also ensures that cy is always within lines[] and cx is valid
- bool region(int &sx, int &sy, int &ex, int &ey)
- {
+ bool region(int &sx, int &sy, int &ex, int &ey) {
int n = lines.length();
ASSERT(n != 0);
if(cy < 0) cy = 0; else if(cy >= n) cy = n-1;
int len = lines[cy].len;
if(cx < 0) cx = 0; else if(cx > len) cx = len;
- if(mx >= 0)
- {
+ if(mx >= 0) {
if(my < 0) my = 0; else if(my >= n) my = n-1;
len = lines[my].len;
if(mx > len) mx = len;
else if(sy==ey && sx > ex) swap(sx, ex);
return (sx != ex) || (sy != ey);
}
-
bool region() { int sx, sy, ex, ey; return region(sx, sy, ex, ey); }
-
// also ensures that cy is always within lines[] and cx is valid
- editline ¤tline()
- {
+ editline ¤tline() {
int n = lines.length();
ASSERT(n != 0);
if(cy < 0) cy = 0; else if(cy >= n) cy = n-1;
if(cx < 0) cx = 0; else if(cx > lines[cy].len) cx = lines[cy].len;
return lines[cy];
}
-
- void copyselectionto(editor *b)
- {
+ void copyselectionto(editor *b) {
if(b==this) return;
-
b->clear(NULL);
int sx, sy, ex, ey;
region(sx, sy, ex, ey);
- loopi(1+ey-sy)
- {
+ loopi(1+ey-sy) {
if(b->maxy != -1 && b->lines.length() >= b->maxy) break;
int y = sy+i;
char *line = lines[y].text;
int len = lines[y].len;
- if(y == sy && y == ey)
- {
+ if(y == sy && y == ey) {
line += sx;
len = ex - sx;
}
}
if(b->lines.empty()) b->lines.add().set("");
}
-
- char *tostring()
- {
+ char *tostring() {
int len = 0;
loopv(lines) len += lines[i].len + 1;
char *str = newstring(len);
int offset = 0;
- loopv(lines)
- {
+ loopv(lines) {
editline &l = lines[i];
memcpy(&str[offset], l.text, l.len);
offset += l.len;
str[offset] = '\0';
return str;
}
-
- char *selectiontostring()
- {
+ char *selectiontostring() {
vector<char> buf;
int sx, sy, ex, ey;
region(sx, sy, ex, ey);
- loopi(1+ey-sy)
- {
+ loopi(1+ey-sy) {
int y = sy+i;
char *line = lines[y].text;
int len = lines[y].len;
- if(y == sy && y == ey)
- {
+ if(y == sy && y == ey) {
line += sx;
len = ex - sx;
}
buf.add('\0');
return newstring(buf.getbuf(), buf.length()-1);
}
-
- void removelines(int start, int count)
- {
+ void removelines(int start, int count) {
loopi(count) lines[start+i].clear();
lines.remove(start, count);
}
-
- bool del() // removes the current selection (if any)
- {
+ bool del() { // removes the current selection (if any) {
int sx, sy, ex, ey;
- if(!region(sx, sy, ex, ey))
- {
+ if(!region(sx, sy, ex, ey)) {
mark(false);
return false;
}
- if(sy == ey)
- {
+ if(sy == ey) {
if(sx == 0 && ex == lines[ey].len) removelines(sy, 1);
else lines[sy].del(sx, ex - sx);
}
- else
- {
+ else {
if(ey > sy+1) { removelines(sy+1, ey-(sy+1)); ey = sy+1; }
if(ex == lines[ey].len) removelines(ey, 1); else lines[ey].del(0, ex);
if(sx == 0) removelines(sy, 1); else lines[sy].del(sx, lines[sy].len - sx);
cx = sx;
cy = sy;
editline ¤t = currentline();
- if(cx >= current.len && cy < lines.length() - 1)
- {
+ if(cx >= current.len && cy < lines.length() - 1) {
current.append(lines[cy+1].text);
removelines(cy + 1, 1);
}
return true;
}
-
- void insert(char ch)
- {
+ void insert(char ch) {
del();
editline ¤t = currentline();
- if(ch == '\n')
- {
- if(maxy == -1 || cy < maxy-1)
- {
+ if(ch == '\n') {
+ if(maxy == -1 || cy < maxy-1) {
editline newline(¤t.text[cx]);
current.chop(cx);
cy = min(lines.length(), cy+1);
else current.chop(cx);
cx = 0;
}
- else
- {
+ else {
int len = current.len;
if(maxx >= 0 && len > maxx-1) len = maxx-1;
if(cx <= len) current.insert(&ch, cx++, 1);
}
}
-
- void insert(const char *s)
- {
+ void insert(const char *s) {
while(*s) insert(*s++);
}
-
- void insertallfrom(editor *b)
- {
+ void insertallfrom(editor *b) {
if(b==this) return;
-
del();
-
- if(b->lines.length() == 1 || maxy == 1)
- {
+ if(b->lines.length() == 1 || maxy == 1) {
editline ¤t = currentline();
char *str = b->lines[0].text;
int slen = b->lines[0].len;
if(maxx >= 0 && b->lines[0].len + cx > maxx) slen = maxx-cx;
- if(slen > 0)
- {
+ if(slen > 0) {
int len = current.len;
if(maxx >= 0 && slen + cx + len > maxx) len = max(0, maxx-(cx+slen));
current.insert(str, cx, slen);
cx += slen;
}
}
- else
- {
- loopv(b->lines)
- {
- if(!i)
- {
+ else {
+ loopv(b->lines) {
+ if(!i) {
lines[cy++].append(b->lines[i].text);
}
- else if(i >= b->lines.length())
- {
+ else if(i >= b->lines.length()) {
cx = b->lines[i].len;
lines[cy].prepend(b->lines[i].text);
}
}
}
}
-
- void key(int code)
- {
- switch(code)
- {
+ void key(int code) {
+ switch(code) {
case SDLK_UP:
- if(linewrap)
- {
+ if(linewrap) {
int x, y;
char *str = currentline().text;
text_pos(str, cx+1, x, y, pixelwidth);
cy--;
break;
case SDLK_DOWN:
- if(linewrap)
- {
+ if(linewrap) {
int x, y, width, height;
char *str = currentline().text;
text_pos(str, cx, x, y, pixelwidth);
cx++;
break;
case SDLK_DELETE:
- if(!del())
- {
+ if(!del()) {
editline ¤t = currentline();
if(cx < current.len) current.del(cx, 1);
- else if(cy < lines.length()-1)
- { //combine with next line
+ else if(cy < lines.length()-1) {
+ //combine with next line
current.append(lines[cy+1].text);
removelines(cy+1, 1);
}
}
break;
case SDLK_BACKSPACE:
- if(!del())
- {
+ if(!del()) {
editline ¤t = currentline();
if(cx > 0) current.del(--cx, 1);
- else if(cy > 0)
- { //combine with previous line
+ else if(cy > 0) {
+ //combine with previous line
cx = lines[cy-1].len;
lines[cy-1].append(current.text);
removelines(cy--, 1);
break;
}
}
-
- void input(const char *str, int len)
- {
+ void input(const char *str, int len) {
loopi(len) insert(str[i]);
}
-
- void hit(int hitx, int hity, bool dragged)
- {
+ void hit(int hitx, int hity, bool dragged) {
int maxwidth = linewrap?pixelwidth:-1;
int h = 0;
- for(int i = scrolly; i < lines.length(); i++)
- {
+ for(int i = scrolly; i < lines.length(); i++) {
int width, height;
text_bounds(lines[i].text, width, height, maxwidth);
if(h + height > pixelheight) break;
-
- if(hity >= h && hity <= h+height)
- {
+ if(hity >= h && hity <= h+height) {
int x = text_visible(lines[i].text, hitx, hity-h, maxwidth);
if(dragged) { mx = x; my = i; } else { cx = x; cy = i; };
break;
h+=height;
}
}
-
- int limitscrolly()
- {
+ int limitscrolly() {
int maxwidth = linewrap?pixelwidth:-1;
int slines = lines.length();
- for(int ph = pixelheight; slines > 0 && ph > 0;)
- {
+ for(int ph = pixelheight; slines > 0 && ph > 0;) {
int width, height;
text_bounds(lines[slines-1].text, width, height, maxwidth);
if(height > ph) break;
}
return slines;
}
-
- void draw(int x, int y, int color, bool hit)
- {
+ void draw(int x, int y, int color, bool hit) {
int maxwidth = linewrap?pixelwidth:-1;
-
int sx, sy, ex, ey;
bool selection = region(sx, sy, ex, ey);
-
// fix scrolly so that <cx, cy> is always on screen
if(cy < scrolly) scrolly = cy;
- else
- {
+ else {
if(scrolly < 0) scrolly = 0;
int h = 0;
- for(int i = cy; i >= scrolly; i--)
- {
+ for(int i = cy; i >= scrolly; i--) {
int width, height;
text_bounds(lines[i].text, width, height, maxwidth);
if(h + height > pixelheight) { scrolly = i+1; break; }
h += height;
}
}
-
- if(selection)
- {
+ if(selection) {
// convert from cursor coords into pixel coords
int psx, psy, pex, pey;
text_pos(lines[sy].text, sx, psx, psy, maxwidth);
text_pos(lines[ey].text, ex, pex, pey, maxwidth);
int maxy = lines.length();
int h = 0;
- for(int i = scrolly; i < maxy; i++)
- {
+ for(int i = scrolly; i < maxy; i++) {
int width, height;
text_bounds(lines[i].text, width, height, maxwidth);
if(h + height > pixelheight) { maxy = i; break; }
h += height;
}
maxy--;
-
- if(ey >= scrolly && sy <= maxy)
- {
+ if(ey >= scrolly && sy <= maxy) {
// crop top/bottom within window
if(sy < scrolly) { sy = scrolly; psy = 0; psx = 0; }
if(ey > maxy) { ey = maxy; pey = pixelheight - FONTH; pex = pixelwidth; }
-
hudnotextureshader->set();
gle::colorub(0xA0, 0x80, 0x80);
gle::defvertex(2);
gle::begin(GL_QUADS);
- if(psy == pey)
- {
+ if(psy == pey) {
gle::attribf(x+psx, y+psy);
gle::attribf(x+pex, y+psy);
gle::attribf(x+pex, y+pey+FONTH);
gle::attribf(x+psx, y+pey+FONTH);
}
- else
- { gle::attribf(x+psx, y+psy);
+ else {
+ gle::attribf(x+psx, y+psy);
gle::attribf(x+psx, y+psy+FONTH);
gle::attribf(x+pixelwidth, y+psy+FONTH);
gle::attribf(x+pixelwidth, y+psy);
- if(pey-psy > FONTH)
- {
+ if(pey-psy > FONTH) {
gle::attribf(x, y+psy+FONTH);
gle::attribf(x+pixelwidth, y+psy+FONTH);
gle::attribf(x+pixelwidth, y+pey);
hudshader->set();
}
}
-
int h = 0;
- for(int i = scrolly; i < lines.length(); i++)
- {
+ for(int i = scrolly; i < lines.length(); i++) {
int width, height;
text_bounds(lines[i].text, width, height, maxwidth);
if(h + height > pixelheight) break;
-
draw_text(lines[i].text, x, y+h, color>>16, (color>>8)&0xFF, color&0xFF, 0xFF, hit&&(cy==i)?cx:-1, maxwidth);
- if(linewrap && height > FONTH) // line wrap indicator
- {
+ if(linewrap && height > FONTH) { // line wrap indicator {
hudnotextureshader->set();
gle::colorub(0x80, 0xA0, 0x80);
gle::defvertex(2);
static editor *currentfocus() { return editors.length() ? editors.last() : NULL; }
-static void readyeditors()
-{
+static void readyeditors() {
loopv(editors) editors[i]->active = (editors[i]->mode==EDITORFOREVER);
}
-static void flusheditors()
-{
- loopvrev(editors) if(!editors[i]->active)
- {
+static void flusheditors() {
+ loopvrev(editors) if(!editors[i]->active) {
editor *e = editors.remove(i);
DELETEP(e);
}
}
-static editor *useeditor(const char *name, int mode, bool focus, const char *initval = NULL)
-{
- loopv(editors) if(strcmp(editors[i]->name, name) == 0)
- {
+static editor *useeditor(const char *name, int mode, bool focus, const char *initval = NULL) {
+ loopv(editors) if(strcmp(editors[i]->name, name) == 0) {
editor *e = editors[i];
if(focus) { editors.add(e); editors.remove(i); } // re-position as last
e->active = true;
ICOMMAND(textlist, "", (), // @DEBUG return list of all the editors
vector<char> s;
- loopv(editors)
- {
+ loopv(editors) {
if(i > 0) s.put(", ", 2);
s.put(editors[i]->name, strlen(editors[i]->name));
}
top->save();
);
TEXTCOMMAND(textload, "s", (char *file), // loads into the topmost editor, returns filename if no args
- if(*file)
- {
+ if(*file) {
top->setfile(path(file, true));
top->load();
}
else if(top->filename) result(top->filename);
);
-TEXTCOMMAND(textinit, "sss", (char *name, char *file, char *initval), // loads into named editor if no file assigned and editor has been rendered
-{
+TEXTCOMMAND(textinit, "sss", (char *name, char *file, char *initval), { // loads into named editor if no file assigned and editor has been rendered {
editor *e = NULL;
loopv(editors) if(!strcmp(editors[i]->name, name)) { e = editors[i]; break; }
- if(e && e->rendered && !e->filename && *file && (e->lines.empty() || (e->lines.length() == 1 && !strcmp(e->lines[0].text, initval))))
- {
+ if(e && e->rendered && !e->filename && *file && (e->lines.empty() || (e->lines.length() == 1 && !strcmp(e->lines[0].text, initval)))) {
e->setfile(path(file, true));
e->load();
}
(SDL_VERSIONNUM(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_PATCHLEVEL) >= SDL_VERSIONNUM(X, Y, Z))
#endif
-template<int BPP> static void halvetexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst)
-{
- for(uchar *yend = &src[sh*stride]; src < yend;)
- {
- for(uchar *xend = &src[sw*BPP], *xsrc = src; xsrc < xend; xsrc += 2*BPP, dst += BPP)
- {
+template<int BPP> static void halvetexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst) {
+ for(uchar *yend = &src[sh*stride]; src < yend;) {
+ for(uchar *xend = &src[sw*BPP], *xsrc = src; xsrc < xend; xsrc += 2*BPP, dst += BPP) {
loopi(BPP) dst[i] = (uint(xsrc[i]) + uint(xsrc[i+BPP]) + uint(xsrc[stride+i]) + uint(xsrc[stride+i+BPP]))>>2;
}
src += 2*stride;
}
}
-template<int BPP> static void shifttexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh)
-{
+template<int BPP> static void shifttexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh) {
uint wfrac = sw/dw, hfrac = sh/dh, wshift = 0, hshift = 0;
while(dw<<wshift < sw) wshift++;
while(dh<<hshift < sh) hshift++;
uint tshift = wshift + hshift;
- for(uchar *yend = &src[sh*stride]; src < yend;)
- {
- for(uchar *xend = &src[sw*BPP], *xsrc = src; xsrc < xend; xsrc += wfrac*BPP, dst += BPP)
- {
+ for(uchar *yend = &src[sh*stride]; src < yend;) {
+ for(uchar *xend = &src[sw*BPP], *xsrc = src; xsrc < xend; xsrc += wfrac*BPP, dst += BPP) {
uint t[BPP] = {0};
for(uchar *ycur = xsrc, *xend = &ycur[wfrac*BPP], *yend = &src[hfrac*stride];
ycur < yend;
- ycur += stride, xend += stride)
- {
+ ycur += stride, xend += stride) {
for(uchar *xcur = ycur; xcur < xend; xcur += BPP)
loopi(BPP) t[i] += xcur[i];
}
}
}
-template<int BPP> static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh)
-{
+template<int BPP> static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint stride, uchar * RESTRICT dst, uint dw, uint dh) {
uint wfrac = (sw<<12)/dw, hfrac = (sh<<12)/dh, darea = dw*dh, sarea = sw*sh;
int over, under;
for(over = 0; (darea>>over) > sarea; over++);
area = ((ullong)darea<<ascale)/sarea;
dw *= wfrac;
dh *= hfrac;
- for(uint y = 0; y < dh; y += hfrac)
- {
+ for(uint y = 0; y < dh; y += hfrac) {
const uint yn = y + hfrac - 1, yi = y>>12, h = (yn>>12) - yi, ylow = ((yn|(-int(h)>>24))&0xFFFU) + 1 - (y&0xFFFU), yhigh = (yn&0xFFFU) + 1;
const uchar *ysrc = &src[yi*stride];
- for(uint x = 0; x < dw; x += wfrac, dst += BPP)
- {
+ for(uint x = 0; x < dw; x += wfrac, dst += BPP) {
const uint xn = x + wfrac - 1, xi = x>>12, w = (xn>>12) - xi, xlow = ((w+0xFFFU)&0x1000U) - (x&0xFFFU), xhigh = (xn&0xFFFU) + 1;
const uchar *xsrc = &ysrc[xi*BPP], *xend = &xsrc[w*BPP];
uint t[BPP] = {0};
for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP)
loopi(BPP) t[i] += xcur[i];
loopi(BPP) t[i] = (ylow*(t[i] + ((xsrc[i]*xlow + xend[i]*xhigh)>>12)))>>cscale;
- if(h)
- {
+ if(h) {
xsrc += stride;
xend += stride;
- for(uint hcur = h; --hcur; xsrc += stride, xend += stride)
- {
+ for(uint hcur = h; --hcur; xsrc += stride, xend += stride) {
uint c[BPP] = {0};
for(const uchar *xcur = &xsrc[BPP]; xcur < xend; xcur += BPP)
loopi(BPP) c[i] += xcur[i];
}
}
-static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint bpp, uint pitch, uchar * RESTRICT dst, uint dw, uint dh)
-{
- if(sw == dw*2 && sh == dh*2)
- {
- switch(bpp)
- {
+static void scaletexture(uchar * RESTRICT src, uint sw, uint sh, uint bpp, uint pitch, uchar * RESTRICT dst, uint dw, uint dh) {
+ if(sw == dw*2 && sh == dh*2) {
+ switch(bpp) {
case 1: return halvetexture<1>(src, sw, sh, pitch, dst);
case 2: return halvetexture<2>(src, sw, sh, pitch, dst);
case 3: return halvetexture<3>(src, sw, sh, pitch, dst);
case 4: return halvetexture<4>(src, sw, sh, pitch, dst);
}
}
- else if(sw < dw || sh < dh || sw&(sw-1) || sh&(sh-1) || dw&(dw-1) || dh&(dh-1))
- {
- switch(bpp)
- {
+ else if(sw < dw || sh < dh || sw&(sw-1) || sh&(sh-1) || dw&(dw-1) || dh&(dh-1)) {
+ switch(bpp) {
case 1: return scaletexture<1>(src, sw, sh, pitch, dst, dw, dh);
case 2: return scaletexture<2>(src, sw, sh, pitch, dst, dw, dh);
case 3: return scaletexture<3>(src, sw, sh, pitch, dst, dw, dh);
case 4: return scaletexture<4>(src, sw, sh, pitch, dst, dw, dh);
}
}
- else
- {
- switch(bpp)
- {
+ else {
+ switch(bpp) {
case 1: return shifttexture<1>(src, sw, sh, pitch, dst, dw, dh);
case 2: return shifttexture<2>(src, sw, sh, pitch, dst, dw, dh);
case 3: return shifttexture<3>(src, sw, sh, pitch, dst, dw, dh);
}
}
-static void reorientnormals(uchar * RESTRICT src, int sw, int sh, int bpp, int stride, uchar * RESTRICT dst, bool flipx, bool flipy, bool swapxy)
-{
+static void reorientnormals(uchar * RESTRICT src, int sw, int sh, int bpp, int stride, uchar * RESTRICT dst, bool flipx, bool flipy, bool swapxy) {
int stridex = bpp, stridey = bpp;
if(swapxy) stridex *= sh; else stridey *= sw;
if(flipx) { dst += (sw-1)*stridex; stridex = -stridex; }
if(flipy) { dst += (sh-1)*stridey; stridey = -stridey; }
uchar *srcrow = src;
- loopi(sh)
- {
- for(uchar *curdst = dst, *src = srcrow, *end = &srcrow[sw*bpp]; src < end;)
- {
+ loopi(sh) {
+ for(uchar *curdst = dst, *src = srcrow, *end = &srcrow[sw*bpp]; src < end;) {
uchar nx = *src++, ny = *src++;
if(flipx) nx = 255-nx;
if(flipy) ny = 255-ny;
}
template<int BPP>
-static inline void reorienttexture(uchar * RESTRICT src, int sw, int sh, int stride, uchar * RESTRICT dst, bool flipx, bool flipy, bool swapxy)
-{
+static inline void reorienttexture(uchar * RESTRICT src, int sw, int sh, int stride, uchar * RESTRICT dst, bool flipx, bool flipy, bool swapxy) {
int stridex = BPP, stridey = BPP;
if(swapxy) stridex *= sh; else stridey *= sw;
if(flipx) { dst += (sw-1)*stridex; stridex = -stridex; }
if(flipy) { dst += (sh-1)*stridey; stridey = -stridey; }
uchar *srcrow = src;
- loopi(sh)
- {
- for(uchar *curdst = dst, *src = srcrow, *end = &srcrow[sw*BPP]; src < end;)
- {
+ loopi(sh) {
+ for(uchar *curdst = dst, *src = srcrow, *end = &srcrow[sw*BPP]; src < end;) {
loopk(BPP) curdst[k] = *src++;
curdst += stridex;
}
}
}
-static void reorienttexture(uchar * RESTRICT src, int sw, int sh, int bpp, int stride, uchar * RESTRICT dst, bool flipx, bool flipy, bool swapxy)
-{
- switch(bpp)
- {
+static void reorienttexture(uchar * RESTRICT src, int sw, int sh, int bpp, int stride, uchar * RESTRICT dst, bool flipx, bool flipy, bool swapxy) {
+ switch(bpp) {
case 1: return reorienttexture<1>(src, sw, sh, stride, dst, flipx, flipy, swapxy);
case 2: return reorienttexture<2>(src, sw, sh, stride, dst, flipx, flipy, swapxy);
case 3: return reorienttexture<3>(src, sw, sh, stride, dst, flipx, flipy, swapxy);
}
}
-static void reorients3tc(GLenum format, int blocksize, int w, int h, uchar *src, uchar *dst, bool flipx, bool flipy, bool swapxy, bool normals = false)
-{
+static void reorients3tc(GLenum format, int blocksize, int w, int h, uchar *src, uchar *dst, bool flipx, bool flipy, bool swapxy, bool normals = false) {
int bx1 = 0, by1 = 0, bx2 = min(w, 4), by2 = min(h, 4), bw = (w+3)/4, bh = (h+3)/4, stridex = blocksize, stridey = blocksize;
if(swapxy) stridex *= bw; else stridey *= bh;
if(flipx) { dst += (bw-1)*stridex; stridex = -stridex; bx1 += 4-bx2; bx2 = 4; }
if(flipy) { dst += (bh-1)*stridey; stridey = -stridey; by1 += 4-by2; by2 = 4; }
- loopi(bh)
- {
- for(uchar *curdst = dst, *end = &src[bw*blocksize]; src < end; src += blocksize, curdst += stridex)
- {
- if(format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT)
- {
+ loopi(bh) {
+ for(uchar *curdst = dst, *end = &src[bw*blocksize]; src < end; src += blocksize, curdst += stridex) {
+ if(format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) {
ullong salpha = lilswap(*(const ullong *)src), dalpha = 0;
uint xmask = flipx ? 15 : 0, ymask = flipy ? 15 : 0, xshift = 2, yshift = 4;
if(swapxy) swap(xshift, yshift);
- for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++)
- {
+ for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++) {
dalpha |= ((salpha&15) << (((xmask^x)<<xshift) + ((ymask^y)<<yshift)));
salpha >>= 4;
}
src += 8;
curdst += 8;
}
- else if(format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
- {
+ else if(format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) {
uchar alpha1 = src[0], alpha2 = src[1];
ullong salpha = lilswap(*(const ushort *)&src[2]) + ((ullong)lilswap(*(const uint *)&src[4]) << 16), dalpha = 0;
uint xmask = flipx ? 7 : 0, ymask = flipy ? 7 : 0, xshift = 0, yshift = 2;
if(swapxy) swap(xshift, yshift);
- for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++)
- {
+ for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++) {
dalpha |= ((salpha&7) << (3*((xmask^x)<<xshift) + ((ymask^y)<<yshift)));
salpha >>= 3;
}
src += 8;
curdst += 8;
}
-
ushort color1 = lilswap(*(const ushort *)src), color2 = lilswap(*(const ushort *)&src[2]);
uint sbits = lilswap(*(const uint *)&src[4]);
- if(normals)
- {
+ if(normals) {
ushort ncolor1 = color1, ncolor2 = color2;
- if(flipx)
- {
+ if(flipx) {
ncolor1 = (ncolor1 & ~0xF800) | (0xF800 - (ncolor1 & 0xF800));
ncolor2 = (ncolor2 & ~0xF800) | (0xF800 - (ncolor2 & 0xF800));
}
- if(flipy)
- {
+ if(flipy) {
ncolor1 = (ncolor1 & ~0x7E0) | (0x7E0 - (ncolor1 & 0x7E0));
ncolor2 = (ncolor2 & ~0x7E0) | (0x7E0 - (ncolor2 & 0x7E0));
}
- if(swapxy)
- {
+ if(swapxy) {
ncolor1 = (ncolor1 & 0x1F) | (((((ncolor1 >> 11) & 0x1F) * 0x3F) / 0x1F) << 5) | (((((ncolor1 >> 5) & 0x3F) * 0x1F) / 0x3F) << 11);
ncolor2 = (ncolor2 & 0x1F) | (((((ncolor2 >> 11) & 0x1F) * 0x3F) / 0x1F) << 5) | (((((ncolor2 >> 5) & 0x3F) * 0x1F) / 0x3F) << 11);
}
}
uint dbits = 0, xmask = flipx ? 3 : 0, ymask = flipy ? 3 : 0, xshift = 1, yshift = 3;
if(swapxy) swap(xshift, yshift);
- for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++)
- {
+ for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++) {
dbits |= ((sbits&3) << (((xmask^x)<<xshift) + ((ymask^y)<<yshift)));
sbits >>= 2;
}
*(ushort *)curdst = lilswap(color1);
*(ushort *)&curdst[2] = lilswap(color2);
*(uint *)&curdst[4] = lilswap(dbits);
-
if(blocksize > 8) { src -= 8; curdst -= 8; }
}
dst += stridey;
}
}
-static void reorientrgtc(GLenum format, int blocksize, int w, int h, uchar *src, uchar *dst, bool flipx, bool flipy, bool swapxy)
-{
+static void reorientrgtc(GLenum format, int blocksize, int w, int h, uchar *src, uchar *dst, bool flipx, bool flipy, bool swapxy) {
int bx1 = 0, by1 = 0, bx2 = min(w, 4), by2 = min(h, 4), bw = (w+3)/4, bh = (h+3)/4, stridex = blocksize, stridey = blocksize;
if(swapxy) stridex *= bw; else stridey *= bh;
if(flipx) { dst += (bw-1)*stridex; stridex = -stridex; bx1 += 4-bx2; bx2 = 4; }
if(flipy) { dst += (bh-1)*stridey; stridey = -stridey; by1 += 4-by2; by2 = 4; }
stridex -= blocksize;
- loopi(bh)
- {
- for(uchar *curdst = dst, *end = &src[bw*blocksize]; src < end; curdst += stridex)
- {
- loopj(blocksize/8)
- {
+ loopi(bh) {
+ for(uchar *curdst = dst, *end = &src[bw*blocksize]; src < end; curdst += stridex) {
+ loopj(blocksize/8) {
uchar val1 = src[0], val2 = src[1];
ullong sval = lilswap(*(const ushort *)&src[2]) + ((ullong)lilswap(*(const uint *)&src[4] )<< 16), dval = 0;
uint xmask = flipx ? 7 : 0, ymask = flipy ? 7 : 0, xshift = 0, yshift = 2;
if(swapxy) swap(xshift, yshift);
- for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++)
- {
+ for(int y = by1; y < by2; y++) for(int x = bx1; x < bx2; x++) {
dval |= ((sval&7) << (3*((xmask^x)<<xshift) + ((ymask^y)<<yshift)));
sval >>= 3;
}
}
}
-#define writetex(t, body) do \
- { \
+#define writetex(t, body) do { \
+ \
uchar *dstrow = t.data; \
- loop(y, t.h) \
- { \
- for(uchar *dst = dstrow, *end = &dstrow[t.w*t.bpp]; dst < end; dst += t.bpp) \
- { \
+ loop(y, t.h) { \
+ \
+ for(uchar *dst = dstrow, *end = &dstrow[t.w*t.bpp]; dst < end; dst += t.bpp) { \
+ \
body; \
} \
dstrow += t.pitch; \
} \
} while(0)
-#define readwritetex(t, s, body) do \
- { \
+#define readwritetex(t, s, body) do { \
+ \
uchar *dstrow = t.data, *srcrow = s.data; \
- loop(y, t.h) \
- { \
- for(uchar *dst = dstrow, *src = srcrow, *end = &srcrow[s.w*s.bpp]; src < end; dst += t.bpp, src += s.bpp) \
- { \
+ loop(y, t.h) { \
+ \
+ for(uchar *dst = dstrow, *src = srcrow, *end = &srcrow[s.w*s.bpp]; src < end; dst += t.bpp, src += s.bpp) { \
+ \
body; \
} \
dstrow += t.pitch; \
} \
} while(0)
-#define read2writetex(t, s1, src1, s2, src2, body) do \
- { \
+#define read2writetex(t, s1, src1, s2, src2, body) do { \
+ \
uchar *dstrow = t.data, *src1row = s1.data, *src2row = s2.data; \
- loop(y, t.h) \
- { \
- for(uchar *dst = dstrow, *end = &dstrow[t.w*t.bpp], *src1 = src1row, *src2 = src2row; dst < end; dst += t.bpp, src1 += s1.bpp, src2 += s2.bpp) \
- { \
+ loop(y, t.h) { \
+ \
+ for(uchar *dst = dstrow, *end = &dstrow[t.w*t.bpp], *src1 = src1row, *src2 = src2row; dst < end; dst += t.bpp, src1 += s1.bpp, src2 += s2.bpp) { \
+ \
body; \
} \
dstrow += t.pitch; \
} \
} while(0)
-#define readwritergbtex(t, s, body) \
- { \
+#define readwritergbtex(t, s, body) { \
+ \
if(t.bpp >= 3) readwritetex(t, s, body); \
- else \
- { \
+ else { \
+ \
ImageData rgb(t.w, t.h, 3); \
read2writetex(rgb, t, orig, s, src, { dst[0] = dst[1] = dst[2] = orig[0]; body; }); \
t.replace(rgb); \
} \
}
-void forcergbimage(ImageData &s)
-{
+void forcergbimage(ImageData &s) {
if(s.bpp >= 3) return;
ImageData d(s.w, s.h, 3);
readwritetex(d, s, { dst[0] = dst[1] = dst[2] = src[0]; });
s.replace(d);
}
-#define readwritergbatex(t, s, body) \
- { \
+#define readwritergbatex(t, s, body) { \
+ \
if(t.bpp >= 4) { readwritetex(t, s, body); } \
- else \
- { \
+ else { \
+ \
ImageData rgba(t.w, t.h, 4); \
if(t.bpp==3) read2writetex(rgba, t, orig, s, src, { dst[0] = orig[0]; dst[1] = orig[1]; dst[2] = orig[2]; body; }); \
else read2writetex(rgba, t, orig, s, src, { dst[0] = dst[1] = dst[2] = orig[0]; body; }); \
} \
}
-void forcergbaimage(ImageData &s)
-{
+void forcergbaimage(ImageData &s) {
if(s.bpp >= 4) return;
ImageData d(s.w, s.h, 4);
if(s.bpp==3) readwritetex(d, s, { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; });
s.replace(d);
}
-void swizzleimage(ImageData &s)
-{
- if(s.bpp==2)
- {
+void swizzleimage(ImageData &s) {
+ if(s.bpp==2) {
ImageData d(s.w, s.h, 4);
readwritetex(d, s, { dst[0] = dst[1] = dst[2] = src[0]; dst[3] = src[1]; });
s.replace(d);
}
- else if(s.bpp==1)
- {
+ else if(s.bpp==1) {
ImageData d(s.w, s.h, 3);
readwritetex(d, s, { dst[0] = dst[1] = dst[2] = src[0]; });
s.replace(d);
}
}
-void texreorient(ImageData &s, bool flipx, bool flipy, bool swapxy, int type = TEX_DIFFUSE)
-{
+void texreorient(ImageData &s, bool flipx, bool flipy, bool swapxy, int type = TEX_DIFFUSE) {
ImageData d(swapxy ? s.h : s.w, swapxy ? s.w : s.h, s.bpp, s.levels, s.align, s.compressed);
- switch(s.compressed)
- {
+ switch(s.compressed) {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
[[fallthrough]];
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
[[fallthrough]];
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
[[fallthrough]];
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- {
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
uchar *dst = d.data, *src = s.data;
- loopi(s.levels)
- {
+ loopi(s.levels) {
reorients3tc(s.compressed, s.bpp, max(s.w>>i, 1), max(s.h>>i, 1), src, dst, flipx, flipy, swapxy, type==TEX_NORMAL);
src += s.calclevelsize(i);
dst += d.calclevelsize(i);
[[fallthrough]];
case GL_COMPRESSED_LUMINANCE_LATC1_EXT:
[[fallthrough]];
- case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
- {
+ case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: {
uchar *dst = d.data, *src = s.data;
- loopi(s.levels)
- {
+ loopi(s.levels) {
reorientrgtc(s.compressed, s.bpp, max(s.w>>i, 1), max(s.h>>i, 1), src, dst, flipx, flipy, swapxy);
src += s.calclevelsize(i);
dst += d.calclevelsize(i);
s.replace(d);
}
-extern const texrotation texrotations[8] =
-{
- { false, false, false }, // 0: default
- { false, true, true }, // 1: 90 degrees
- { true, true, false }, // 2: 180 degrees
- { true, false, true }, // 3: 270 degrees
- { true, false, false }, // 4: flip X
- { false, true, false }, // 5: flip Y
- { false, false, true }, // 6: transpose
+extern const texrotation texrotations[8] = {
+ { false, false, false }, // 0: default {
+ { false, true, true }, // 1: 90 degrees {
+ { true, true, false }, // 2: 180 degrees {
+ { true, false, true }, // 3: 270 degrees {
+ { true, false, false }, // 4: flip X {
+ { false, true, false }, // 5: flip Y {
+ { false, false, true }, // 6: transpose {
{ true, true, true }, // 7: flipped transpose
};
-void texrotate(ImageData &s, int numrots, int type = TEX_DIFFUSE)
-{
- if(numrots>=1 && numrots<=7)
- {
+void texrotate(ImageData &s, int numrots, int type = TEX_DIFFUSE) {
+ if(numrots>=1 && numrots<=7) {
const texrotation &r = texrotations[numrots];
texreorient(s, r.flipx, r.flipy, r.swapxy, type);
}
}
-void texoffset(ImageData &s, int xoffset, int yoffset)
-{
+void texoffset(ImageData &s, int xoffset, int yoffset) {
xoffset = max(xoffset, 0);
xoffset %= s.w;
yoffset = max(yoffset, 0);
if(!xoffset && !yoffset) return;
ImageData d(s.w, s.h, s.bpp);
uchar *src = s.data;
- loop(y, s.h)
- {
+ loop(y, s.h) {
uchar *dst = (uchar *)d.data+((y+yoffset)%d.h)*d.pitch;
memcpy(dst+xoffset*s.bpp, src, (s.w-xoffset)*s.bpp);
memcpy(dst, src+(s.w-xoffset)*s.bpp, xoffset*s.bpp);
s.replace(d);
}
-void texmad(ImageData &s, const vec &mul, const vec &add)
-{
+void texmad(ImageData &s, const vec &mul, const vec &add) {
if(s.bpp < 3 && (mul.x != mul.y || mul.y != mul.z || add.x != add.y || add.y != add.z))
swizzleimage(s);
int maxk = min(int(s.bpp), 3);
);
}
-void texcolorify(ImageData &s, const vec &color, vec weights)
-{
+void texcolorify(ImageData &s, const vec &color, vec weights) {
if(s.bpp < 3) return;
if(weights.iszero()) weights = vec(0.21f, 0.72f, 0.07f);
writetex(s,
);
}
-void texcolormask(ImageData &s, const vec &color1, const vec &color2)
-{
+void texcolormask(ImageData &s, const vec &color1, const vec &color2) {
if(s.bpp < 4) return;
ImageData d(s.w, s.h, 3);
readwritetex(d, s,
s.replace(d);
}
-void texdup(ImageData &s, int srcchan, int dstchan)
-{
+void texdup(ImageData &s, int srcchan, int dstchan) {
if(srcchan==dstchan || max(srcchan, dstchan) >= s.bpp) return;
writetex(s, dst[dstchan] = dst[srcchan]);
}
-void texmix(ImageData &s, int c1, int c2, int c3, int c4)
-{
+void texmix(ImageData &s, int c1, int c2, int c3, int c4) {
int numchans = c1 < 0 ? 0 : (c2 < 0 ? 1 : (c3 < 0 ? 2 : (c4 < 0 ? 3 : 4)));
if(numchans <= 0) return;
ImageData d(s.w, s.h, numchans);
readwritetex(d, s,
- switch(numchans)
- {
+ switch(numchans) {
case 4: dst[3] = src[c4];
[[fallthrough]];
case 3: dst[2] = src[c3];
s.replace(d);
}
-void texgrey(ImageData &s)
-{
+void texgrey(ImageData &s) {
if(s.bpp <= 2) return;
ImageData d(s.w, s.h, s.bpp >= 4 ? 2 : 1);
- if(s.bpp >= 4)
- {
+ if(s.bpp >= 4) {
readwritetex(d, s,
dst[0] = src[0];
dst[1] = src[3];
);
}
- else
- {
+ else {
readwritetex(d, s, dst[0] = src[0]);
}
s.replace(d);
}
-void texpremul(ImageData &s)
-{
- switch(s.bpp)
- {
+void texpremul(ImageData &s) {
+ switch(s.bpp) {
case 2:
writetex(s,
dst[0] = uchar((uint(dst[0])*uint(dst[1]))/255);
}
}
-void texagrad(ImageData &s, float x2, float y2, float x1, float y1)
-{
+void texagrad(ImageData &s, float x2, float y2, float x1, float y1) {
if(s.bpp != 2 && s.bpp != 4) return;
y1 = 1 - y1;
y2 = 1 - y2;
float minx = 1, miny = 1, maxx = 1, maxy = 1;
- if(x1 != x2)
- {
+ if(x1 != x2) {
minx = (0 - x1) / (x2 - x1);
maxx = (1 - x1) / (x2 - x1);
}
- if(y1 != y2)
- {
+ if(y1 != y2) {
miny = (0 - y1) / (y2 - y1);
maxy = (1 - y1) / (y2 - y1);
}
float dx = (maxx - minx)/max(s.w-1, 1),
dy = (maxy - miny)/max(s.h-1, 1),
cury = miny;
- for(uchar *dstrow = s.data + s.bpp - 1, *endrow = dstrow + s.h*s.pitch; dstrow < endrow; dstrow += s.pitch)
- {
+ for(uchar *dstrow = s.data + s.bpp - 1, *endrow = dstrow + s.h*s.pitch; dstrow < endrow; dstrow += s.pitch) {
float curx = minx;
- for(uchar *dst = dstrow, *end = &dstrow[s.w*s.bpp]; dst < end; dst += s.bpp)
- {
+ for(uchar *dst = dstrow, *end = &dstrow[s.w*s.bpp]; dst < end; dst += s.bpp) {
dst[0] = uchar(dst[0]*clamp(curx, 0.0f, 1.0f)*clamp(cury, 0.0f, 1.0f));
curx += dx;
}
extern int usetexcompress;
-void setuptexcompress()
-{
+void setuptexcompress() {
if(!usetexcompress) return;
-
GLenum hint = GL_DONT_CARE;
- switch(texcompressquality)
- {
+ switch(texcompressquality) {
case 1: hint = GL_NICEST; break;
case 0: hint = GL_FASTEST; break;
}
glHint(GL_TEXTURE_COMPRESSION_HINT, hint);
}
-GLenum compressedformat(GLenum format, int w, int h, int force = 0)
-{
- if(usetexcompress && texcompress && force >= 0 && (force || max(w, h) >= texcompress)) switch(format)
- {
+GLenum compressedformat(GLenum format, int w, int h, int force = 0) {
+ if(usetexcompress && texcompress && force >= 0 && (force || max(w, h) >= texcompress)) switch(format) {
case GL_RGB5:
case GL_RGB8:
case GL_RGB: return usetexcompress > 1 ? GL_COMPRESSED_RGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGB;
return format;
}
-GLenum uncompressedformat(GLenum format)
-{
- switch(format)
- {
+GLenum uncompressedformat(GLenum format) {
+ switch(format) {
case GL_COMPRESSED_ALPHA:
return GL_ALPHA;
case GL_COMPRESSED_LUMINANCE:
return GL_FALSE;
}
-int formatsize(GLenum format)
-{
- switch(format)
- {
+int formatsize(GLenum format) {
+ switch(format) {
case GL_RED:
case GL_LUMINANCE:
case GL_ALPHA: return 1;
VARFP(usenp2, 0, 0, 1, initwarning("texture quality", INIT_LOAD));
-void resizetexture(int w, int h, bool mipmap, bool canreduce, GLenum target, int compress, int &tw, int &th)
-{
+void resizetexture(int w, int h, bool mipmap, bool canreduce, GLenum target, int compress, int &tw, int &th) {
int hwlimit = target==GL_TEXTURE_CUBE_MAP ? hwcubetexsize : hwtexsize,
sizelimit = mipmap && maxtexsize ? min(maxtexsize, hwlimit) : hwlimit;
- if(compress > 0 && !usetexcompress)
- {
+ if(compress > 0 && !usetexcompress) {
w = max(w/compress, 1);
h = max(h/compress, 1);
}
- if(canreduce && texreduce)
- {
+ if(canreduce && texreduce) {
w = max(w>>texreduce, 1);
h = max(h>>texreduce, 1);
}
w = min(w, sizelimit);
h = min(h, sizelimit);
- if(!usenp2 && (w&(w-1) || h&(h-1)))
- {
+ if(!usenp2 && (w&(w-1) || h&(h-1))) {
tw = th = 1;
while(tw < w) tw *= 2;
while(th < h) th *= 2;
if(w < tw - tw/4) tw /= 2;
if(h < th - th/4) th /= 2;
}
- else
- {
+ else {
tw = w;
th = h;
}
}
-void uploadtexture(int tnum, GLenum target, GLenum internal, int tw, int th, GLenum format, GLenum type, void *pixels, int pw, int ph, int pitch, bool mipmap)
-{
+void uploadtexture(int tnum, GLenum target, GLenum internal, int tw, int th, GLenum format, GLenum type, void *pixels, int pw, int ph, int pitch, bool mipmap) {
int bpp = formatsize(format), row = 0, rowalign = 0;
if(!pitch) pitch = pw*bpp;
uchar *buf = NULL;
- if(pw!=tw || ph!=th)
- {
+ if(pw!=tw || ph!=th) {
buf = new uchar[tw*th*bpp];
scaletexture((uchar *)pixels, pw, ph, bpp, pitch, buf, tw, th);
}
- else if(tw*bpp != pitch)
- {
+ else if(tw*bpp != pitch) {
row = pitch/bpp;
rowalign = texalign(pixels, pitch, 1);
while(rowalign > 0 && ((row*bpp + rowalign - 1)/rowalign)*rowalign != pitch) rowalign >>= 1;
- if(!rowalign)
- {
+ if(!rowalign) {
row = 0;
buf = new uchar[tw*th*bpp];
loopi(th) memcpy(&buf[i*tw*bpp], &((uchar *)pixels)[i*pitch], tw*bpp);
}
}
- for(int level = 0, align = 0, mw = tw, mh = th;; level++)
- {
+ for(int level = 0, align = 0, mw = tw, mh = th;; level++) {
uchar *src = buf ? buf : (uchar *)pixels;
if(buf) pitch = mw*bpp;
int srcalign = row > 0 ? rowalign : texalign(src, pitch, 1);
int srcw = mw, srch = mh;
if(mw > 1) mw /= 2;
if(mh > 1) mh /= 2;
- if(src)
- {
+ if(src) {
if(!buf) buf = new uchar[mw*mh*bpp];
scaletexture(src, srcw, srch, bpp, pitch, buf, mw, mh);
}
if(buf) delete[] buf;
}
-void uploadcompressedtexture(GLenum target, GLenum subtarget, GLenum format, int w, int h, uchar *data, int align, int blocksize, int levels, bool mipmap)
-{
+void uploadcompressedtexture(GLenum target, GLenum subtarget, GLenum format, int w, int h, uchar *data, int align, int blocksize, int levels, bool mipmap) {
int hwlimit = target==GL_TEXTURE_CUBE_MAP ? hwcubetexsize : hwtexsize,
sizelimit = levels > 1 && maxtexsize ? min(maxtexsize, hwlimit) : hwlimit;
int level = 0;
- loopi(levels)
- {
+ loopi(levels) {
int size = ((w + align-1)/align) * ((h + align-1)/align) * blocksize;
- if(w <= sizelimit && h <= sizelimit)
- {
+ if(w <= sizelimit && h <= sizelimit) {
glCompressedTexImage2D_(subtarget, level, format, w, h, 0, size, data);
level++;
if(!mipmap) break;
}
}
-GLenum textarget(GLenum subtarget)
-{
- switch(subtarget)
- {
+GLenum textarget(GLenum subtarget) {
+ switch(subtarget) {
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
return subtarget;
}
-const GLint *swizzlemask(GLenum format)
-{
+const GLint *swizzlemask(GLenum format) {
static const GLint luminance[4] = { GL_RED, GL_RED, GL_RED, GL_ONE };
static const GLint luminancealpha[4] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
- switch(format)
- {
+ switch(format) {
case GL_RED: return luminance;
case GL_RG: return luminancealpha;
}
return NULL;
}
-void setuptexparameters(int tnum, void *pixels, int clamp, int filter, GLenum format, GLenum target, bool swizzle)
-{
+void setuptexparameters(int tnum, void *pixels, int clamp, int filter, GLenum format, GLenum target, bool swizzle) {
glBindTexture(target, tnum);
glTexParameteri(target, GL_TEXTURE_WRAP_S, clamp&1 ? GL_CLAMP_TO_EDGE : (clamp&0x100 ? GL_MIRRORED_REPEAT : GL_REPEAT));
glTexParameteri(target, GL_TEXTURE_WRAP_T, clamp&2 ? GL_CLAMP_TO_EDGE : (clamp&0x200 ? GL_MIRRORED_REPEAT : GL_REPEAT));
(bilinear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR) :
(bilinear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST)) :
(filter && bilinear ? GL_LINEAR : GL_NEAREST));
- if(swizzle && hasTRG && hasTSW)
- {
+ if(swizzle && hasTRG && hasTSW) {
const GLint *mask = swizzlemask(format);
if(mask) glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, mask);
}
}
-static GLenum textype(GLenum &component, GLenum &format)
-{
+static GLenum textype(GLenum &component, GLenum &format) {
GLenum type = GL_UNSIGNED_BYTE;
- switch(component)
- {
+ switch(component) {
case GL_R16F:
case GL_R32F:
if(!format) format = GL_RED;
type = GL_FLOAT;
break;
-
case GL_RG16F:
case GL_RG32F:
if(!format) format = GL_RG;
type = GL_FLOAT;
break;
-
case GL_RGB16F:
case GL_RGB32F:
if(!format) format = GL_RGB;
type = GL_FLOAT;
break;
-
case GL_RGBA16F:
case GL_RGBA32F:
if(!format) format = GL_RGBA;
type = GL_FLOAT;
break;
-
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32:
if(!format) format = GL_DEPTH_COMPONENT;
break;
-
case GL_RGB5:
case GL_RGB8:
case GL_RGB10:
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
if(!format) format = GL_RGB;
break;
-
case GL_RGB5_A1:
case GL_RGBA8:
case GL_RGB10_A2:
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
if(!format) format = GL_RGBA;
break;
-
case GL_DEPTH_STENCIL:
case GL_DEPTH24_STENCIL8:
if(!format) format = GL_DEPTH_STENCIL;
type = GL_UNSIGNED_INT_24_8;
break;
-
case GL_R8:
case GL_R16:
case GL_COMPRESSED_RED:
case GL_COMPRESSED_RED_RGTC1:
if(!format) format = GL_RED;
break;
-
case GL_RG8:
case GL_RG16:
case GL_COMPRESSED_RG:
case GL_COMPRESSED_RG_RGTC2:
if(!format) format = GL_RG;
break;
-
case GL_LUMINANCE8:
case GL_LUMINANCE16:
case GL_COMPRESSED_LUMINANCE:
case GL_COMPRESSED_LUMINANCE_LATC1_EXT:
if(!format) format = GL_LUMINANCE;
break;
-
case GL_LUMINANCE8_ALPHA8:
case GL_LUMINANCE16_ALPHA16:
case GL_COMPRESSED_LUMINANCE_ALPHA:
case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
if(!format) format = GL_LUMINANCE_ALPHA;
break;
-
case GL_ALPHA8:
case GL_ALPHA16:
case GL_COMPRESSED_ALPHA:
return type;
}
-void createtexture(int tnum, int w, int h, void *pixels, int clamp, int filter, GLenum component, GLenum subtarget, int pw, int ph, int pitch, bool resize, GLenum format, bool swizzle)
-{
+void createtexture(int tnum, int w, int h, void *pixels, int clamp, int filter, GLenum component, GLenum subtarget, int pw, int ph, int pitch, bool resize, GLenum format, bool swizzle) {
GLenum target = textarget(subtarget), type = textype(component, format);
if(filter >= 0 && clamp >= 0) setuptexparameters(tnum, pixels, clamp, filter, format, target, swizzle);
if(!pw) pw = w;
if(!ph) ph = h;
int tw = w, th = h;
bool mipmap = filter > 1 && pixels;
- if(resize && pixels)
- {
+ if(resize && pixels) {
resizetexture(w, h, mipmap, false, target, 0, tw, th);
if(mipmap) component = compressedformat(component, tw, th);
}
uploadtexture(tnum, subtarget, component, tw, th, format, type, pixels, pw, ph, pitch, mipmap);
}
-void createcompressedtexture(int tnum, int w, int h, uchar *data, int align, int blocksize, int levels, int clamp, int filter, GLenum format, GLenum subtarget, bool swizzle = false)
-{
+void createcompressedtexture(int tnum, int w, int h, uchar *data, int align, int blocksize, int levels, int clamp, int filter, GLenum format, GLenum subtarget, bool swizzle = false) {
GLenum target = textarget(subtarget);
if(filter >= 0 && clamp >= 0) setuptexparameters(tnum, data, clamp, filter, format, target);
uploadcompressedtexture(target, subtarget, format, w, h, data, align, blocksize, levels, filter > 1);
Texture *notexture = NULL; // used as default, ensured to be loaded
-static GLenum texformat(int bpp, bool swizzle = false)
-{
- switch(bpp)
- {
+static GLenum texformat(int bpp, bool swizzle = false) {
+ switch(bpp) {
case 1: return hasTRG && (hasTSW || !glcompat || !swizzle) ? GL_RED : GL_LUMINANCE;
case 2: return hasTRG && (hasTSW || !glcompat || !swizzle) ? GL_RG : GL_LUMINANCE_ALPHA;
case 3: return GL_RGB;
}
}
-static bool alphaformat(GLenum format)
-{
- switch(format)
- {
+static bool alphaformat(GLenum format) {
+ switch(format) {
case GL_ALPHA:
case GL_LUMINANCE_ALPHA:
case GL_RG:
}
}
-int texalign(const void *data, int w, int bpp)
-{
+int texalign(const void *data, int w, int bpp) {
int stride = w*bpp;
if(stride&1) return 1;
if(stride&2) return 2;
return 4;
}
-static Texture *newtexture(Texture *t, const char *rname, ImageData &s, int clamp = 0, bool mipit = true, bool canreduce = false, bool transient = false, int compress = 0)
-{
- if(!t)
- {
+static Texture *newtexture(Texture *t, const char *rname, ImageData &s, int clamp = 0, bool mipit = true, bool canreduce = false, bool transient = false, int compress = 0) {
+ if(!t) {
char *key = newstring(rname);
t = &textures[key];
t->name = key;
}
-
t->clamp = clamp;
t->mipmap = mipit;
t->type = Texture::IMAGE;
if(transient) t->type |= Texture::TRANSIENT;
if(clamp&0x300) t->type |= Texture::MIRROR;
- if(!s.data)
- {
+ if(!s.data) {
t->type |= Texture::STUB;
t->w = t->h = t->xs = t->ys = t->bpp = 0;
return t;
}
-
bool swizzle = !(clamp&0x10000);
GLenum format;
- if(s.compressed)
- {
+ if(s.compressed) {
format = uncompressedformat(s.compressed);
t->bpp = formatsize(format);
t->type |= Texture::COMPRESSED;
}
- else
- {
+ else {
format = texformat(s.bpp, swizzle);
t->bpp = s.bpp;
- if(swizzle && hasTRG && !hasTSW && swizzlemask(format))
- {
+ if(swizzle && hasTRG && !hasTSW && swizzlemask(format)) {
swizzleimage(s);
format = texformat(s.bpp, swizzle);
t->bpp = s.bpp;
if(alphaformat(format)) t->type |= Texture::ALPHA;
t->w = t->xs = s.w;
t->h = t->ys = s.h;
-
int filter = !canreduce || reducefilter ? (mipit ? 2 : 1) : 0;
glGenTextures(1, &t->id);
- if(s.compressed)
- {
+ if(s.compressed) {
uchar *data = s.data;
int levels = s.levels, level = 0;
- if(canreduce && texreduce) loopi(min(texreduce, s.levels-1))
- {
+ if(canreduce && texreduce) loopi(min(texreduce, s.levels-1)) {
data += s.calclevelsize(level++);
levels--;
if(t->w > 1) t->w /= 2;
if(t->h > 1) t->h /= 2;
}
int sizelimit = mipit && maxtexsize ? min(maxtexsize, hwtexsize) : hwtexsize;
- while(t->w > sizelimit || t->h > sizelimit)
- {
+ while(t->w > sizelimit || t->h > sizelimit) {
data += s.calclevelsize(level++);
levels--;
if(t->w > 1) t->w /= 2;
}
createcompressedtexture(t->id, t->w, t->h, data, s.align, s.bpp, levels, clamp, filter, s.compressed, GL_TEXTURE_2D, swizzle);
}
- else
- {
+ else {
resizetexture(t->w, t->h, mipit, canreduce, GL_TEXTURE_2D, compress, t->w, t->h);
GLenum component = compressedformat(format, t->w, t->h, compress);
createtexture(t->id, t->w, t->h, s.data, clamp, filter, component, GL_TEXTURE_2D, t->xs, t->ys, s.pitch, false, format, swizzle);
#define RGBMASKS 0x0000ff, 0x00ff00, 0xff0000, 0
#endif
-SDL_Surface *wrapsurface(void *data, int width, int height, int bpp)
-{
- switch(bpp)
- {
+SDL_Surface *wrapsurface(void *data, int width, int height, int bpp) {
+ switch(bpp) {
case 3: return SDL_CreateRGBSurfaceFrom(data, width, height, 8*bpp, bpp*width, RGBMASKS);
case 4: return SDL_CreateRGBSurfaceFrom(data, width, height, 8*bpp, bpp*width, RGBAMASKS);
}
return NULL;
}
-SDL_Surface *creatergbsurface(SDL_Surface *os)
-{
+SDL_Surface *creatergbsurface(SDL_Surface *os) {
SDL_Surface *ns = SDL_CreateRGBSurface(SDL_SWSURFACE, os->w, os->h, 24, RGBMASKS);
if(ns) SDL_BlitSurface(os, NULL, ns, NULL);
SDL_FreeSurface(os);
return ns;
}
-SDL_Surface *creatergbasurface(SDL_Surface *os)
-{
+SDL_Surface *creatergbasurface(SDL_Surface *os) {
SDL_Surface *ns = SDL_CreateRGBSurface(SDL_SWSURFACE, os->w, os->h, 32, RGBAMASKS);
- if(ns)
- {
+ if(ns) {
SDL_SetSurfaceBlendMode(os, SDL_BLENDMODE_NONE);
SDL_BlitSurface(os, NULL, ns, NULL);
}
return ns;
}
-bool checkgrayscale(SDL_Surface *s)
-{
+bool checkgrayscale(SDL_Surface *s) {
// gray scale images have 256 levels, no colorkey, and the palette is a ramp
- if(s->format->palette)
- {
+ if(s->format->palette) {
if(s->format->palette->ncolors != 256 || SDL_GetColorKey(s, NULL) >= 0) return false;
const SDL_Color *colors = s->format->palette->colors;
loopi(256) if(colors[i].r != i || colors[i].g != i || colors[i].b != i) return false;
return true;
}
-SDL_Surface *fixsurfaceformat(SDL_Surface *s)
-{
+SDL_Surface *fixsurfaceformat(SDL_Surface *s) {
if(!s) return NULL;
- if(!s->pixels || min(s->w, s->h) <= 0 || s->format->BytesPerPixel <= 0)
- {
+ if(!s->pixels || min(s->w, s->h) <= 0 || s->format->BytesPerPixel <= 0) {
SDL_FreeSurface(s);
return NULL;
}
static const uint rgbmasks[] = { RGBMASKS }, rgbamasks[] = { RGBAMASKS };
- switch(s->format->BytesPerPixel)
- {
+ switch(s->format->BytesPerPixel) {
case 1:
if(!checkgrayscale(s)) return SDL_GetColorKey(s, NULL) >= 0 ? creatergbasurface(s) : creatergbsurface(s);
break;
return s;
}
-void texflip(ImageData &s)
-{
+void texflip(ImageData &s) {
ImageData d(s.w, s.h, s.bpp);
uchar *dst = d.data, *src = &s.data[s.pitch*s.h];
- loopi(s.h)
- {
+ loopi(s.h) {
src -= s.pitch;
memcpy(dst, src, s.bpp*s.w);
dst += d.pitch;
s.replace(d);
}
-void texnormal(ImageData &s, int emphasis)
-{
+void texnormal(ImageData &s, int emphasis) {
ImageData d(s.w, s.h, 3);
uchar *src = s.data, *dst = d.data;
- loop(y, s.h) loop(x, s.w)
- {
+ loop(y, s.h) loop(x, s.w) {
vec normal(0.0f, 0.0f, 255.0f/emphasis);
normal.x += src[y*s.pitch + ((x+s.w-1)%s.w)*s.bpp];
normal.x -= src[y*s.pitch + ((x+1)%s.w)*s.bpp];
}
template<int n, int bpp, bool normals>
-static void blurtexture(int w, int h, uchar *dst, const uchar *src, int margin)
-{
- static const int weights3x3[9] =
- {
+static void blurtexture(int w, int h, uchar *dst, const uchar *src, int margin) {
+ static const int weights3x3[9] = {
0x10, 0x20, 0x10,
0x20, 0x40, 0x20,
0x10, 0x20, 0x10
};
- static const int weights5x5[25] =
- {
+ static const int weights5x5[25] = {
0x05, 0x05, 0x09, 0x05, 0x05,
0x05, 0x0A, 0x14, 0x0A, 0x05,
0x09, 0x14, 0x28, 0x14, 0x09,
nextoffset1 = stride + mstride*bpp,
nextoffset2 = stride - mstride*bpp;
src += margin*(stride + bpp);
- for(int y = margin; y < h-margin; y++)
- {
- for(int x = margin; x < w-margin; x++)
- {
+ for(int y = margin; y < h-margin; y++) {
+ for(int x = margin; x < w-margin; x++) {
int dr = 0, dg = 0, db = 0;
const uchar *p = src - startoffset;
const int *m = mat + mstartoffset;
- for(int t = y; t >= y-n; t--, p -= nextoffset1, m -= mstride)
- {
+ for(int t = y; t >= y-n; t--, p -= nextoffset1, m -= mstride) {
if(t < 0) p += stride;
int a = 0;
if(n > 1) { a += m[-2]; if(x >= 2) { dr += p[0] * a; dg += p[1] * a; db += p[2] * a; a = 0; } p += bpp; }
}
p = src - startoffset + stride;
m = mat + mstartoffset + mstride;
- for(int t = y+1; t <= y+n; t++, p += nextoffset2, m += mstride)
- {
+ for(int t = y+1; t <= y+n; t++, p += nextoffset2, m += mstride) {
if(t >= h) p -= stride;
int a = 0;
if(n > 1) { a += m[-2]; if(x >= 2) { dr += p[0] * a; dg += p[1] * a; db += p[2] * a; a = 0; } p += bpp; }
if(x+1 < w) { cr = p[0]; cg = p[1]; cb = p[2]; } dr += cr * m[1]; dg += cg * m[1]; db += cb * m[1]; p += bpp;
if(n > 1) { if(x+2 < w) { cr = p[0]; cg = p[1]; cb = p[2]; } dr += cr * m[2]; dg += cg * m[2]; db += cb * m[2]; p += bpp; }
}
- if(normals)
- {
+ if(normals) {
vec v(dr-0x7F80, dg-0x7F80, db-0x7F80);
float mag = 127.5f/v.magnitude();
dst[0] = uchar(v.x*mag + 127.5f);
dst[1] = uchar(v.y*mag + 127.5f);
dst[2] = uchar(v.z*mag + 127.5f);
}
- else
- {
+ else {
dst[0] = dr>>8;
dst[1] = dg>>8;
dst[2] = db>>8;
}
}
-void blurtexture(int n, int bpp, int w, int h, uchar *dst, const uchar *src, int margin)
-{
- switch((clamp(n, 1, 2)<<4) | bpp)
- {
+void blurtexture(int n, int bpp, int w, int h, uchar *dst, const uchar *src, int margin) {
+ switch((clamp(n, 1, 2)<<4) | bpp) {
case 0x13: blurtexture<1, 3, false>(w, h, dst, src, margin); break;
case 0x23: blurtexture<2, 3, false>(w, h, dst, src, margin); break;
case 0x14: blurtexture<1, 4, false>(w, h, dst, src, margin); break;
}
}
-void blurnormals(int n, int w, int h, bvec *dst, const bvec *src, int margin)
-{
- switch(clamp(n, 1, 2))
- {
+void blurnormals(int n, int w, int h, bvec *dst, const bvec *src, int margin) {
+ switch(clamp(n, 1, 2)) {
case 1: blurtexture<1, 3, true>(w, h, dst->v, src->v, margin); break;
case 2: blurtexture<2, 3, true>(w, h, dst->v, src->v, margin); break;
}
}
-void texblur(ImageData &s, int n, int r)
-{
+void texblur(ImageData &s, int n, int r) {
if(s.bpp < 3) return;
- loopi(r)
- {
+ loopi(r) {
ImageData d(s.w, s.h, s.bpp);
blurtexture(n, s.bpp, s.w, s.h, d.data, s.data);
s.replace(d);
}
}
-void scaleimage(ImageData &s, int w, int h)
-{
+void scaleimage(ImageData &s, int w, int h) {
ImageData d(w, h, s.bpp);
scaletexture(s.data, s.w, s.h, s.bpp, s.pitch, d.data, w, h);
s.replace(d);
}
-bool canloadsurface(const char *name)
-{
+bool canloadsurface(const char *name) {
stream *f = openfile(name, "rb");
if(!f) return false;
delete f;
return true;
}
-SDL_Surface *loadsurface(const char *name)
-{
+SDL_Surface *loadsurface(const char *name) {
SDL_Surface *s = NULL;
stream *z = openzipfile(name, "rb");
- if(z)
- {
+ if(z) {
SDL_RWops *rw = z->rwops();
- if(rw)
- {
+ if(rw) {
char *ext = (char *)strrchr(name, '.');
if(ext) ++ext;
s = IMG_LoadTyped_RW(rw, 0, ext);
return fixsurfaceformat(s);
}
-static vec parsevec(const char *arg)
-{
+static vec parsevec(const char *arg) {
vec v(0, 0, 0);
int i = 0;
- for(; arg[0] && (!i || arg[0]=='/') && i<3; arg += strcspn(arg, "/,><"), i++)
- {
+ for(; arg[0] && (!i || arg[0]=='/') && i<3; arg += strcspn(arg, "/,><"), i++) {
if(i) arg++;
v[i] = atof(arg);
}
return v;
}
-static bool texturedata(ImageData &d, const char *tname, Slot::Tex *tex = NULL, bool msg = true, int *compress = NULL, int *wrap = NULL)
-{
+static bool texturedata(ImageData &d, const char *tname, Slot::Tex *tex = NULL, bool msg = true, int *compress = NULL, int *wrap = NULL) {
const char *cmds = NULL, *file = tname;
-
- if(!tname)
- {
+ if(!tname) {
if(!tex) return false;
- if(tex->name[0]=='<')
- {
+ if(tex->name[0]=='<') {
cmds = tex->name;
file = strrchr(tex->name, '>');
if(!file) { if(msg) conoutf(CON_ERROR, "could not load texture packages/%s", tex->name); return false; }
file++;
}
else file = tex->name;
-
static string pname;
formatstring(pname, "packages/%s", file);
file = path(pname);
}
- else if(tname[0]=='<')
- {
+ else if(tname[0]=='<') {
cmds = tname;
file = strrchr(tname, '>');
if(!file) { if(msg) conoutf(CON_ERROR, "could not load texture %s", tname); return false; }
file++;
}
-
int flen = strlen(file);
- bool raw = !compress, guess = false;
- for(const char *pcmds = cmds; pcmds;)
- {
+ bool guess = false;
+ for(const char *pcmds = cmds; pcmds;) {
#define PARSETEXCOMMANDS(cmds) \
const char *cmd = NULL, *end = NULL, *arg[4] = { NULL, NULL, NULL, NULL }; \
cmd = &cmds[1]; \
if(!end) break; \
cmds = strchr(cmd, '<'); \
size_t len = strcspn(cmd, ":,><"); \
- loopi(4) \
- { \
+ loopi(4) { \
+ \
arg[i] = strchr(i ? arg[i-1] : cmd, i ? ',' : ':'); \
if(!arg[i] || arg[i] >= end) arg[i] = ""; \
else arg[i]++; \
}
PARSETEXCOMMANDS(pcmds);
- if(matchstring(cmd, len, "thumbnail"))
- {
- raw = true;
+ if(matchstring(cmd, len, "thumbnail")) {
guess = flen >= 4 && !strchr(file+flen-4, '.');
}
else if(matchstring(cmd, len, "stub")) return canloadsurface(file);
}
-
if(msg) renderprogress(loadprogress, file);
-
- if(!d.data)
- {
+ if(!d.data) {
SDL_Surface *s = NULL;
- if(guess)
- {
+ if(guess) {
static const char *exts[] = {".jpg", ".png"};
string ext;
- loopi(sizeof(exts)/sizeof(exts[0]))
- {
+ loopi(sizeof(exts)/sizeof(exts[0])) {
copystring(ext, file);
concatstring(ext, exts[i]);
s = loadsurface(ext);
if(max(s->w, s->h) > (1<<12)) { SDL_FreeSurface(s); conoutf(CON_ERROR, "texture size exceeded %dx%d pixels: %s", 1<<12, 1<<12, file); return false; }
d.wrap(s);
}
-
- while(cmds)
- {
+ while(cmds) {
PARSETEXCOMMANDS(cmds);
if(d.compressed) goto compressed;
if(matchstring(cmd, len, "mad")) texmad(d, parsevec(arg[0]), parsevec(arg[1]));
else if(matchstring(cmd, len, "colorify")) texcolorify(d, parsevec(arg[0]), parsevec(arg[1]));
else if(matchstring(cmd, len, "colormask")) texcolormask(d, parsevec(arg[0]), *arg[1] ? parsevec(arg[1]) : vec(1, 1, 1));
- else if(matchstring(cmd, len, "normal"))
- {
+ else if(matchstring(cmd, len, "normal")) {
int emphasis = atoi(arg[0]);
texnormal(d, emphasis > 0 ? emphasis : 3);
}
else if(matchstring(cmd, len, "reorient")) texreorient(d, atoi(arg[0])>0, atoi(arg[1])>0, atoi(arg[2])>0, tex ? tex->type : TEX_DIFFUSE);
else if(matchstring(cmd, len, "mix")) texmix(d, *arg[0] ? atoi(arg[0]) : -1, *arg[1] ? atoi(arg[1]) : -1, *arg[2] ? atoi(arg[2]) : -1, *arg[3] ? atoi(arg[3]) : -1);
else if(matchstring(cmd, len, "grey")) texgrey(d);
- else if(matchstring(cmd, len, "blur"))
- {
+ else if(matchstring(cmd, len, "blur")) {
int emphasis = atoi(arg[0]), repeat = atoi(arg[1]);
texblur(d, emphasis > 0 ? clamp(emphasis, 1, 2) : 1, repeat > 0 ? repeat : 1);
}
else if(matchstring(cmd, len, "premul")) texpremul(d);
else if(matchstring(cmd, len, "agrad")) texagrad(d, atof(arg[0]), atof(arg[1]), atof(arg[2]), atof(arg[3]));
- else if(matchstring(cmd, len, "compress"))
- {
+ else if(matchstring(cmd, len, "compress")) {
int scale = atoi(arg[0]);
if(scale <= 0) scale = 2;
if(compress) *compress = scale;
}
- else if(matchstring(cmd, len, "nocompress"))
- {
+ else if(matchstring(cmd, len, "nocompress")) {
if(compress) *compress = -1;
}
- else if(matchstring(cmd, len, "thumbnail"))
- {
+ else if(matchstring(cmd, len, "thumbnail")) {
int w = atoi(arg[0]), h = atoi(arg[1]);
if(w <= 0 || w > (1<<12)) w = 64;
if(h <= 0 || h > (1<<12)) h = w;
}
else
compressed:
- if(matchstring(cmd, len, "mirror"))
- {
+ if(matchstring(cmd, len, "mirror")) {
if(wrap) *wrap |= 0x300;
}
- else if(matchstring(cmd, len, "noswizzle"))
- {
+ else if(matchstring(cmd, len, "noswizzle")) {
if(wrap) *wrap |= 0x10000;
}
}
-
return true;
}
-uchar *loadalphamask(Texture *t)
-{
+uchar *loadalphamask(Texture *t) {
if(t->alphamask) return t->alphamask;
if(!(t->type&Texture::ALPHA)) return NULL;
ImageData s;
if(!texturedata(s, t->name, NULL, false) || !s.data || s.compressed) return NULL;
t->alphamask = new uchar[s.h * ((s.w+7)/8)];
uchar *srcrow = s.data, *dst = t->alphamask-1;
- loop(y, s.h)
- {
+ loop(y, s.h) {
uchar *src = srcrow+s.bpp-1;
- loop(x, s.w)
- {
+ loop(x, s.w) {
int offset = x%8;
if(!offset) *++dst = 0;
if(*src) *dst |= 1<<offset;
return t->alphamask;
}
-Texture *textureload(const char *name, int clamp, bool mipit, bool msg)
-{
+Texture *textureload(const char *name, int clamp, bool mipit, bool msg) {
string tname;
copystring(tname, name);
Texture *t = textures.access(path(tname));
return notexture;
}
-bool settexture(const char *name, int clamp)
-{
+bool settexture(const char *name, int clamp) {
Texture *t = textureload(name, clamp, true, false);
glBindTexture(GL_TEXTURE_2D, t->id);
return t != notexture;
Slot dummyslot;
VSlot dummyvslot(&dummyslot);
-void texturereset(int *n)
-{
+void texturereset(int *n) {
if(!(identflags&IDF_OVERRIDDEN) && !game::allowedittoggle()) return;
resetslotshader();
int limit = clamp(*n, 0, slots.length());
- for(int i = limit; i < slots.length(); i++)
- {
+ for(int i = limit; i < slots.length(); i++) {
Slot *s = slots[i];
for(VSlot *vs = s->variants; vs; vs = vs->next) vs->slot = &dummyslot;
delete s;
}
slots.setsize(limit);
- while(vslots.length())
- {
+ while(vslots.length()) {
VSlot *vs = vslots.last();
if(vs->slot != &dummyslot || vs->changed) break;
delete vslots.pop();
static int compactedvslots = 0, compactvslotsprogress = 0, clonedvslots = 0;
static bool markingvslots = false;
-void clearslots()
-{
+void clearslots() {
resetslotshader();
slots.deletecontents();
vslots.deletecontents();
static void assignvslot(VSlot &vs);
-static inline void assignvslotlayer(VSlot &vs)
-{
- if(vs.layer && vslots.inrange(vs.layer))
- {
+static inline void assignvslotlayer(VSlot &vs) {
+ if(vs.layer && vslots.inrange(vs.layer)) {
VSlot &layer = *vslots[vs.layer];
if(layer.index < 0) assignvslot(layer);
}
}
-static void assignvslot(VSlot &vs)
-{
+static void assignvslot(VSlot &vs) {
vs.index = compactedvslots++;
assignvslotlayer(vs);
}
-void compactvslot(int &index)
-{
- if(vslots.inrange(index))
- {
+void compactvslot(int &index) {
+ if(vslots.inrange(index)) {
VSlot &vs = *vslots[index];
if(vs.index < 0) assignvslot(vs);
if(!markingvslots) index = vs.index;
}
}
-void compactvslot(VSlot &vs)
-{
+void compactvslot(VSlot &vs) {
if(vs.index < 0) assignvslot(vs);
}
-void compactvslots(cube *c, int n)
-{
+void compactvslots(cube *c, int n) {
if((compactvslotsprogress++&0xFFF)==0) renderprogress(min(float(compactvslotsprogress)/allocnodes, 1.0f), markingvslots ? "marking slots..." : "compacting slots...");
- loopi(n)
- {
+ loopi(n) {
if(c[i].children) compactvslots(c[i].children);
- else loopj(6) if(vslots.inrange(c[i].texture[j]))
- {
+ else loopj(6) if(vslots.inrange(c[i].texture[j])) {
VSlot &vs = *vslots[c[i].texture[j]];
if(vs.index < 0) assignvslot(vs);
if(!markingvslots) c[i].texture[j] = vs.index;
}
}
-int compactvslots()
-{
+int compactvslots() {
clonedvslots = 0;
markingvslots = false;
compactedvslots = 0;
loopv(vslots) vslots[i]->index = -1;
loopv(slots) slots[i]->variants->index = compactedvslots++;
loopv(slots) assignvslotlayer(*slots[i]->variants);
- loopv(vslots)
- {
+ loopv(vslots) {
VSlot &vs = *vslots[i];
if(!vs.changed && vs.index < 0) { markingvslots = true; break; }
}
compactvslots(worldroot);
int total = compactedvslots;
compacteditvslots();
- loopv(vslots)
- {
+ loopv(vslots) {
VSlot *vs = vslots[i];
if(vs->changed) continue;
- while(vs->next)
- {
+ while(vs->next) {
if(vs->next->index < 0) vs->next = vs->next->next;
else vs = vs->next;
}
}
- if(markingvslots)
- {
+ if(markingvslots) {
markingvslots = false;
compactedvslots = 0;
compactvslotsprogress = 0;
int lastdiscard = 0;
- loopv(vslots)
- {
+ loopv(vslots) {
VSlot &vs = *vslots[i];
if(vs.changed || (vs.index < 0 && !vs.next)) vs.index = -1;
- else
- {
- while(lastdiscard < i)
- {
+ else {
+ while(lastdiscard < i) {
VSlot &ds = *vslots[lastdiscard++];
if(!ds.changed && ds.index < 0) ds.index = compactedvslots++;
}
compacteditvslots();
}
compactmruvslots();
- loopv(vslots)
- {
+ loopv(vslots) {
VSlot &vs = *vslots[i];
if(vs.index >= 0 && vs.layer && vslots.inrange(vs.layer)) vs.layer = vslots[vs.layer]->index;
}
- loopv(vslots)
- {
+ loopv(vslots) {
while(vslots[i]->index >= 0 && vslots[i]->index != i)
swap(vslots[i], vslots[vslots[i]->index]);
}
return total;
}
-ICOMMAND(compactvslots, "", (),
-{
+ICOMMAND(compactvslots, "", (), {
extern int nompedit;
if(nompedit && multiplayer()) return;
compactvslots();
static Slot &loadslot(Slot &s, bool forceload);
-static void clampvslotoffset(VSlot &dst, Slot *slot = NULL)
-{
+static void clampvslotoffset(VSlot &dst, Slot *slot = NULL) {
if(!slot) slot = dst.slot;
- if(slot && slot->sts.inrange(0))
- {
+ if(slot && slot->sts.inrange(0)) {
if(!slot->loaded) loadslot(*slot, false);
Texture *t = slot->sts[0].t;
int xs = t->xs, ys = t->ys;
else dst.offset.max(0);
}
-static void propagatevslot(VSlot &dst, const VSlot &src, int diff, bool edit = false)
-{
+static void propagatevslot(VSlot &dst, const VSlot &src, int diff, bool edit = false) {
if(diff & (1<<VSLOT_SHPARAM)) loopv(src.params) dst.params.add(src.params[i]);
if(diff & (1<<VSLOT_SCALE)) dst.scale = src.scale;
- if(diff & (1<<VSLOT_ROTATION))
- {
+ if(diff & (1<<VSLOT_ROTATION)) {
dst.rotation = src.rotation;
if(edit && !dst.offset.iszero()) clampvslotoffset(dst);
}
- if(diff & (1<<VSLOT_OFFSET))
- {
+ if(diff & (1<<VSLOT_OFFSET)) {
dst.offset = src.offset;
if(edit) clampvslotoffset(dst);
}
if(diff & (1<<VSLOT_SCROLL)) dst.scroll = src.scroll;
if(diff & (1<<VSLOT_LAYER)) dst.layer = src.layer;
- if(diff & (1<<VSLOT_ALPHA))
- {
+ if(diff & (1<<VSLOT_ALPHA)) {
dst.alphafront = src.alphafront;
dst.alphaback = src.alphaback;
}
if(diff & (1<<VSLOT_COLOR)) dst.colorscale = src.colorscale;
}
-static void propagatevslot(VSlot *root, int changed)
-{
- for(VSlot *vs = root->next; vs; vs = vs->next)
- {
+static void propagatevslot(VSlot *root, int changed) {
+ for(VSlot *vs = root->next; vs; vs = vs->next) {
int diff = changed & ~vs->changed;
if(diff) propagatevslot(*vs, *root, diff);
}
}
-static void mergevslot(VSlot &dst, const VSlot &src, int diff, Slot *slot = NULL)
-{
- if(diff & (1<<VSLOT_SHPARAM)) loopv(src.params)
- {
+static void mergevslot(VSlot &dst, const VSlot &src, int diff, Slot *slot = NULL) {
+ if(diff & (1<<VSLOT_SHPARAM)) loopv(src.params) {
const SlotShaderParam &sp = src.params[i];
- loopvj(dst.params)
- {
+ loopvj(dst.params) {
SlotShaderParam &dp = dst.params[j];
- if(sp.name == dp.name)
- {
+ if(sp.name == dp.name) {
memcpy(dp.val, sp.val, sizeof(dp.val));
goto nextparam;
}
dst.params.add(sp);
nextparam:;
}
- if(diff & (1<<VSLOT_SCALE))
- {
+ if(diff & (1<<VSLOT_SCALE)) {
dst.scale = clamp(dst.scale*src.scale, 1/8.0f, 8.0f);
}
- if(diff & (1<<VSLOT_ROTATION))
- {
+ if(diff & (1<<VSLOT_ROTATION)) {
dst.rotation = clamp(dst.rotation + src.rotation, 0, 7);
if(!dst.offset.iszero()) clampvslotoffset(dst, slot);
}
- if(diff & (1<<VSLOT_OFFSET))
- {
+ if(diff & (1<<VSLOT_OFFSET)) {
dst.offset.add(src.offset);
clampvslotoffset(dst, slot);
}
if(diff & (1<<VSLOT_SCROLL)) dst.scroll.add(src.scroll);
if(diff & (1<<VSLOT_LAYER)) dst.layer = src.layer;
- if(diff & (1<<VSLOT_ALPHA))
- {
+ if(diff & (1<<VSLOT_ALPHA)) {
dst.alphafront = src.alphafront;
dst.alphaback = src.alphaback;
}
if(diff & (1<<VSLOT_COLOR)) dst.colorscale.mul(src.colorscale);
}
-void mergevslot(VSlot &dst, const VSlot &src, const VSlot &delta)
-{
+void mergevslot(VSlot &dst, const VSlot &src, const VSlot &delta) {
dst.changed = src.changed | delta.changed;
propagatevslot(dst, src, (1<<VSLOT_NUM)-1);
mergevslot(dst, delta, delta.changed, src.slot);
}
-static VSlot *reassignvslot(Slot &owner, VSlot *vs)
-{
+static VSlot *reassignvslot(Slot &owner, VSlot *vs) {
owner.variants = vs;
- while(vs)
- {
+ while(vs) {
vs->slot = &owner;
vs->linked = false;
vs = vs->next;
return owner.variants;
}
-static VSlot *emptyvslot(Slot &owner)
-{
+static VSlot *emptyvslot(Slot &owner) {
int offset = 0;
loopvrev(slots) if(slots[i]->variants) { offset = slots[i]->variants->index + 1; break; }
for(int i = offset; i < vslots.length(); i++) if(!vslots[i]->changed) return reassignvslot(owner, vslots[i]);
return vslots.add(new VSlot(&owner, vslots.length()));
}
-static bool comparevslot(const VSlot &dst, const VSlot &src, int diff)
-{
- if(diff & (1<<VSLOT_SHPARAM))
- {
+static bool comparevslot(const VSlot &dst, const VSlot &src, int diff) {
+ if(diff & (1<<VSLOT_SHPARAM)) {
if(src.params.length() != dst.params.length()) return false;
- loopv(src.params)
- {
+ loopv(src.params) {
const SlotShaderParam &sp = src.params[i], &dp = dst.params[i];
if(sp.name != dp.name || memcmp(sp.val, dp.val, sizeof(sp.val))) return false;
}
return true;
}
-void packvslot(vector<uchar> &buf, const VSlot &src)
-{
- if(src.changed & (1<<VSLOT_SHPARAM))
- {
- loopv(src.params)
- {
+void packvslot(vector<uchar> &buf, const VSlot &src) {
+ if(src.changed & (1<<VSLOT_SHPARAM)) {
+ loopv(src.params) {
const SlotShaderParam &p = src.params[i];
buf.put(VSLOT_SHPARAM);
sendstring(p.name, buf);
loopj(4) putfloat(buf, p.val[j]);
}
}
- if(src.changed & (1<<VSLOT_SCALE))
- {
+ if(src.changed & (1<<VSLOT_SCALE)) {
buf.put(VSLOT_SCALE);
putfloat(buf, src.scale);
}
- if(src.changed & (1<<VSLOT_ROTATION))
- {
+ if(src.changed & (1<<VSLOT_ROTATION)) {
buf.put(VSLOT_ROTATION);
putint(buf, src.rotation);
}
- if(src.changed & (1<<VSLOT_OFFSET))
- {
+ if(src.changed & (1<<VSLOT_OFFSET)) {
buf.put(VSLOT_OFFSET);
putint(buf, src.offset.x);
putint(buf, src.offset.y);
}
- if(src.changed & (1<<VSLOT_SCROLL))
- {
+ if(src.changed & (1<<VSLOT_SCROLL)) {
buf.put(VSLOT_SCROLL);
putfloat(buf, src.scroll.x);
putfloat(buf, src.scroll.y);
}
- if(src.changed & (1<<VSLOT_LAYER))
- {
+ if(src.changed & (1<<VSLOT_LAYER)) {
buf.put(VSLOT_LAYER);
putuint(buf, vslots.inrange(src.layer) && !vslots[src.layer]->changed ? src.layer : 0);
}
- if(src.changed & (1<<VSLOT_ALPHA))
- {
+ if(src.changed & (1<<VSLOT_ALPHA)) {
buf.put(VSLOT_ALPHA);
putfloat(buf, src.alphafront);
putfloat(buf, src.alphaback);
}
- if(src.changed & (1<<VSLOT_COLOR))
- {
+ if(src.changed & (1<<VSLOT_COLOR)) {
buf.put(VSLOT_COLOR);
putfloat(buf, src.colorscale.r);
putfloat(buf, src.colorscale.g);
buf.put(0xFF);
}
-void packvslot(vector<uchar> &buf, int index)
-{
+void packvslot(vector<uchar> &buf, int index) {
if(vslots.inrange(index)) packvslot(buf, *vslots[index]);
else buf.put(0xFF);
}
-void packvslot(vector<uchar> &buf, const VSlot *vs)
-{
+void packvslot(vector<uchar> &buf, const VSlot *vs) {
if(vs) packvslot(buf, *vs);
else buf.put(0xFF);
}
-bool unpackvslot(ucharbuf &buf, VSlot &dst, bool delta)
-{
- while(buf.remaining())
- {
+bool unpackvslot(ucharbuf &buf, VSlot &dst, bool delta) {
+ while(buf.remaining()) {
int changed = buf.get();
if(changed >= 0x80) break;
- switch(changed)
- {
- case VSLOT_SHPARAM:
- {
+ switch(changed) {
+ case VSLOT_SHPARAM: {
string name;
getstring(name, buf);
SlotShaderParam p = { name[0] ? getshaderparamname(name) : NULL, -1, { 0, 0, 0, 0 } };
dst.scroll.x = getfloat(buf);
dst.scroll.y = getfloat(buf);
break;
- case VSLOT_LAYER:
- {
+ case VSLOT_LAYER: {
int tex = getuint(buf);
dst.layer = vslots.inrange(tex) ? tex : 0;
break;
return true;
}
-VSlot *findvslot(Slot &slot, const VSlot &src, const VSlot &delta)
-{
- for(VSlot *dst = slot.variants; dst; dst = dst->next)
- {
+VSlot *findvslot(Slot &slot, const VSlot &src, const VSlot &delta) {
+ for(VSlot *dst = slot.variants; dst; dst = dst->next) {
if((!dst->changed || dst->changed == (src.changed | delta.changed)) &&
comparevslot(*dst, src, src.changed & ~delta.changed) &&
comparevslot(*dst, delta, delta.changed))
return NULL;
}
-static VSlot *clonevslot(const VSlot &src, const VSlot &delta)
-{
+static VSlot *clonevslot(const VSlot &src, const VSlot &delta) {
VSlot *dst = vslots.add(new VSlot(src.slot, vslots.length()));
dst->changed = src.changed | delta.changed;
propagatevslot(*dst, src, ((1<<VSLOT_NUM)-1) & ~delta.changed);
VARP(autocompactvslots, 0, 256, 0x10000);
-VSlot *editvslot(const VSlot &src, const VSlot &delta)
-{
+VSlot *editvslot(const VSlot &src, const VSlot &delta) {
VSlot *exists = findvslot(*src.slot, src, delta);
if(exists) return exists;
- if(vslots.length()>=0x10000)
- {
+ if(vslots.length()>=0x10000) {
compactvslots();
allchanged();
if(vslots.length()>=0x10000) return NULL;
}
- if(autocompactvslots && ++clonedvslots >= autocompactvslots)
- {
+ if(autocompactvslots && ++clonedvslots >= autocompactvslots) {
compactvslots();
allchanged();
}
return clonevslot(src, delta);
}
-static void fixinsidefaces(cube *c, const ivec &o, int size, int tex)
-{
- loopi(8)
- {
+static void fixinsidefaces(cube *c, const ivec &o, int size, int tex) {
+ loopi(8) {
ivec co(i, o, size);
if(c[i].children) fixinsidefaces(c[i].children, co, size>>1, tex);
else loopj(6) if(!visibletris(c[i], j, co, size))
}
}
-ICOMMAND(fixinsidefaces, "i", (int *tex),
-{
+ICOMMAND(fixinsidefaces, "i", (int *tex), {
extern int nompedit;
if(noedit(true) || (nompedit && multiplayer())) return;
fixinsidefaces(worldroot, ivec(0, 0, 0), worldsize>>1, *tex && vslots.inrange(*tex) ? *tex : DEFAULT_GEOM);
allchanged();
});
-const struct slottex
-{
+const struct slottex {
const char *name;
int id;
-} slottexs[] =
-{
- {"c", TEX_DIFFUSE},
- {"u", TEX_UNKNOWN},
- {"d", TEX_DECAL},
- {"n", TEX_NORMAL},
- {"s", TEX_SPEC},
- {"z", TEX_DEPTH},
- {"a", TEX_ALPHA}
+} slottexs[] = {
+ {
+ "c", TEX_DIFFUSE}, {
+ "u", TEX_UNKNOWN}, {
+ "d", TEX_DECAL}, {
+ "n", TEX_NORMAL}, {
+ "s", TEX_SPEC}, {
+ "z", TEX_DEPTH}, {
+ "a", TEX_ALPHA}
};
-int findslottex(const char *name)
-{
- loopi(sizeof(slottexs)/sizeof(slottex))
- {
+int findslottex(const char *name) {
+ loopi(sizeof(slottexs)/sizeof(slottex)) {
if(!strcmp(slottexs[i].name, name)) return slottexs[i].id;
}
return -1;
}
-void texture(char *type, char *name, int *rot, int *xoffset, int *yoffset, float *scale)
-{
+void texture(char *type, char *name, int *rot, int *xoffset, int *yoffset, float *scale) {
if(slots.length()>=0x10000) return;
int tnum = findslottex(type);
if(tnum<0) tnum = atoi(type);
st.t = NULL;
copystring(st.name, name);
path(st.name);
- if(tnum==TEX_DIFFUSE)
- {
+ if(tnum==TEX_DIFFUSE) {
setslotshader(s);
VSlot &vs = *emptyvslot(s);
vs.reset();
COMMAND(texture, "ssiiif");
-void texscroll(float *scrollS, float *scrollT)
-{
+void texscroll(float *scrollS, float *scrollT) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->scroll = vec2(*scrollS, *scrollT).div(1000.0f);
}
COMMAND(texscroll, "ff");
-void texoffset_(int *xoffset, int *yoffset)
-{
+void texoffset_(int *xoffset, int *yoffset) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->offset = ivec2(*xoffset, *yoffset).max(0);
}
COMMANDN(texoffset, texoffset_, "ii");
-void texrotate_(int *rot)
-{
+void texrotate_(int *rot) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->rotation = clamp(*rot, 0, 7);
}
COMMANDN(texrotate, texrotate_, "i");
-void texscale(float *scale)
-{
+void texscale(float *scale) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->scale = *scale <= 0 ? 1 : *scale;
}
COMMAND(texscale, "f");
-void texlayer(int *layer, char *name, int *mode, float *scale)
-{
+void texlayer(int *layer, char *name, int *mode, float *scale) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->layer = *layer < 0 ? max(slots.length()-1+*layer, 0) : *layer;
}
COMMAND(texlayer, "isif");
-void texalpha(float *front, float *back)
-{
+void texalpha(float *front, float *back) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->alphafront = clamp(*front, 0.0f, 1.0f);
}
COMMAND(texalpha, "ff");
-void texcolor(float *r, float *g, float *b)
-{
+void texcolor(float *r, float *g, float *b) {
if(slots.empty()) return;
Slot &s = *slots.last();
s.variants->colorscale = vec(clamp(*r, 0.0f, 1.0f), clamp(*g, 0.0f, 1.0f), clamp(*b, 0.0f, 1.0f));
}
COMMAND(texcolor, "fff");
-static int findtextype(Slot &s, int type, int last = -1)
-{
+static int findtextype(Slot &s, int type, int last = -1) {
for(int i = last+1; i<s.sts.length(); i++) if((type&(1<<s.sts[i].type)) && s.sts[i].combined<0) return i;
return -1;
}
-static void mergespec(ImageData &c, ImageData &s)
-{
+static void mergespec(ImageData &c, ImageData &s) {
if(s.bpp < 3) { readwritergbatex(c, s, dst[3] = src[0]; ); }
else { readwritergbatex(c, s, dst[3] = (int(src[0]) + int(src[1]) + int(src[2]))/3; ); }
}
-static void mergedepth(ImageData &c, ImageData &z)
-{
+static void mergedepth(ImageData &c, ImageData &z) {
readwritergbatex(c, z, dst[3] = src[0]; );
}
-static void mergealpha(ImageData &c, ImageData &s)
-{
+static void mergealpha(ImageData &c, ImageData &s) {
if(s.bpp < 3) { readwritergbatex(c, s, dst[3] = src[0]; ); }
else if(s.bpp == 3) { readwritergbatex(c, s, dst[3] = (int(src[0]) + int(src[1]) + int(src[2]))/3; ); }
else { readwritergbatex(c, s, dst[3] = src[3]; ); }
}
-static void addname(vector<char> &key, Slot &slot, Slot::Tex &t, bool combined = false, const char *prefix = NULL)
-{
+static void addname(vector<char> &key, Slot &slot, Slot::Tex &t, bool combined = false, const char *prefix = NULL) {
if(combined) key.add('&');
if(prefix) { while(*prefix) key.add(*prefix++); }
defformatstring(tname, "packages/%s", t.name);
for(const char *s = path(tname); *s; key.add(*s++));
}
-static void texcombine(Slot &s, int index, Slot::Tex &t, bool forceload = false)
-{
+static void texcombine(Slot &s, int index, Slot::Tex &t, bool forceload = false) {
vector<char> key;
addname(key, s, t);
int texmask = 0;
- if(!forceload) switch(t.type)
- {
+ if(!forceload) switch(t.type) {
case TEX_DIFFUSE:
- case TEX_NORMAL:
- {
+ case TEX_NORMAL: {
int i = findtextype(s, t.type==TEX_DIFFUSE ? (s.texmask&(1<<TEX_SPEC) ? 1<<TEX_SPEC : 1<<TEX_ALPHA) : (s.texmask&(1<<TEX_DEPTH) ? 1<<TEX_DEPTH : 1<<TEX_ALPHA));
if(i<0) break;
texmask |= 1<<s.sts[i].type;
int compress = 0, wrap = 0;
ImageData ts;
if(!texturedata(ts, NULL, &t, true, &compress, &wrap)) { t.t = notexture; return; }
- if(!ts.compressed) switch(t.type)
- {
+ if(!ts.compressed) switch(t.type) {
case TEX_DIFFUSE:
case TEX_NORMAL:
- loopv(s.sts)
- {
+ loopv(s.sts) {
Slot::Tex &a = s.sts[i];
if(a.combined!=index) continue;
ImageData as;
if(!texturedata(as, NULL, &a)) continue;
//if(ts.bpp!=4) forcergbaimage(ts);
if(as.w!=ts.w || as.h!=ts.h) scaleimage(as, ts.w, ts.h);
- switch(a.type)
- {
+ switch(a.type) {
case TEX_SPEC: mergespec(ts, as); break;
case TEX_DEPTH: mergedepth(ts, as); break;
case TEX_ALPHA: mergealpha(ts, as); break;
t.t = newtexture(NULL, key.getbuf(), ts, wrap, true, true, true, compress);
}
-static Slot &loadslot(Slot &s, bool forceload)
-{
+static Slot &loadslot(Slot &s, bool forceload) {
linkslotshader(s);
- loopv(s.sts)
- {
+ loopv(s.sts) {
Slot::Tex &t = s.sts[i];
if(t.combined >= 0) continue;
- switch(t.type)
- {
+ switch(t.type) {
default:
texcombine(s, i, t, forceload);
break;
return s;
}
-Slot &lookupslot(int index, bool load)
-{
+Slot &lookupslot(int index, bool load) {
Slot &s = slots.inrange(index) ? *slots[index] : (slots.inrange(DEFAULT_GEOM) ? *slots[DEFAULT_GEOM] : dummyslot);
return s.loaded || !load ? s : loadslot(s, false);
}
-VSlot &lookupvslot(int index, bool load)
-{
+VSlot &lookupvslot(int index, bool load) {
VSlot &s = vslots.inrange(index) && vslots[index]->slot ? *vslots[index] : (slots.inrange(DEFAULT_GEOM) && slots[DEFAULT_GEOM]->variants ? *slots[DEFAULT_GEOM]->variants : dummyvslot);
- if(load && !s.linked)
- {
+ if(load && !s.linked) {
if(!s.slot->loaded) loadslot(*s.slot, false);
linkvslotshader(s);
s.linked = true;
return s;
}
-void linkslotshaders()
-{
+void linkslotshaders() {
loopv(slots) if(slots[i]->loaded) linkslotshader(*slots[i]);
loopv(vslots) if(vslots[i]->linked) linkvslotshader(*vslots[i]);
}
-Texture *loadthumbnail(Slot &slot)
-{
+Texture *loadthumbnail(Slot &slot) {
if(slot.thumbnail) return slot.thumbnail;
- if(!slot.variants)
- {
+ if(!slot.variants) {
slot.thumbnail = notexture;
return slot.thumbnail;
}
linkvslotshader(vslot, false);
vector<char> name;
if(vslot.colorscale == vec(1, 1, 1)) addname(name, slot, slot.sts[0], false, "<thumbnail>");
- else
- {
+ else {
defformatstring(prefix, "<thumbnail:%.2f/%.2f/%.2f>", vslot.colorscale.x, vslot.colorscale.y, vslot.colorscale.z);
addname(name, slot, slot.sts[0], false, prefix);
}
VSlot *layer = vslot.layer ? &lookupvslot(vslot.layer, false) : NULL;
- if(layer)
- {
+ if(layer) {
if(layer->colorscale == vec(1, 1, 1)) addname(name, *layer->slot, layer->slot->sts[0], true, "<layer>");
- else
- {
+ else {
defformatstring(prefix, "<layer:%.2f/%.2f/%.2f>", vslot.colorscale.x, vslot.colorscale.y, vslot.colorscale.z);
addname(name, *layer->slot, layer->slot->sts[0], true, prefix);
}
name.add('\0');
Texture *t = textures.access(path(name.getbuf()));
if(t) slot.thumbnail = t;
- else
- {
+ else {
ImageData s, g, l;
texturedata(s, NULL, &slot.sts[0], false);
if(layer) texturedata(l, NULL, &layer->slot->sts[0], false);
if(!s.data) t = slot.thumbnail = notexture;
- else
- {
+ else {
if(vslot.colorscale != vec(1, 1, 1)) texmad(s, vslot.colorscale, vec(0, 0, 0));
int xs = s.w, ys = s.h;
if(s.w > 64 || s.h > 64) scaleimage(s, min(s.w, 64), min(s.h, 64));
- if(g.data)
- {
+ if(g.data) {
if(g.w != s.w || g.h != s.h) scaleimage(g, s.w, s.h);
}
- if(l.data)
- {
+ if(l.data) {
if(layer->colorscale != vec(1, 1, 1)) texmad(l, layer->colorscale, vec(0, 0, 0));
if(l.w != s.w/2 || l.h != s.h/2) scaleimage(l, s.w/2, s.h/2);
forcergbimage(s);
forcergbimage(l);
uchar *dstrow = &s.data[s.pitch*l.h + s.bpp*l.w], *srcrow = l.data;
- loop(y, l.h)
- {
+ loop(y, l.h) {
for(uchar *dst = dstrow, *src = srcrow, *end = &srcrow[l.w*l.bpp]; src < end; dst += s.bpp, src += l.bpp)
loopk(3) dst[k] = src[k];
dstrow += s.pitch;
return t;
}
-void loadlayermasks()
-{
- loopv(slots)
- {
+void loadlayermasks() {
+ loopv(slots) {
Slot &slot = *slots[i];
- if(slot.loaded && slot.layermaskname && !slot.layermask)
- {
+ if(slot.loaded && slot.layermaskname && !slot.layermask) {
slot.layermask = new ImageData;
texturedata(*slot.layermask, slot.layermaskname);
if(!slot.layermask->data) DELETEP(slot.layermask);
}
}
-void cleanuptexture(Texture *t)
-{
+void cleanuptexture(Texture *t) {
DELETEA(t->alphamask);
if(t->id) { glDeleteTextures(1, &t->id); t->id = 0; }
if(t->type&Texture::TRANSIENT) textures.remove(t->name);
}
-void cleanuptextures()
-{
+void cleanuptextures() {
loopv(slots) slots[i]->cleanup();
loopv(vslots) vslots[i]->cleanup();
enumerate(textures, Texture, tex, cleanuptexture(&tex));
}
-bool reloadtexture(const char *name)
-{
+bool reloadtexture(const char *name) {
Texture *t = textures.access(path(name, true));
if(t) return reloadtexture(*t);
return true;
}
-bool reloadtexture(Texture &tex)
-{
+bool reloadtexture(Texture &tex) {
if(tex.id) return true;
- switch(tex.type&Texture::TYPE)
- {
- case Texture::IMAGE:
- {
+ switch(tex.type&Texture::TYPE) {
+ case Texture::IMAGE: {
int compress = 0;
ImageData s;
if(!texturedata(s, tex.name, NULL, true, &compress) || !newtexture(&tex, NULL, s, tex.clamp, tex.mipmap, false, false, compress)) return false;
return true;
}
-void reloadtex(char *name)
-{
+void reloadtex(char *name) {
Texture *t = textures.access(path(name, true));
if(!t) { conoutf(CON_ERROR, "texture %s is not loaded", name); return; }
if(t->type&Texture::TRANSIENT) { conoutf(CON_ERROR, "can't reload transient texture %s", name); return; }
DELETEA(t->alphamask);
Texture oldtex = *t;
t->id = 0;
- if(!reloadtexture(*t))
- {
+ if(!reloadtexture(*t)) {
if(t->id) glDeleteTextures(1, &t->id);
*t = oldtex;
conoutf(CON_ERROR, "failed to reload texture %s", name);
COMMAND(reloadtex, "s");
-void reloadtextures()
-{
+void reloadtextures() {
int reloaded = 0;
- enumerate(textures, Texture, tex,
- {
+ enumerate(textures, Texture, tex, {
loadprogress = float(++reloaded)/textures.numelems;
reloadtexture(tex);
});
loadprogress = 0;
}
-void writepngchunk(stream *f, const char *type, uchar *data = NULL, uint len = 0)
-{
+void writepngchunk(stream *f, const char *type, uchar *data = NULL, uint len = 0) {
f->putbig<uint>(len);
f->write(type, 4);
f->write(data, len);
-
uint crc = crc32(0, Z_NULL, 0);
crc = crc32(crc, (const Bytef *)type, 4);
if(data) crc = crc32(crc, data, len);
VARP(compresspng, 0, 9, 9);
-void savepng(const char *filename, ImageData &image, bool flip)
-{
+void savepng(const char *filename, ImageData &image, bool flip) {
uchar ctype = 0;
- switch(image.bpp)
- {
+ switch(image.bpp) {
case 1: ctype = 0; break;
case 2: ctype = 4; break;
case 3: ctype = 2; break;
}
stream *f = openfile(filename, "wb");
if(!f) { conoutf(CON_ERROR, "could not write to %s", filename); return; }
-
uchar signature[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
f->write(signature, sizeof(signature));
-
- struct pngihdr
- {
+ struct pngihdr {
uint width, height;
uchar bitdepth, colortype, compress, filter, interlace;
} ihdr = { bigswap<uint>(image.w), bigswap<uint>(image.h), 8, ctype, 0, 0, 0 };
writepngchunk(f, "IHDR", (uchar *)&ihdr, 13);
-
stream::offset idat = f->tell();
uint len = 0;
f->write("\0\0\0\0IDAT", 8);
uint crc = crc32(0, Z_NULL, 0);
crc = crc32(crc, (const Bytef *)"IDAT", 4);
-
z_stream z;
z.zalloc = NULL;
z.zfree = NULL;
z.opaque = NULL;
-
if(deflateInit(&z, compresspng) != Z_OK)
goto error;
-
uchar buf[1<<12];
z.next_out = (Bytef *)buf;
z.avail_out = sizeof(buf);
-
- loopi(image.h)
- {
+ loopi(image.h) {
uchar filter = 0;
- loopj(2)
- {
+ loopj(2) {
z.next_in = j ? (Bytef *)image.data + (flip ? image.h-i-1 : i)*image.pitch : (Bytef *)&filter;
z.avail_in = j ? image.w*image.bpp : 1;
- while(z.avail_in > 0)
- {
+ while(z.avail_in > 0) {
if(deflate(&z, Z_NO_FLUSH) != Z_OK) goto cleanuperror;
#define FLUSHZ do { \
int flush = sizeof(buf) - z.avail_out; \
}
}
}
-
- for(;;)
- {
+ for(;;) {
int err = deflate(&z, Z_FINISH);
if(err != Z_OK && err != Z_STREAM_END) goto cleanuperror;
FLUSHZ;
if(err == Z_STREAM_END) break;
}
-
deflateEnd(&z);
-
f->seek(idat, SEEK_SET);
f->putbig<uint>(len);
f->seek(0, SEEK_END);
f->putbig<uint>(crc);
-
writepngchunk(f, "IEND");
-
delete f;
return;
error:
delete f;
-
conoutf(CON_ERROR, "failed saving png to %s", filename);
}
const char *imageexts[NUMIMG] = { ".bmp", ".png", ".jpg" };
-int guessimageformat(const char *filename, int format = IMG_BMP)
-{
+int guessimageformat(const char *filename, int format = IMG_BMP) {
int len = strlen(filename);
- loopi(NUMIMG)
- {
+ loopi(NUMIMG) {
int extlen = strlen(imageexts[i]);
if(len >= extlen && !strcasecmp(&filename[len-extlen], imageexts[i])) return i;
}
return format;
}
-void saveimage(const char *filename, int format, ImageData &image, bool flip = false)
-{
- switch(format)
- {
+void saveimage(const char *filename, int format, ImageData &image, bool flip = false) {
+ switch(format) {
case IMG_PNG: savepng(filename, image, flip); break;
- default:
- {
+ default: {
ImageData flipped(image.w, image.h, image.bpp, image.data);
if(flip) texflip(flipped);
SDL_Surface *s = wrapsurface(flipped.data, flipped.w, flipped.h, flipped.bpp);
if(!s) break;
stream *f = openfile(filename, "wb");
- if(f)
- {
+ if(f) {
switch(format) {
case IMG_JPG:
#if SDL_IMAGE_VERSION_ATLEAST(2, 0, 2)
}
}
-bool loadimage(const char *filename, ImageData &image)
-{
+bool loadimage(const char *filename, ImageData &image) {
SDL_Surface *s = loadsurface(path(filename, true));
if(!s) return false;
image.wrap(s);
SVARP(screenshotdir, "screenshot");
-void screenshot(char *filename)
-{
+void screenshot(char *filename) {
static string buf;
int format = -1, dirlen = 0;
copystring(buf, screenshotdir);
- if(screenshotdir[0])
- {
+ if(screenshotdir[0]) {
dirlen = strlen(buf);
if(buf[dirlen] != '/' && buf[dirlen] != '\\' && dirlen+1 < (int)sizeof(buf)) { buf[dirlen++] = '/'; buf[dirlen] = '\0'; }
const char *dir = findfile(buf, "w");
if(!fileexists(dir, "w")) createdir(dir);
}
- if(filename[0])
- {
+ if(filename[0]) {
concatstring(buf, filename);
format = guessimageformat(buf, -1);
}
- else
- {
+ else {
string sstime;
time_t t = time(NULL);
size_t len = strftime(sstime, sizeof(sstime), "%Y-%m-%d_%H.%M.%S", localtime(&t));
sstime[min(len, sizeof(sstime)-1)] = '\0';
concatstring(buf, sstime);
-
const char *map = game::getclientmap(), *ssinfo = game::getscreenshotinfo();
- if(map && map[0])
- {
+ if(map && map[0]) {
concatstring(buf, "_");
concatstring(buf, map);
}
- if(ssinfo && ssinfo[0])
- {
+ if(ssinfo && ssinfo[0]) {
concatstring(buf, "_");
concatstring(buf, ssinfo);
}
-
for(char *s = &buf[dirlen]; *s; s++) if(iscubespace(*s) || *s == '/' || *s == '\\') *s = '-';
}
- if(format < 0)
- {
+ if(format < 0) {
format = screenshotformat;
concatstring(buf, imageexts[format]);
}
-
ImageData image(screenw, screenh, 3);
glPixelStorei(GL_PACK_ALIGNMENT, texalign(image.data, screenw, 3));
glReadPixels(0, 0, screenw, screenh, GL_RGB, GL_UNSIGNED_BYTE, image.data);
-struct GlobalShaderParamState
-{
+struct GlobalShaderParamState {
const char *name;
- union
- {
+ union {
float fval[32];
int ival[32];
uint uval[32];
uchar buf[32*sizeof(float)];
};
int version;
-
static int nextversion;
-
void resetversions();
-
- void changed()
- {
+ void changed() {
if(++nextversion < 0) resetversions();
version = nextversion;
}
};
-struct ShaderParamBinding
-{
+struct ShaderParamBinding {
int loc, size;
GLenum format;
};
-struct GlobalShaderParamUse : ShaderParamBinding
-{
-
+struct GlobalShaderParamUse : ShaderParamBinding {
GlobalShaderParamState *param;
int version;
-
- void flush()
- {
+ void flush() {
if(version == param->version) return;
- switch(format)
- {
+ switch(format) {
case GL_BOOL:
case GL_FLOAT: glUniform1fv_(loc, size, param->fval); break;
case GL_BOOL_VEC2:
}
};
-struct LocalShaderParamState : ShaderParamBinding
-{
+struct LocalShaderParamState : ShaderParamBinding {
const char *name;
};
-struct SlotShaderParam
-{
+struct SlotShaderParam {
const char *name;
int loc;
float val[4];
};
-struct SlotShaderParamState : LocalShaderParamState
-{
+struct SlotShaderParamState : LocalShaderParamState {
float val[4];
-
SlotShaderParamState() {}
- SlotShaderParamState(const SlotShaderParam &p)
- {
+ SlotShaderParamState(const SlotShaderParam &p) {
name = p.name;
loc = -1;
size = 1;
}
};
-enum
-{
+enum {
SHADER_DEFAULT = 0,
SHADER_NORMALSLMS = 1<<0,
SHADER_OPTION = 1<<3,
-
SHADER_INVALID = 1<<8,
SHADER_DEFERRED = 1<<9
};
struct Slot;
struct VSlot;
-struct UniformLoc
-{
+struct UniformLoc {
const char *name, *blockname;
int loc, version, binding, stride, offset, size;
void *data;
UniformLoc(const char *name = NULL, const char *blockname = NULL, int binding = -1, int stride = -1) : name(name), blockname(blockname), loc(-1), version(-1), binding(binding), stride(stride), offset(-1), size(-1), data(NULL) {}
};
-struct AttribLoc
-{
+struct AttribLoc {
const char *name;
int loc;
AttribLoc(const char *name = NULL, int loc = -1) : name(name), loc(loc) {}
};
-struct Shader
-{
+struct Shader {
static Shader *lastshader;
-
char *name, *vsstr, *psstr, *defer;
int type;
GLuint program, vsobj, psobj;
vector<UniformLoc> uniformlocs;
vector<AttribLoc> attriblocs;
const void *owner;
-
- Shader() : name(NULL), vsstr(NULL), psstr(NULL), defer(NULL), type(SHADER_DEFAULT), program(0), vsobj(0), psobj(0), detailshader(NULL), variantshader(NULL), altshader(NULL), variantrows(NULL), standard(false), forced(false), used(false), reusevs(NULL), reuseps(NULL), owner(NULL)
- {
+ Shader() : name(NULL), vsstr(NULL), psstr(NULL), defer(NULL), type(SHADER_DEFAULT), program(0), vsobj(0), psobj(0), detailshader(NULL), variantshader(NULL), altshader(NULL), variantrows(NULL), standard(false), forced(false), used(false), reusevs(NULL), reuseps(NULL), owner(NULL) {
loopi(MAXSHADERDETAIL) fastshader[i] = this;
}
-
- ~Shader()
- {
+ ~Shader() {
DELETEA(name);
DELETEA(vsstr);
DELETEA(psstr);
DELETEA(defer);
DELETEA(variantrows);
}
-
void fixdetailshader(bool force = true, bool recurse = true);
void allocparams(Slot *slot = NULL);
void setslotparams(Slot &slot);
void setslotparams(Slot &slot, VSlot &vslot);
void bindprograms();
-
- void flushparams(Slot *slot = NULL)
- {
+ void flushparams(Slot *slot = NULL) {
if(!used) { allocparams(slot); used = true; }
loopv(globalparams) globalparams[i].flush();
}
-
void force();
-
bool invalid() const { return (type&SHADER_INVALID)!=0; }
bool deferred() const { return (type&SHADER_DEFERRED)!=0; }
bool loaded() const { return detailshader!=NULL; }
-
static bool isnull(const Shader *s);
-
bool isnull() const { return isnull(this); }
-
- int numvariants(int row) const
- {
+ int numvariants(int row) const {
if(row < 0 || row >= MAXVARIANTROWS || !variantrows) return 0;
return variantrows[row+1] - variantrows[row];
}
-
- Shader *getvariant(int col, int row) const
- {
+ Shader *getvariant(int col, int row) const {
if(row < 0 || row >= MAXVARIANTROWS || col < 0 || !variantrows) return NULL;
int start = variantrows[row], end = variantrows[row+1];
return col < end - start ? variants[start + col] : NULL;
}
-
- bool hasoption(int row)
- {
- if(detailshader)
- {
+ bool hasoption(int row) {
+ if(detailshader) {
Shader *s = getvariant(0, row);
if(s) return (s->type&SHADER_OPTION)!=0;
}
return false;
}
-
- void addvariant(int row, Shader *s)
- {
+ void addvariant(int row, Shader *s) {
if(row < 0 || row >= MAXVARIANTROWS || variants.length() >= USHRT_MAX) return;
if(!variantrows) { variantrows = new ushort[MAXVARIANTROWS+1]; memset(variantrows, 0, (MAXVARIANTROWS+1)*sizeof(ushort)); }
variants.insert(variantrows[row+1], s);
for(int i = row+1; i <= MAXVARIANTROWS; ++i) ++variantrows[i];
}
-
- void setvariant_(int col, int row, Shader *fallbackshader)
- {
+ void setvariant_(int col, int row, Shader *fallbackshader) {
Shader *s = fallbackshader;
- if(detailshader->variantrows)
- {
+ if(detailshader->variantrows) {
int start = detailshader->variantrows[row], end = detailshader->variantrows[row+1];
- for(col = min(start + col, end-1); col >= start; --col)
- {
+ for(col = min(start + col, end-1); col >= start; --col) {
if(!detailshader->variants[col]->invalid()) { s = detailshader->variants[col]; break; }
}
}
if(lastshader!=s) s->bindprograms();
}
-
- void setvariant(int col, int row, Shader *fallbackshader)
- {
+ void setvariant(int col, int row, Shader *fallbackshader) {
if(isnull() || !loaded()) return;
setvariant_(col, row, fallbackshader);
lastshader->flushparams();
}
-
- void setvariant(int col, int row)
- {
+ void setvariant(int col, int row) {
if(isnull() || !loaded()) return;
setvariant_(col, row, detailshader);
lastshader->flushparams();
}
-
- void setvariant(int col, int row, Slot &slot, VSlot &vslot, Shader *fallbackshader)
- {
+ void setvariant(int col, int row, Slot &slot, VSlot &vslot, Shader *fallbackshader) {
if(isnull() || !loaded()) return;
setvariant_(col, row, fallbackshader);
lastshader->flushparams(&slot);
lastshader->setslotparams(slot, vslot);
}
-
- void setvariant(int col, int row, Slot &slot, VSlot &vslot)
- {
+ void setvariant(int col, int row, Slot &slot, VSlot &vslot) {
if(isnull() || !loaded()) return;
setvariant_(col, row, detailshader);
lastshader->flushparams(&slot);
lastshader->setslotparams(slot, vslot);
}
-
- void set_()
- {
+ void set_() {
if(lastshader!=detailshader) detailshader->bindprograms();
}
-
- void set()
- {
+ void set() {
if(isnull() || !loaded()) return;
set_();
lastshader->flushparams();
}
-
- void set(Slot &slot, VSlot &vslot)
- {
+ void set(Slot &slot, VSlot &vslot) {
if(isnull() || !loaded()) return;
set_();
lastshader->flushparams(&slot);
lastshader->setslotparams(slot, vslot);
}
-
bool compile();
void cleanup(bool invalid = false);
-
static int uniformlocversion();
};
-struct GlobalShaderParam
-{
+struct GlobalShaderParam {
const char *name;
GlobalShaderParamState *param;
-
GlobalShaderParam(const char *name) : name(name), param(NULL) {}
-
- GlobalShaderParamState *resolve()
- {
+ GlobalShaderParamState *resolve() {
extern GlobalShaderParamState *getglobalparam(const char *name);
if(!param) param = getglobalparam(name);
param->changed();
return param;
}
-
- void setf(float x = 0, float y = 0, float z = 0, float w = 0)
- {
+ void setf(float x = 0, float y = 0, float z = 0, float w = 0) {
GlobalShaderParamState *g = resolve();
g->fval[0] = x;
g->fval[1] = y;
void set(const matrix2 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); }
void set(const matrix3 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); }
void set(const matrix4 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); }
-
template<class T>
void setv(const T *v, int n = 1) { memcpy(resolve()->buf, v, n*sizeof(T)); }
-
- void seti(int x = 0, int y = 0, int z = 0, int w = 0)
- {
+ void seti(int x = 0, int y = 0, int z = 0, int w = 0) {
GlobalShaderParamState *g = resolve();
g->ival[0] = x;
g->ival[1] = y;
void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); }
void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); }
void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); }
-
- void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0)
- {
+ void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0) {
GlobalShaderParamState *g = resolve();
g->uval[0] = x;
g->uval[1] = y;
g->uval[2] = z;
g->uval[3] = w;
}
-
template<class T>
T *reserve(int n = 1) { return (T *)resolve()->buf; }
};
-struct LocalShaderParam
-{
+struct LocalShaderParam {
const char *name;
int loc;
-
LocalShaderParam(const char *name) : name(name), loc(-1) {}
-
- LocalShaderParamState *resolve()
- {
+ LocalShaderParamState *resolve() {
Shader *s = Shader::lastshader;
if(!s) return NULL;
- if(!s->localparamremap.inrange(loc))
- {
+ if(!s->localparamremap.inrange(loc)) {
extern int getlocalparam(const char *name);
if(loc == -1) loc = getlocalparam(name);
if(!s->localparamremap.inrange(loc)) return NULL;
uchar remap = s->localparamremap[loc];
return s->localparams.inrange(remap) ? &s->localparams[remap] : NULL;
}
-
- void setf(float x = 0, float y = 0, float z = 0, float w = 0)
- {
+ void setf(float x = 0, float y = 0, float z = 0, float w = 0) {
ShaderParamBinding *b = resolve();
- if(b) switch(b->format)
- {
+ if(b) switch(b->format) {
case GL_BOOL:
case GL_FLOAT: glUniform1f_(b->loc, x); break;
case GL_BOOL_VEC2:
void set(const matrix2 &m) { setv(&m); }
void set(const matrix3 &m) { setv(&m); }
void set(const matrix4 &m) { setv(&m); }
-
template<class T>
- void sett(T x, T y, T z, T w)
- {
+ void sett(T x, T y, T z, T w) {
ShaderParamBinding *b = resolve();
- if(b) switch(b->format)
- {
+ if(b) switch(b->format) {
case GL_FLOAT: glUniform1f_(b->loc, x); break;
case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break;
case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break;
name##shader->setvariant(__VA_ARGS__); \
} while(0)
-struct ImageData
-{
+struct ImageData {
int w, h, bpp, levels, align, pitch;
GLenum compressed;
uchar *data;
void *owner;
void (*freefunc)(void *);
-
ImageData()
- : data(NULL), owner(NULL), freefunc(NULL)
- {}
-
+ : data(NULL), owner(NULL), freefunc(NULL) {
+ }
- ImageData(int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE)
- {
+ ImageData(int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE) {
setdata(NULL, nw, nh, nbpp, nlevels, nalign, ncompressed);
}
-
ImageData(int nw, int nh, int nbpp, uchar *data)
- : owner(NULL), freefunc(NULL)
- {
+ : owner(NULL), freefunc(NULL) {
setdata(data, nw, nh, nbpp);
}
-
ImageData(SDL_Surface *s) { wrap(s); }
~ImageData() { cleanup(); }
-
- void setdata(uchar *ndata, int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE)
- {
+ void setdata(uchar *ndata, int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE) {
w = nw;
h = nh;
bpp = nbpp;
data = ndata ? ndata : new uchar[calcsize()];
if(!ndata) { owner = this; freefunc = NULL; }
}
-
int calclevelsize(int level) const { return ((max(w>>level, 1)+align-1)/align)*((max(h>>level, 1)+align-1)/align)*bpp; }
-
- int calcsize() const
- {
+ int calcsize() const {
if(!align) return w*h*bpp;
int lw = w, lh = h,
size = 0;
- loopi(levels)
- {
+ loopi(levels) {
if(lw<=0) lw = 1;
if(lh<=0) lh = 1;
size += ((lw+align-1)/align)*((lh+align-1)/align)*bpp;
}
return size;
}
-
- void disown()
- {
+ void disown() {
data = NULL;
owner = NULL;
freefunc = NULL;
}
-
- void cleanup()
- {
+ void cleanup() {
if(owner==this) delete[] data;
else if(freefunc) (*freefunc)(owner);
disown();
}
-
- void replace(ImageData &d)
- {
+ void replace(ImageData &d) {
cleanup();
*this = d;
if(owner == &d) owner = this;
d.disown();
}
-
- void wrap(SDL_Surface *s)
- {
+ void wrap(SDL_Surface *s) {
setdata((uchar *)s->pixels, s->w, s->h, s->format->BytesPerPixel);
pitch = s->pitch;
owner = s;
// each texture slot can have multiple texture frames, of which currently only the first is used
// additional frames can be used for various shaders
-struct Texture
-{
- enum
- {
+struct Texture {
+ enum {
IMAGE = 0,
CUBEMAP = 1,
TYPE = 0xFF,
-
STUB = 1<<8,
TRANSIENT = 1<<9,
COMPRESSED = 1<<10,
MIRROR = 1<<12,
FLAGS = 0xFF00
};
-
char *name;
int type, w, h, xs, ys, bpp, clamp;
bool mipmap, canreduce;
GLuint id;
uchar *alphamask;
-
Texture() : alphamask(NULL) {}
};
-enum
-{
+enum {
TEX_DIFFUSE = 0,
TEX_UNKNOWN,
TEX_DECAL,
TEX_ALPHA
};
-enum
-{
+enum {
VSLOT_SHPARAM = 0,
VSLOT_SCALE,
VSLOT_ROTATION,
VSLOT_NUM
};
-struct VSlot
-{
+struct VSlot {
Slot *slot;
VSlot *next;
int index, changed;
int layer;
float alphafront, alphaback;
vec colorscale;
-
- VSlot(Slot *slot = NULL, int index = -1) : slot(slot), next(NULL), index(index), changed(0)
- {
+ VSlot(Slot *slot = NULL, int index = -1) : slot(slot), next(NULL), index(index), changed(0) {
reset();
if(slot) addvariant(slot);
}
-
void addvariant(Slot *slot);
-
- void reset()
- {
+ void reset() {
params.shrink(0);
linked = false;
scale = 1;
alphaback = 0;
colorscale = vec(1, 1, 1);
}
-
- void cleanup()
- {
+ void cleanup() {
linked = false;
}
};
-struct Slot
-{
- struct Tex
- {
+struct Slot {
+ struct Tex {
int type;
Texture *t;
string name;
int combined;
};
-
int index;
vector<Tex> sts;
Shader *shader;
int layermaskmode;
float layermaskscale;
ImageData *layermask;
-
Slot(int index = -1) : index(index), variants(NULL), layermaskname(NULL), layermask(NULL) { reset(); }
-
- void reset()
- {
+ void reset() {
sts.shrink(0);
shader = NULL;
params.shrink(0);
layermaskscale = 1;
if(layermask) DELETEP(layermask);
}
-
- void cleanup()
- {
+ void cleanup() {
loaded = false;
thumbnail = NULL;
- loopv(sts)
- {
+ loopv(sts) {
Tex &t = sts[i];
t.t = NULL;
t.combined = -1;
}
};
-inline void VSlot::addvariant(Slot *slot)
-{
+inline void VSlot::addvariant(Slot *slot) {
if(!slot->variants) slot->variants = this;
- else
- {
+ else {
VSlot *prev = slot->variants;
while(prev->next) prev = prev->next;
prev->next = this;
}
}
-struct MSlot : Slot, VSlot
-{
+struct MSlot : Slot, VSlot {
MSlot() : VSlot(this) {}
-
- void reset()
- {
+ void reset() {
Slot::reset();
VSlot::reset();
}
-
- void cleanup()
- {
+ void cleanup() {
Slot::cleanup();
VSlot::cleanup();
}
};
-struct texrotation
-{
+struct texrotation {
bool flipx, flipy, swapxy;
};
-struct cubemapside
-{
+struct cubemapside {
GLenum target;
const char *name;
bool flipx, flipy, swapxy;
+++ /dev/null
-struct vertmodel : animmodel
-{
- struct vert { vec pos, norm; };
- struct vvert { vec pos; vec2 tc; };
- struct vvertn : vvert { vec norm; };
- struct vvertbump : vvert { squat tangent; };
- struct tcvert { vec2 tc; };
- struct bumpvert { vec4 tangent; };
- struct tri { ushort vert[3]; };
-
- struct vbocacheentry
- {
- GLuint vbuf;
- animstate as;
- int millis;
-
- vbocacheentry() : vbuf(0) { as.cur.fr1 = as.prev.fr1 = -1; }
- };
-
- struct vertmesh : mesh
- {
- vert *verts;
- tcvert *tcverts;
- bumpvert *bumpverts;
- tri *tris;
- int numverts, numtris;
-
- int voffset, eoffset, elen;
- ushort minvert, maxvert;
-
- vertmesh() : verts(0), tcverts(0), bumpverts(0), tris(0)
- {
- }
-
- virtual ~vertmesh()
- {
- DELETEA(verts);
- DELETEA(tcverts);
- DELETEA(bumpverts);
- DELETEA(tris);
- }
-
- void smoothnorms(float limit = 0, bool areaweight = true)
- {
- if(((vertmeshgroup *)group)->numframes == 1) mesh::smoothnorms(verts, numverts, tris, numtris, limit, areaweight);
- else buildnorms(areaweight);
- }
-
- void buildnorms(bool areaweight = true)
- {
- mesh::buildnorms(verts, numverts, tris, numtris, areaweight, ((vertmeshgroup *)group)->numframes);
- }
-
- void calctangents(bool areaweight = true)
- {
- if(bumpverts) return;
- bumpverts = new bumpvert[((vertmeshgroup *)group)->numframes*numverts];
- mesh::calctangents(bumpverts, verts, tcverts, numverts, tris, numtris, areaweight, ((vertmeshgroup *)group)->numframes);
- }
-
- void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m)
- {
- loopj(numverts)
- {
- vec v = m.transform(verts[j].pos);
- loopi(3)
- {
- bbmin[i] = min(bbmin[i], v[i]);
- bbmax[i] = max(bbmax[i], v[i]);
- }
- }
- }
-
- void genBIH(BIH::mesh &m)
- {
- m.tris = (const BIH::tri *)tris;
- m.numtris = numtris;
- m.pos = (const uchar *)&verts->pos;
- m.posstride = sizeof(vert);
- m.tc = (const uchar *)&tcverts->tc;
- m.tcstride = sizeof(tcvert);
- }
-
- static inline void assignvert(vvertn &vv, int j, tcvert &tc, vert &v)
- {
- vv.pos = v.pos;
- vv.norm = v.norm;
- vv.tc = tc.tc;
- }
-
- inline void assignvert(vvertbump &vv, int j, tcvert &tc, vert &v)
- {
- vv.pos = v.pos;
- vv.tc = tc.tc;
- vv.tangent = bumpverts[j].tangent;
- }
-
- template<class T>
- int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts, int *htdata, int htlen)
- {
- voffset = offset;
- eoffset = idxs.length();
- minvert = 0xFFFF;
- loopi(numtris)
- {
- tri &t = tris[i];
- loopj(3)
- {
- int index = t.vert[j];
- tcvert &tc = tcverts[index];
- vert &v = verts[index];
- T vv;
- assignvert(vv, index, tc, v);
- int htidx = hthash(v.pos)&(htlen-1);
- loopk(htlen)
- {
- int &vidx = htdata[(htidx+k)&(htlen-1)];
- if(vidx < 0) { vidx = idxs.add(ushort(vverts.length())); vverts.add(vv); break; }
- else if(!memcmp(&vverts[vidx], &vv, sizeof(vv))) { minvert = min(minvert, idxs.add(ushort(vidx))); break; }
- }
- }
- }
- minvert = min(minvert, ushort(voffset));
- maxvert = max(minvert, ushort(vverts.length()-1));
- elen = idxs.length()-eoffset;
- return vverts.length()-voffset;
- }
-
- int genvbo(vector<ushort> &idxs, int offset)
- {
- voffset = offset;
- eoffset = idxs.length();
- loopi(numtris)
- {
- tri &t = tris[i];
- loopj(3) idxs.add(voffset+t.vert[j]);
- }
- minvert = voffset;
- maxvert = voffset + numverts-1;
- elen = idxs.length()-eoffset;
- return numverts;
- }
-
- template<class T>
- static inline void fillvert(T &vv, int j, tcvert &tc, vert &v)
- {
- vv.tc = tc.tc;
- }
-
- template<class T>
- void fillverts(T *vdata)
- {
- vdata += voffset;
- loopi(numverts) fillvert(vdata[i], i, tcverts[i], verts[i]);
- }
-
- void interpverts(const animstate &as, bool tangents, void * RESTRICT vdata, skin &s)
- {
- const vert * RESTRICT vert1 = &verts[as.cur.fr1 * numverts],
- * RESTRICT vert2 = &verts[as.cur.fr2 * numverts],
- * RESTRICT pvert1 = as.interp<1 ? &verts[as.prev.fr1 * numverts] : NULL,
- * RESTRICT pvert2 = as.interp<1 ? &verts[as.prev.fr2 * numverts] : NULL;
- #define ipvert(attrib) v.attrib.lerp(vert1[i].attrib, vert2[i].attrib, as.cur.t)
- #define ipbvert(attrib, type) v.attrib.lerp(bvert1[i].attrib, bvert2[i].attrib, as.cur.t)
- #define ipvertp(attrib) v.attrib.lerp(pvert1[i].attrib, pvert2[i].attrib, as.prev.t).lerp(vec().lerp(vert1[i].attrib, vert2[i].attrib, as.cur.t), as.interp)
- #define ipbvertp(attrib, type) v.attrib.lerp(type().lerp(bpvert1[i].attrib, bpvert2[i].attrib, as.prev.t), type().lerp(bvert1[i].attrib, bvert2[i].attrib, as.cur.t), as.interp)
- #define iploop(type, body) \
- loopi(numverts) \
- { \
- type &v = ((type * RESTRICT)vdata)[i]; \
- body; \
- }
- if(tangents)
- {
- const bumpvert * RESTRICT bvert1 = &bumpverts[as.cur.fr1 * numverts],
- * RESTRICT bvert2 = &bumpverts[as.cur.fr2 * numverts],
- * RESTRICT bpvert1 = as.interp<1 ? &bumpverts[as.prev.fr1 * numverts] : NULL,
- * RESTRICT bpvert2 = as.interp<1 ? &bumpverts[as.prev.fr2 * numverts] : NULL;
- if(as.interp<1) iploop(vvertbump, { ipvertp(pos); ipbvertp(tangent, vec4); })
- else iploop(vvertbump, { ipvert(pos); ipbvert(tangent, vec4); })
- }
- else
- {
- if(as.interp<1) iploop(vvertn, { ipvertp(pos); ipvertp(norm); })
- else iploop(vvertn, { ipvert(pos); ipvert(norm); })
- }
- #undef iploop
- #undef ipvert
- #undef ipbvert
- #undef ipvertp
- #undef ipbvertp
- }
-
- void render(const animstate *as, skin &s, vbocacheentry &vc)
- {
- if(!Shader::lastshader) return;
- glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_SHORT, &((vertmeshgroup *)group)->edata[eoffset]);
- glde++;
- xtravertsva += numverts;
- }
- };
-
- struct tag
- {
- char *name;
- matrix4x3 transform;
-
- tag() : name(NULL) {}
- ~tag() { DELETEA(name); }
- };
-
- struct vertmeshgroup : meshgroup
- {
- int numframes;
- tag *tags;
- int numtags;
-
- static const int MAXVBOCACHE = 16;
- vbocacheentry vbocache[MAXVBOCACHE];
-
- ushort *edata;
- GLuint ebuf;
- bool vtangents;
- int vlen, vertsize;
- uchar *vdata;
-
- vertmeshgroup() : numframes(0), tags(NULL), numtags(0), edata(NULL), ebuf(0), vtangents(false), vlen(0), vertsize(0), vdata(NULL)
- {
- }
-
- virtual ~vertmeshgroup()
- {
- DELETEA(tags);
- if(ebuf) glDeleteBuffers_(1, &ebuf);
- loopi(MAXVBOCACHE)
- {
- if(vbocache[i].vbuf) glDeleteBuffers_(1, &vbocache[i].vbuf);
- }
- DELETEA(vdata);
- }
-
- int findtag(const char *name)
- {
- loopi(numtags) if(!strcmp(tags[i].name, name)) return i;
- return -1;
- }
-
- int totalframes() const { return numframes; }
-
- void concattagtransform(part *p, int i, const matrix4x3 &m, matrix4x3 &n)
- {
- n.mul(m, tags[numtags + i].transform);
- n.posttranslate(m.transformnormal(p->translate), p->model->scale);
- }
-
- void calctagmatrix(part *p, int i, const animstate &as, matrix4 &matrix)
- {
- const matrix4x3 &tag1 = tags[as.cur.fr1*numtags + i].transform,
- &tag2 = tags[as.cur.fr2*numtags + i].transform;
- matrix4x3 tag;
- tag.lerp(tag1, tag2, as.cur.t);
- if(as.interp<1)
- {
- const matrix4x3 &tag1p = tags[as.prev.fr1*numtags + i].transform,
- &tag2p = tags[as.prev.fr2*numtags + i].transform;
- matrix4x3 tagp;
- tagp.lerp(tag1p, tag2p, as.prev.t);
- tag.lerp(tagp, tag, as.interp);
- }
- tag.d.add(p->translate).mul(p->model->scale);
- matrix = matrix4(tag);
- }
-
- void genvbo(bool tangents, vbocacheentry &vc)
- {
- if(!vc.vbuf) glGenBuffers_(1, &vc.vbuf);
- if(ebuf) return;
-
- vector<ushort> idxs;
-
- if(tangents) loopv(meshes) ((vertmesh *)meshes[i])->calctangents();
-
- vtangents = tangents;
- vertsize = tangents ? sizeof(vvertbump) : sizeof(vvertn);
- vlen = 0;
- if(numframes>1)
- {
- loopv(meshes) vlen += ((vertmesh *)meshes[i])->genvbo(idxs, vlen);
- DELETEA(vdata);
- vdata = new uchar[vlen*vertsize];
- #define FILLVDATA(type) do { \
- loopv(meshes) ((vertmesh *)meshes[i])->fillverts((type *)vdata); \
- } while(0)
- if(tangents) FILLVDATA(vvertbump);
- else FILLVDATA(vvertn);
- #undef FILLVDATA
- }
- else
- {
- gle::bindvbo(vc.vbuf);
- #define GENVBO(type) do { \
- vector<type> vverts; \
- loopv(meshes) vlen += ((vertmesh *)meshes[i])->genvbo(idxs, vlen, vverts, htdata, htlen); \
- glBufferData_(GL_ARRAY_BUFFER, vverts.length()*sizeof(type), vverts.getbuf(), GL_STATIC_DRAW); \
- } while(0)
- int numverts = 0, htlen = 128;
- loopv(meshes) numverts += ((vertmesh *)meshes[i])->numverts;
- while(htlen < numverts) htlen *= 2;
- if(numverts*4 > htlen*3) htlen *= 2;
- int *htdata = new int[htlen];
- memset(htdata, -1, htlen*sizeof(int));
- if(tangents) GENVBO(vvertbump);
- else GENVBO(vvertn);
- delete[] htdata;
- #undef GENVBO
- gle::clearvbo();
- }
-
- glGenBuffers_(1, &ebuf);
- gle::bindebo(ebuf);
- glBufferData_(GL_ELEMENT_ARRAY_BUFFER, idxs.length()*sizeof(ushort), idxs.getbuf(), GL_STATIC_DRAW);
- gle::clearebo();
- }
-
- void bindvbo(const animstate *as, vbocacheentry &vc)
- {
- vvert *vverts = 0;
- bindpos(ebuf, vc.vbuf, &vverts->pos, vertsize);
- if(as->cur.anim&ANIM_NOSKIN)
- {
- if(enabletc) disabletc();
- if(enablenormals) disablenormals();
- if(enabletangents) disabletangents();
- }
- else
- {
- if(vtangents)
- {
- if(enablenormals) disablenormals();
- vvertbump *vvertbumps = 0;
- bindtangents(&vvertbumps->tangent, vertsize);
- }
- else
- {
- if(enabletangents) disabletangents();
- vvertn *vvertns = 0;
- bindnormals(&vvertns->norm, vertsize);
- }
-
- bindtc(&vverts->tc, vertsize);
- }
- if(enablebones) disablebones();
- }
-
- void cleanup()
- {
- loopi(MAXVBOCACHE)
- {
- vbocacheentry &c = vbocache[i];
- if(c.vbuf) { glDeleteBuffers_(1, &c.vbuf); c.vbuf = 0; }
- c.as.cur.fr1 = -1;
- }
- if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; }
- }
-
- void preload(part *p)
- {
- if(numframes > 1) return;
- bool tangents = p->tangents();
- if(tangents!=vtangents) cleanup();
- if(!vbocache->vbuf) genvbo(tangents, *vbocache);
- }
-
- void render(const animstate *as, float pitch, const vec &axis, const vec &forward, dynent *d, part *p)
- {
- if(as->cur.anim&ANIM_NORENDER)
- {
- loopv(p->links) calctagmatrix(p, p->links[i].tag, *as, p->links[i].matrix);
- return;
- }
-
- bool tangents = p->tangents();
- if(tangents!=vtangents) { cleanup(); disablevbo(); }
- vbocacheentry *vc = NULL;
- if(numframes<=1) vc = vbocache;
- else
- {
- loopi(MAXVBOCACHE)
- {
- vbocacheentry &c = vbocache[i];
- if(!c.vbuf) continue;
- if(c.as==*as) { vc = &c; break; }
- }
- if(!vc) loopi(MAXVBOCACHE) { vc = &vbocache[i]; if(!vc->vbuf || vc->millis < lastmillis) break; }
- }
- if(!vc->vbuf) genvbo(tangents, *vc);
- if(numframes>1)
- {
- if(vc->as!=*as)
- {
- vc->as = *as;
- vc->millis = lastmillis;
- loopv(meshes)
- {
- vertmesh &m = *(vertmesh *)meshes[i];
- m.interpverts(*as, tangents, vdata + m.voffset*vertsize, p->skins[i]);
- }
- gle::bindvbo(vc->vbuf);
- glBufferData_(GL_ARRAY_BUFFER, vlen*vertsize, vdata, GL_STREAM_DRAW);
- }
- vc->millis = lastmillis;
- }
-
- bindvbo(as, *vc);
- loopv(meshes)
- {
- vertmesh *m = (vertmesh *)meshes[i];
- p->skins[i].bind(m, as);
- m->render(as, p->skins[i], *vc);
- }
-
- loopv(p->links) calctagmatrix(p, p->links[i].tag, *as, p->links[i].matrix);
- }
- };
-
- vertmodel(const char *name) : animmodel(name)
- {
- }
-};
-
-template<class MDL> struct vertloader : modelloader<MDL, vertmodel>
-{
- vertloader(const char *name) : modelloader<MDL, vertmodel>(name) {}
-};
-
-template<class MDL> struct vertcommands : modelcommands<MDL, struct MDL::vertmesh>
-{
- typedef struct MDL::part part;
- typedef struct MDL::skin skin;
-
- static void loadpart(char *model, float *smooth)
- {
- if(!MDL::loading) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
- defformatstring(filename, "%s/%s", MDL::dir, model);
- part &mdl = MDL::loading->addpart();
- if(mdl.index) mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
- mdl.meshes = MDL::loading->sharemeshes(path(filename), double(*smooth > 0 ? cos(clamp(*smooth, 0.0f, 180.0f)*RAD) : 2));
- if(!mdl.meshes) conoutf(CON_ERROR, "could not load %s", filename);
- else mdl.initskins();
- }
-
- static void setpitch(float *pitchscale, float *pitchoffset, float *pitchmin, float *pitchmax)
- {
- if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
- part &mdl = *MDL::loading->parts.last();
-
- mdl.pitchscale = *pitchscale;
- mdl.pitchoffset = *pitchoffset;
- if(*pitchmin || *pitchmax)
- {
- mdl.pitchmin = *pitchmin;
- mdl.pitchmax = *pitchmax;
- }
- else
- {
- mdl.pitchmin = -360*fabs(mdl.pitchscale) + mdl.pitchoffset;
- mdl.pitchmax = 360*fabs(mdl.pitchscale) + mdl.pitchoffset;
- }
- }
-
- static void setanim(char *anim, int *frame, int *range, float *speed, int *priority)
- {
- if(!MDL::loading || MDL::loading->parts.empty()) { conoutf(CON_ERROR, "not loading an %s", MDL::formatname()); return; }
- vector<int> anims;
- findanims(anim, anims);
- if(anims.empty()) conoutf(CON_ERROR, "could not find animation %s", anim);
- else loopv(anims)
- {
- MDL::loading->parts.last()->setanim(0, anims[i], *frame, *range, *speed, *priority);
- }
- }
-
- vertcommands()
- {
- if(MDL::multiparted()) this->modelcommand(loadpart, "load", "sf");
- this->modelcommand(setpitch, "pitch", "ffff");
- if(MDL::animated()) this->modelcommand(setanim, "anim", "siiff");
- }
-};
-
VAR(octaentsize, 0, 64, 1024);
VAR(entselradius, 0, 2, 10);
-static inline void mmboundbox(const entity &e, model *m, vec ¢er, vec &radius)
-{
+static inline void mmboundbox(const entity &e, model *m, vec ¢er, vec &radius) {
m->boundbox(center, radius);
rotatebb(center, radius, e.attr1);
}
-static inline void mmcollisionbox(const entity &e, model *m, vec ¢er, vec &radius)
-{
+static inline void mmcollisionbox(const entity &e, model *m, vec ¢er, vec &radius) {
m->collisionbox(center, radius);
rotatebb(center, radius, e.attr1);
}
-bool getentboundingbox(const extentity &e, ivec &o, ivec &r)
-{
- switch(e.type)
- {
+bool getentboundingbox(const extentity &e, ivec &o, ivec &r) {
+ switch(e.type) {
case ET_EMPTY:
return false;
- case ET_MAPMODEL:
- {
+ case ET_MAPMODEL: {
model *m = loadmapmodel(e.attr2);
- if(m)
- {
+ if(m) {
vec center, radius;
mmboundbox(e, m, center, radius);
center.add(e.o);
return true;
}
-enum
-{
+enum {
MODOE_ADD = 1<<0,
MODOE_UPDATEBB = 1<<1,
MODOE_LIGHTENT = 1<<2
};
-void modifyoctaentity(int flags, int id, extentity &e, cube *c, const ivec &cor, int size, const ivec &bo, const ivec &br, int leafsize, vtxarray *lastva = NULL)
-{
- loopoctabox(cor, size, bo, br)
- {
+void modifyoctaentity(int flags, int id, extentity &e, cube *c, const ivec &cor, int size, const ivec &bo, const ivec &br, int leafsize, vtxarray *lastva = NULL) {
+ loopoctabox(cor, size, bo, br) {
ivec o(i, cor, size);
vtxarray *va = c[i].ext && c[i].ext->va ? c[i].ext->va : lastva;
if(c[i].children != NULL && size > leafsize)
modifyoctaentity(flags, id, e, c[i].children, o, size>>1, bo, br, leafsize, va);
- else if(flags&MODOE_ADD)
- {
+ else if(flags&MODOE_ADD) {
if(!c[i].ext || !c[i].ext->ents) ext(c[i]).ents = new octaentities(o, size);
octaentities &oe = *c[i].ext->ents;
- switch(e.type)
- {
+ switch(e.type) {
case ET_MAPMODEL:
- if(loadmapmodel(e.attr2))
- {
- if(va)
- {
+ if(loadmapmodel(e.attr2)) {
+ if(va) {
va->bbmin.x = -1;
if(oe.mapmodels.empty()) va->mapmodels.add(&oe);
}
oe.other.add(id);
break;
}
-
}
- else if(c[i].ext && c[i].ext->ents)
- {
+ else if(c[i].ext && c[i].ext->ents) {
octaentities &oe = *c[i].ext->ents;
- switch(e.type)
- {
+ switch(e.type) {
case ET_MAPMODEL:
- if(loadmapmodel(e.attr2))
- {
+ if(loadmapmodel(e.attr2)) {
oe.mapmodels.removeobj(id);
- if(va)
- {
+ if(va) {
va->bbmin.x = -1;
if(oe.mapmodels.empty()) va->mapmodels.removeobj(&oe);
}
oe.bbmin = oe.bbmax = oe.o;
oe.bbmin.add(oe.size);
- loopvj(oe.mapmodels)
- {
+ loopvj(oe.mapmodels) {
extentity &e = *entities::getents()[oe.mapmodels[j]];
ivec eo, er;
if(getentboundingbox(e, eo, er))
freeoctaentities(c[i]);
}
if(c[i].ext && c[i].ext->ents) c[i].ext->ents->query = NULL;
- if(va && va!=lastva)
- {
- if(lastva)
- {
+ if(va && va!=lastva) {
+ if(lastva) {
if(va->bbmin.x < 0) lastva->bbmin.x = -1;
}
else if(flags&MODOE_UPDATEBB) updatevabb(va);
vector<int> outsideents;
-static bool modifyoctaent(int flags, int id, extentity &e)
-{
+static bool modifyoctaent(int flags, int id, extentity &e) {
if(flags&MODOE_ADD ? e.flags&EF_OCTA : !(e.flags&EF_OCTA)) return false;
-
ivec o, r;
if(!getentboundingbox(e, o, r)) return false;
-
- if(!insideworld(e.o))
- {
+ if(!insideworld(e.o)) {
int idx = outsideents.find(id);
- if(flags&MODOE_ADD)
- {
+ if(flags&MODOE_ADD) {
if(idx < 0) outsideents.add(id);
}
else if(idx >= 0) outsideents.removeunordered(idx);
}
- else
- {
+ else {
int leafsize = octaentsize, limit = max(r.x - o.x, max(r.y - o.y, r.z - o.z));
while(leafsize < limit) leafsize *= 2;
int diff = ~(leafsize-1) & ((o.x^r.x)|(o.y^r.y)|(o.z^r.z));
return true;
}
-static inline bool modifyoctaent(int flags, int id)
-{
+static inline bool modifyoctaent(int flags, int id) {
vector<extentity *> &ents = entities::getents();
return ents.inrange(id) && modifyoctaent(flags, id, *ents[id]);
}
static inline void addentity(int id) { modifyoctaent(MODOE_ADD|MODOE_UPDATEBB|MODOE_LIGHTENT, id); }
static inline void removeentity(int id) { modifyoctaent(MODOE_UPDATEBB, id); }
-void freeoctaentities(cube &c)
-{
+void freeoctaentities(cube &c) {
if(!c.ext) return;
- if(entities::getents().length())
- {
+ if(entities::getents().length()) {
while(c.ext->ents && !c.ext->ents->mapmodels.empty()) removeentity(c.ext->ents->mapmodels.pop());
while(c.ext->ents && !c.ext->ents->other.empty()) removeentity(c.ext->ents->other.pop());
}
- if(c.ext->ents)
- {
+ if(c.ext->ents) {
delete c.ext->ents;
c.ext->ents = NULL;
}
}
-void entitiesinoctanodes()
-{
+void entitiesinoctanodes() {
vector<extentity *> &ents = entities::getents();
loopv(ents) modifyoctaent(MODOE_ADD, i, *ents[i]);
}
-static inline void findents(octaentities &oe, int low, int high, bool notspawned, const vec &pos, const vec &invradius, vector<int> &found)
-{
+static inline void findents(octaentities &oe, int low, int high, bool notspawned, const vec &pos, const vec &invradius, vector<int> &found) {
vector<extentity *> &ents = entities::getents();
- loopv(oe.other)
- {
+ loopv(oe.other) {
int id = oe.other[i];
extentity &e = *ents[id];
if(e.type >= low && e.type <= high && (e.spawned() || notspawned) && vec(e.o).sub(pos).mul(invradius).squaredlen() <= 1) found.add(id);
}
}
-static inline void findents(cube *c, const ivec &o, int size, const ivec &bo, const ivec &br, int low, int high, bool notspawned, const vec &pos, const vec &invradius, vector<int> &found)
-{
- loopoctabox(o, size, bo, br)
- {
+static inline void findents(cube *c, const ivec &o, int size, const ivec &bo, const ivec &br, int low, int high, bool notspawned, const vec &pos, const vec &invradius, vector<int> &found) {
+ loopoctabox(o, size, bo, br) {
if(c[i].ext && c[i].ext->ents) findents(*c[i].ext->ents, low, high, notspawned, pos, invradius, found);
- if(c[i].children && size > octaentsize)
- {
+ if(c[i].children && size > octaentsize) {
ivec co(i, o, size);
findents(c[i].children, co, size>>1, bo, br, low, high, notspawned, pos, invradius, found);
}
}
}
-void findents(int low, int high, bool notspawned, const vec &pos, const vec &radius, vector<int> &found)
-{
+void findents(int low, int high, bool notspawned, const vec &pos, const vec &radius, vector<int> &found) {
vec invradius(1/radius.x, 1/radius.y, 1/radius.z);
ivec bo(vec(pos).sub(radius).sub(1)),
br(vec(pos).add(radius).add(1));
int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z) | octaentsize,
scale = worldscale-1;
- if(diff&~((1<<scale)-1) || uint(bo.x|bo.y|bo.z|br.x|br.y|br.z) >= uint(worldsize))
- {
+ if(diff&~((1<<scale)-1) || uint(bo.x|bo.y|bo.z|br.x|br.y|br.z) >= uint(worldsize)) {
findents(worldroot, ivec(0, 0, 0), 1<<scale, bo, br, low, high, notspawned, pos, invradius, found);
return;
}
cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)];
if(c->ext && c->ext->ents) findents(*c->ext->ents, low, high, notspawned, pos, invradius, found);
scale--;
- while(c->children && !(diff&(1<<scale)))
- {
+ while(c->children && !(diff&(1<<scale))) {
c = &c->children[octastep(bo.x, bo.y, bo.z, scale)];
if(c->ext && c->ext->ents) findents(*c->ext->ents, low, high, notspawned, pos, invradius, found);
scale--;
if(c->children && 1<<scale >= octaentsize) findents(c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale, bo, br, low, high, notspawned, pos, invradius, found);
}
-char *entname(entity &e)
-{
+char *entname(entity &e) {
static string fullentname;
copystring(fullentname, entities::entname(e.type));
const char *einfo = entities::entnameinfo(e);
- if(*einfo)
- {
+ if(*einfo) {
concatstring(fullentname, ": ");
concatstring(fullentname, einfo);
}
VARF(entediting, 0, 0, 1, { if(!entediting) { entcancel(); efocus = enthover = -1; } });
-bool noentedit()
-{
+bool noentedit() {
if(!editmode) { conoutf(CON_ERROR, "operation only allowed in edit mode"); return true; }
return !entediting;
}
-bool pointinsel(const selinfo &sel, const vec &o)
-{
+bool pointinsel(const selinfo &sel, const vec &o) {
return(o.x <= sel.o.x+sel.s.x*sel.grid
&& o.x >= sel.o.x
&& o.y <= sel.o.y+sel.s.y*sel.grid
vector<int> entgroup;
-bool haveselent()
-{
+bool haveselent() {
return entgroup.length() > 0;
}
-void entcancel()
-{
+void entcancel() {
entgroup.shrink(0);
}
-void entadd(int id)
-{
+void entadd(int id) {
undonext = true;
entgroup.add(id);
}
-undoblock *newundoent()
-{
+undoblock *newundoent() {
int numents = entgroup.length();
if(numents <= 0) return NULL;
undoblock *u = (undoblock *)new uchar[sizeof(undoblock) + numents*sizeof(undoent)];
u->numents = numents;
undoent *e = (undoent *)(u + 1);
- loopv(entgroup)
- {
+ loopv(entgroup) {
e->i = entgroup[i];
e->e = *entities::getents()[entgroup[i]];
e++;
return u;
}
-void makeundoent()
-{
+void makeundoent() {
if(!undonext) return;
undonext = false;
oldhover = enthover;
if(u) addundo(u);
}
-void detachentity(extentity &e)
-{
+void detachentity(extentity &e) {
if(!e.attached) return;
e.attached->attached = NULL;
e.attached = NULL;
VAR(attachradius, 1, 100, 1000);
-void attachentity(extentity &e)
-{
- switch(e.type)
- {
+void attachentity(extentity &e) {
+ switch(e.type) {
case ET_SPOTLIGHT:
break;
-
default:
if(e.type<ET_GAMESPECIFIC || !entities::mayattach(e)) return;
break;
}
-
detachentity(e);
-
vector<extentity *> &ents = entities::getents();
int closest = -1;
float closedist = 1e10f;
- loopv(ents)
- {
+ loopv(ents) {
extentity *a = ents[i];
if(a->attached) continue;
- switch(e.type)
- {
+ switch(e.type) {
case ET_SPOTLIGHT:
if(a->type!=ET_LIGHT) continue;
break;
-
default:
if(e.type<ET_GAMESPECIFIC || !entities::attachent(e, *a)) continue;
break;
}
float dist = e.o.dist(a->o);
- if(dist < closedist)
- {
+ if(dist < closedist) {
closest = i;
closedist = dist;
}
ents[closest]->attached = &e;
}
-void attachentities()
-{
+void attachentities() {
vector<extentity *> &ents = entities::getents();
loopv(ents) attachentity(*ents[i]);
}
#define addimplicit(f) { if(entgroup.empty() && enthover>=0) { entadd(enthover); undonext = (enthover != oldhover); f; entgroup.drop(); } else f; }
#define entfocusv(i, f, v){ int n = efocus = (i); if(n>=0) { extentity &e = *v[n]; f; } }
#define entfocus(i, f) entfocusv(i, f, entities::getents())
-#define enteditv(i, f, v) \
-{ \
- entfocusv(i, \
- { \
+#define enteditv(i, f, v) { \
+ \
+ entfocusv(i, { \
+ \
int oldtype = e.type; \
removeentity(n); \
f; \
}, v); \
}
#define entedit(i, f) enteditv(i, f, entities::getents())
-#define addgroup(exp) { vector<extentity *> &ents = entities::getents(); loopv(ents) entfocusv(i, if(exp) entadd(n), ents); }
-#define setgroup(exp) { entcancel(); addgroup(exp); }
+#define addgroup(exp) { vector<extentity *> &ents = entities::getents(); loopv(ents) entfocusv(i, if(exp) entadd(n), ents); }
+#define setgroup(exp) { entcancel(); addgroup(exp); }
#define groupeditloop(f){ vector<extentity *> &ents = entities::getents(); entlooplevel++; int _ = efocus; loopv(entgroup) enteditv(entgroup[i], f, ents); efocus = _; entlooplevel--; }
#define groupeditpure(f){ if(entlooplevel>0) { entedit(efocus, f); } else groupeditloop(f); }
#define groupeditundo(f){ makeundoent(); groupeditpure(f); }
#define groupedit(f) { addimplicit(groupeditundo(f)); }
-vec getselpos()
-{
+vec getselpos() {
vector<extentity *> &ents = entities::getents();
if(entgroup.length() && ents.inrange(entgroup[0])) return ents[entgroup[0]]->o;
if(ents.inrange(enthover)) return ents[enthover]->o;
return vec(sel.o);
}
-undoblock *copyundoents(undoblock *u)
-{
+undoblock *copyundoents(undoblock *u) {
entcancel();
undoent *e = u->ents();
loopi(u->numents)
return c;
}
-void pasteundoent(int idx, const entity &ue)
-{
+void pasteundoent(int idx, const entity &ue) {
if(idx < 0 || idx >= MAXENTS) return;
vector<extentity *> &ents = entities::getents();
while(ents.length() < idx) ents.add(entities::newentity())->type = ET_EMPTY;
entedit(idx, (entity &)e = ue);
}
-void pasteundoents(undoblock *u)
-{
+void pasteundoents(undoblock *u) {
undoent *ue = u->ents();
loopi(u->numents)
entedit(ue[i].i, (entity &)e = ue[i].e);
}
-void entflip()
-{
+void entflip() {
if(noentedit()) return;
int d = dimension(sel.orient);
float mid = sel.s[d]*sel.grid/2+sel.o[d];
groupeditundo(e.o[d] -= (e.o[d]-mid)*2);
}
-void entrotate(int *cw)
-{
+void entrotate(int *cw) {
if(noentedit()) return;
int d = dimension(sel.orient);
int dd = (*cw<0) == dimcoord(sel.orient) ? R[d] : C[d];
);
}
-void entselectionbox(const entity &e, vec &eo, vec &es)
-{
+void entselectionbox(const entity &e, vec &eo, vec &es) {
model *m = NULL;
const char *mname = entities::entmodel(e);
- if(mname && (m = loadmodel(mname)))
- {
+ if(mname && (m = loadmodel(mname))) {
m->collisionbox(eo, es);
if(es.x > es.y) es.y = es.x; else es.x = es.y; // square
es.z = (es.z + eo.z + 1 + entselradius)/2; // enclose ent radius box and model box
eo.y += e.o.y;
eo.z = e.o.z - entselradius + es.z;
}
- else if(e.type == ET_MAPMODEL && (m = loadmapmodel(e.attr2)))
- {
+ else if(e.type == ET_MAPMODEL && (m = loadmapmodel(e.attr2))) {
mmcollisionbox(e, m, eo, es);
es.max(entselradius);
eo.add(e.o);
}
- else
- {
+ else {
es = vec(entselradius);
eo = e.o;
}
int entmoving = 0;
-void entdrag(const vec &ray)
-{
+void entdrag(const vec &ray) {
if(noentedit() || !haveselent()) return;
-
float r = 0, c = 0;
static vec v, handle;
vec eo, es;
int d = dimension(entorient),
dc= dimcoord(entorient);
-
entfocus(entgroup.last(),
entselectionbox(e, eo, es);
-
if(!editmoveplane(e.o, ray, d, eo[d] + (dc ? es[d] : 0), handle, v, entmoving==1))
return;
-
ivec g(v);
int z = g[d]&(~(sel.grid-1));
g.add(sel.grid/2).mask(~(sel.grid-1));
g[d] = z;
-
r = (entselsnap ? g[R[d]] : v[R[d]]) - e.o[R[d]];
c = (entselsnap ? g[C[d]] : v[C[d]]) - e.o[C[d]];
);
-
if(entmoving==1) makeundoent();
groupeditpure(e.o[R[d]] += r; e.o[C[d]] += c);
entmoving = 2;
VAR(showentradius, 0, 1, 1);
-void renderentring(const extentity &e, float radius, int axis)
-{
+void renderentring(const extentity &e, float radius, int axis) {
if(radius <= 0) return;
gle::defvertex();
gle::begin(GL_LINE_LOOP);
- loopi(15)
- {
+ loopi(15) {
vec p(e.o);
const vec2 &sc = sincos360[i*(360/15)];
p[axis>=2 ? 1 : 0] += radius*sc.x;
xtraverts += gle::end();
}
-void renderentsphere(const extentity &e, float radius)
-{
+void renderentsphere(const extentity &e, float radius) {
if(radius <= 0) return;
loopk(3) renderentring(e, radius, k);
}
-void renderentattachment(const extentity &e)
-{
+void renderentattachment(const extentity &e) {
if(!e.attached) return;
gle::defvertex();
gle::begin(GL_LINES);
xtraverts += gle::end();
}
-void renderentarrow(const extentity &e, const vec &dir, float radius)
-{
+void renderentarrow(const extentity &e, const vec &dir, float radius) {
if(radius <= 0) return;
float arrowsize = min(radius/8, 0.5f);
vec target = vec(dir).mul(radius).add(e.o), arrowbase = vec(dir).mul(radius - arrowsize).add(e.o), spoke;
spoke.orthogonal(dir);
spoke.normalize();
spoke.mul(arrowsize);
-
gle::defvertex();
-
gle::begin(GL_LINES);
gle::attrib(e.o);
gle::attrib(target);
xtraverts += gle::end();
-
gle::begin(GL_TRIANGLE_FAN);
gle::attrib(target);
loopi(5) gle::attrib(vec(spoke).rotate(2*M_PI*i/4.0f, dir).add(arrowbase));
xtraverts += gle::end();
}
-void renderentcone(const extentity &e, const vec &dir, float radius, float angle)
-{
+void renderentcone(const extentity &e, const vec &dir, float radius, float angle) {
if(radius <= 0) return;
vec spot = vec(dir).mul(radius*cosf(angle*RAD)).add(e.o), spoke;
spoke.orthogonal(dir);
spoke.normalize();
spoke.mul(radius*sinf(angle*RAD));
-
gle::defvertex();
-
gle::begin(GL_LINES);
- loopi(8)
- {
+ loopi(8) {
gle::attrib(e.o);
gle::attrib(vec(spoke).rotate(2*M_PI*i/8.0f, dir).add(spot));
}
xtraverts += gle::end();
-
gle::begin(GL_LINE_LOOP);
loopi(8) gle::attrib(vec(spoke).rotate(2*M_PI*i/8.0f, dir).add(spot));
xtraverts += gle::end();
}
-void renderentradius(extentity &e, bool color)
-{
- switch(e.type)
- {
+void renderentradius(extentity &e, bool color) {
+ switch(e.type) {
case ET_LIGHT:
if(color) gle::colorf(e.attr2/255.0f, e.attr3/255.0f, e.attr4/255.0f);
renderentsphere(e, e.attr1);
break;
-
case ET_SPOTLIGHT:
- if(e.attached)
- {
+ if(e.attached) {
if(color) gle::colorf(0, 1, 1);
float radius = e.attached->attr1;
if(!radius) radius = 2*e.o.dist(e.attached->o);
renderentcone(*e.attached, dir, radius, angle);
}
break;
-
case ET_SOUND:
if(color) gle::colorf(0, 1, 1);
renderentsphere(e, e.attr2);
break;
-
case ET_MAPMODEL:
- case ET_PLAYERSTART:
- {
+ case ET_PLAYERSTART: {
if(color) gle::colorf(0, 1, 1);
entities::entradius(e, color);
vec dir;
renderentarrow(e, dir, 4);
break;
}
-
default:
- if(e.type>=ET_GAMESPECIFIC)
- {
+ if(e.type>=ET_GAMESPECIFIC) {
if(color) gle::colorf(0, 1, 1);
entities::entradius(e, color);
}
}
}
-static void renderentbox(const vec &eo, vec es)
-{
+static void renderentbox(const vec &eo, vec es) {
es.add(eo);
-
// bottom quad
gle::attrib(eo.x, eo.y, eo.z); gle::attrib(es.x, eo.y, eo.z);
gle::attrib(es.x, eo.y, eo.z); gle::attrib(es.x, es.y, eo.z);
gle::attrib(es.x, es.y, eo.z); gle::attrib(eo.x, es.y, eo.z);
gle::attrib(eo.x, es.y, eo.z); gle::attrib(eo.x, eo.y, eo.z);
-
// top quad
gle::attrib(eo.x, eo.y, es.z); gle::attrib(es.x, eo.y, es.z);
gle::attrib(es.x, eo.y, es.z); gle::attrib(es.x, es.y, es.z);
gle::attrib(es.x, es.y, es.z); gle::attrib(eo.x, es.y, es.z);
gle::attrib(eo.x, es.y, es.z); gle::attrib(eo.x, eo.y, es.z);
-
// sides
gle::attrib(eo.x, eo.y, eo.z); gle::attrib(eo.x, eo.y, es.z);
gle::attrib(es.x, eo.y, eo.z); gle::attrib(es.x, eo.y, es.z);
gle::attrib(eo.x, es.y, eo.z); gle::attrib(eo.x, es.y, es.z);
}
-void renderentselection(const vec &o, const vec &ray, bool entmoving)
-{
+void renderentselection(const vec &o, bool entmoving) {
if(noentedit()) return;
vec eo, es;
-
- if(entgroup.length())
- {
+ if(entgroup.length()) {
gle::colorub(0, 40, 0);
gle::defvertex();
gle::begin(GL_LINES, entgroup.length()*24);
);
xtraverts += gle::end();
}
-
- if(enthover >= 0)
- {
+ if(enthover >= 0) {
gle::colorub(0, 40, 0);
entfocus(enthover, entselectionbox(e, eo, es)); // also ensures enthover is back in focus
boxs3D(eo, es, 1);
- if(entmoving && entmovingshadow==1)
- {
+ if(entmoving && entmovingshadow==1) {
vec a, b;
gle::colorub(20, 20, 20);
(a = eo).x = eo.x - fmod(eo.x, worldsize); (b = es).x = a.x + worldsize; boxs3D(a, b, 1);
boxs(entorient, eo, es);
boxs(entorient, eo, es, clamp(0.015f*camera1->o.dist(eo)*tan(fovy*0.5f*RAD), 0.1f, 1.0f));
}
-
- if(showentradius && (entgroup.length() || enthover >= 0))
- {
+ if(showentradius && (entgroup.length() || enthover >= 0)) {
glDepthFunc(GL_GREATER);
gle::colorf(0.25f, 0.25f, 0.25f);
loopv(entgroup) entfocus(entgroup[i], renderentradius(e, false));
}
}
-bool enttoggle(int id)
-{
+bool enttoggle(int id) {
undonext = true;
int i = entgroup.find(id);
if(i < 0)
return i < 0;
}
-bool hoveringonent(int ent, int orient)
-{
+bool hoveringonent(int ent, int orient) {
if(noentedit()) return false;
entorient = orient;
if((efocus = enthover = ent) >= 0)
VAR(entitysurf, 0, 0, 1);
-ICOMMAND(entadd, "", (),
-{
- if(enthover >= 0 && !noentedit())
- {
+ICOMMAND(entadd, "", (), {
+ if(enthover >= 0 && !noentedit()) {
if(entgroup.find(enthover) < 0) entadd(enthover);
if(entmoving > 1) entmoving = 1;
}
});
-ICOMMAND(enttoggle, "", (),
-{
+ICOMMAND(enttoggle, "", (), {
if(enthover < 0 || noentedit() || !enttoggle(enthover)) { entmoving = 0; intret(0); }
else { if(entmoving > 1) entmoving = 1; intret(1); }
});
-ICOMMAND(entmoving, "b", (int *n),
-{
- if(*n >= 0)
- {
+ICOMMAND(entmoving, "b", (int *n), {
+ if(*n >= 0) {
if(!*n || enthover < 0 || noentedit()) entmoving = 0;
- else
- {
+ else {
if(entgroup.find(enthover) < 0) { entadd(enthover); entmoving = 1; }
else if(!entmoving) entmoving = 1;
}
intret(entmoving);
});
-void entpush(int *dir)
-{
+void entpush(int *dir) {
if(noentedit()) return;
int d = dimension(entorient);
int s = dimcoord(entorient) ? -*dir : *dir;
- if(entmoving)
- {
+ if(entmoving) {
groupeditpure(e.o[d] += float(s*sel.grid)); // editdrag supplies the undo
}
else
groupedit(e.o[d] += float(s*sel.grid));
- if(entitysurf==1)
- {
+ if(entitysurf==1) {
player->o[d] += float(s*sel.grid);
player->resetinterp();
}
}
VAR(entautoviewdist, 0, 25, 100);
-void entautoview(int *dir)
-{
+void entautoview(int *dir) {
if(!haveselent()) return;
static int s = 0;
vec v(player->o);
COMMAND(entrotate, "i");
COMMAND(entpush, "i");
-void delent()
-{
+void delent() {
if(noentedit()) return;
groupedit(e.type = ET_EMPTY;);
entcancel();
}
-int findtype(char *what)
-{
+int findtype(char *what) {
for(int i = 0; *entities::entname(i); i++) if(strcmp(what, entities::entname(i))==0) return i;
conoutf(CON_ERROR, "unknown entity type \"%s\"", what);
return ET_EMPTY;
VAR(entdrop, 0, 2, 3);
-bool dropentity(entity &e, int drop = -1)
-{
+bool dropentity(entity &e, int drop = -1) {
vec radius(4.0f, 4.0f, 4.0f);
if(drop<0) drop = entdrop;
- if(e.type == ET_MAPMODEL)
- {
+ if(e.type == ET_MAPMODEL) {
model *m = loadmapmodel(e.attr2);
- if(m)
- {
+ if(m) {
vec center;
mmboundbox(e, m, center, radius);
radius.x += fabs(center.x);
}
radius.z = 0.0f;
}
- switch(drop)
- {
+ switch(drop) {
case 1:
if(e.type != ET_LIGHT && e.type != ET_SPOTLIGHT)
dropenttofloor(&e);
case 2:
case 3:
int cx = 0, cy = 0;
- if(sel.cxs == 1 && sel.cys == 1)
- {
+ if(sel.cxs == 1 && sel.cys == 1) {
cx = (sel.cx ? 1 : -1) * sel.grid / 2;
cy = (sel.cy ? 1 : -1) * sel.grid / 2;
}
e.o[D[d]] -= radius[D[d]];
else
e.o[D[d]] += sel.grid + radius[D[d]];
-
if(drop == 3)
dropenttofloor(&e);
break;
return true;
}
-void dropent()
-{
+void dropent() {
if(noentedit()) return;
groupedit(dropentity(e));
}
-void attachent()
-{
+void attachent() {
if(noentedit()) return;
groupedit(attachentity(e));
}
static int keepents = 0;
-extentity *newentity(bool local, const vec &o, int type, int v1, int v2, int v3, int v4, int v5, int &idx)
-{
+extentity *newentity(bool local, const vec &o, int type, int v1, int v2, int v3, int v4, int v5, int &idx) {
vector<extentity *> &ents = entities::getents();
- if(local)
- {
+ if(local) {
idx = -1;
for(int i = keepents; i < ents.length(); i++) if(ents[i]->type == ET_EMPTY) { idx = i; break; }
if(idx < 0 && ents.length() >= MAXENTS) { conoutf(CON_ERROR, "too many entities"); return NULL; }
e.reserved = 0;
e.light.color = vec(1, 1, 1);
e.light.dir = vec(0, 0, 1);
- if(local)
- {
- if(entcamdir) switch(type)
- {
+ if(local) {
+ if(entcamdir) switch(type) {
case ET_MAPMODEL:
case ET_PLAYERSTART:
e.attr5 = e.attr4;
return &e;
}
-void newentity(int type, int a1, int a2, int a3, int a4, int a5)
-{
+void newentity(int type, int a1, int a2, int a3, int a4, int a5) {
int idx;
extentity *t = newentity(true, player->o, type, a1, a2, a3, a4, a5, idx);
if(!t) return;
entedit(idx, e.type = type);
}
-void newent(char *what, int *a1, int *a2, int *a3, int *a4, int *a5)
-{
+void newent(char *what, int *a1, int *a2, int *a3, int *a4, int *a5) {
if(noentedit()) return;
int type = findtype(what);
if(type != ET_EMPTY)
int entcopygrid;
vector<entity> entcopybuf;
-void entcopy()
-{
+void entcopy() {
if(noentedit()) return;
entcopygrid = sel.grid;
entcopybuf.shrink(0);
entfocus(entgroup[i], entcopybuf.add(e).o.sub(vec(sel.o)));
}
-void entpaste()
-{
+void entpaste() {
if(noentedit()) return;
if(entcopybuf.length()==0) return;
entcancel();
float m = float(sel.grid)/float(entcopygrid);
- loopv(entcopybuf)
- {
+ loopv(entcopybuf) {
entity &c = entcopybuf[i];
vec o(c.o);
o.mul(m).add(vec(sel.o));
COMMAND(entcopy, "");
COMMAND(entpaste, "");
-void entset(char *what, int *a1, int *a2, int *a3, int *a4, int *a5)
-{
+void entset(char *what, int *a1, int *a2, int *a3, int *a4, int *a5) {
if(noentedit()) return;
int type = findtype(what);
if(type != ET_EMPTY)
e.attr5=*a5);
}
-void printent(extentity &e, char *buf, int len)
-{
- switch(e.type)
- {
+void printent(extentity &e, char *buf, int len) {
+ switch(e.type) {
case ET_PARTICLES:
if(printparticles(e, buf, len)) return;
break;
-
default:
if(e.type >= ET_GAMESPECIFIC && entities::printent(e, buf, len)) return;
break;
nformatstring(buf, len, "%s %d %d %d %d %d", entities::entname(e.type), e.attr1, e.attr2, e.attr3, e.attr4, e.attr5);
}
-void nearestent()
-{
+void nearestent() {
if(noentedit()) return;
int closest = -1;
float closedist = 1e16f;
vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
if(e.type == ET_EMPTY) continue;
float dist = e.o.dist(player->o);
- if(dist < closedist)
- {
+ if(dist < closedist) {
closest = i;
closedist = dist;
}
COMMAND(entset, "siiiii");
COMMAND(nearestent, "");
-void enttype(char *type, int *numargs)
-{
- if(*numargs >= 1)
- {
+void enttype(char *type, int *numargs) {
+ if(*numargs >= 1) {
int typeidx = findtype(type);
if(typeidx != ET_EMPTY) groupedit(e.type = typeidx);
}
- else entfocus(efocus,
- {
+ else entfocus(efocus, {
result(entities::entname(e.type));
})
}
-void entattr(int *attr, int *val, int *numargs)
-{
- if(*numargs >= 2)
- {
+void entattr(int *attr, int *val, int *numargs) {
+ if(*numargs >= 2) {
if(*attr >= 0 && *attr <= 4)
groupedit(
- switch(*attr)
- {
+ switch(*attr) {
case 0: e.attr1 = *val; break;
case 1: e.attr2 = *val; break;
case 2: e.attr3 = *val; break;
}
);
}
- else entfocus(efocus,
- {
- switch(*attr)
- {
+ else entfocus(efocus, {
+ switch(*attr) {
case 0: intret(e.attr1); break;
case 1: intret(e.attr2); break;
case 2: intret(e.attr3); break;
COMMAND(enttype, "sN");
COMMAND(entattr, "iiN");
-int findentity(int type, int index, int attr1, int attr2)
-{
+int findentity(int type, int index, int attr1, int attr2) {
const vector<extentity *> &ents = entities::getents();
if(index > ents.length()) index = ents.length();
- else for(int i = index; i<ents.length(); i++)
- {
+ else for(int i = index; i<ents.length(); i++) {
extentity &e = *ents[i];
if(e.type==type && (attr1<0 || e.attr1==attr1) && (attr2<0 || e.attr2==attr2))
return i;
}
- loopj(index)
- {
+ loopj(index) {
extentity &e = *ents[j];
if(e.type==type && (attr1<0 || e.attr1==attr1) && (attr2<0 || e.attr2==attr2))
return j;
// Compiles a vector of available playerstarts, each with a non-zero weight
// which serves as a measure of its desirability for a spawning player.
-float gatherspawninfos(dynent *d, int tag, vector<spawninfo> &spawninfos)
-{
+float gatherspawninfos(dynent *d, int tag, vector<spawninfo> &spawninfos) {
const vector<extentity *> &ents = entities::getents();
float total = 0.0f;
- loopv(ents)
- {
+ loopv(ents) {
const extentity &e = *ents[i];
if(e.type != ET_PLAYERSTART || e.attr2 != tag) continue;
spawninfo &s = spawninfos.add();
// Randomly picks a weighted spawn from the provided vector and removes it.
// The probability of a given spawn being picked is proportional to its weight.
// If all weights are zero, the index is picked uniformly.
-static const extentity *poprandomspawn(vector<spawninfo> &spawninfos, float &total)
-{
+static const extentity *poprandomspawn(vector<spawninfo> &spawninfos, float &total) {
if(spawninfos.empty()) return NULL;
int index = 0;
- if(total > 0.0f)
- {
+ if(total > 0.0f) {
float x = rndscale(total);
do x -= spawninfos[index].weight; while(x > 0 && ++index < spawninfos.length()-1);
}
return s.e;
}
-static inline bool tryspawn(dynent *d, const extentity &e)
-{
+static inline bool tryspawn(dynent *d, const extentity &e) {
d->o = e.o;
d->yaw = e.attr1;
return entinmap(d, true);
}
-void findplayerspawn(dynent *d, int forceent, int tag)
-{
+void findplayerspawn(dynent *d, int forceent, int tag) {
const vector<extentity *> &ents = entities::getents();
d->pitch = 0;
d->roll = 0;
entinmap(d);
}
-void splitocta(cube *c, int size)
-{
+void splitocta(cube *c, int size) {
if(size <= 0x1000) return;
- loopi(8)
- {
+ loopi(8) {
if(!c[i].children) c[i].children = newcubes(isempty(c[i]) ? F_EMPTY : F_SOLID);
splitocta(c[i].children, size>>1);
}
}
-void resetmap()
-{
+void resetmap() {
clearoverrides();
clearmapsounds();
resetlightmaps();
cancelsel();
pruneundos();
clearmapcrc();
-
entities::clearents();
outsideents.setsize(0);
}
-void startmap(const char *name)
-{
+void startmap(const char *name) {
game::startmap(name);
}
-bool emptymap(int scale, bool force, const char *mname, bool usecfg) // main empty world creation routine
-{
- if(!force && !editmode)
- {
+bool emptymap(int scale, bool force, const char *mname, bool usecfg) { // main empty world creation routine {
+ if(!force && !editmode) {
conoutf(CON_ERROR, "newmap only allowed in edit mode");
return false;
}
-
resetmap();
-
setvar("mapscale", scale<10 ? 10 : (scale>16 ? 16 : scale), true, false);
setvar("mapsize", 1<<worldscale, true, false);
-
texmru.shrink(0);
freeocta(worldroot);
worldroot = newcubes(F_EMPTY);
loopi(4) solidfaces(worldroot[i]);
-
if(worldsize > 0x1000) splitocta(worldroot, worldsize>>1);
-
clearmainmenu();
-
- if(usecfg)
- {
+ if(usecfg) {
identflags |= IDF_OVERRIDDEN;
execfile("data/default_map.cfg", false);
identflags &= ~IDF_OVERRIDDEN;
}
-
initlights();
allchanged(true);
-
startmap(mname);
-
return true;
}
-bool enlargemap(bool force)
-{
- if(!force && !editmode)
- {
+bool enlargemap(bool force) {
+ if(!force && !editmode) {
conoutf(CON_ERROR, "mapenlarge only allowed in edit mode");
return false;
}
if(worldsize >= 1<<16) return false;
-
while(outsideents.length()) removeentity(outsideents.pop());
-
worldscale++;
worldsize *= 2;
cube *c = newcubes(F_EMPTY);
c[0].children = worldroot;
loopi(3) solidfaces(c[i+1]);
worldroot = c;
-
if(worldsize > 0x1000) splitocta(worldroot, worldsize>>1);
-
allchanged();
-
return true;
}
-static bool isallempty(cube &c)
-{
+static bool isallempty(cube &c) {
if(!c.children) return isempty(c);
loopi(8) if(!isallempty(c.children[i])) return false;
return true;
}
-void shrinkmap()
-{
+void shrinkmap() {
extern int nompedit;
if(noedit(true) || (nompedit && multiplayer())) return;
if(worldsize <= 1<<10) return;
-
int octant = -1;
- loopi(8) if(!isallempty(worldroot[i]))
- {
+ loopi(8) if(!isallempty(worldroot[i])) {
if(octant >= 0) return;
octant = i;
}
if(octant < 0) return;
-
while(outsideents.length()) removeentity(outsideents.pop());
-
if(!worldroot[octant].children) subdividecube(worldroot[octant], false, false);
cube *root = worldroot[octant].children;
worldroot[octant].children = NULL;
worldroot = root;
worldscale--;
worldsize /= 2;
-
ivec offset(octant, ivec(0, 0, 0), worldsize);
vector<extentity *> &ents = entities::getents();
loopv(ents) ents[i]->o.sub(vec(offset));
-
allchanged();
-
conoutf("shrunk map to size %d", worldscale);
}
COMMAND(mapenlarge, "");
COMMAND(shrinkmap, "");
-void mapname()
-{
+void mapname() {
result(game::getclientmap());
}
COMMAND(mapname, "");
-void mpeditent(int i, const vec &o, int type, int attr1, int attr2, int attr3, int attr4, int attr5, bool local)
-{
+void mpeditent(int i, const vec &o, int type, int attr1, int attr2, int attr3, int attr4, int attr5, bool local) {
if(i < 0 || i >= MAXENTS) return;
vector<extentity *> &ents = entities::getents();
- if(ents.length()<=i)
- {
+ if(ents.length()<=i) {
extentity *e = newentity(local, o, type, attr1, attr2, attr3, attr4, attr5, i);
if(!e) return;
addentity(i);
attachentity(*e);
}
- else
- {
+ else {
extentity &e = *ents[i];
removeentity(i);
int oldtype = e.type;
-enum // hardcoded texture numbers
-{
+enum { // hardcoded texture numbers {
DEFAULT_GEOM
};
#define MAPVERSION 34 // bump if map format changes, see worldio.cpp
-struct octaheader
-{
+struct octaheader {
char magic[4]; // "OCTA"
int version; // any >8bit quantity is little endian
int headersize; // sizeof(header)
int numvslots;
};
-enum
-{
+enum {
MATSURF_NOT_VISIBLE = 0,
MATSURF_VISIBLE,
MATSURF_EDIT_ONLY
#define TEX_SCALE 8.0f
struct vertex { vec pos; bvec4 norm; vec2 tc; svec2 lm; bvec4 tangent; };
-
#include "engine.h"
-void validmapname(char *dst, const char *src, const char *prefix = NULL, const char *alt = "untitled", size_t maxlen = 100)
-{
+void validmapname(char *dst, const char *src, const char *prefix = NULL, const char *alt = "untitled", size_t maxlen = 100) {
if(prefix) while(*prefix) *dst++ = *prefix++;
const char *start = dst;
- if(src) loopi(maxlen)
- {
+ if(src) loopi(maxlen) {
char c = *src++;
if(iscubealnum(c) || c == '_' || c == '-' || c == '/' || c == '\\') *dst++ = c;
else break;
else if(dst != alt) copystring(dst, alt, maxlen);
}
-void fixmapname(char *name)
-{
+void fixmapname(char *name) {
validmapname(name, name, NULL, "");
}
-void getmapfilenames(const char *fname, const char *cname, char *pakname, char *mapname, char *cfgname)
-{
+void getmapfilenames(const char *fname, const char *cname, char *pakname, char *mapname, char *cfgname) {
if(!cname) cname = fname;
string name;
validmapname(name, cname);
char *slash = strpbrk(name, "/\\");
- if(slash)
- {
+ if(slash) {
copystring(pakname, name, slash-name+1);
copystring(cfgname, slash+1, MAXSTRLEN);
}
- else
- {
+ else {
copystring(pakname, "maps", MAXSTRLEN);
copystring(cfgname, name, MAXSTRLEN);
}
validmapname(mapname, fname, strpbrk(fname, "/\\") ? NULL : "maps/");
}
-bool loadents(const char *fname, vector<entity> &ents, uint *crc)
-{
+bool loadents(const char *fname, vector<entity> &ents, uint *crc) {
string pakname, mapname, mcfgname, ogzname;
getmapfilenames(fname, NULL, pakname, mapname, mcfgname);
formatstring(ogzname, "packages/%s.ogz", mapname);
lilswap(&hdr.version, 6);
if(memcmp(hdr.magic, "OCTA", 4) || hdr.worldsize <= 0|| hdr.numents < 0) { conoutf(CON_ERROR, "map %s has malformatted header", ogzname); delete f; return false; }
if(hdr.version>MAPVERSION) { conoutf(CON_ERROR, "map %s requires a newer version of Cube 2: Sauerbraten", ogzname); delete f; return false; }
-
lilswap(&hdr.numvslots, 1);
-
- loopi(hdr.numvars)
- {
+ loopi(hdr.numvars) {
int type = f->getchar(), ilen = f->getlil<ushort>();
f->seek(ilen, SEEK_CUR);
- switch(type)
- {
+ switch(type) {
case ID_VAR: f->getlil<int>(); break;
case ID_FVAR: f->getlil<float>(); break;
case ID_SVAR: { int slen = f->getlil<ushort>(); f->seek(slen, SEEK_CUR); break; }
}
}
-
string gametype;
copystring(gametype, "fps");
int eif = 0;
eif = f->getlil<ushort>();
int extrasize = f->getlil<ushort>();
f->seek(extrasize, SEEK_CUR);
-
ushort nummru = f->getlil<ushort>();
f->seek(nummru*sizeof(ushort), SEEK_CUR);
-
- loopi(min(hdr.numents, MAXENTS))
- {
+ loopi(min(hdr.numents, MAXENTS)) {
entity &e = ents.add();
f->read(&e, sizeof(entity));
lilswap(&e.o.x, 3);
lilswap(&e.attr1, 5);
if(eif > 0) f->seek(eif, SEEK_CUR);
- if(e.type>=ET_GAMESPECIFIC)
- {
+ if(e.type>=ET_GAMESPECIFIC) {
ents.pop();
continue;
}
}
-
- if(crc)
- {
+ if(crc) {
f->seek(0, SEEK_END);
*crc = f->getcrc();
}
-
delete f;
-
return true;
}
VARP(savebak, 0, 2, 2);
-void setmapfilenames(const char *fname, const char *cname = NULL)
-{
+void setmapfilenames(const char *fname, const char *cname = NULL) {
string pakname, mapname, mcfgname;
getmapfilenames(fname, cname, pakname, mapname, mcfgname);
-
formatstring(ogzname, "packages/%s.ogz", mapname);
if(savebak==1) formatstring(bakname, "packages/%s.BAK", mapname);
else formatstring(bakname, "packages/%s_%d.BAK", mapname, totalmillis);
formatstring(cfgname, "packages/%s/%s.cfg", pakname, mcfgname);
formatstring(picname, "packages/%s.png", mapname);
-
path(ogzname);
path(bakname);
path(cfgname);
path(picname);
}
-void mapcfgname()
-{
+void mapcfgname() {
const char *mname = game::getclientmap();
string pakname, mapname, mcfgname;
getmapfilenames(mname, NULL, pakname, mapname, mcfgname);
COMMAND(mapcfgname, "");
-void backup(char *name, char *backupname)
-{
+void backup(char *name, char *backupname) {
string backupfile;
copystring(backupfile, findfile(backupname, "wb"));
remove(backupfile);
static int savemapprogress = 0;
-void savec(cube *c, const ivec &o, int size, stream *f, bool nolms)
-{
+void savec(cube *c, const ivec &o, int size, stream *f, bool nolms) {
if((savemapprogress++&0xFFF)==0) renderprogress(float(savemapprogress)/allocnodes, "saving octree...");
-
- loopi(8)
- {
+ loopi(8) {
ivec co(i, o, size);
- if(c[i].children)
- {
+ if(c[i].children) {
f->putchar(OCTSAV_CHILDREN);
savec(c[i].children, co, size>>1, f, nolms);
}
- else
- {
+ else {
int oflags = 0, surfmask = 0, totalverts = 0;
if(c[i].material!=MAT_AIR) oflags |= 0x40;
if(isempty(c[i])) f->putchar(oflags | OCTSAV_EMPTY);
- else
- {
- if(!nolms)
- {
+ else {
+ if(!nolms) {
if(c[i].merged) oflags |= 0x80;
- if(c[i].ext) loopj(6)
- {
+ if(c[i].ext) loopj(6) {
const surfaceinfo &surf = c[i].ext->surfaces[j];
if(!surf.used()) continue;
oflags |= 0x20;
totalverts += surf.totalverts();
}
}
-
if(isentirelysolid(c[i])) f->putchar(oflags | OCTSAV_SOLID);
- else
- {
+ else {
f->putchar(oflags | OCTSAV_NORMAL);
f->write(c[i].edges, 12);
}
}
-
loopj(6) f->putlil<ushort>(c[i].texture[j]);
-
if(oflags&0x40) f->putlil<ushort>(c[i].material);
if(oflags&0x80) f->putchar(c[i].merged);
- if(oflags&0x20)
- {
+ if(oflags&0x20) {
f->putchar(surfmask);
f->putchar(totalverts);
- loopj(6) if(surfmask&(1<<j))
- {
+ loopj(6) if(surfmask&(1<<j)) {
surfaceinfo surf = c[i].ext->surfaces[j];
vertinfo *verts = c[i].ext->verts() + surf.verts;
int layerverts = surf.numverts&MAXFACEVERTS, numverts = surf.totalverts(),
vertmask = 0, vertorder = 0, uvorder = 0,
dim = dimension(j), vc = C[dim], vr = R[dim];
- if(numverts)
- {
- if(c[i].merged&(1<<j))
- {
+ if(numverts) {
+ if(c[i].merged&(1<<j)) {
vertmask |= 0x04;
if(layerverts == 4)
{
}
}
}
- else
- {
+ else {
int vis = visibletris(c[i], j, co, size);
if(vis&4 || faceconvexity(c[i], j) < 0) vertmask |= 0x01;
if(layerverts < 4 && vis&2) vertmask |= 0x02;
}
bool matchnorm = true;
- loopk(numverts)
- {
+ loopk(numverts) {
const vertinfo &v = verts[k];
if(v.u || v.v) vertmask |= 0x40;
if(v.norm) { vertmask |= 0x80; if(v.norm != verts[0].norm) matchnorm = false; }
}
if(matchnorm) vertmask |= 0x08;
- if(vertmask&0x40 && layerverts == 4)
- {
+ if(vertmask&0x40 && layerverts == 4) {
loopk(4)
{
const vertinfo &v0 = verts[k], &v1 = verts[(k+1)&3], &v2 = verts[(k+2)&3], &v3 = verts[(k+3)&3];
surf.verts = vertmask;
f->write(&surf, sizeof(surfaceinfo));
bool hasxyz = (vertmask&0x04)!=0, hasuv = (vertmask&0x40)!=0, hasnorm = (vertmask&0x80)!=0;
- if(layerverts == 4)
- {
- if(hasxyz && vertmask&0x01)
- {
+ if(layerverts == 4) {
+ if(hasxyz && vertmask&0x01) {
ivec v0 = verts[vertorder].getxyz(), v2 = verts[(vertorder+2)&3].getxyz();
f->putlil<ushort>(v0[vc]); f->putlil<ushort>(v0[vr]);
f->putlil<ushort>(v2[vc]); f->putlil<ushort>(v2[vr]);
hasxyz = false;
}
- if(hasuv && vertmask&0x02)
- {
+ if(hasuv && vertmask&0x02) {
const vertinfo &v0 = verts[uvorder], &v2 = verts[(uvorder+2)&3];
f->putlil<ushort>(v0.u); f->putlil<ushort>(v0.v);
f->putlil<ushort>(v2.u); f->putlil<ushort>(v2.v);
}
}
if(hasnorm && vertmask&0x08) { f->putlil<ushort>(verts[0].norm); hasnorm = false; }
- if(hasxyz || hasuv || hasnorm) loopk(layerverts)
- {
+ if(hasxyz || hasuv || hasnorm) loopk(layerverts) {
const vertinfo &v = verts[(k+vertorder)%layerverts];
- if(hasxyz)
- {
+ if(hasxyz) {
ivec xyz = v.getxyz();
f->putlil<ushort>(xyz[vc]); f->putlil<ushort>(xyz[vr]);
}
if(hasuv) { f->putlil<ushort>(v.u); f->putlil<ushort>(v.v); }
if(hasnorm) f->putlil<ushort>(v.norm);
}
- if(surf.numverts&LAYER_DUP) loopk(layerverts)
- {
+ if(surf.numverts&LAYER_DUP) loopk(layerverts) {
const vertinfo &v = verts[layerverts + (k+vertorder)%layerverts];
if(hasuv) { f->putlil<ushort>(v.u); f->putlil<ushort>(v.v); }
}
}
}
-struct surfacecompat
-{
+struct surfacecompat {
uchar texcoords[8];
uchar w, h;
ushort x, y;
uchar lmid, layer;
};
-struct normalscompat
-{
+struct normalscompat {
bvec normals[4];
};
-struct mergecompat
-{
+struct mergecompat {
ushort u1, u2, v1, v2;
};
cube *loadchildren(stream *f, const ivec &co, int size, bool &failed);
-void loadc(stream *f, cube &c, const ivec &co, int size, bool &failed)
-{
+void loadc(stream *f, cube &c, const ivec &co, int size, bool &failed) {
bool haschildren = false;
int octsav = f->getchar();
- switch(octsav&0x7)
- {
+ switch(octsav&0x7) {
case OCTSAV_CHILDREN:
c.children = loadchildren(f, co, size>>1, failed);
return;
-
case OCTSAV_LODCUBE: haschildren = true; break;
case OCTSAV_EMPTY: emptyfaces(c); break;
case OCTSAV_SOLID: solidfaces(c); break;
default: failed = true; return;
}
loopi(6) c.texture[i] = mapversion<14 ? f->getchar() : f->getlil<ushort>();
-
- {
+ {
if(octsav&0x40) c.material = f->getlil<ushort>();
if(octsav&0x80) c.merged = f->getchar();
- if(octsav&0x20)
- {
+ if(octsav&0x20) {
int surfmask, totalverts;
surfmask = f->getchar();
totalverts = max(f->getchar(), 0);
memset(c.ext->surfaces, 0, sizeof(c.ext->surfaces));
memset(c.ext->verts(), 0, totalverts*sizeof(vertinfo));
int offset = 0;
- loopi(6) if(surfmask&(1<<i))
- {
+ loopi(6) if(surfmask&(1<<i)) {
surfaceinfo &surf = c.ext->surfaces[i];
f->read(&surf, sizeof(surfaceinfo));
int vertmask = surf.verts, numverts = surf.totalverts();
int layerverts = surf.numverts&MAXFACEVERTS, dim = dimension(i), vc = C[dim], vr = R[dim], bias = 0;
genfaceverts(c, i, v);
bool hasxyz = (vertmask&0x04)!=0, hasuv = (vertmask&0x40)!=0, hasnorm = (vertmask&0x80)!=0;
- if(hasxyz)
- {
+ if(hasxyz) {
ivec e1, e2, e3;
n.cross((e1 = v[1]).sub(v[0]), (e2 = v[2]).sub(v[0]));
if(n.iszero()) n.cross(e2, (e3 = v[3]).sub(v[0]));
bias = -n.dot(ivec(v[0]).mul(size).add(vo));
}
- else
- {
+ else {
int vis = layerverts < 4 ? (vertmask&0x02 ? 2 : 1) : 3, order = vertmask&0x01 ? 1 : 0, k = 0;
verts[k++].setxyz(v[order].mul(size).add(vo));
if(vis&1) verts[k++].setxyz(v[order+1].mul(size).add(vo));
verts[k++].setxyz(v[order+2].mul(size).add(vo));
if(vis&2) verts[k++].setxyz(v[(order+3)&3].mul(size).add(vo));
}
- if(layerverts == 4)
- {
- if(hasxyz && vertmask&0x01)
- {
+ if(layerverts == 4) {
+ if(hasxyz && vertmask&0x01) {
ushort c1 = f->getlil<ushort>(), r1 = f->getlil<ushort>(), c2 = f->getlil<ushort>(), r2 = f->getlil<ushort>();
ivec xyz;
xyz[vc] = c1; xyz[vr] = r1; xyz[dim] = n[dim] ? -(bias + n[vc]*xyz[vc] + n[vr]*xyz[vr])/n[dim] : vo[dim];
verts[3].setxyz(xyz);
hasxyz = false;
}
- if(hasuv && vertmask&0x02)
- {
+ if(hasuv && vertmask&0x02) {
int uvorder = (vertmask&0x30)>>4;
vertinfo &v0 = verts[uvorder], &v1 = verts[(uvorder+1)&3], &v2 = verts[(uvorder+2)&3], &v3 = verts[(uvorder+3)&3];
v0.u = f->getlil<ushort>(); v0.v = f->getlil<ushort>();
v2.u = f->getlil<ushort>(); v2.v = f->getlil<ushort>();
v1.u = v0.u; v1.v = v2.v;
v3.u = v2.u; v3.v = v0.v;
- if(surf.numverts&LAYER_DUP)
- {
+ if(surf.numverts&LAYER_DUP) {
vertinfo &b0 = verts[4+uvorder], &b1 = verts[4+((uvorder+1)&3)], &b2 = verts[4+((uvorder+2)&3)], &b3 = verts[4+((uvorder+3)&3)];
b0.u = f->getlil<ushort>(); b0.v = f->getlil<ushort>();
b2.u = f->getlil<ushort>(); b2.v = f->getlil<ushort>();
hasuv = false;
}
}
- if(hasnorm && vertmask&0x08)
- {
+ if(hasnorm && vertmask&0x08) {
ushort norm = f->getlil<ushort>();
loopk(layerverts) verts[k].norm = norm;
hasnorm = false;
}
- if(hasxyz || hasuv || hasnorm) loopk(layerverts)
- {
+ if(hasxyz || hasuv || hasnorm) loopk(layerverts) {
vertinfo &v = verts[k];
- if(hasxyz)
- {
+ if(hasxyz) {
ivec xyz;
xyz[vc] = f->getlil<ushort>(); xyz[vr] = f->getlil<ushort>();
xyz[dim] = n[dim] ? -(bias + n[vc]*xyz[vc] + n[vr]*xyz[vr])/n[dim] : vo[dim];
if(hasuv) { v.u = f->getlil<ushort>(); v.v = f->getlil<ushort>(); }
if(hasnorm) v.norm = f->getlil<ushort>();
}
- if(surf.numverts&LAYER_DUP) loopk(layerverts)
- {
+ if(surf.numverts&LAYER_DUP) loopk(layerverts) {
vertinfo &v = verts[k+layerverts], &t = verts[k];
v.setxyz(t.x, t.y, t.z);
if(hasuv) { v.u = f->getlil<ushort>(); v.v = f->getlil<ushort>(); }
}
}
}
-
c.children = (haschildren ? loadchildren(f, co, size>>1, failed) : NULL);
}
-cube *loadchildren(stream *f, const ivec &co, int size, bool &failed)
-{
+cube *loadchildren(stream *f, const ivec &co, int size, bool &failed) {
cube *c = newcubes();
- loopi(8)
- {
+ loopi(8) {
loadc(f, c[i], ivec(i, co, size), size, failed);
if(failed) break;
}
return c;
}
-void savevslot(stream *f, VSlot &vs, int prev)
-{
+void savevslot(stream *f, VSlot &vs, int prev) {
f->putlil<int>(vs.changed);
f->putlil<int>(prev);
- if(vs.changed & (1<<VSLOT_SHPARAM))
- {
+ if(vs.changed & (1<<VSLOT_SHPARAM)) {
f->putlil<ushort>(vs.params.length());
- loopv(vs.params)
- {
+ loopv(vs.params) {
SlotShaderParam &p = vs.params[i];
f->putlil<ushort>(strlen(p.name));
f->write(p.name, strlen(p.name));
}
if(vs.changed & (1<<VSLOT_SCALE)) f->putlil<float>(vs.scale);
if(vs.changed & (1<<VSLOT_ROTATION)) f->putlil<int>(vs.rotation);
- if(vs.changed & (1<<VSLOT_OFFSET))
- {
+ if(vs.changed & (1<<VSLOT_OFFSET)) {
f->putlil<int>(vs.offset.x);
f->putlil<int>(vs.offset.y);
}
- if(vs.changed & (1<<VSLOT_SCROLL))
- {
+ if(vs.changed & (1<<VSLOT_SCROLL)) {
f->putlil<float>(vs.scroll.x);
f->putlil<float>(vs.scroll.y);
}
if(vs.changed & (1<<VSLOT_LAYER)) f->putlil<int>(vs.layer);
- if(vs.changed & (1<<VSLOT_ALPHA))
- {
+ if(vs.changed & (1<<VSLOT_ALPHA)) {
f->putlil<float>(vs.alphafront);
f->putlil<float>(vs.alphaback);
}
- if(vs.changed & (1<<VSLOT_COLOR))
- {
+ if(vs.changed & (1<<VSLOT_COLOR)) {
loopk(3) f->putlil<float>(vs.colorscale[k]);
}
}
-void savevslots(stream *f, int numvslots)
-{
+void savevslots(stream *f, int numvslots) {
if(vslots.empty()) return;
int *prev = new int[numvslots];
for(int i=0;i<numvslots;++i)prev[i]=-1;
- loopi(numvslots)
- {
+ loopi(numvslots) {
VSlot *vs = vslots[i];
if(vs->changed) continue;
- for(;;)
- {
+ for(;;) {
VSlot *cur = vs;
do vs = vs->next; while(vs && vs->index >= numvslots);
if(!vs) break;
}
}
int lastroot = 0;
- loopi(numvslots)
- {
+ loopi(numvslots) {
VSlot &vs = *vslots[i];
if(!vs.changed) continue;
if(lastroot < i) f->putlil<int>(-(i - lastroot));
delete[] prev;
}
-void loadvslot(stream *f, VSlot &vs, int changed)
-{
+void loadvslot(stream *f, VSlot &vs, int changed) {
vs.changed = changed;
- if(vs.changed & (1<<VSLOT_SHPARAM))
- {
+ if(vs.changed & (1<<VSLOT_SHPARAM)) {
int numparams = f->getlil<ushort>();
string name;
- loopi(numparams)
- {
+ loopi(numparams) {
SlotShaderParam &p = vs.params.add();
int nlen = f->getlil<ushort>();
f->read(name, min(nlen, MAXSTRLEN-1));
}
if(vs.changed & (1<<VSLOT_SCALE)) vs.scale = f->getlil<float>();
if(vs.changed & (1<<VSLOT_ROTATION)) vs.rotation = clamp(f->getlil<int>(), 0, 7);
- if(vs.changed & (1<<VSLOT_OFFSET))
- {
+ if(vs.changed & (1<<VSLOT_OFFSET)) {
vs.offset.x = f->getlil<int>();
vs.offset.y = f->getlil<int>();
}
- if(vs.changed & (1<<VSLOT_SCROLL))
- {
+ if(vs.changed & (1<<VSLOT_SCROLL)) {
vs.scroll.x = f->getlil<float>();
vs.scroll.y = f->getlil<float>();
}
if(vs.changed & (1<<VSLOT_LAYER)) vs.layer = f->getlil<int>();
- if(vs.changed & (1<<VSLOT_ALPHA))
- {
+ if(vs.changed & (1<<VSLOT_ALPHA)) {
vs.alphafront = f->getlil<float>();
vs.alphaback = f->getlil<float>();
}
- if(vs.changed & (1<<VSLOT_COLOR))
- {
+ if(vs.changed & (1<<VSLOT_COLOR)) {
loopk(3) vs.colorscale[k] = f->getlil<float>();
}
}
-void loadvslots(stream *f, int numvslots)
-{
+void loadvslots(stream *f, int numvslots) {
int *prev = new (false) int[numvslots];
if(!prev) return;
for(int i=0;i<numvslots;++i)prev[i]=-1;
- while(numvslots > 0)
- {
+ while(numvslots > 0) {
int changed = f->getlil<int>();
- if(changed < 0)
- {
+ if(changed < 0) {
loopi(-changed) vslots.add(new VSlot(NULL, vslots.length()));
numvslots += changed;
}
- else
- {
+ else {
prev[vslots.length()] = f->getlil<int>();
loadvslot(f, *vslots.add(new VSlot(NULL, vslots.length())), changed);
numvslots--;
delete[] prev;
}
-bool save_world(const char *mname, bool nolms)
-{
+bool save_world(const char *mname, bool nolms) {
if(!*mname) mname = game::getclientmap();
setmapfilenames(mname);
if(savebak) backup(ogzname, bakname);
stream *f = opengzfile(ogzname, "wb");
if(!f) { conoutf(CON_WARN, "could not write map to %s", ogzname); return false; }
-
int numvslots = vslots.length();
- if(!nolms && !multiplayer(false))
- {
+ if(!nolms && !multiplayer(false)) {
numvslots = compactvslots();
allchanged();
}
-
savemapprogress = 0;
renderprogress(0, "saving map...");
-
octaheader hdr;
memcpy(hdr.magic, "OCTA", 4);
hdr.version = MAPVERSION;
hdr.lightmaps = nolms ? 0 : lightmaps.length();
hdr.numvars = 0;
hdr.numvslots = numvslots;
- enumerate(idents, ident, id,
- {
+ enumerate(idents, ident, id, {
if((id.type == ID_VAR || id.type == ID_FVAR || id.type == ID_SVAR) && id.flags&IDF_OVERRIDE && !(id.flags&IDF_READONLY) && id.flags&IDF_OVERRIDDEN) hdr.numvars++;
});
lilswap(&hdr.version, 9);
f->write(&hdr, sizeof(hdr));
-
- enumerate(idents, ident, id,
- {
+ enumerate(idents, ident, id, {
if((id.type!=ID_VAR && id.type!=ID_FVAR && id.type!=ID_SVAR) || !(id.flags&IDF_OVERRIDE) || id.flags&IDF_READONLY || !(id.flags&IDF_OVERRIDDEN)) continue;
f->putchar(id.type);
f->putlil<ushort>(strlen(id.name));
f->write(id.name, strlen(id.name));
- switch(id.type)
- {
+ switch(id.type) {
case ID_VAR:
f->putlil<int>(*id.storage.i);
break;
-
case ID_FVAR:
f->putlil<float>(*id.storage.f);
break;
-
case ID_SVAR:
f->putlil<ushort>(strlen(*id.storage.s));
f->write(*id.storage.s, strlen(*id.storage.s));
break;
}
});
-
f->putchar((int)strlen(game::gameident()));
f->write(game::gameident(), (int)strlen(game::gameident())+1);
f->putlil<ushort>(entities::extraentinfosize());
game::writegamedata(extras);
f->putlil<ushort>(extras.length());
f->write(extras.getbuf(), extras.length());
-
f->putlil<ushort>(texmru.length());
loopv(texmru) f->putlil<ushort>(texmru[i]);
char *ebuf = new char[entities::extraentinfosize()];
- loopv(ents)
- {
- if(ents[i]->type!=ET_EMPTY || nolms)
- {
+ loopv(ents) {
+ if(ents[i]->type!=ET_EMPTY || nolms) {
entity tmp = *ents[i];
lilswap(&tmp.o.x, 3);
lilswap(&tmp.attr1, 5);
}
}
delete[] ebuf;
-
savevslots(f, numvslots);
-
renderprogress(0, "saving octree...");
savec(worldroot, ivec(0, 0, 0), worldsize>>1, f, nolms);
-
- if(!nolms)
- {
+ if(!nolms) {
if(lightmaps.length()) renderprogress(0, "saving lightmaps...");
- loopv(lightmaps)
- {
+ loopv(lightmaps) {
LightMap &lm = lightmaps[i];
f->putchar(lm.type | (lm.unlitx>=0 ? 0x80 : 0));
- if(lm.unlitx>=0)
- {
+ if(lm.unlitx>=0) {
f->putlil<ushort>(ushort(lm.unlitx));
f->putlil<ushort>(ushort(lm.unlity));
}
renderprogress(float(i+1)/lightmaps.length(), "saving lightmaps...");
}
}
-
delete f;
conoutf("wrote map file %s", ogzname);
return true;
uint getmapcrc() { return mapcrc; }
void clearmapcrc() { mapcrc = 0; }
-bool load_world(const char *mname, const char *cname) // still supports all map formats that have existed since the earliest cube betas!
-{
+bool load_world(const char *mname, const char *cname) { // still supports all map formats that have existed since the earliest cube betas! {
int loadingstart = SDL_GetTicks();
setmapfilenames(mname, cname);
stream *f = opengzfile(ogzname, "rb");
lilswap(&hdr.version, 6);
if(memcmp(hdr.magic, "OCTA", 4) || hdr.worldsize <= 0|| hdr.numents < 0) { conoutf(CON_ERROR, "map %s has malformatted header", ogzname); delete f; return false; }
if(hdr.version>MAPVERSION) { conoutf(CON_ERROR, "map %s requires a newer version of Cube 2: Sauerbraten", ogzname); delete f; return false; }
-
resetmap();
-
Texture *mapshot = textureload(picname, 3, true, false);
renderbackground("loading...", mapshot, mname, game::getmapinfo());
-
game::loadingmap(cname ? cname : mname);
-
setvar("mapversion", hdr.version, true, false);
-
lilswap(&hdr.numvslots, 1);
-
renderprogress(0, "clearing world...");
-
freeocta(worldroot);
worldroot = NULL;
-
int worldscale = 0;
while(1<<worldscale < hdr.worldsize) worldscale++;
setvar("mapsize", 1<<worldscale, true, false);
setvar("mapscale", worldscale, true, false);
-
renderprogress(0, "loading vars...");
-
- loopi(hdr.numvars)
- {
+ loopi(hdr.numvars) {
int type = f->getchar(), ilen = f->getlil<ushort>();
string name;
f->read(name, min(ilen, MAXSTRLEN-1));
if(ilen >= MAXSTRLEN) f->seek(ilen - (MAXSTRLEN-1), SEEK_CUR);
ident *id = getident(name);
bool exists = id && id->type == type && id->flags&IDF_OVERRIDE;
- switch(type)
- {
- case ID_VAR:
- {
+ switch(type) {
+ case ID_VAR: {
int val = f->getlil<int>();
if(exists && id->minval <= id->maxval) setvar(name, val);
break;
}
-
- case ID_FVAR:
- {
+ case ID_FVAR: {
float val = f->getlil<float>();
if(exists && id->minvalf <= id->maxvalf) setfvar(name, val);
break;
}
-
- case ID_SVAR:
- {
+ case ID_SVAR: {
int slen = f->getlil<ushort>();
string val;
f->read(val, min(slen, MAXSTRLEN-1));
}
}
}
-
string gametype;
copystring(gametype, "fps");
- int eif = 0;
int len = f->getchar();
f->read(gametype, len+1);
- eif = f->getlil<ushort>();
int extrasize = f->getlil<ushort>();
vector<char> extras;
f->read(extras.pad(extrasize), extrasize);
game::readgamedata(extras);
-
texmru.shrink(0);
ushort nummru = f->getlil<ushort>();
loopi(nummru) texmru.add(f->getlil<ushort>());
-
renderprogress(0, "loading entities...");
-
vector<extentity *> &ents = entities::getents();
int einfosize = entities::extraentinfosize();
char *ebuf = einfosize > 0 ? new char[einfosize] : NULL;
- loopi(min(hdr.numents, MAXENTS))
- {
+ loopi(min(hdr.numents, MAXENTS)) {
extentity &e = *entities::newentity();
ents.add(&e);
f->read(&e, sizeof(entity));
lilswap(&e.o.x, 3);
lilswap(&e.attr1, 5);
if(einfosize > 0) f->read(ebuf, einfosize);
- if(!insideworld(e.o))
- {
- if(e.type != ET_LIGHT && e.type != ET_SPOTLIGHT)
- {
+ if(!insideworld(e.o)) {
+ if(e.type != ET_LIGHT && e.type != ET_SPOTLIGHT) {
conoutf(CON_WARN, "warning: ent outside of world: enttype[%s] index %d (%f, %f, %f)", entities::entname(e.type), i, e.o.x, e.o.y, e.o.z);
}
}
}
if(ebuf) delete[] ebuf;
-
- if(hdr.numents > MAXENTS)
- {
+ if(hdr.numents > MAXENTS) {
conoutf(CON_WARN, "warning: map has %d entities", hdr.numents);
f->seek((hdr.numents-MAXENTS)*(sizeof(entity) + einfosize), SEEK_CUR);
}
-
renderprogress(0, "loading slots...");
loadvslots(f, hdr.numvslots);
-
renderprogress(0, "loading octree...");
bool failed = false;
worldroot = loadchildren(f, ivec(0, 0, 0), hdr.worldsize>>1, failed);
if(failed) conoutf(CON_ERROR, "garbage in map");
-
renderprogress(0, "validating...");
validatec(worldroot, hdr.worldsize>>1);
-
- if(!failed)
- {
- loopi(hdr.lightmaps)
- {
+ if(!failed) {
+ loopi(hdr.lightmaps) {
renderprogress(i/(float)hdr.lightmaps, "loading lightmaps...");
- LightMap &lm = lightmaps.add();
- {
+ LightMap &lm = lightmaps.add(); {
int type = f->getchar();
lm.type = type&0x7F;
- if(type&0x80)
- {
+ if(type&0x80) {
lm.unlitx = f->getlil<ushort>();
lm.unlity = f->getlil<ushort>();
}
lm.finalize();
}
}
-
mapcrc = f->getcrc();
delete f;
-
conoutf("read map %s (%.1f seconds)", ogzname, (SDL_GetTicks()-loadingstart)/1000.0f);
-
clearmainmenu();
-
identflags |= IDF_OVERRIDDEN;
execfile("data/default_map.cfg", false);
execfile(cfgname, false);
identflags &= ~IDF_OVERRIDDEN;
-
preloadusedmapmodels(true);
-
game::preload();
flushpreloadedmodels();
-
preloadmapsounds();
-
entitiesinoctanodes();
attachentities();
initlights();
allchanged(true);
-
renderbackground("loading...", mapshot, mname, game::getmapinfo());
-
if(maptitle[0] && strcmp(maptitle, "Untitled Map by Unknown")) conoutf(CON_ECHO, "%s", maptitle);
-
startmap(cname ? cname : mname);
-
return true;
}
#include "game.h"
-namespace ai
-{
+namespace ai {
using namespace game;
-
avoidset obstacles;
int updatemillis = 0, iteration = 0, itermillis = 0, forcegun = -1;
vec aitarget(0, 0, 0);
-
VAR(aidebug, 0, 0, 6);
VAR(aiforcegun, -1, -1, NUMGUNS-1);
-
ICOMMAND(addbot, "s", (char *s), addmsg(N_ADDBOT, "ri", *s ? clamp(parseint(s), 1, 101) : -1));
ICOMMAND(delbot, "", (), addmsg(N_DELBOT, "r"));
ICOMMAND(botlimit, "i", (int *n), addmsg(N_BOTLIMIT, "ri", *n));
ICOMMAND(botbalance, "i", (int *n), addmsg(N_BOTBALANCE, "ri", *n));
-
- float viewdist(int x)
- {
+ float viewdist(int x) {
return x <= 100 ? clamp((SIGHTMIN+(SIGHTMAX-SIGHTMIN))/100.f*float(x), float(SIGHTMIN), 10000.0f) : 10000.0f;
}
-
- float viewfieldx(int x)
- {
+ float viewfieldx(int x) {
return x <= 100 ? clamp((VIEWMIN+(VIEWMAX-VIEWMIN))/100.f*float(x), float(VIEWMIN), float(VIEWMAX)) : float(VIEWMAX);
}
-
- float viewfieldy(int x)
- {
+ float viewfieldy(int x) {
return viewfieldx(x)*3.f/4.f;
}
-
- bool canmove(fpsent *d)
- {
+ bool canmove(fpsent *d) {
return d->state != CS_DEAD && !intermission;
}
-
- float weapmindist(int weap)
- {
+ float weapmindist(int weap) {
return max(int(guns[weap].exprad), 2);
}
-
- float weapmaxdist(int weap)
- {
+ float weapmaxdist(int weap) {
return guns[weap].range + 4;
}
-
- bool weaprange(fpsent *d, int weap, float dist)
- {
+ bool weaprange(fpsent *d, int weap, float dist) {
float mindist = weapmindist(weap), maxdist = weapmaxdist(weap);
return dist >= mindist*mindist && dist <= maxdist*maxdist;
}
-
- bool targetable(fpsent *d, fpsent *e)
- {
+ bool targetable(fpsent *d, fpsent *e) {
if(d == e || !canmove(d)) return false;
return e->state == CS_ALIVE && !isteam(d->team, e->team);
}
-
- bool getsight(vec &o, float yaw, float pitch, vec &q, vec &v, float mdist, float fovx, float fovy)
- {
+ bool getsight(vec &o, float yaw, float pitch, vec &q, vec &v, float mdist, float fovx, float fovy) {
float dist = o.dist(q);
-
- if(dist <= mdist)
- {
+ if(dist <= mdist) {
float x = fmod(fabs(asin((q.z-o.z)/dist)/RAD-pitch), 360);
float y = fmod(fabs(-atan2(q.x-o.x, q.y-o.y)/RAD-yaw), 360);
if(min(x, 360-x) <= fovx && min(y, 360-y) <= fovy) return raycubelos(o, q, v);
}
return false;
}
-
- bool cansee(fpsent *d, vec &x, vec &y, vec &targ)
- {
+ bool cansee(fpsent *d, vec &x, vec &y, vec &targ) {
aistate &b = d->ai->getstate();
if(canmove(d) && b.type != AI_S_WAIT)
return getsight(x, d->yaw, d->pitch, y, targ, d->ai->views[2], d->ai->views[0], d->ai->views[1]);
return false;
}
-
- bool canshoot(fpsent *d, fpsent *e)
- {
+ bool canshoot(fpsent *d, fpsent *e) {
if(weaprange(d, d->gunselect, e->o.squaredist(d->o)) && targetable(d, e))
return d->ammo[d->gunselect] > 0 && lastmillis - d->lastaction >= d->gunwait;
return false;
}
-
- bool canshoot(fpsent *d)
- {
+ bool canshoot(fpsent *d) {
return !d->ai->becareful && d->ammo[d->gunselect] > 0 && lastmillis - d->lastaction >= d->gunwait;
}
-
- bool hastarget(fpsent *d, aistate &b, fpsent *e, float yaw, float pitch, float dist)
- { // add margins of error
- if(weaprange(d, d->gunselect, dist) || (d->skill <= 100 && !rnd(d->skill)))
- {
+ bool hastarget(fpsent *d, aistate &b, fpsent *e, float yaw, float pitch, float dist) {
+ // add margins of error
+ if(weaprange(d, d->gunselect, dist) || (d->skill <= 100 && !rnd(d->skill))) {
if(d->gunselect == GUN_FIST) return true;
float skew = clamp(float(lastmillis-d->ai->enemymillis)/float((d->skill*guns[d->gunselect].attackdelay/200.f)), 0.f, guns[d->gunselect].projspeed ? 0.25f : 1e16f),
offy = yaw-d->yaw, offp = pitch-d->pitch;
}
return false;
}
-
- vec getaimpos(fpsent *d, fpsent *e)
- {
+ vec getaimpos(fpsent *d, fpsent *e) {
vec o = e->o;
if(d->gunselect == GUN_RL) o.z += (e->aboveeye*0.2f)-(0.8f*d->eyeheight);
else if(d->gunselect != GUN_GL) o.z += (e->aboveeye-e->eyeheight)*0.5f;
- if(d->skill <= 100)
- {
- if(lastmillis >= d->ai->lastaimrnd)
- {
+ if(d->skill <= 100) {
+ if(lastmillis >= d->ai->lastaimrnd) {
const int aiskew[NUMGUNS] = { 1, 10, 50, 5, 20, 1, 100 };
#define rndaioffset(r) ((rnd(int(r*aiskew[d->gunselect]*2)+1)-(r*aiskew[d->gunselect]))*(1.f/float(max(d->skill, 1))))
loopk(3) d->ai->aimrnd[k] = rndaioffset(e->radius);
}
return o;
}
-
- void create(fpsent *d)
- {
+ void create(fpsent *d) {
if(!d->ai) d->ai = new aiinfo;
}
-
- void destroy(fpsent *d)
- {
+ void destroy(fpsent *d) {
if(d->ai) DELETEP(d->ai);
}
-
- void init(fpsent *d, int at, int ocn, int sk, int bn, int pm, const char *name, const char *team)
- {
+ void init(fpsent *d, int at, int ocn, int sk, int bn, int pm, const char *name, const char *team) {
loadwaypoints();
-
fpsent *o = newclient(ocn);
-
d->aitype = at;
-
bool resetthisguy = false;
- if(!d->name[0])
- {
+ if(!d->name[0]) {
if(aidebug) conoutf(CON_DEBUG, "%s assigned to %s at skill %d", colorname(d, name), o ? colorname(o) : "?", sk);
else conoutf("\f0join:\f7 %s", colorname(d, name));
resetthisguy = true;
}
- else
- {
- if(d->ownernum != ocn)
- {
+ else {
+ if(d->ownernum != ocn) {
if(aidebug) conoutf(CON_DEBUG, "%s reassigned to %s", colorname(d, name), o ? colorname(o) : "?");
resetthisguy = true;
}
if(d->skill != sk && aidebug) conoutf(CON_DEBUG, "%s changed skill to %d", colorname(d, name), sk);
}
-
copystring(d->name, name, MAXNAMELEN+1);
copystring(d->team, team, MAXTEAMLEN+1);
d->ownernum = ocn;
d->plag = 0;
d->skill = sk;
d->playermodel = 0;
-
if(resetthisguy) removeweapons(d);
- if(d->ownernum >= 0 && player1->clientnum == d->ownernum)
- {
+ if(d->ownernum >= 0 && player1->clientnum == d->ownernum) {
create(d);
- if(d->ai)
- {
+ if(d->ai) {
d->ai->views[0] = viewfieldx(d->skill);
d->ai->views[1] = viewfieldy(d->skill);
d->ai->views[2] = viewdist(d->skill);
}
else if(d->ai) destroy(d);
}
-
- void update()
- {
+ void update() {
if(intermission) { loopv(players) if(players[i]->ai) players[i]->stopmoving(); }
- else // fixed rate logic done out-of-sequence at 1 frame per second for each ai
- {
- if(totalmillis-updatemillis > 1000)
- {
+ else { // fixed rate logic done out-of-sequence at 1 frame per second for each ai {
+ if(totalmillis-updatemillis > 1000) {
avoid();
forcegun = multiplayer(false) ? -1 : aiforcegun;
updatemillis = totalmillis;
}
- if(!iteration && totalmillis-itermillis > 1000)
- {
+ if(!iteration && totalmillis-itermillis > 1000) {
iteration = 1;
itermillis = totalmillis;
}
if(++iteration > count) iteration = 0;
}
}
-
- bool checkothers(vector<int> &targets, fpsent *d, int state, int targtype, int target, bool teams, int *members)
- { // checks the states of other ai for a match
+ bool checkothers(vector<int> &targets, fpsent *d, int state, int targtype, int target, bool teams, int *members) {
+ // checks the states of other ai for a match
targets.setsize(0);
- loopv(players)
- {
+ loopv(players) {
fpsent *e = players[i];
if(targets.find(e->clientnum) >= 0) continue;
if(teams && d && !isteam(d->team, e->team)) continue;
}
return !targets.empty();
}
-
- bool makeroute(fpsent *d, aistate &b, int node, bool changed, int retries)
- {
+ bool makeroute(fpsent *d, aistate &b, int node, bool changed, int retries) {
if(!iswaypoint(d->lastnode)) return false;
if(changed && d->ai->route.length() > 1 && d->ai->route[0] == node) return true;
- if(route(d, d->lastnode, node, d->ai->route, obstacles, retries))
- {
+ if(route(d, d->lastnode, node, d->ai->route, obstacles, retries)) {
b.override = false;
return true;
}
if(retries <= 1) return makeroute(d, b, node, false, retries+1);
return false;
}
-
- bool makeroute(fpsent *d, aistate &b, const vec &pos, bool changed, int retries)
- {
+ bool makeroute(fpsent *d, aistate &b, const vec &pos, bool changed, int retries) {
int node = closestwaypoint(pos, SIGHTMIN, true);
return makeroute(d, b, node, changed, retries);
}
-
- bool randomnode(fpsent *d, aistate &b, const vec &pos, float guard, float wander)
- {
+ bool randomnode(fpsent *d, aistate &b, const vec &pos, float guard, float wander) {
static vector<int> candidates;
candidates.setsize(0);
findwaypointswithin(pos, guard, wander, candidates);
-
- while(!candidates.empty())
- {
+ while(!candidates.empty()) {
int w = rnd(candidates.length()), n = candidates.removeunordered(w);
if(n != d->lastnode && !d->ai->hasprevnode(n) && !obstacles.find(n, d) && makeroute(d, b, n)) return true;
}
return false;
}
-
- bool randomnode(fpsent *d, aistate &b, float guard, float wander)
- {
+ bool randomnode(fpsent *d, aistate &b, float guard, float wander) {
return randomnode(d, b, d->feetpos(), guard, wander);
}
-
- bool badhealth(fpsent *d)
- {
+ bool badhealth(fpsent *d) {
if(d->skill <= 100) return d->health <= (111-d->skill)/4;
return false;
}
-
- bool enemy(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, int pursue = 0)
- {
+ bool enemy(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, int pursue = 0) {
fpsent *t = NULL;
vec dp = d->headpos();
float mindist = guard*guard, bestdist = 1e16f;
- loopv(players)
- {
+ loopv(players) {
fpsent *e = players[i];
if(e == d || !targetable(d, e)) continue;
vec ep = getaimpos(d, e);
float dist = ep.squaredist(dp);
- if(dist < bestdist && (cansee(d, dp, ep) || dist <= mindist))
- {
+ if(dist < bestdist && (cansee(d, dp, ep) || dist <= mindist)) {
t = e;
bestdist = dist;
}
if(t && violence(d, b, t, pursue)) return true;
return false;
}
-
- bool patrol(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk, bool retry)
- {
+ bool patrol(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk, bool retry) {
vec feet = d->feetpos();
- if(walk == 2 || b.override || (walk && feet.squaredist(pos) <= guard*guard) || !makeroute(d, b, pos))
- { // run away and back to keep ourselves busy
- if(!b.override && randomnode(d, b, pos, guard, wander))
- {
+ if(walk == 2 || b.override || (walk && feet.squaredist(pos) <= guard*guard) || !makeroute(d, b, pos)) {
+ // run away and back to keep ourselves busy
+ if(!b.override && randomnode(d, b, pos, guard, wander)) {
b.override = true;
return true;
}
- else if(d->ai->route.empty())
- {
- if(!retry)
- {
+ else if(d->ai->route.empty()) {
+ if(!retry) {
b.override = false;
return patrol(d, b, pos, guard, wander, walk, true);
}
b.override = false;
return true;
}
-
- bool defend(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk)
- {
+ bool defend(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk) {
bool hasenemy = enemy(d, b, pos, wander, d->gunselect == GUN_FIST ? 1 : 0);
- if(!walk)
- {
- if(d->feetpos().squaredist(pos) <= guard*guard)
- {
+ if(!walk) {
+ if(d->feetpos().squaredist(pos) <= guard*guard) {
b.idle = hasenemy ? 2 : 1;
return true;
}
}
return patrol(d, b, pos, guard, wander, walk);
}
-
- bool violence(fpsent *d, aistate &b, fpsent *e, int pursue)
- {
- if(e && targetable(d, e))
- {
- if(pursue)
- {
+ bool violence(fpsent *d, aistate &b, fpsent *e, int pursue) {
+ if(e && targetable(d, e)) {
+ if(pursue) {
if((b.targtype != AI_T_AFFINITY || !(pursue%2)) && makeroute(d, b, e->lastnode))
d->ai->switchstate(b, AI_S_PURSUE, AI_T_PLAYER, e->clientnum);
else if(pursue >= 3) return false; // can't pursue
}
- if(d->ai->enemy != e->clientnum)
- {
+ if(d->ai->enemy != e->clientnum) {
d->ai->enemyseen = d->ai->enemymillis = lastmillis;
d->ai->enemy = e->clientnum;
}
}
return false;
}
-
- bool target(fpsent *d, aistate &b, int pursue = 0, bool force = false, float mindist = 0.f)
- {
+ bool target(fpsent *d, aistate &b, int pursue = 0, bool force = false, float mindist = 0.f) {
static vector<fpsent *> hastried; hastried.setsize(0);
vec dp = d->headpos();
- while(true)
- {
+ while(true) {
float dist = 1e16f;
fpsent *t = NULL;
- loopv(players)
- {
+ loopv(players) {
fpsent *e = players[i];
if(e == d || hastried.find(e) >= 0 || !targetable(d, e)) continue;
vec ep = getaimpos(d, e);
float v = ep.squaredist(dp);
- if((!t || v < dist) && (mindist <= 0 || v <= mindist) && (force || cansee(d, dp, ep)))
- {
+ if((!t || v < dist) && (mindist <= 0 || v <= mindist) && (force || cansee(d, dp, ep))) {
t = e;
dist = v;
}
}
- if(t)
- {
+ if(t) {
if(violence(d, b, t, pursue)) return true;
hastried.add(t);
}
}
return false;
}
-
int isgoodammo(int gun) { return gun >= GUN_SG && gun <= GUN_GL; }
-
- bool hasgoodammo(fpsent *d)
- {
+ bool hasgoodammo(fpsent *d) {
static const int goodguns[] = { GUN_CG, GUN_RL, GUN_SG, GUN_RIFLE };
loopi(sizeof(goodguns)/sizeof(goodguns[0])) if(d->hasammo(goodguns[0])) return true;
if(d->ammo[GUN_GL] > 5) return true;
return false;
}
-
- void assist(fpsent *d, aistate &b, vector<interest> &interests, bool all, bool force)
- {
- loopv(players)
- {
+ void assist(fpsent *d, aistate &b, vector<interest> &interests, bool all, bool force) {
+ loopv(players) {
fpsent *e = players[i];
if(e == d || (!all && e->aitype != AI_NONE) || !isteam(d->team, e->team)) continue;
interest &n = interests.add();
n.score = e->o.squaredist(d->o)/(hasgoodammo(d) ? 1e8f : (force ? 1e4f : 1e2f));
}
}
-
- static void tryitem(fpsent *d, extentity &e, int id, aistate &b, vector<interest> &interests, bool force = false)
- {
+ static void tryitem(fpsent *d, extentity &e, int id, aistate &b, vector<interest> &interests, bool force = false) {
float score = 0;
- switch(e.type)
- {
+ switch(e.type) {
case I_HEALTH:
if(d->health < min(d->skill, 75)) score = 1e3f;
break;
case I_QUAD: score = 1e3f; break;
case I_BOOST: score = 1e2f; break;
- case I_GREENARMOUR: case I_YELLOWARMOUR:
- {
+ case I_GREENARMOUR: case I_YELLOWARMOUR: {
int atype = A_GREEN + e.type - I_GREENARMOUR;
if(atype > d->armourtype) score = atype == A_YELLOW ? 1e2f : 1e1f;
else if(d->armour < 50) score = 1e1f;
break;
}
- default:
- {
- if(e.type >= I_SHELLS && e.type <= I_CARTRIDGES && !d->hasmaxammo(e.type))
- {
+ default: {
+ if(e.type >= I_SHELLS && e.type <= I_CARTRIDGES && !d->hasmaxammo(e.type)) {
int gun = e.type - I_SHELLS + GUN_SG;
// go get a weapon upgrade
if(gun == d->ai->weappref) score = 1e8f;
break;
}
}
- if(score != 0)
- {
+ if(score != 0) {
interest &n = interests.add();
n.state = AI_S_INTEREST;
n.node = closestwaypoint(e.o, SIGHTMIN, true);
n.score = d->feetpos().squaredist(e.o)/(force ? -1 : score);
}
}
-
- void items(fpsent *d, aistate &b, vector<interest> &interests, bool force = false)
- {
- loopv(entities::ents)
- {
+ void items(fpsent *d, aistate &b, vector<interest> &interests, bool force = false) {
+ loopv(entities::ents) {
extentity &e = *(extentity *)entities::ents[i];
if(!e.spawned() || e.nopickup() || !d->canpickup(e.type)) continue;
tryitem(d, e, i, b, interests, force);
}
}
-
static vector<int> targets;
-
- bool parseinterests(fpsent *d, aistate &b, vector<interest> &interests, bool override, bool ignore)
- {
- while(!interests.empty())
- {
+ bool parseinterests(fpsent *d, aistate &b, vector<interest> &interests, bool override, bool ignore) {
+ while(!interests.empty()) {
int q = interests.length()-1;
loopi(interests.length()-1) if(interests[i].score < interests[q].score) q = i;
interest n = interests.removeunordered(q);
bool proceed = true;
- if(!ignore) switch(n.state)
- {
- case AI_S_DEFEND: // don't get into herds
- {
+ if(!ignore) switch(n.state) {
+ case AI_S_DEFEND: { // don't get into herds {
int members = 0;
proceed = !checkothers(targets, d, n.state, n.targtype, n.target, true, &members) && members > 1;
break;
}
default: break;
}
- if(proceed && makeroute(d, b, n.node))
- {
+ if(proceed && makeroute(d, b, n.node)) {
d->ai->switchstate(b, n.state, n.targtype, n.target);
return true;
}
}
return false;
}
-
- bool find(fpsent *d, aistate &b, bool override = false)
- {
+ bool find(fpsent *d, aistate &b, bool override = false) {
static vector<interest> interests;
interests.setsize(0);
- if(!m_noitems)
- {
+ if(!m_noitems) {
if((!m_noammo && !hasgoodammo(d)) || d->health < min(d->skill - 15, 75))
items(d, b, interests);
- else
- {
+ else {
static vector<int> nearby;
nearby.setsize(0);
findents(I_SHELLS, I_QUAD, false, d->feetpos(), vec(32, 32, 24), nearby);
- loopv(nearby)
- {
+ loopv(nearby) {
int id = nearby[i];
extentity &e = *(extentity *)entities::ents[id];
if(d->canpickup(e.type)) tryitem(d, e, id, b, interests);
if(m_teammode) assist(d, b, interests);
return parseinterests(d, b, interests, override);
}
-
- bool findassist(fpsent *d, aistate &b, bool override = false)
- {
+ bool findassist(fpsent *d, aistate &b, bool override = false) {
static vector<interest> interests;
interests.setsize(0);
assist(d, b, interests);
- while(!interests.empty())
- {
+ while(!interests.empty()) {
int q = interests.length()-1;
loopi(interests.length()-1) if(interests[i].score < interests[q].score) q = i;
interest n = interests.removeunordered(q);
bool proceed = true;
- switch(n.state)
- {
- case AI_S_DEFEND: // don't get into herds
- {
+ switch(n.state) {
+ case AI_S_DEFEND: { // don't get into herds {
int members = 0;
proceed = !checkothers(targets, d, n.state, n.targtype, n.target, true, &members) && members > 1;
break;
}
default: break;
}
- if(proceed && makeroute(d, b, n.node))
- {
+ if(proceed && makeroute(d, b, n.node)) {
d->ai->switchstate(b, n.state, n.targtype, n.target);
return true;
}
}
return false;
}
-
- void damaged(fpsent *d, fpsent *e)
- {
- if(d->ai && canmove(d) && targetable(d, e)) // see if this ai is interested in a grudge
- {
+ void damaged(fpsent *d, fpsent *e) {
+ if(d->ai && canmove(d) && targetable(d, e)) { // see if this ai is interested in a grudge {
aistate &b = d->ai->getstate();
if(violence(d, b, e, d->gunselect == GUN_FIST ? 1 : 0)) return;
}
- if(checkothers(targets, d, AI_S_DEFEND, AI_T_PLAYER, d->clientnum, true))
- {
- loopv(targets)
- {
+ if(checkothers(targets, d, AI_S_DEFEND, AI_T_PLAYER, d->clientnum, true)) {
+ loopv(targets) {
fpsent *t = getclient(targets[i]);
if(!t->ai || !canmove(t) || !targetable(t, e)) continue;
aistate &c = t->ai->getstate();
}
}
}
-
- void findorientation(vec &o, float yaw, float pitch, vec &pos)
- {
+ void findorientation(vec &o, float yaw, float pitch, vec &pos) {
vec dir;
vecfromyawpitch(yaw, pitch, 1, 0, dir);
if(raycubepos(o, dir, pos, 0, RAY_CLIPMAT|RAY_SKIPFIRST) == -1)
pos = dir.mul(2*getworldsize()).add(o);
}
-
- void setup(fpsent *d)
- {
+ void setup(fpsent *d) {
d->ai->clearsetup();
d->ai->reset(true);
d->ai->lastrun = lastmillis;
if(m_insta) d->ai->weappref = GUN_RIFLE;
- else
- {
+ else {
if(forcegun >= 0 && forcegun < NUMGUNS) d->ai->weappref = forcegun;
else if(m_noammo) d->ai->weappref = -1;
else d->ai->weappref = rnd(GUN_GL-GUN_SG+1)+GUN_SG;
vec dp = d->headpos();
findorientation(dp, d->yaw, d->pitch, d->ai->target);
}
-
- void spawned(fpsent *d)
- {
+ void spawned(fpsent *d) {
if(d->ai) setup(d);
}
-
- void killed(fpsent *d, fpsent *e)
- {
+ void killed(fpsent *d, fpsent *e) {
if(d->ai) d->ai->reset();
}
-
- void itemspawned(int ent)
- {
- if(entities::ents.inrange(ent) && entities::ents[ent]->type >= I_SHELLS && entities::ents[ent]->type <= I_QUAD)
- {
- loopv(players) if(players[i] && players[i]->ai && players[i]->aitype == AI_BOT && players[i]->canpickup(entities::ents[ent]->type))
- {
+ void itemspawned(int ent) {
+ if(entities::ents.inrange(ent) && entities::ents[ent]->type >= I_SHELLS && entities::ents[ent]->type <= I_QUAD) {
+ loopv(players) if(players[i] && players[i]->ai && players[i]->aitype == AI_BOT && players[i]->canpickup(entities::ents[ent]->type)) {
fpsent *d = players[i];
bool wantsitem = false;
- switch(entities::ents[ent]->type)
- {
+ switch(entities::ents[ent]->type) {
case I_BOOST:
-
case I_HEALTH: wantsitem = badhealth(d); break;
case I_GREENARMOUR:
-
case I_YELLOWARMOUR:
-
case I_QUAD: break;
- default:
- {
+ default: {
itemstat &is = itemstats[entities::ents[ent]->type-I_SHELLS];
wantsitem = isgoodammo(is.info) && d->ammo[is.info] <= (d->ai->weappref == is.info ? is.add : is.add/2);
break;
}
}
- if(wantsitem)
- {
+ if(wantsitem) {
aistate &b = d->ai->getstate();
if(b.targtype == AI_T_AFFINITY) continue;
- if(b.type == AI_S_INTEREST && b.targtype == AI_T_ENTITY)
- {
- if(entities::ents.inrange(b.target))
- {
+ if(b.type == AI_S_INTEREST && b.targtype == AI_T_ENTITY) {
+ if(entities::ents.inrange(b.target)) {
if(d->o.squaredist(entities::ents[ent]->o) < d->o.squaredist(entities::ents[b.target]->o))
d->ai->switchstate(b, AI_S_INTEREST, AI_T_ENTITY, ent);
}
}
}
}
-
- int dowait(fpsent *d, aistate &b)
- {
+ int dowait(fpsent *d, aistate &b) {
d->ai->clear(true); // ensure they're clean
if(find(d, b)) return 1;
if(target(d, b, 4, false)) return 1;
if(target(d, b, 4, true)) return 1;
- if(randomnode(d, b, SIGHTMIN, 1e16f))
- {
+ if(randomnode(d, b, SIGHTMIN, 1e16f)) {
d->ai->switchstate(b, AI_S_INTEREST, AI_T_NODE, d->ai->route[0]);
return 1;
}
return 0; // but don't pop the state
}
-
- int dodefend(fpsent *d, aistate &b)
- {
- if(d->state == CS_ALIVE)
- {
- switch(b.targtype)
- {
+ int dodefend(fpsent *d, aistate &b) {
+ if(d->state == CS_ALIVE) {
+ switch(b.targtype) {
case AI_T_NODE:
if(iswaypoint(b.target)) return defend(d, b, waypoints[b.target].o) ? 1 : 0;
break;
case AI_T_ENTITY:
if(entities::ents.inrange(b.target)) return defend(d, b, entities::ents[b.target]->o) ? 1 : 0;
break;
- case AI_T_PLAYER:
- {
+ case AI_T_PLAYER: {
fpsent *e = getclient(b.target);
if(e && e->state == CS_ALIVE) return defend(d, b, e->feetpos()) ? 1 : 0;
break;
}
return 0;
}
-
- int dointerest(fpsent *d, aistate &b)
- {
+ int dointerest(fpsent *d, aistate &b) {
if(d->state != CS_ALIVE) return 0;
- switch(b.targtype)
- {
+ switch(b.targtype) {
case AI_T_NODE: // this is like a wait state without sitting still..
if(find(d, b)) return 1;
if(target(d, b, 4, true)) return 1;
return makeroute(d, b, waypoints[b.target].o) ? 1 : 0;
break;
case AI_T_ENTITY:
- if(entities::ents.inrange(b.target))
- {
+ if(entities::ents.inrange(b.target)) {
extentity &e = *(extentity *)entities::ents[b.target];
if(!e.spawned() || e.nopickup() || e.type < I_SHELLS || e.type > I_CARTRIDGES || d->hasmaxammo(e.type)) return 0;
//if(d->feetpos().squaredist(e.o) <= CLOSEDIST*CLOSEDIST)
}
return 0;
}
-
- int dopursue(fpsent *d, aistate &b)
- {
- if(d->state == CS_ALIVE)
- {
- switch(b.targtype)
- {
- case AI_T_NODE:
- {
+ int dopursue(fpsent *d, aistate &b) {
+ if(d->state == CS_ALIVE) {
+ switch(b.targtype) {
+ case AI_T_NODE: {
if(iswaypoint(b.target))
return defend(d, b, waypoints[b.target].o) ? 1 : 0;
break;
}
-
- case AI_T_PLAYER:
- {
+ case AI_T_PLAYER: {
fpsent *e = getclient(b.target);
- if(e && e->state == CS_ALIVE)
- {
+ if(e && e->state == CS_ALIVE) {
float guard = SIGHTMIN, wander = guns[d->gunselect].range;
if(d->gunselect == GUN_FIST) guard = 0.f;
return patrol(d, b, e->feetpos(), guard, wander) ? 1 : 0;
}
return 0;
}
-
- int closenode(fpsent *d)
- {
+ int closenode(fpsent *d) {
vec pos = d->feetpos();
int node1 = -1, node2 = -1;
float mindist1 = CLOSEDIST*CLOSEDIST, mindist2 = CLOSEDIST*CLOSEDIST;
- loopv(d->ai->route) if(iswaypoint(d->ai->route[i]))
- {
+ loopv(d->ai->route) if(iswaypoint(d->ai->route[i])) {
vec epos = waypoints[d->ai->route[i]].o;
float dist = epos.squaredist(pos);
if(dist > FARDIST*FARDIST) continue;
int entid = obstacles.remap(d, d->ai->route[i], epos);
- if(entid >= 0)
- {
+ if(entid >= 0) {
if(entid != i) dist = epos.squaredist(pos);
if(dist < mindist1) { node1 = i; mindist1 = dist; }
}
}
return node1 >= 0 ? node1 : node2;
}
-
- int wpspot(fpsent *d, int n, bool check = false)
- {
- if(iswaypoint(n)) loopk(2)
- {
+ int wpspot(fpsent *d, int n, bool check = false) {
+ if(iswaypoint(n)) loopk(2) {
vec epos = waypoints[n].o;
int entid = obstacles.remap(d, n, epos, k!=0);
- if(iswaypoint(entid))
- {
+ if(iswaypoint(entid)) {
d->ai->spot = epos;
d->ai->targnode = entid;
return !check || d->feetpos().squaredist(epos) > MINWPDIST*MINWPDIST ? 1 : 2;
}
return 0;
}
-
- int randomlink(fpsent *d, int n)
- {
- if(iswaypoint(n) && waypoints[n].haslinks())
- {
+ int randomlink(fpsent *d, int n) {
+ if(iswaypoint(n) && waypoints[n].haslinks()) {
waypoint &w = waypoints[n];
static vector<int> linkmap; linkmap.setsize(0);
- loopi(MAXWAYPOINTLINKS)
- {
+ loopi(MAXWAYPOINTLINKS) {
if(!w.links[i]) break;
if(iswaypoint(w.links[i]) && !d->ai->hasprevnode(w.links[i]) && d->ai->route.find(w.links[i]) < 0)
linkmap.add(w.links[i]);
}
return -1;
}
-
- bool anynode(fpsent *d, aistate &b, int len = NUMPREVNODES)
- {
- if(iswaypoint(d->lastnode)) loopk(2)
- {
+ bool anynode(fpsent *d, aistate &b, int len = NUMPREVNODES) {
+ if(iswaypoint(d->lastnode)) loopk(2) {
d->ai->clear(k ? true : false);
int n = randomlink(d, d->lastnode);
- if(wpspot(d, n))
- {
+ if(wpspot(d, n)) {
d->ai->route.add(n);
d->ai->route.add(d->lastnode);
- loopi(len)
- {
+ loopi(len) {
n = randomlink(d, n);
if(iswaypoint(n)) d->ai->route.insert(0, n);
else break;
}
return false;
}
-
- bool checkroute(fpsent *d, int n)
- {
+ bool checkroute(fpsent *d, int n) {
if(d->ai->route.empty() || !d->ai->route.inrange(n)) return false;
int last = d->ai->lastcheck ? lastmillis-d->ai->lastcheck : 0;
if(last < 500 || n < 3) return false; // route length is too short
d->ai->lastcheck = lastmillis;
int w = iswaypoint(d->lastnode) ? d->lastnode : d->ai->route[n], c = min(n-1, NUMPREVNODES);
- loopj(c) // check ahead to see if we need to go around something
- {
+ loopj(c) { // check ahead to see if we need to go around something {
int p = n-j-1, v = d->ai->route[p];
- if(d->ai->hasprevnode(v) || obstacles.find(v, d)) // something is in the way, try to remap around it
- {
+ if(d->ai->hasprevnode(v) || obstacles.find(v, d)) { // something is in the way, try to remap around it {
int m = p-1;
if(m < 3) return false; // route length is too short from this point
- loopirev(m)
- {
+ loopirev(m) {
int t = d->ai->route[i];
- if(!d->ai->hasprevnode(t) && !obstacles.find(t, d))
- {
+ if(!d->ai->hasprevnode(t) && !obstacles.find(t, d)) {
static vector<int> remap; remap.setsize(0);
- if(route(d, w, t, remap, obstacles))
- { // kill what we don't want and put the remap in
+ if(route(d, w, t, remap, obstacles)) {
+ // kill what we don't want and put the remap in
while(d->ai->route.length() > i) d->ai->route.pop();
loopvk(remap) d->ai->route.add(remap[k]);
return true;
}
return false;
}
-
- bool hunt(fpsent *d, aistate &b)
- {
- if(!d->ai->route.empty())
- {
+ bool hunt(fpsent *d, aistate &b) {
+ if(!d->ai->route.empty()) {
int n = closenode(d);
if(d->ai->route.inrange(n) && checkroute(d, n)) n = closenode(d);
- if(d->ai->route.inrange(n))
- {
- if(!n)
- {
- switch(wpspot(d, d->ai->route[n], true))
- {
+ if(d->ai->route.inrange(n)) {
+ if(!n) {
+ switch(wpspot(d, d->ai->route[n], true)) {
case 2: d->ai->clear(false);
[[fallthrough]];
-
case 1: return true; // not close enough to pop it yet
default: break;
}
}
- else
- {
+ else {
while(d->ai->route.length() > n+1) d->ai->route.pop(); // waka-waka-waka-waka
int m = n-1; // next, please!
if(d->ai->route.inrange(m) && wpspot(d, d->ai->route[m])) return true;
b.override = false;
return anynode(d, b);
}
-
- void jumpto(fpsent *d, aistate &b, const vec &pos)
- {
+ void jumpto(fpsent *d, aistate &b, const vec &pos) {
vec off = vec(pos).sub(d->feetpos()), dir(off.x, off.y, 0);
bool sequenced = d->ai->blockseq || d->ai->targseq, offground = d->timeinair && !d->inwater,
jump = !offground && lastmillis >= d->ai->jumpseed && (sequenced || off.z >= JUMPMIN || lastmillis >= d->ai->jumprand);
- if(jump)
- {
+ if(jump) {
vec old = d->o;
d->o = vec(pos).add(vec(0, 0, d->eyeheight));
if(collide(d, vec(0, 0, 1))) jump = false;
d->o = old;
- if(jump)
- {
+ if(jump) {
float radius = 18*18;
- loopv(entities::ents) if(entities::ents[i]->type == JUMPPAD)
- {
+ loopv(entities::ents) if(entities::ents[i]->type == JUMPPAD) {
extentity &e = *(extentity *)entities::ents[i];
if(e.o.squaredist(pos) <= radius) { jump = false; break; }
}
}
}
- if(jump)
- {
+ if(jump) {
d->jumping = true;
int seed = (111-d->skill)*(d->inwater ? 3 : 5);
d->ai->jumpseed = lastmillis+seed+rnd(seed);
d->ai->jumprand = lastmillis+seed+rnd(seed);
}
}
-
- void fixfullrange(float &yaw, float &pitch, float &roll, bool full)
- {
- if(full)
- {
+ void fixfullrange(float &yaw, float &pitch, float &roll, bool full) {
+ if(full) {
while(pitch < -180.0f) pitch += 360.0f;
while(pitch >= 180.0f) pitch -= 360.0f;
while(roll < -180.0f) roll += 360.0f;
while(roll >= 180.0f) roll -= 360.0f;
}
- else
- {
+ else {
if(pitch > 89.9f) pitch = 89.9f;
if(pitch < -89.9f) pitch = -89.9f;
if(roll > 89.9f) roll = 89.9f;
while(yaw < 0.0f) yaw += 360.0f;
while(yaw >= 360.0f) yaw -= 360.0f;
}
-
- void fixrange(float &yaw, float &pitch)
- {
+ void fixrange(float &yaw, float &pitch) {
float r = 0.f;
fixfullrange(yaw, pitch, r, false);
}
-
- void getyawpitch(const vec &from, const vec &pos, float &yaw, float &pitch)
- {
+ void getyawpitch(const vec &from, const vec &pos, float &yaw, float &pitch) {
float dist = from.dist(pos);
yaw = -atan2(pos.x-from.x, pos.y-from.y)/RAD;
pitch = asin((pos.z-from.z)/dist)/RAD;
}
-
- void scaleyawpitch(float &yaw, float &pitch, float targyaw, float targpitch, float frame, float scale)
- {
+ void scaleyawpitch(float &yaw, float &pitch, float targyaw, float targpitch, float frame, float scale) {
if(yaw < targyaw-180.0f) yaw += 360.0f;
if(yaw > targyaw+180.0f) yaw -= 360.0f;
float offyaw = fabs(targyaw-yaw)*frame, offpitch = fabs(targpitch-pitch)*frame*scale;
- if(targyaw > yaw)
- {
+ if(targyaw > yaw) {
yaw += offyaw;
if(targyaw < yaw) yaw = targyaw;
}
- else if(targyaw < yaw)
- {
+ else if(targyaw < yaw) {
yaw -= offyaw;
if(targyaw > yaw) yaw = targyaw;
}
- if(targpitch > pitch)
- {
+ if(targpitch > pitch) {
pitch += offpitch;
if(targpitch < pitch) pitch = targpitch;
}
- else if(targpitch < pitch)
- {
+ else if(targpitch < pitch) {
pitch -= offpitch;
if(targpitch > pitch) pitch = targpitch;
}
fixrange(yaw, pitch);
}
-
- bool lockon(fpsent *d, fpsent *e, float maxdist)
- {
- if(d->gunselect == GUN_FIST && !d->blocked && !d->timeinair)
- {
+ bool lockon(fpsent *d, fpsent *e, float maxdist) {
+ if(d->gunselect == GUN_FIST && !d->blocked && !d->timeinair) {
vec dir = vec(e->o).sub(d->o);
float xydist = dir.x*dir.x+dir.y*dir.y, zdist = dir.z*dir.z, mdist = maxdist*maxdist, ddist = d->radius*d->radius+e->radius*e->radius;
if(zdist <= ddist && xydist >= ddist+4 && xydist <= mdist+ddist) return true;
}
return false;
}
-
- int process(fpsent *d, aistate &b)
- {
+ int process(fpsent *d, aistate &b) {
int result = 0, stupify = d->skill <= 10+rnd(15) ? rnd(d->skill*1000) : 0, skmod = 101-d->skill;
float frame = d->skill <= 100 ? float(lastmillis-d->ai->lastrun)/float(max(skmod,1)*10) : 1;
vec dp = d->headpos();
-
bool idle = b.idle == 1 || (stupify && stupify <= skmod);
d->ai->dontmove = false;
- if(idle)
- {
+ if(idle) {
d->ai->lastaction = d->ai->lasthunt = lastmillis;
d->ai->dontmove = true;
d->ai->spot = vec(0, 0, 0);
}
- else if(hunt(d, b))
- {
+ else if(hunt(d, b)) {
getyawpitch(dp, vec(d->ai->spot).add(vec(0, 0, d->eyeheight)), d->ai->targyaw, d->ai->targpitch);
d->ai->lasthunt = lastmillis;
}
- else
- {
+ else {
idle = d->ai->dontmove = true;
d->ai->spot = vec(0, 0, 0);
}
-
if(!d->ai->dontmove) jumpto(d, b, d->ai->spot);
-
fpsent *e = getclient(d->ai->enemy);
bool enemyok = e && targetable(d, e);
- if(!enemyok || d->skill >= 50)
- {
+ if(!enemyok || d->skill >= 50) {
fpsent *f = (fpsent *)intersectclosest(dp, d->ai->target, d);
- if(f)
- {
- if(targetable(d, f))
- {
+ if(f) {
+ if(targetable(d, f)) {
if(!enemyok) violence(d, b, f, d->gunselect == GUN_FIST ? 1 : 0);
enemyok = true;
e = f;
else if(!enemyok && target(d, b, d->gunselect == GUN_FIST ? 1 : 0, false, SIGHTMIN))
enemyok = (e = getclient(d->ai->enemy)) != NULL;
}
- if(enemyok)
- {
+ if(enemyok) {
vec ep = getaimpos(d, e);
float yaw, pitch;
getyawpitch(dp, ep, yaw, pitch);
bool insight = cansee(d, dp, ep), hasseen = d->ai->enemyseen && lastmillis-d->ai->enemyseen <= (d->skill*10)+3000,
quick = d->ai->enemyseen && lastmillis-d->ai->enemyseen <= (d->gunselect == GUN_CG ? 300 : skmod)+30;
if(insight) d->ai->enemyseen = lastmillis;
- if(idle || insight || hasseen || quick)
- {
+ if(idle || insight || hasseen || quick) {
float sskew = insight || d->skill > 100 ? 1.5f : (hasseen ? 1.f : 0.5f);
- if(insight && lockon(d, e, 16))
- {
+ if(insight && lockon(d, e, 16)) {
d->ai->targyaw = yaw;
d->ai->targpitch = pitch;
if(!idle) frame *= 2;
d->ai->becareful = false;
}
scaleyawpitch(d->yaw, d->pitch, yaw, pitch, frame, sskew);
- if(insight || quick)
- {
- if(canshoot(d, e) && hastarget(d, b, e, yaw, pitch, dp.squaredist(ep)))
- {
+ if(insight || quick) {
+ if(canshoot(d, e) && hastarget(d, b, e, yaw, pitch, dp.squaredist(ep))) {
d->attacking = true;
d->ai->lastaction = lastmillis;
result = 3;
}
else result = 1;
}
- else
- {
- if(!d->ai->enemyseen || lastmillis-d->ai->enemyseen > (d->skill*50)+3000)
- {
+ else {
+ if(!d->ai->enemyseen || lastmillis-d->ai->enemyseen > (d->skill*50)+3000) {
d->ai->enemy = -1;
d->ai->enemyseen = d->ai->enemymillis = 0;
}
result = 0;
}
}
- else
- {
- if(!enemyok)
- {
+ else {
+ if(!enemyok) {
d->ai->enemy = -1;
d->ai->enemyseen = d->ai->enemymillis = 0;
}
enemyok = false;
result = 0;
}
-
fixrange(d->ai->targyaw, d->ai->targpitch);
if(!result) scaleyawpitch(d->yaw, d->pitch, d->ai->targyaw, d->ai->targpitch, frame*0.25f, 1.f);
-
- if(d->ai->becareful && d->physstate == PHYS_FALL)
- {
+ if(d->ai->becareful && d->physstate == PHYS_FALL) {
float offyaw, offpitch;
vectoyawpitch(d->vel, offyaw, offpitch);
offyaw -= d->yaw; offpitch -= d->pitch;
else if(d->ai->becareful) d->ai->dontmove = true;
}
else d->ai->becareful = false;
-
if(d->ai->dontmove) d->move = d->strafe = 0;
- else
- { // our guys move one way.. but turn another?! :)
- const struct aimdir { int move, strafe, offset; } aimdirs[8] =
- {
+ else {
+ // our guys move one way.. but turn another?! :)
+ const struct aimdir { int move, strafe, offset; } aimdirs[8] = {
{ 1, 0, 0 },
- { 1, -1, 45 },
- { 0, -1, 90 },
- { -1, -1, 135 },
+ { 1, -1, 45 },
+ { 0, -1, 90 },
+ { -1, -1, 135 },
{ -1, 0, 180 },
- { -1, 1, 225 },
- { 0, 1, 270 },
- { 1, 1, 315 }
+ { -1, 1, 225 },
+ { 0, 1, 270 },
+ { 1, 1, 315 }
};
float yaw = d->ai->targyaw-d->yaw;
while(yaw < 0.0f) yaw += 360.0f;
findorientation(dp, d->yaw, d->pitch, d->ai->target);
return result;
}
-
- bool hasrange(fpsent *d, fpsent *e, int weap)
- {
+ bool hasrange(fpsent *d, fpsent *e, int weap) {
if(!e) return true;
- if(targetable(d, e))
- {
+ if(targetable(d, e)) {
vec ep = getaimpos(d, e);
float dist = ep.squaredist(d->headpos());
if(weaprange(d, weap, dist)) return true;
}
return false;
}
-
- bool request(fpsent *d, aistate &b)
- {
+ bool request(fpsent *d, aistate &b) {
fpsent *e = getclient(d->ai->enemy);
- if(!d->hasammo(d->gunselect) || !hasrange(d, e, d->gunselect) || (d->gunselect != d->ai->weappref && (!isgoodammo(d->gunselect) || d->hasammo(d->ai->weappref))))
- {
+ if(!d->hasammo(d->gunselect) || !hasrange(d, e, d->gunselect) || (d->gunselect != d->ai->weappref && (!isgoodammo(d->gunselect) || d->hasammo(d->ai->weappref)))) {
static const int gunprefs[] = { GUN_CG, GUN_RL, GUN_SG, GUN_RIFLE, GUN_GL, GUN_PISTOL, GUN_FIST };
int gun = -1;
if(d->hasammo(d->ai->weappref) && hasrange(d, e, d->ai->weappref)) gun = d->ai->weappref;
- else
- {
- loopi(sizeof(gunprefs)/sizeof(gunprefs[0])) if(d->hasammo(gunprefs[i]) && hasrange(d, e, gunprefs[i]))
- {
+ else {
+ loopi(sizeof(gunprefs)/sizeof(gunprefs[0])) if(d->hasammo(gunprefs[i]) && hasrange(d, e, gunprefs[i])) {
gun = gunprefs[i];
break;
}
}
return process(d, b) >= 2;
}
-
- void timeouts(fpsent *d, aistate &b)
- {
- if(d->blocked)
- {
+ void timeouts(fpsent *d, aistate &b) {
+ if(d->blocked) {
d->ai->blocktime += lastmillis-d->ai->lastrun;
- if(d->ai->blocktime > (d->ai->blockseq+1)*1000)
- {
+ if(d->ai->blocktime > (d->ai->blockseq+1)*1000) {
d->ai->blockseq++;
- switch(d->ai->blockseq)
- {
+ switch(d->ai->blockseq) {
case 1: case 2: case 3:
if(entities::ents.inrange(d->ai->targnode)) d->ai->addprevnode(d->ai->targnode);
d->ai->clear(false);
}
}
else d->ai->blocktime = d->ai->blockseq = 0;
-
- if(d->ai->targnode == d->ai->targlast)
- {
+ if(d->ai->targnode == d->ai->targlast) {
d->ai->targtime += lastmillis-d->ai->lastrun;
- if(d->ai->targtime > (d->ai->targseq+1)*1000)
- {
+ if(d->ai->targtime > (d->ai->targseq+1)*1000) {
d->ai->targseq++;
- switch(d->ai->targseq)
- {
+ switch(d->ai->targseq) {
case 1: case 2: case 3:
if(entities::ents.inrange(d->ai->targnode)) d->ai->addprevnode(d->ai->targnode);
d->ai->clear(false);
}
}
}
- else
- {
+ else {
d->ai->targtime = d->ai->targseq = 0;
d->ai->targlast = d->ai->targnode;
}
-
- if(d->ai->lasthunt)
- {
+ if(d->ai->lasthunt) {
int millis = lastmillis-d->ai->lasthunt;
if(millis <= 1000) { d->ai->tryreset = false; d->ai->huntseq = 0; }
- else if(millis > (d->ai->huntseq+1)*1000)
- {
+ else if(millis > (d->ai->huntseq+1)*1000) {
d->ai->huntseq++;
- switch(d->ai->huntseq)
- {
+ switch(d->ai->huntseq) {
case 1: d->ai->reset(true); break;
case 2: d->ai->reset(false); break;
case 3: default: suicide(d); return; break; // this is our last resort..
}
}
}
-
- void logic(fpsent *d, aistate &b, bool run)
- {
+ void logic(fpsent *d, aistate &b, bool run) {
bool allowmove = canmove(d) && b.type != AI_S_WAIT;
if(d->state != CS_ALIVE || !allowmove) d->stopmoving();
- if(d->state == CS_ALIVE)
- {
- if(allowmove)
- {
+ if(d->state == CS_ALIVE) {
+ if(allowmove) {
if(!request(d, b)) target(d, b, d->gunselect == GUN_FIST ? 1 : 0, b.idle ? true : false);
shoot(d, d->ai->target);
}
- if(!intermission)
- {
+ if(!intermission) {
if(d->ragdoll) cleanragdoll(d);
moveplayer(d, 10, true);
if(allowmove && !b.idle) timeouts(d, b);
entities::checkitems(d);
}
}
- else if(d->state == CS_DEAD)
- {
+ else if(d->state == CS_DEAD) {
if(d->ragdoll) moveragdoll(d);
- else if(lastmillis-d->lastpain<2000)
- {
+ else if(lastmillis-d->lastpain<2000) {
d->move = d->strafe = 0;
moveplayer(d, 10, false);
}
}
d->attacking = d->jumping = false;
}
-
- void avoid()
- {
+ void avoid() {
// guess as to the radius of ai and other critters relying on the avoid set for now
float guessradius = player1->radius;
obstacles.clear();
- loopv(players)
- {
+ loopv(players) {
dynent *d = players[i];
if(d->state != CS_ALIVE) continue;
obstacles.avoidnear(d, d->o.z + d->aboveeye + 1, d->feetpos(), guessradius + d->radius);
obstacles.add(wpavoid);
avoidweapons(obstacles, guessradius);
}
-
- void think(fpsent *d, bool run)
- {
+ void think(fpsent *d, bool run) {
// the state stack works like a chain of commands, certain commands simply replace each other
// others spawn new commands to the stack the ai reads the top command from the stack and executes
// it or pops the stack and goes back along the history until it finds a suitable command to execute
bool cleannext = false;
if(d->ai->state.empty()) d->ai->addstate(AI_S_WAIT);
- loopvrev(d->ai->state)
- {
+ loopvrev(d->ai->state) {
aistate &c = d->ai->state[i];
- if(cleannext)
- {
+ if(cleannext) {
c.millis = lastmillis;
c.override = false;
cleannext = false;
}
- if(d->state == CS_DEAD && d->respawned!=d->lifesequence && lastmillis - d->lastpain >= 500)
- {
+ if(d->state == CS_DEAD && d->respawned!=d->lifesequence && lastmillis - d->lastpain >= 500) {
addmsg(N_TRYSPAWN, "rc", d);
d->respawned = d->lifesequence;
}
- else if(d->state == CS_ALIVE && run)
- {
+ else if(d->state == CS_ALIVE && run) {
int result = 0;
c.idle = 0;
- switch(c.type)
- {
+ switch(c.type) {
case AI_S_WAIT: result = dowait(d, c); break;
case AI_S_DEFEND: result = dodefend(d, c); break;
case AI_S_PURSUE: result = dopursue(d, c); break;
case AI_S_INTEREST: result = dointerest(d, c); break;
default: result = 0; break;
}
- if(result <= 0)
- {
- if(c.type != AI_S_WAIT)
- {
- switch(result)
- {
+ if(result <= 0) {
+ if(c.type != AI_S_WAIT) {
+ switch(result) {
case 0: default: d->ai->removestate(i); cleannext = true; break;
case -1: i = d->ai->state.length()-1; break;
}
if(d->ai->trywipe) d->ai->wipe();
d->ai->lastrun = lastmillis;
}
-
- void drawroute(fpsent *d, float amt = 1.f)
- {
+ void drawroute(fpsent *d, float amt = 1.f) {
int last = -1;
- loopvrev(d->ai->route)
- {
- if(d->ai->route.inrange(last))
- {
+ loopvrev(d->ai->route) {
+ if(d->ai->route.inrange(last)) {
int index = d->ai->route[i], prev = d->ai->route[last];
- if(iswaypoint(index) && iswaypoint(prev))
- {
+ if(iswaypoint(index) && iswaypoint(prev)) {
waypoint &e = waypoints[index], &f = waypoints[prev];
vec fr = f.o, dr = e.o;
fr.z += amt; dr.z += amt;
}
last = i;
}
- if(aidebug >= 5)
- {
- vec pos = d->feetpos();
- if(d->ai->spot != vec(0, 0, 0)) particle_flare(pos, d->ai->spot, 1, PART_LIGHTNING, 0x00FFFF);
- if(iswaypoint(d->ai->targnode))
- particle_flare(pos, waypoints[d->ai->targnode].o, 1, PART_LIGHTNING, 0xFF00FF);
- if(iswaypoint(d->lastnode))
- particle_flare(pos, waypoints[d->lastnode].o, 1, PART_LIGHTNING, 0xFFFF00);
- loopi(NUMPREVNODES) if(iswaypoint(d->ai->prevnodes[i]))
- {
- particle_flare(pos, waypoints[d->ai->prevnodes[i]].o, 1, PART_LIGHTNING, 0x884400);
- pos = waypoints[d->ai->prevnodes[i]].o;
- }
- }
}
-
VAR(showwaypoints, 0, 0, 1);
VAR(showwaypointsradius, 0, 200, 10000);
-
- const char *stnames[AI_S_MAX] = {
- "wait", "defend", "pursue", "interest"
- }, *sttypes[AI_T_MAX+1] = {
- "none", "node", "player", "affinity", "entity"
- };
- void render()
- {
- if(aidebug > 1)
- {
+ const char *stnames[AI_S_MAX] = { "wait", "defend", "pursue", "interest" },
+ *sttypes[AI_T_MAX+1] = { "none", "node", "player", "affinity", "entity" };
+ void render() {
+ if(aidebug > 1) {
int total = 0, alive = 0;
loopv(players) if(players[i]->ai) total++;
- loopv(players) if(players[i]->state == CS_ALIVE && players[i]->ai)
- {
+ loopv(players) if(players[i]->state == CS_ALIVE && players[i]->ai) {
fpsent *d = players[i];
vec pos = d->abovehead();
pos.z += 3;
alive++;
if(aidebug >= 4) drawroute(d, 4.f*(float(alive)/float(total)));
- if(aidebug >= 3)
- {
+ if(aidebug >= 3) {
defformatstring(q, "node: %d route: %d (%d)",
d->lastnode,
!d->ai->route.empty() ? d->ai->route[0] : -1,
pos.z += 2;
}
bool top = true;
- loopvrev(d->ai->state)
- {
+ loopvrev(d->ai->state) {
aistate &b = d->ai->state[i];
defformatstring(s, "%s%s (%d ms) %s:%d",
top ? "\fg" : "\fy",
);
particle_textcopy(pos, s, PART_TEXT, 1);
pos.z += 2;
- if(top)
- {
+ if(top) {
if(aidebug >= 3) top = false;
else break;
}
}
- if(aidebug >= 3)
- {
- if(d->ai->weappref >= 0 && d->ai->weappref < NUMGUNS)
- {
+ if(aidebug >= 3) {
+ if(d->ai->weappref >= 0 && d->ai->weappref < NUMGUNS) {
particle_textcopy(pos, guns[d->ai->weappref].name, PART_TEXT, 1);
pos.z += 2;
}
fpsent *e = getclient(d->ai->enemy);
- if(e)
- {
+ if(e) {
particle_textcopy(pos, colorname(e), PART_TEXT, 1);
pos.z += 2;
}
}
}
- if(aidebug >= 4)
- {
+ if(aidebug >= 4) {
int cur = 0;
- loopv(obstacles.obstacles)
- {
+ loopv(obstacles.obstacles) {
const avoidset::obstacle &ob = obstacles.obstacles[i];
int next = cur + ob.numwaypoints;
- for(; cur < next; cur++)
- {
+ for(; cur < next; cur++) {
int ent = obstacles.waypoints[cur];
if(iswaypoint(ent))
regular_particle_splash(PART_EDIT, 2, 40, waypoints[ent].o, 0xFF6600, 1.5f);
}
}
}
- if(showwaypoints || aidebug >= 6)
- {
+ if(showwaypoints || aidebug >= 6) {
vector<int> close;
int len = waypoints.length();
- if(showwaypointsradius)
- {
+ if(showwaypointsradius) {
findwaypointswithin(camera1->o, 0, showwaypointsradius, close);
len = close.length();
}
- loopi(len)
- {
+ loopi(len) {
waypoint &w = waypoints[showwaypointsradius ? close[i] : i];
- loopj(MAXWAYPOINTLINKS)
- {
+ loopj(MAXWAYPOINTLINKS) {
int link = w.links[j];
if(!link) break;
particle_flare(w.o, waypoints[link].o, 1, PART_STREAK, 0x0000FF);
}
}
-
}
}
}
enum { AI_NONE = 0, AI_BOT, AI_MAX };
#define isaitype(a) (a >= 0 && a <= AI_MAX-1)
-namespace ai
-{
+namespace ai {
const int MAXWAYPOINTS = USHRT_MAX - 2;
const int MAXWAYPOINTLINKS = 6;
const int WAYPOINTRADIUS = 16;
-
const float MINWPDIST = 4.f; // is on top of
const float CLOSEDIST = 32.f; // is close
const float FARDIST = 128.f; // too far to remap close
const float SIGHTMAX = 1024.f; // maximum line of sight
const float VIEWMIN = 90.f; // minimum field of view
const float VIEWMAX = 180.f; // maximum field of view
-
- struct waypoint
- {
+ struct waypoint {
vec o;
float curscore, estscore;
int weight;
ushort route, prev;
ushort links[MAXWAYPOINTLINKS];
-
waypoint() {}
waypoint(const vec &o, int weight = 0) : o(o), weight(weight), route(0) { memset(links, 0, sizeof(links)); }
-
int score() const { return int(curscore) + int(estscore); }
-
- int find(int wp)
- {
+ int find(int wp) {
loopi(MAXWAYPOINTLINKS) if(links[i] == wp) return i;
return -1;
}
-
bool haslinks() { return links[0]!=0; }
};
extern vector<waypoint> waypoints;
-
- static inline bool iswaypoint(int n)
- {
+ static inline bool iswaypoint(int n) {
return n > 0 && n < waypoints.length();
}
-
extern int showwaypoints, dropwaypoints;
- extern int closestwaypoint(const vec &pos, float mindist, bool links, fpsent *d = NULL);
+ extern int closestwaypoint(const vec &pos, float mindist, bool links);
extern void findwaypointswithin(const vec &pos, float mindist, float maxdist, vector<int> &results);
extern void inferwaypoints(fpsent *d, const vec &o, const vec &v, float mindist = ai::CLOSEDIST);
-
- struct avoidset
- {
- struct obstacle
- {
+ struct avoidset {
+ struct obstacle {
void *owner;
int numwaypoints;
float above;
-
obstacle(void *owner, float above = -1) : owner(owner), numwaypoints(0), above(above) {}
};
-
vector<obstacle> obstacles;
vector<int> waypoints;
-
- void clear()
- {
+ void clear() {
obstacles.setsize(0);
waypoints.setsize(0);
}
-
- void add(void *owner, float above)
- {
+ void add(void *owner, float above) {
obstacles.add(obstacle(owner, above));
}
-
- void add(void *owner, float above, int wp)
- {
+ void add(void *owner, float above, int wp) {
if(obstacles.empty() || owner != obstacles.last().owner) add(owner, above);
obstacles.last().numwaypoints++;
waypoints.add(wp);
}
-
- void add(avoidset &avoid)
- {
+ void add(avoidset &avoid) {
waypoints.put(avoid.waypoints.getbuf(), avoid.waypoints.length());
- loopv(avoid.obstacles)
- {
+ loopv(avoid.obstacles) {
obstacle &o = avoid.obstacles[i];
if(obstacles.empty() || o.owner != obstacles.last().owner) add(o.owner, o.above);
obstacles.last().numwaypoints += o.numwaypoints;
}
}
-
void avoidnear(void *owner, float above, const vec &pos, float limit);
-
#define loopavoid(v, d, body) \
- if(!(v).obstacles.empty()) \
- { \
+ if(!(v).obstacles.empty()) { \
+ \
int cur = 0; \
- loopv((v).obstacles) \
- { \
+ loopv((v).obstacles) { \
+ \
const ai::avoidset::obstacle &ob = (v).obstacles[i]; \
int next = cur + ob.numwaypoints; \
- if(ob.owner != d) \
- { \
- for(; cur < next; cur++) \
- { \
+ if(ob.owner != d) { \
+ \
+ for(; cur < next; cur++) { \
+ \
int wp = (v).waypoints[cur]; \
body; \
} \
cur = next; \
} \
}
-
- bool find(int n, fpsent *d) const
- {
+ bool find(int n, fpsent *d) const {
loopavoid(*this, d, { if(wp == n) return true; });
return false;
}
-
int remap(fpsent *d, int n, vec &pos, bool retry = false);
};
-
extern bool route(fpsent *d, int node, int goal, vector<int> &route, const avoidset &obstacles, int retries = 0);
extern void navigate();
extern void clearwaypoints(bool full = false);
extern void seedwaypoints();
extern void loadwaypoints(bool force = false, const char *mname = NULL);
extern void savewaypoints(bool force = false, const char *mname = NULL);
-
// ai state information for the owner client
- enum
- {
+ enum {
AI_S_WAIT = 0, // waiting for next command
AI_S_DEFEND, // defend goal target
AI_S_PURSUE, // pursue goal target
AI_S_INTEREST, // interest in goal entity
AI_S_MAX
};
-
- enum
- {
+ enum {
AI_T_NODE,
AI_T_PLAYER,
AI_T_AFFINITY,
AI_T_ENTITY,
AI_T_MAX
};
-
- struct interest
- {
+ struct interest {
int state, node, target, targtype;
float score;
interest() : state(-1), node(-1), target(-1), targtype(-1), score(0.f) {}
~interest() {}
};
-
- struct aistate
- {
+ struct aistate {
int type, millis, targtype, target, idle;
bool override;
-
- aistate(int m, int t, int r = -1, int v = -1) : type(t), millis(m), targtype(r), target(v)
- {
+ aistate(int m, int t, int r = -1, int v = -1) : type(t), millis(m), targtype(r), target(v) {
reset();
}
~aistate() {}
-
- void reset()
- {
+ void reset() {
idle = 0;
override = false;
}
};
-
const int NUMPREVNODES = 6;
-
- struct aiinfo
- {
+ struct aiinfo {
vector<aistate> state;
vector<int> route;
vec target, spot;
lastrun, lasthunt, lastaction, lastcheck, jumpseed, jumprand, blocktime, huntseq, blockseq, lastaimrnd;
float targyaw, targpitch, views[3], aimrnd[3];
bool dontmove, becareful, tryreset, trywipe;
-
- aiinfo()
- {
+ aiinfo() {
clearsetup();
reset();
loopk(3) views[k] = 0.f;
}
~aiinfo() {}
-
- void clearsetup()
- {
+ void clearsetup() {
weappref = GUN_PISTOL;
spot = target = vec(0, 0, 0);
lastaction = lasthunt = lastcheck = enemyseen = enemymillis = blocktime = huntseq = blockseq = targtime = targseq = lastaimrnd = 0;
jumprand = lastmillis+5000;
targnode = targlast = enemy = -1;
}
-
- void clear(bool prev = false)
- {
+ void clear(bool prev = false) {
if(prev) memset(prevnodes, -1, sizeof(prevnodes));
route.setsize(0);
}
-
- void wipe(bool prev = false)
- {
+ void wipe(bool prev = false) {
clear(prev);
state.setsize(0);
addstate(AI_S_WAIT);
trywipe = false;
}
-
- void clean(bool tryit = false)
- {
+ void clean(bool tryit = false) {
if(!tryit) becareful = dontmove = false;
targyaw = rnd(360);
targpitch = 0.f;
tryreset = tryit;
}
-
void reset(bool tryit = false) { wipe(); clean(tryit); }
-
- bool hasprevnode(int n) const
- {
+ bool hasprevnode(int n) const {
loopi(NUMPREVNODES) if(prevnodes[i] == n) return true;
return false;
}
-
- void addprevnode(int n)
- {
- if(prevnodes[0] != n)
- {
+ void addprevnode(int n) {
+ if(prevnodes[0] != n) {
memmove(&prevnodes[1], prevnodes, sizeof(prevnodes) - sizeof(prevnodes[0]));
prevnodes[0] = n;
}
}
-
- aistate &addstate(int t, int r = -1, int v = -1)
- {
+ aistate &addstate(int t, int r = -1, int v = -1) {
return state.add(aistate(lastmillis, t, r, v));
}
-
- void removestate(int index = -1)
- {
+ void removestate(int index = -1) {
if(index < 0) state.pop();
else if(state.inrange(index)) state.remove(index);
if(!state.length()) addstate(AI_S_WAIT);
}
-
- aistate &getstate(int idx = -1)
- {
+ aistate &getstate(int idx = -1) {
if(state.inrange(idx)) return state[idx];
return state.last();
}
-
- aistate &switchstate(aistate &b, int t, int r = -1, int v = -1)
- {
- if((b.type == t && b.targtype == r) || (b.type == AI_S_INTEREST && b.targtype == AI_T_NODE))
- {
+ aistate &switchstate(aistate &b, int t, int r = -1, int v = -1) {
+ if((b.type == t && b.targtype == r) || (b.type == AI_S_INTEREST && b.targtype == AI_T_NODE)) {
b.millis = lastmillis;
b.target = v;
b.reset();
return addstate(t, r, v);
}
};
-
extern avoidset obstacles;
extern vec aitarget;
-
extern float viewdist(int x = 101);
extern float viewfieldx(int x = 101);
extern float viewfieldy(int x = 101);
extern bool targetable(fpsent *d, fpsent *e);
extern bool cansee(fpsent *d, vec &x, vec &y, vec &targ = aitarget);
-
extern void init(fpsent *d, int at, int on, int sk, int bn, int pm, const char *name, const char *team);
extern void update();
extern void avoid();
extern void think(fpsent *d, bool run);
-
extern bool badhealth(fpsent *d);
extern bool checkothers(vector<int> &targets, fpsent *d = NULL, int state = -1, int targtype = -1, int target = -1, bool teams = false, int *members = NULL);
extern bool makeroute(fpsent *d, aistate &b, int node, bool changed = true, int retries = 0);
extern bool defend(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, float wander = SIGHTMAX, int walk = 1);
extern void assist(fpsent *d, aistate &b, vector<interest> &interests, bool all = false, bool force = false);
extern bool parseinterests(fpsent *d, aistate &b, vector<interest> &interests, bool override = false, bool ignore = false);
-
extern void spawned(fpsent *d);
extern void damaged(fpsent *d, fpsent *e);
extern void killed(fpsent *d, fpsent *e);
extern void itemspawned(int ent);
-
extern void render();
}
// server-side ai manager
-namespace aiman
-{
+namespace aiman {
bool dorefresh = false, botbalance = true;
VARN(serverbotlimit, botlimit, 0, 8, MAXBOTS);
VAR(serverbotbalance, 0, 1, 1);
-
- void calcteams(vector<teamscore> &teams)
- {
+ void calcteams(vector<teamscore> &teams) {
static const char * const defaults[2] = { "good", "evil" };
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->state.state==CS_SPECTATOR || !ci->team[0]) continue;
teamscore *t = NULL;
else teams.add(teamscore(ci->team, 1));
}
teams.sort(teamscore::compare);
- if(teams.length() < int(sizeof(defaults)/sizeof(defaults[0])))
- {
+ if(teams.length() < int(sizeof(defaults)/sizeof(defaults[0]))) {
loopi(sizeof(defaults)/sizeof(defaults[0])) if(teams.htfind(defaults[i]) < 0) teams.add(teamscore(defaults[i], 0));
}
}
-
- void balanceteams()
- {
+ void balanceteams() {
vector<teamscore> teams;
calcteams(teams);
vector<clientinfo *> reassign;
loopv(bots) if(bots[i]) reassign.add(bots[i]);
- while(reassign.length() && teams.length() && teams[0].score > teams.last().score + 1)
- {
+ while(reassign.length() && teams.length() && teams[0].score > teams.last().score + 1) {
teamscore &t = teams.last();
clientinfo *bot = NULL;
- loopv(reassign) if(reassign[i] && !strcmp(reassign[i]->team, teams[0].team))
- {
+ loopv(reassign) if(reassign[i] && !strcmp(reassign[i]->team, teams[0].team)) {
bot = reassign.removeunordered(i);
teams[0].score--;
t.score++;
- for(int j = teams.length() - 2; j >= 0; j--)
- {
+ for(int j = teams.length() - 2; j >= 0; j--) {
if(teams[j].score >= teams[j+1].score) break;
swap(teams[j], teams[j+1]);
}
break;
}
- if(bot)
- {
+ if(bot) {
copystring(bot->team, t.team, MAXTEAMLEN+1);
sendf(-1, 1, "riisi", N_SETTEAM, bot->clientnum, bot->team, 0);
}
else teams.remove(0, 1);
}
}
-
- const char *chooseteam()
- {
+ const char *chooseteam() {
vector<teamscore> teams;
calcteams(teams);
return teams.length() ? teams.last().team : "";
}
-
- static inline bool validaiclient(clientinfo *ci)
- {
+ static inline bool validaiclient(clientinfo *ci) {
return ci->clientnum >= 0 && ci->state.aitype == AI_NONE && (ci->state.state!=CS_SPECTATOR || ci->local || (ci->privilege && !ci->warned));
}
-
- clientinfo *findaiclient(clientinfo *exclude = NULL)
- {
+ clientinfo *findaiclient(clientinfo *exclude = NULL) {
clientinfo *least = NULL;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(!validaiclient(ci) || ci==exclude) continue;
if(!least || ci->bots.length() < least->bots.length()) least = ci;
}
return least;
}
-
- bool addai(int skill, int limit)
- {
+ bool addai(int skill, int limit) {
int numai = 0, cn = -1, maxai = limit >= 0 ? min(limit, MAXBOTS) : MAXBOTS;
- loopv(bots)
- {
+ loopv(bots) {
clientinfo *ci = bots[i];
if(!ci || ci->ownernum < 0) { if(cn < 0) cn = i; continue; }
numai++;
}
if(numai >= maxai) return false;
- if(bots.inrange(cn))
- {
+ if(bots.inrange(cn)) {
clientinfo *ci = bots[cn];
- if(ci)
- { // reuse a slot that was going to removed
-
+ if(ci) {
+ // reuse a slot that was going to removed
clientinfo *owner = findaiclient();
ci->ownernum = owner ? owner->clientnum : -1;
if(owner) owner->bots.add(ci);
dorefresh = true;
return true;
}
-
- void deleteai(clientinfo *ci)
- {
+ void deleteai(clientinfo *ci) {
int cn = ci->clientnum - MAXCLIENTS;
if(!bots.inrange(cn)) return;
sendf(-1, 1, "ri2", N_CDIS, ci->clientnum);
DELETEP(bots[cn]);
dorefresh = true;
}
-
- bool deleteai()
- {
- loopvrev(bots) if(bots[i] && bots[i]->ownernum >= 0)
- {
+ bool deleteai() {
+ loopvrev(bots) if(bots[i] && bots[i]->ownernum >= 0) {
deleteai(bots[i]);
return true;
}
return false;
}
-
- void reinitai(clientinfo *ci)
- {
+ void reinitai(clientinfo *ci) {
if(ci->ownernum < 0) deleteai(ci);
- else if(ci->aireinit >= 1)
- {
+ else if(ci->aireinit >= 1) {
sendf(-1, 1, "ri6ss", N_INITAI, ci->clientnum, ci->ownernum, ci->state.aitype, ci->state.skill, ci->playermodel, ci->name, ci->team);
- if(ci->aireinit == 2)
- {
+ if(ci->aireinit == 2) {
ci->reassign();
if(ci->state.state==CS_ALIVE) sendspawn(ci);
else sendresume(ci);
ci->aireinit = 0;
}
}
-
- void shiftai(clientinfo *ci, clientinfo *owner = NULL)
- {
+ void shiftai(clientinfo *ci, clientinfo *owner = NULL) {
clientinfo *prevowner = (clientinfo *)getclientinfo(ci->ownernum);
if(prevowner) prevowner->bots.removeobj(ci);
if(!owner) { ci->aireinit = 0; ci->ownernum = -1; }
else if(ci->ownernum != owner->clientnum) { ci->aireinit = 2; ci->ownernum = owner->clientnum; owner->bots.add(ci); }
dorefresh = true;
}
-
- void removeai(clientinfo *ci)
- { // either schedules a removal, or someone else to assign to
-
+ void removeai(clientinfo *ci) {
+ // either schedules a removal, or someone else to assign to
loopvrev(ci->bots) shiftai(ci->bots[i], findaiclient(ci));
}
-
- bool reassignai()
- {
+ bool reassignai() {
clientinfo *hi = NULL, *lo = NULL;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(!validaiclient(ci)) continue;
if(!lo || ci->bots.length() < lo->bots.length()) lo = ci;
if(!hi || ci->bots.length() > hi->bots.length()) hi = ci;
}
- if(hi && lo && hi->bots.length() - lo->bots.length() > 1)
- {
- loopvrev(hi->bots)
- {
+ if(hi && lo && hi->bots.length() - lo->bots.length() > 1) {
+ loopvrev(hi->bots) {
shiftai(hi->bots[i], lo);
return true;
}
return false;
}
-
- void checksetup()
- {
+ void checksetup() {
if(m_teammode && botbalance) balanceteams();
loopvrev(bots) if(bots[i]) reinitai(bots[i]);
}
-
- void clearai()
- { // clear and remove all ai immediately
+ void clearai() {
+ // clear and remove all ai immediately
loopvrev(bots) if(bots[i]) deleteai(bots[i]);
}
-
- void checkai()
- {
+ void checkai() {
if(!dorefresh) return;
dorefresh = false;
- if(m_botmode && numclients(-1, false, true))
- {
+ if(m_botmode && numclients(-1, false, true)) {
checksetup();
while(reassignai());
}
else clearai();
}
-
- void reqadd(clientinfo *ci, int skill)
- {
+ void reqadd(clientinfo *ci, int skill) {
if(!ci->local && !ci->privilege) return;
if(!addai(skill, !ci->local && ci->privilege < PRIV_ADMIN ? botlimit : -1)) sendf(ci->clientnum, 1, "ris", N_SERVMSG, "failed to create or assign bot");
}
-
- void reqdel(clientinfo *ci)
- {
+ void reqdel(clientinfo *ci) {
if(!ci->local && !ci->privilege) return;
if(!deleteai()) sendf(ci->clientnum, 1, "ris", N_SERVMSG, "failed to remove any bots");
}
-
- void setbotlimit(clientinfo *ci, int limit)
- {
+ void setbotlimit(clientinfo *ci, int limit) {
if(ci && !ci->local && ci->privilege < PRIV_ADMIN) return;
botlimit = clamp(limit, 0, MAXBOTS);
dorefresh = true;
defformatstring(msg, "bot limit is now %d", botlimit);
sendservmsg(msg);
}
-
- void setbotbalance(clientinfo *ci, bool balance)
- {
+ void setbotbalance(clientinfo *ci, bool balance) {
if(ci && !ci->local && !ci->privilege) return;
botbalance = balance ? 1 : 0;
dorefresh = true;
sendservmsg(msg);
}
-
- void changemap()
- {
+ void changemap() {
dorefresh = true;
loopv(clients) if(clients[i]->local || clients[i]->privilege) return;
if(botbalance != (serverbotbalance != 0)) setbotbalance(NULL, serverbotbalance != 0);
}
-
- void addclient(clientinfo *ci)
- {
+ void addclient(clientinfo *ci) {
if(ci->state.aitype == AI_NONE) dorefresh = true;
}
-
- void changeteam(clientinfo *ci)
- {
+ void changeteam(clientinfo *ci) {
if(ci->state.aitype == AI_NONE) dorefresh = true;
}
}
#include "game.h"
-namespace game
-{
+namespace game {
bool senditemstoserver = false, sendcrc = false; // after a map change, since server doesn't have map data
int lastping = 0;
-
bool connected = false, remote = false, demoplayback = false, gamepaused = false;
int sessionid = 0, mastermode = MM_OPEN, gamespeed = 100;
string servinfo = "", servauth = "", connectpass = "";
-
VARP(deadpush, 1, 2, 20);
-
- void switchname(const char *name)
- {
+ void switchname(const char *name) {
filtertext(player1->name, name, false, false, MAXNAMELEN);
if(!player1->name[0]) copystring(player1->name, "Anonymous");
addmsg(N_SWITCHNAME, "rs", player1->name);
}
- void printname()
- {
+ void printname() {
conoutf("your name is: %s", colorname(player1));
}
- ICOMMAND(name, "sN", (char *s, int *numargs),
- {
+ ICOMMAND(name, "sN", (char *s, int *numargs), {
if(*numargs > 0) switchname(s);
else if(!*numargs) printname();
else result(colorname(player1));
});
ICOMMAND(getname, "", (), result(player1->name));
-
- void switchteam(const char *team)
- {
+ void switchteam(const char *team) {
if(player1->clientnum < 0) filtertext(player1->team, team, false, false, MAXTEAMLEN);
else addmsg(N_SWITCHTEAM, "rs", team);
}
- void printteam()
- {
+ void printteam() {
conoutf("your team is: %s", player1->team);
}
- ICOMMAND(team, "sN", (char *s, int *numargs),
- {
+ ICOMMAND(team, "sN", (char *s, int *numargs), {
if(*numargs > 0) switchteam(s);
else if(!*numargs) printteam();
else result(player1->team);
});
ICOMMAND(getteam, "", (), result(player1->team));
-
- struct authkey
- {
+ struct authkey {
char *name, *key, *desc;
int lastauth;
-
authkey(const char *name, const char *key, const char *desc)
: name(newstring(name)), key(newstring(key)), desc(newstring(desc)),
- lastauth(0)
- {
+ lastauth(0) {
}
-
- ~authkey()
- {
+ ~authkey() {
DELETEA(name);
DELETEA(key);
DELETEA(desc);
}
};
vector<authkey *> authkeys;
-
- authkey *findauthkey(const char *desc = "")
- {
+ authkey *findauthkey(const char *desc = "") {
loopv(authkeys) if(!strcmp(authkeys[i]->desc, desc) && !strcasecmp(authkeys[i]->name, player1->name)) return authkeys[i];
loopv(authkeys) if(!strcmp(authkeys[i]->desc, desc)) return authkeys[i];
return NULL;
}
-
VARP(autoauth, 0, 1, 1);
-
- void addauthkey(const char *name, const char *key, const char *desc)
- {
+ void addauthkey(const char *name, const char *key, const char *desc) {
loopvrev(authkeys) if(!strcmp(authkeys[i]->desc, desc) && !strcmp(authkeys[i]->name, name)) delete authkeys.remove(i);
if(name[0] && key[0]) authkeys.add(new authkey(name, key, desc));
}
ICOMMAND(authkey, "sss", (char *name, char *key, char *desc), addauthkey(name, key, desc));
-
- bool hasauthkey(const char *name, const char *desc)
- {
+ bool hasauthkey(const char *name, const char *desc) {
if(!name[0] && !desc[0]) return authkeys.length() > 0;
loopvrev(authkeys) if(!strcmp(authkeys[i]->desc, desc) && !strcmp(authkeys[i]->name, name)) return true;
return false;
}
-
ICOMMAND(hasauthkey, "ss", (char *name, char *desc), intret(hasauthkey(name, desc) ? 1 : 0));
-
- void genauthkey(const char *secret)
- {
+ void genauthkey(const char *secret) {
if(!secret[0]) { conoutf(CON_ERROR, "you must specify a secret password"); return; }
vector<char> privkey, pubkey;
genprivkey(secret, privkey, pubkey);
result(privkey.getbuf());
}
COMMAND(genauthkey, "s");
-
- void getpubkey(const char *desc)
- {
+ void getpubkey(const char *desc) {
authkey *k = findauthkey(desc);
if(!k) { if(desc[0]) conoutf(CON_ERROR, "no authkey found: %s", desc); else conoutf(CON_ERROR, "no global authkey found"); return; }
vector<char> pubkey;
result(pubkey.getbuf());
}
COMMAND(getpubkey, "s");
-
- void saveauthkeys()
- {
+ void saveauthkeys() {
stream *f = openfile("auth.cfg", "w");
if(!f) { conoutf(CON_ERROR, "failed to open auth.cfg for writing"); return; }
- loopv(authkeys)
- {
+ loopv(authkeys) {
authkey *a = authkeys[i];
f->printf("authkey %s %s %s\n", escapestring(a->name), escapestring(a->key), escapestring(a->desc));
}
delete f;
}
COMMAND(saveauthkeys, "");
-
- void sendmapinfo()
- {
+ void sendmapinfo() {
if(!connected) return;
sendcrc = true;
if(player1->state!=CS_SPECTATOR || player1->privilege || !remote) senditemstoserver = true;
}
-
- void writeclientinfo(stream *f)
- {
+ void writeclientinfo(stream *f) {
f->printf("name %s\n", escapestring(player1->name));
}
-
- bool allowedittoggle()
- {
+ bool allowedittoggle() {
if(editmode) return true;
- if(isconnected() && multiplayer(false) && !m_edit)
- {
+ if(isconnected() && multiplayer(false) && !m_edit) {
conoutf(CON_ERROR, "editing in multiplayer requires coop edit mode (1)");
return false;
}
return execidentbool("allowedittoggle", true);
}
-
- void edittoggled(bool on)
- {
+ void edittoggled(bool on) {
addmsg(N_EDITMODE, "ri", on ? 1 : 0);
if(player1->state==CS_DEAD) deathstate(player1, true);
else if(player1->state==CS_EDITING && player1->editstate==CS_DEAD) showscores(false);
disablezoom();
player1->suicided = player1->respawned = -2;
}
-
- const char *getclientname(int cn)
- {
+ const char *getclientname(int cn) {
fpsent *d = getclient(cn);
return d ? d->name : "";
}
ICOMMAND(getclientname, "i", (int *cn), result(getclientname(*cn)));
-
- const char *getclientteam(int cn)
- {
+ const char *getclientteam(int cn) {
fpsent *d = getclient(cn);
return d ? d->team : "";
}
ICOMMAND(getclientteam, "i", (int *cn), result(getclientteam(*cn)));
-
- const char *getclienticon(int cn)
- {
+ const char *getclienticon(int cn) {
fpsent *d = getclient(cn);
if(!d || d->state==CS_SPECTATOR) return "spectator";
const playermodelinfo &mdl = getplayermodelinfo(d);
return m_teammode ? (isteam(player1->team, d->team) ? mdl.blueicon : mdl.redicon) : mdl.ffaicon;
}
ICOMMAND(getclienticon, "i", (int *cn), result(getclienticon(*cn)));
-
- bool ismaster(int cn)
- {
+ bool ismaster(int cn) {
fpsent *d = getclient(cn);
return d && d->privilege >= PRIV_MASTER;
}
ICOMMAND(ismaster, "i", (int *cn), intret(ismaster(*cn) ? 1 : 0));
-
- bool isauth(int cn)
- {
+ bool isauth(int cn) {
fpsent *d = getclient(cn);
return d && d->privilege >= PRIV_AUTH;
}
ICOMMAND(isauth, "i", (int *cn), intret(isauth(*cn) ? 1 : 0));
-
- bool isadmin(int cn)
- {
+ bool isadmin(int cn) {
fpsent *d = getclient(cn);
return d && d->privilege >= PRIV_ADMIN;
}
ICOMMAND(isadmin, "i", (int *cn), intret(isadmin(*cn) ? 1 : 0));
-
ICOMMAND(getmastermode, "", (), intret(mastermode));
ICOMMAND(mastermodename, "i", (int *mm), result(server::mastermodename(*mm, "")));
-
- bool isspectator(int cn)
- {
+ bool isspectator(int cn) {
fpsent *d = getclient(cn);
return d && d->state==CS_SPECTATOR;
}
ICOMMAND(isspectator, "i", (int *cn), intret(isspectator(*cn) ? 1 : 0));
-
- bool isai(int cn, int type)
- {
+ bool isai(int cn, int type) {
fpsent *d = getclient(cn);
int aitype = type > 0 && type < AI_MAX ? type : AI_BOT;
return d && d->aitype==aitype;
}
ICOMMAND(isai, "ii", (int *cn, int *type), intret(isai(*cn, *type) ? 1 : 0));
-
- int parseplayer(const char *arg)
- {
+ int parseplayer(const char *arg) {
char *end;
int n = strtol(arg, &end, 10);
- if(*arg && !*end)
- {
+ if(*arg && !*end) {
if(n!=player1->clientnum && !clients.inrange(n)) return -1;
return n;
}
// try case sensitive first
- loopv(players)
- {
+ loopv(players) {
fpsent *o = players[i];
if(!strcmp(arg, o->name)) return o->clientnum;
}
// nothing found, try case insensitive
- loopv(players)
- {
+ loopv(players) {
fpsent *o = players[i];
if(!strcasecmp(arg, o->name)) return o->clientnum;
}
return -1;
}
ICOMMAND(getclientnum, "s", (char *name), intret(name[0] ? parseplayer(name) : player1->clientnum));
-
- void listclients(bool local, bool bots)
- {
+ void listclients(bool local, bool bots) {
vector<char> buf;
string cn;
int numclients = 0;
- if(local && connected)
- {
+ if(local && connected) {
formatstring(cn, "%d", player1->clientnum);
buf.put(cn, strlen(cn));
numclients++;
}
- loopv(clients) if(clients[i] && (bots || clients[i]->aitype == AI_NONE))
- {
+ loopv(clients) if(clients[i] && (bots || clients[i]->aitype == AI_NONE)) {
formatstring(cn, "%d", clients[i]->clientnum);
if(numclients++) buf.add(' ');
buf.put(cn, strlen(cn));
result(buf.getbuf());
}
ICOMMAND(listclients, "bb", (int *local, int *bots), listclients(*local>0, *bots!=0));
-
- void clearbans()
- {
+ void clearbans() {
addmsg(N_CLEARBANS, "r");
}
COMMAND(clearbans, "");
-
- void kick(const char *victim, const char *reason)
- {
+ void kick(const char *victim, const char *reason) {
int vn = parseplayer(victim);
if(vn>=0 && vn!=player1->clientnum) addmsg(N_KICK, "ris", vn, reason);
}
COMMAND(kick, "ss");
-
- void authkick(const char *desc, const char *victim, const char *reason)
- {
+ void authkick(const char *desc, const char *victim, const char *reason) {
authkey *a = findauthkey(desc);
int vn = parseplayer(victim);
- if(a && vn>=0 && vn!=player1->clientnum)
- {
+ if(a && vn>=0 && vn!=player1->clientnum) {
a->lastauth = lastmillis;
addmsg(N_AUTHKICK, "rssis", a->desc, a->name, vn, reason);
}
ICOMMAND(authkick, "ss", (const char *victim, const char *reason), authkick("", victim, reason));
ICOMMAND(sauthkick, "ss", (const char *victim, const char *reason), if(servauth[0]) authkick(servauth, victim, reason));
ICOMMAND(dauthkick, "sss", (const char *desc, const char *victim, const char *reason), if(desc[0]) authkick(desc, victim, reason));
-
vector<int> ignores;
-
- void ignore(int cn)
- {
+ void ignore(int cn) {
fpsent *d = getclient(cn);
if(!d || d == player1) return;
conoutf("ignoring %s", d->name);
if(ignores.find(cn) < 0) ignores.add(cn);
}
-
- void unignore(int cn)
- {
+ void unignore(int cn) {
if(ignores.find(cn) < 0) return;
fpsent *d = getclient(cn);
if(d) conoutf("stopped ignoring %s", d->name);
ignores.removeobj(cn);
}
-
bool isignored(int cn) { return ignores.find(cn) >= 0; }
-
ICOMMAND(ignore, "s", (char *arg), ignore(parseplayer(arg)));
ICOMMAND(unignore, "s", (char *arg), unignore(parseplayer(arg)));
ICOMMAND(isignored, "s", (char *arg), intret(isignored(parseplayer(arg)) ? 1 : 0));
-
- void setteam(const char *arg1, const char *arg2)
- {
+ void setteam(const char *arg1, const char *arg2) {
int i = parseplayer(arg1);
if(i>=0) addmsg(N_SETTEAM, "ris", i, arg2);
}
COMMAND(setteam, "ss");
-
- void hashpwd(const char *pwd)
- {
+ void hashpwd(const char *pwd) {
if(player1->clientnum<0) return;
string hash;
server::hashpassword(player1->clientnum, sessionid, pwd, hash);
result(hash);
}
COMMAND(hashpwd, "s");
-
- void setmaster(const char *arg, const char *who)
- {
+ void setmaster(const char *arg, const char *who) {
if(!arg[0]) return;
int val = 1, cn = player1->clientnum;
- if(who[0])
- {
+ if(who[0]) {
cn = parseplayer(who);
if(cn < 0) return;
}
string hash = "";
if(!arg[1] && isdigit(arg[0])) val = parseint(arg);
- else
- {
+ else {
if(cn != player1->clientnum) return;
server::hashpassword(player1->clientnum, sessionid, arg, hash);
}
}
COMMAND(setmaster, "ss");
ICOMMAND(mastermode, "i", (int *val), addmsg(N_MASTERMODE, "ri", *val));
-
- bool tryauth(const char *desc)
- {
+ bool tryauth(const char *desc) {
authkey *a = findauthkey(desc);
if(!a) return false;
a->lastauth = lastmillis;
ICOMMAND(auth, "s", (char *desc), tryauth(desc));
ICOMMAND(sauth, "", (), if(servauth[0]) tryauth(servauth));
ICOMMAND(dauth, "s", (char *desc), if(desc[0]) tryauth(desc));
-
ICOMMAND(getservauth, "", (), result(servauth));
-
- void togglespectator(int val, const char *who)
- {
+ void togglespectator(int val, const char *who) {
int i = who[0] ? parseplayer(who) : player1->clientnum;
if(i>=0) addmsg(N_SPECTATOR, "rii", i, val);
}
ICOMMAND(spectator, "is", (int *val, char *who), togglespectator(*val, who));
-
ICOMMAND(checkmaps, "", (), addmsg(N_CHECKMAPS, "r"));
-
int gamemode = INT_MAX, nextmode = INT_MAX;
string clientmap = "";
-
- void changemapserv(const char *name, int mode) // forced map change from the server
- {
- if(multiplayer(false) && !m_mp(mode))
- {
+ void changemapserv(const char *name, int mode) { // forced map change from the server {
+ if(multiplayer(false) && !m_mp(mode)) {
conoutf(CON_ERROR, "mode %s (%d) not supported in multiplayer", server::modename(gamemode), gamemode);
loopi(NUMGAMEMODES) if(m_mp(STARTGAMEMODE + i)) { mode = STARTGAMEMODE + i; break; }
}
-
gamemode = mode;
nextmode = mode;
if(editmode) toggleedit();
if(m_demo) { entities::resetspawns(); return; }
- if((m_edit && !name[0]) || !load_world(name))
- {
+ if((m_edit && !name[0]) || !load_world(name)) {
emptymap(0, true, name);
senditemstoserver = false;
}
startgame();
}
-
- void setmode(int mode)
- {
- if(multiplayer(false) && !m_mp(mode))
- {
+ void setmode(int mode) {
+ if(multiplayer(false) && !m_mp(mode)) {
conoutf(CON_ERROR, "mode %s (%d) not supported in multiplayer", server::modename(mode), mode);
intret(0);
return;
}
ICOMMAND(mode, "i", (int *val), setmode(*val));
ICOMMAND(getmode, "", (), intret(gamemode));
- ICOMMAND(timeremaining, "i", (int *formatted),
- {
+ ICOMMAND(timeremaining, "i", (int *formatted), {
int val = max(maplimit - lastmillis + 999, 0)/1000;
- if(*formatted)
- {
+ if(*formatted) {
defformatstring(str, "%d:%02d", val/60, val%60);
result(str);
}
ICOMMANDS("m_demo", "i", (int *mode), { int gamemode = *mode; intret(m_demo); });
ICOMMANDS("m_edit", "i", (int *mode), { int gamemode = *mode; intret(m_edit); });
ICOMMANDS("m_lobby", "i", (int *mode), { int gamemode = *mode; intret(m_lobby); });
-
- void changemap(const char *name, int mode) // request map change, server may ignore
- {
- if(!remote)
- {
+ void changemap(const char *name, int mode) { // request map change, server may ignore {
+ if(!remote) {
server::forcemap(name, mode);
if(!isconnected()) localconnect();
}
else if(player1->state!=CS_SPECTATOR || player1->privilege) addmsg(N_MAPVOTE, "rsi", name, mode);
}
- void changemap(const char *name)
- {
+ void changemap(const char *name) {
changemap(name, m_valid(nextmode) ? nextmode : (remote ? 0 : 1));
}
ICOMMAND(map, "s", (char *name), changemap(name));
-
- void forceintermission()
- {
+ void forceintermission() {
if(!remote && !hasnonlocalclients()) server::startintermission();
else addmsg(N_FORCEINTERMISSION, "r");
}
-
- void forceedit(const char *name)
- {
+ void forceedit(const char *name) {
changemap(name, 1);
}
-
- void newmap(int size)
- {
+ void newmap(int size) {
addmsg(N_NEWMAP, "ri", size);
}
-
int needclipboard = -1;
-
- void sendclipboard()
- {
+ void sendclipboard() {
uchar *outbuf = NULL;
int inlen = 0, outlen = 0;
- if(!packeditinfo(localedit, inlen, outbuf, outlen))
- {
+ if(!packeditinfo(localedit, inlen, outbuf, outlen)) {
outbuf = NULL;
inlen = outlen = 0;
}
sendclientpacket(p.finalize(), 1);
needclipboard = -1;
}
-
- void edittrigger(const selinfo &sel, int op, int arg1, int arg2, int arg3, const VSlot *vs)
- {
- if(m_edit) switch(op)
- {
+ void edittrigger(const selinfo &sel, int op, int arg1, int arg2, int arg3, const VSlot *vs) {
+ if(m_edit) switch(op) {
case EDIT_FLIP:
case EDIT_COPY:
case EDIT_PASTE:
- case EDIT_DELCUBE:
- {
- switch(op)
- {
+ case EDIT_DELCUBE: {
+ switch(op) {
case EDIT_COPY: needclipboard = 0; break;
case EDIT_PASTE:
- if(needclipboard > 0)
- {
+ if(needclipboard > 0) {
c2sinfo(true);
sendclipboard();
}
sel.cx, sel.cxs, sel.cy, sel.cys, sel.corner);
break;
}
- case EDIT_ROTATE:
- {
+ case EDIT_ROTATE: {
addmsg(N_EDITF + op, "ri9i5",
sel.o.x, sel.o.y, sel.o.z, sel.s.x, sel.s.y, sel.s.z, sel.grid, sel.orient,
sel.cx, sel.cxs, sel.cy, sel.cys, sel.corner,
break;
}
case EDIT_MAT:
- case EDIT_FACE:
- {
+ case EDIT_FACE: {
addmsg(N_EDITF + op, "ri9i6",
sel.o.x, sel.o.y, sel.o.z, sel.s.x, sel.s.y, sel.s.z, sel.grid, sel.orient,
sel.cx, sel.cxs, sel.cy, sel.cys, sel.corner,
arg1, arg2);
break;
}
- case EDIT_TEX:
- {
+ case EDIT_TEX: {
int tex1 = shouldpacktex(arg1);
if(addmsg(N_EDITF + op, "ri9i6",
sel.o.x, sel.o.y, sel.o.z, sel.s.x, sel.s.y, sel.s.z, sel.grid, sel.orient,
sel.cx, sel.cxs, sel.cy, sel.cys, sel.corner,
- tex1 ? tex1 : arg1, arg2))
- {
+ tex1 ? tex1 : arg1, arg2)) {
messages.pad(2);
int offset = messages.length();
if(tex1) packvslot(messages, arg1);
}
break;
}
- case EDIT_REPLACE:
- {
+ case EDIT_REPLACE: {
int tex1 = shouldpacktex(arg1), tex2 = shouldpacktex(arg2);
if(addmsg(N_EDITF + op, "ri9i7",
sel.o.x, sel.o.y, sel.o.z, sel.s.x, sel.s.y, sel.s.z, sel.grid, sel.orient,
sel.cx, sel.cxs, sel.cy, sel.cys, sel.corner,
- tex1 ? tex1 : arg1, tex2 ? tex2 : arg2, arg3))
- {
+ tex1 ? tex1 : arg1, tex2 ? tex2 : arg2, arg3)) {
messages.pad(2);
int offset = messages.length();
if(tex1) packvslot(messages, arg1);
}
break;
}
- case EDIT_REMIP:
- {
+ case EDIT_REMIP: {
addmsg(N_EDITF + op, "r");
break;
}
- case EDIT_VSLOT:
- {
+ case EDIT_VSLOT: {
if(addmsg(N_EDITF + op, "ri9i6",
sel.o.x, sel.o.y, sel.o.z, sel.s.x, sel.s.y, sel.s.z, sel.grid, sel.orient,
sel.cx, sel.cxs, sel.cy, sel.cys, sel.corner,
- arg1, arg2))
- {
+ arg1, arg2)) {
messages.pad(2);
int offset = messages.length();
packvslot(messages, vs);
break;
}
case EDIT_UNDO:
- case EDIT_REDO:
- {
+ case EDIT_REDO: {
uchar *outbuf = NULL;
int inlen = 0, outlen = 0;
- if(packundo(op, inlen, outbuf, outlen))
- {
+ if(packundo(op, inlen, outbuf, outlen)) {
if(addmsg(N_EDITF + op, "ri2", inlen, outlen)) messages.put(outbuf, outlen);
delete[] outbuf;
}
}
}
}
-
- void printvar(fpsent *d, ident *id)
- {
- if(id) switch(id->type)
- {
- case ID_VAR:
- {
+ void printvar(fpsent *d, ident *id) {
+ if(id) switch(id->type) {
+ case ID_VAR: {
int val = *id->storage.i;
string str;
if(val < 0)
break;
}
}
-
- void vartrigger(ident *id)
- {
+ void vartrigger(ident *id) {
if(!m_edit) return;
- switch(id->type)
- {
+ switch(id->type) {
case ID_VAR:
addmsg(N_EDITVAR, "risi", ID_VAR, id->name, *id->storage.i);
break;
-
case ID_FVAR:
addmsg(N_EDITVAR, "risf", ID_FVAR, id->name, *id->storage.f);
break;
-
case ID_SVAR:
addmsg(N_EDITVAR, "riss", ID_SVAR, id->name, *id->storage.s);
break;
}
printvar(player1, id);
}
-
- void pausegame(bool val)
- {
+ void pausegame(bool val) {
if(!connected) return;
if(!remote) server::forcepaused(val);
else addmsg(N_PAUSEGAME, "ri", val ? 1 : 0);
}
ICOMMAND(pausegame, "i", (int *val), pausegame(*val > 0));
- ICOMMAND(paused, "iN$", (int *val, int *numargs, ident *id),
- {
+ ICOMMAND(paused, "iN$", (int *val, int *numargs, ident *id), {
if(*numargs > 0) pausegame(clampvar(id, *val, 0, 1) > 0);
else if(*numargs < 0) intret(gamepaused ? 1 : 0);
else printvar(id, gamepaused ? 1 : 0);
});
-
bool ispaused() { return gamepaused; }
-
bool allowmouselook() { return !gamepaused || !remote || m_edit; }
-
- void changegamespeed(int val)
- {
+ void changegamespeed(int val) {
if(!connected) return;
if(!remote) server::forcegamespeed(val);
else addmsg(N_GAMESPEED, "ri", val);
}
- ICOMMAND(gamespeed, "iN$", (int *val, int *numargs, ident *id),
- {
+ ICOMMAND(gamespeed, "iN$", (int *val, int *numargs, ident *id), {
if(*numargs > 0) changegamespeed(clampvar(id, *val, 10, 1000));
else if(*numargs < 0) intret(gamespeed);
else printvar(id, gamespeed);
});
-
int scaletime(int t) { return t*gamespeed; }
-
// collect c2s messages conveniently
vector<uchar> messages;
int messagecn = -1, messagereliable = false;
-
- bool addmsg(int type, const char *fmt, ...)
- {
+ bool addmsg(int type, const char *fmt, ...) {
if(!connected) return false;
static uchar buf[MAXTRANS];
ucharbuf p(buf, sizeof(buf));
putint(p, type);
int numi = 1, numf = 0, nums = 0, mcn = -1;
bool reliable = false;
- if(fmt)
- {
+ if(fmt) {
va_list args;
va_start(args, fmt);
- while(*fmt) switch(*fmt++)
- {
+ while(*fmt) switch(*fmt++) {
case 'r': reliable = true; break;
- case 'c':
- {
+ case 'c': {
fpsent *d = va_arg(args, fpsent *);
mcn = !d || d == player1 ? -1 : d->clientnum;
break;
}
- case 'v':
- {
+ case 'v': {
int n = va_arg(args, int);
int *v = va_arg(args, int *);
loopi(n) putint(p, v[i]);
numi += n;
break;
}
-
- case 'i':
- {
+ case 'i': {
int n = isdigit(*fmt) ? *fmt++-'0' : 1;
loopi(n) putint(p, va_arg(args, int));
numi += n;
break;
}
- case 'f':
- {
+ case 'f': {
int n = isdigit(*fmt) ? *fmt++-'0' : 1;
loopi(n) putfloat(p, (float)va_arg(args, double));
numf += n;
int num = nums || numf ? 0 : numi, msgsize = server::msgsizelookup(type);
if(msgsize && num!=msgsize) { fatal("inconsistent msg size for %d (%d != %d)", type, num, msgsize); }
if(reliable) messagereliable = true;
- if(mcn != messagecn)
- {
+ if(mcn != messagecn) {
static uchar mbuf[16];
ucharbuf m(mbuf, sizeof(mbuf));
putint(m, N_FROMAI);
messages.put(buf, p.length());
return true;
}
-
- void connectattempt(const char *name, const char *password, const ENetAddress &address)
- {
+ void connectattempt(const char *name, const char *password, const ENetAddress &address) {
copystring(connectpass, password);
}
-
- void connectfail()
- {
+ void connectfail() {
memset(connectpass, 0, sizeof(connectpass));
}
-
- void gameconnect(bool _remote)
- {
+ void gameconnect(bool _remote) {
remote = _remote;
if(editmode) toggleedit();
}
-
- void gamedisconnect(bool cleanup)
- {
+ void gamedisconnect(bool cleanup) {
if(remote) stopfollowing();
ignores.setsize(0);
connected = remote = false;
gamepaused = false;
gamespeed = 100;
clearclients(false);
- if(cleanup)
- {
+ if(cleanup) {
nextmode = gamemode = INT_MAX;
clientmap[0] = '\0';
}
}
-
VARP(teamcolorchat, 0, 1, 1);
const char *chatcolorname(fpsent *d) { return teamcolorchat ? teamcolorname(d, NULL) : colorname(d); }
-
void toserver(char *text) { conoutf(CON_CHAT, "%s:\f0 %s", chatcolorname(player1), text); addmsg(N_TEXT, "rcs", player1, text); }
COMMANDN(say, toserver, "C");
-
void sayteam(char *text) { conoutf(CON_TEAMCHAT, "\fs\f8[team]\fr %s: \f8%s", chatcolorname(player1), text); addmsg(N_SAYTEAM, "rcs", player1, text); }
COMMAND(sayteam, "C");
-
ICOMMAND(servcmd, "C", (char *cmd), addmsg(N_SERVCMD, "rs", cmd));
-
- static void sendposition(fpsent *d, packetbuf &q)
- {
+ static void sendposition(fpsent *d, packetbuf &q) {
putint(q, N_POS);
putuint(q, d->clientnum);
// 3 bits phys state, 1 bit life sequence, 2 bits move, 2 bits strafe
if(o.y < 0 || o.y > 0xFFFF) flags |= 1<<1;
if(o.z < 0 || o.z > 0xFFFF) flags |= 1<<2;
if(vel > 0xFF) flags |= 1<<3;
- if(fall > 0)
- {
+ if(fall > 0) {
flags |= 1<<4;
if(fall > 0xFF) flags |= 1<<5;
if(d->falling.x || d->falling.y || d->falling.z > 0) flags |= 1<<6;
}
if((lookupmaterial(d->feetpos())&MATF_CLIP) == MAT_GAMECLIP) flags |= 1<<7;
putuint(q, flags);
- loopk(3)
- {
+ loopk(3) {
q.put(o[k]&0xFF);
q.put((o[k]>>8)&0xFF);
if(o[k] < 0 || o[k] > 0xFFFF) q.put((o[k]>>16)&0xFF);
uint veldir = (velyaw < 0 ? 360 + int(velyaw)%360 : int(velyaw)%360) + clamp(int(velpitch+90), 0, 180)*360;
q.put(veldir&0xFF);
q.put((veldir>>8)&0xFF);
- if(fall > 0)
- {
+ if(fall > 0) {
q.put(fall&0xFF);
if(fall > 0xFF) q.put((fall>>8)&0xFF);
- if(d->falling.x || d->falling.y || d->falling.z > 0)
- {
+ if(d->falling.x || d->falling.y || d->falling.z > 0) {
float fallyaw, fallpitch;
vectoyawpitch(d->falling, fallyaw, fallpitch);
uint falldir = (fallyaw < 0 ? 360 + int(fallyaw)%360 : int(fallyaw)%360) + clamp(int(fallpitch+90), 0, 180)*360;
}
}
}
-
- void sendposition(fpsent *d, bool reliable)
- {
+ void sendposition(fpsent *d, bool reliable) {
if(d->state != CS_ALIVE && d->state != CS_EDITING) return;
packetbuf q(100, reliable ? ENET_PACKET_FLAG_RELIABLE : 0);
sendposition(d, q);
sendclientpacket(q.finalize(), 0);
}
-
- void sendpositions()
- {
- loopv(players)
- {
+ void sendpositions() {
+ loopv(players) {
fpsent *d = players[i];
- if((d == player1 || d->ai) && (d->state == CS_ALIVE || d->state == CS_EDITING))
- {
+ if((d == player1 || d->ai) && (d->state == CS_ALIVE || d->state == CS_EDITING)) {
packetbuf q(100);
sendposition(d, q);
- for(int j = i+1; j < players.length(); j++)
- {
+ for(int j = i+1; j < players.length(); j++) {
fpsent *d = players[j];
if((d == player1 || d->ai) && (d->state == CS_ALIVE || d->state == CS_EDITING))
sendposition(d, q);
}
}
}
-
- void sendmessages()
- {
+ void sendmessages() {
packetbuf p(MAXTRANS);
- if(sendcrc)
- {
+ if(sendcrc) {
p.reliable();
sendcrc = false;
const char *mname = getclientmap();
sendstring(mname, p);
putint(p, mname[0] ? getmapcrc() : 0);
}
- if(senditemstoserver)
- {
+ if(senditemstoserver) {
if(!m_noitems) p.reliable();
if(!m_noitems) entities::putitems(p);
senditemstoserver = false;
}
- if(messages.length())
- {
+ if(messages.length()) {
p.put(messages.getbuf(), messages.length());
messages.setsize(0);
if(messagereliable) p.reliable();
messagereliable = false;
messagecn = -1;
}
- if(totalmillis-lastping>250)
- {
+ if(totalmillis-lastping>250) {
putint(p, N_PING);
putint(p, totalmillis);
lastping = totalmillis;
}
sendclientpacket(p.finalize(), 1);
}
-
- void c2sinfo(bool force) // send update to the server
- {
+ void c2sinfo(bool force) { // send update to the server {
static int lastupdate = -1000;
if(totalmillis - lastupdate < 33 && !force) return; // don't update faster than 30fps
lastupdate = totalmillis;
sendmessages();
flushclient();
}
-
- void sendintro()
- {
+ void sendintro() {
packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
putint(p, N_CONNECT);
sendstring(player1->name, p);
putint(p, player1->playermodel);
string hash = "";
- if(connectpass[0])
- {
+ if(connectpass[0]) {
server::hashpassword(player1->clientnum, sessionid, connectpass, hash);
memset(connectpass, 0, sizeof(connectpass));
}
sendstring(hash, p);
authkey *a = servauth[0] && autoauth ? findauthkey(servauth) : NULL;
- if(a)
- {
+ if(a) {
a->lastauth = lastmillis;
sendstring(a->desc, p);
sendstring(a->name, p);
}
- else
- {
+ else {
sendstring("", p);
sendstring("", p);
}
sendclientpacket(p.finalize(), 1);
}
-
- void updatepos(fpsent *d)
- {
+ void updatepos(fpsent *d) {
// update the position of other clients in the game in our world
// don't care if he's in the scenery or other players,
// just don't overlap with our client
-
const float r = player1->radius+d->radius;
const float dx = player1->o.x-d->o.x;
const float dy = player1->o.y-d->o.y;
const float dz = player1->o.z-d->o.z;
const float rz = player1->aboveeye+d->eyeheight;
const float fx = (float)fabs(dx), fy = (float)fabs(dy), fz = (float)fabs(dz);
- if(fx<r && fy<r && fz<rz && player1->state!=CS_SPECTATOR && d->state!=CS_DEAD)
- {
+ if(fx<r && fy<r && fz<rz && player1->state!=CS_SPECTATOR && d->state!=CS_DEAD) {
if(fx<fy) d->o.y += dy<0 ? r-fy : -(r-fy); // push aside
else d->o.x += dx<0 ? r-fx : -(r-fx);
}
int lagtime = totalmillis-d->lastupdate;
- if(lagtime)
- {
+ if(lagtime) {
if(d->state!=CS_SPAWNING && d->lastupdate) d->plag = (d->plag*5+lagtime)/6;
d->lastupdate = totalmillis;
}
}
-
- void parsepositions(ucharbuf &p)
- {
+ void parsepositions(ucharbuf &p) {
int type;
- while(p.remaining()) switch(type = getint(p))
- {
+ while(p.remaining()) switch(type = getint(p)) {
case N_DEMOPACKET: break;
- case N_POS: // position of another client
- {
+ case N_POS: { // position of another client {
int cn = getuint(p), physstate = p.get(), flags = getuint(p);
vec o, vel, falling;
float yaw, pitch, roll;
- loopk(3)
- {
+ loopk(3) {
int n = p.get(); n |= p.get()<<8; if(flags&(1<<k)) { n |= p.get()<<16; if(n&0x800000) n |= ~0U<<24; }
o[k] = n/DMF;
}
dir = p.get(); dir |= p.get()<<8;
vecfromyawpitch(dir%360, clamp(dir/360, 0, 180)-90, 1, 0, vel);
vel.mul(mag/DVELF);
- if(flags&(1<<4))
- {
+ if(flags&(1<<4)) {
mag = p.get(); if(flags&(1<<5)) mag |= p.get()<<8;
- if(flags&(1<<6))
- {
+ if(flags&(1<<6)) {
dir = p.get(); dir |= p.get()<<8;
vecfromyawpitch(dir%360, clamp(dir/360, 0, 180)-90, 1, 0, falling);
}
d->physstate = physstate&7;
updatephysstate(d);
updatepos(d);
- if(smoothmove && d->smoothmillis>=0 && oldpos.dist(d->o) < smoothdist)
- {
+ if(smoothmove && d->smoothmillis>=0 && oldpos.dist(d->o) < smoothdist) {
d->newpos = d->o;
d->newyaw = d->yaw;
d->newpitch = d->pitch;
if(d->state==CS_LAGGED || d->state==CS_SPAWNING) d->state = CS_ALIVE;
break;
}
-
- case N_TELEPORT:
- {
+ case N_TELEPORT: {
int cn = getint(p), tp = getint(p), td = getint(p);
fpsent *d = getclient(cn);
if(!d || d->lifesequence < 0 || d->state==CS_DEAD) continue;
entities::teleporteffects(d, tp, td, false);
break;
}
-
- case N_JUMPPAD:
- {
+ case N_JUMPPAD: {
int cn = getint(p), jp = getint(p);
fpsent *d = getclient(cn);
if(!d || d->lifesequence < 0 || d->state==CS_DEAD) continue;
entities::jumppadeffects(d, jp, false);
break;
}
-
default:
neterr("type");
return;
}
}
-
- void parsestate(fpsent *d, ucharbuf &p, bool resume = false)
- {
+ void parsestate(fpsent *d, ucharbuf &p, bool resume = false) {
if(!d) { static fpsent dummy; d = &dummy; }
- if(resume)
- {
+ if(resume) {
if(d==player1) getint(p);
else d->state = getint(p);
d->frags = getint(p);
d->armour = getint(p);
d->maxarmour = getint(p);
d->armourtype = getint(p);
- if(resume && d==player1)
- {
+ if(resume && d==player1) {
getint(p);
loopi(GUN_PISTOL-GUN_SG+1) getint(p);
}
- else
- {
+ else {
int gun = getint(p);
d->gunselect = clamp(gun, int(GUN_FIST), int(GUN_PISTOL));
loopi(GUN_PISTOL-GUN_SG+1) d->ammo[GUN_SG+i] = getint(p);
}
}
-
extern int deathscore;
-
- void parsemessages(int cn, fpsent *d, ucharbuf &p)
- {
+ void parsemessages(int cn, fpsent *d, ucharbuf &p) {
static char text[MAXTRANS];
int type;
bool mapchanged = false, demopacket = false;
-
- while(p.remaining()) switch(type = getint(p))
- {
+ while(p.remaining()) switch(type = getint(p)) {
case N_DEMOPACKET: demopacket = true; break;
-
- case N_SERVINFO: // welcome messsage from the server
- {
+ case N_SERVINFO: { // welcome messsage from the server {
int mycn = getint(p), prot = getint(p);
- if(prot!=PROTOCOL_VERSION)
- {
+ if(prot!=PROTOCOL_VERSION) {
conoutf(CON_ERROR, "you are using a different game protocol (you: %d, server: %d)", PROTOCOL_VERSION, prot);
disconnect();
return;
sendintro();
break;
}
-
- case N_WELCOME:
- {
+ case N_WELCOME: {
connected = true;
notifywelcome();
break;
}
-
- case N_PAUSEGAME:
- {
+ case N_PAUSEGAME: {
bool val = getint(p) > 0;
int cn = getint(p);
fpsent *a = cn >= 0 ? getclient(cn) : NULL;
- if(!demopacket)
- {
+ if(!demopacket) {
gamepaused = val;
player1->attacking = false;
}
else conoutf("game is %s", val ? "paused" : "resumed");
break;
}
-
- case N_GAMESPEED:
- {
+ case N_GAMESPEED: {
int val = clamp(getint(p), 10, 1000), cn = getint(p);
fpsent *a = cn >= 0 ? getclient(cn) : NULL;
if(!demopacket) gamespeed = val;
else conoutf("gamespeed is %d", val);
break;
}
-
- case N_CLIENT:
- {
+ case N_CLIENT: {
int cn = getint(p), len = getuint(p);
ucharbuf q = p.subbuf(len);
parsemessages(cn, getclient(cn), q);
break;
}
-
case N_SOUND:
if(!d) return;
playsound(getint(p), &d->o);
break;
-
- case N_TEXT:
- {
+ case N_TEXT: {
if(!d) return;
getstring(text, p);
filtertext(text, text, true, true);
conoutf(CON_CHAT, "%s:\f0 %s", chatcolorname(d), text);
break;
}
-
- case N_SAYTEAM:
- {
+ case N_SAYTEAM: {
int tcn = getint(p);
fpsent *t = getclient(tcn);
getstring(text, p);
conoutf(CON_TEAMCHAT, "\fs\f8[team]\fr %s: \f8%s", chatcolorname(t), text);
break;
}
-
case N_MAPCHANGE:
getstring(text, p);
filtertext(text, text, false);
if(getint(p)) entities::spawnitems();
else senditemstoserver = false;
break;
-
- case N_FORCEDEATH:
- {
+ case N_FORCEDEATH: {
int cn = getint(p);
fpsent *d = cn==player1->clientnum ? player1 : newclient(cn);
if(!d) break;
- if(d==player1)
- {
+ if(d==player1) {
if(editmode) toggleedit();
stopfollowing();
if(deathscore) showscores(true);
d->state = CS_DEAD;
break;
}
-
- case N_ITEMLIST:
- {
+ case N_ITEMLIST: {
int n;
- while((n = getint(p))>=0 && !p.overread())
- {
+ while((n = getint(p))>=0 && !p.overread()) {
if(mapchanged) entities::setspawn(n, true);
getint(p); // type
}
break;
}
-
- case N_INITCLIENT: // another client either connected or changed name/team
- {
+ case N_INITCLIENT: { // another client either connected or changed name/team {
int cn = getint(p);
fpsent *d = newclient(cn);
- if(!d)
- {
+ if(!d) {
getstring(text, p);
getstring(text, p);
getint(p);
getstring(text, p);
filtertext(text, text, false, false, MAXNAMELEN);
if(!text[0]) copystring(text, "Anonymous");
- if(d->name[0]) // already connected
- {
+ if(d->name[0]) { // already connected {
if(strcmp(d->name, text) && !isignored(d->clientnum))
conoutf("%s is now known as %s", colorname(d), colorname(d, text));
}
- else // new client
- {
+ else { // new client {
conoutf("\f0join:\f7 %s", colorname(d, text));
if(needclipboard >= 0) needclipboard++;
}
d->playermodel = 0;
break;
}
-
case N_SWITCHNAME:
getstring(text, p);
- if(d)
- {
+ if(d) {
filtertext(text, text, false, false, MAXNAMELEN);
if(!text[0]) copystring(text, "Anonymous");
- if(strcmp(text, d->name))
- {
+ if(strcmp(text, d->name)) {
if(!isignored(d->clientnum)) conoutf("%s is now known as %s", colorname(d), colorname(d, text));
copystring(d->name, text, MAXNAMELEN+1);
}
}
break;
-
case N_SWITCHMODEL:
break;
-
case N_CDIS:
clientdisconnected(getint(p));
break;
-
- case N_SPAWN:
- {
- if(d)
- {
+ case N_SPAWN: {
+ if(d) {
if(d->state==CS_DEAD && d->lastpain) saveragdoll(d);
d->respawn();
}
lasthit = 0;
break;
}
-
- case N_SPAWNSTATE:
- {
+ case N_SPAWNSTATE: {
int scn = getint(p);
fpsent *s = getclient(scn);
if(!s) { parsestate(NULL, p); break; }
if(s->state==CS_DEAD && s->lastpain) saveragdoll(s);
- if(s==player1)
- {
+ if(s==player1) {
if(editmode) toggleedit();
stopfollowing();
}
parsestate(s, p);
s->state = CS_ALIVE;
pickgamespawn(s);
- if(s == player1)
- {
+ if(s == player1) {
showscores(false);
lasthit = 0;
}
addmsg(N_SPAWN, "rcii", s, s->lifesequence, s->gunselect);
break;
}
-
- case N_SHOTFX:
- {
+ case N_SHOTFX: {
int scn = getint(p), gun = getint(p), id = getint(p);
vec from, to;
loopk(3) from[k] = getint(p)/DMF;
shoteffects(s->gunselect, from, to, s, false, id, prevaction);
break;
}
-
- case N_EXPLODEFX:
- {
+ case N_EXPLODEFX: {
int ecn = getint(p), gun = getint(p), id = getint(p);
fpsent *e = getclient(ecn);
if(!e) break;
explodeeffects(gun, e, false, id);
break;
}
- case N_DAMAGE:
- {
+ case N_DAMAGE: {
int tcn = getint(p),
acn = getint(p),
damage = getint(p),
damaged(damage, target, actor, false);
break;
}
-
- case N_HITPUSH:
- {
+ case N_HITPUSH: {
int tcn = getint(p), gun = getint(p), damage = getint(p);
fpsent *target = getclient(tcn);
vec dir;
if(target) target->hitpush(damage * (target->health<=0 ? deadpush : 1), dir, NULL, gun);
break;
}
-
- case N_DIED:
- {
+ case N_DIED: {
int vcn = getint(p), acn = getint(p), frags = getint(p), tfrags = getint(p);
fpsent *victim = getclient(vcn),
*actor = getclient(acn);
actor->frags = frags;
if(m_teammode) setteaminfo(actor->team, tfrags);
extern int hidefrags;
- if(actor!=player1 && (!hidefrags))
- {
+ if(actor!=player1 && (!hidefrags)) {
defformatstring(ds, "%d", actor->frags);
particle_textcopy(actor->abovehead(), ds, PART_TEXT, 2000, 0x32FF64, 4.0f, -8);
}
killed(victim, actor);
break;
}
-
case N_TEAMINFO:
- for(;;)
- {
+ for(;;) {
getstring(text, p);
if(p.overread() || !text[0]) break;
int frags = getint(p);
if(m_teammode) setteaminfo(text, frags);
}
break;
-
- case N_GUNSELECT:
- {
+ case N_GUNSELECT: {
if(!d) return;
int gun = getint(p);
d->gunselect = clamp(gun, int(GUN_FIST), int(GUN_PISTOL));
playsound(S_WEAPLOAD, &d->o);
break;
}
-
- case N_TAUNT:
- {
+ case N_TAUNT: {
if(!d) return;
d->lasttaunt = lastmillis;
break;
}
-
- case N_RESUME:
- {
- for(;;)
- {
+ case N_RESUME: {
+ for(;;) {
int cn = getint(p);
if(p.overread() || cn<0) break;
fpsent *d = (cn == player1->clientnum ? player1 : newclient(cn));
}
break;
}
-
- case N_ITEMSPAWN:
- {
+ case N_ITEMSPAWN: {
int i = getint(p);
if(!entities::ents.inrange(i)) break;
entities::setspawn(i, true);
if(icon >= 0) particle_icon(vec(0.0f, 0.0f, 4.0f).add(entities::ents[i]->o), icon%4, icon/4, PART_HUD_ICON, 2000, 0xFFFFFF, 2.0f, -8);
break;
}
-
- case N_ITEMACC: // server acknowledges that I picked up this item
- {
+ case N_ITEMACC: { // server acknowledges that I picked up this item {
int i = getint(p), cn = getint(p);
- if(cn >= 0)
- {
+ if(cn >= 0) {
fpsent *d = getclient(cn);
entities::pickupeffects(i, d);
}
else entities::setspawn(i, true);
break;
}
-
- case N_CLIPBOARD:
- {
+ case N_CLIPBOARD: {
int cn = getint(p), unpacklen = getint(p), packlen = getint(p);
fpsent *d = getclient(cn);
ucharbuf q = p.subbuf(max(packlen, 0));
break;
}
case N_UNDO:
- case N_REDO:
- {
+ case N_REDO: {
int cn = getint(p), unpacklen = getint(p), packlen = getint(p);
fpsent *d = getclient(cn);
ucharbuf q = p.subbuf(max(packlen, 0));
if(d) unpackundo(q.buf, q.maxlen, unpacklen);
break;
}
-
case N_EDITF: // coop editing messages
case N_EDITT:
case N_EDITM:
case N_ROTATE:
case N_REPLACE:
case N_DELCUBE:
- case N_EDITVSLOT:
- {
+ case N_EDITVSLOT: {
if(!d) return;
selinfo sel;
sel.o.x = getint(p); sel.o.y = getint(p); sel.o.z = getint(p);
sel.grid = getint(p); sel.orient = getint(p);
sel.cx = getint(p); sel.cxs = getint(p); sel.cy = getint(p), sel.cys = getint(p);
sel.corner = getint(p);
- switch(type)
- {
+ switch(type) {
case N_EDITF: { int dir = getint(p), mode = getint(p); if(sel.validate()) mpeditface(dir, mode, sel, false); break; }
- case N_EDITT:
- {
+ case N_EDITT: {
int tex = getint(p),
allfaces = getint(p);
if(p.remaining() < 2) return;
case N_COPY: if(d && sel.validate()) mpcopy(d->edit, sel, false); break;
case N_PASTE: if(d && sel.validate()) mppaste(d->edit, sel, false); break;
case N_ROTATE: { int dir = getint(p); if(sel.validate()) mprotate(dir, sel, false); break; }
- case N_REPLACE:
- {
+ case N_REPLACE: {
int oldtex = getint(p),
newtex = getint(p),
insel = getint(p);
break;
}
case N_DELCUBE: if(sel.validate()) mpdelcube(sel, false); break;
- case N_EDITVSLOT:
- {
+ case N_EDITVSLOT: {
int delta = getint(p),
allfaces = getint(p);
if(p.remaining() < 2) return;
}
break;
}
- case N_REMIP:
- {
+ case N_REMIP: {
if(!d) return;
conoutf("%s remipped", colorname(d));
mpremip(false);
break;
}
- case N_EDITENT: // coop edit of ent
- {
+ case N_EDITENT: { // coop edit of ent {
if(!d) return;
int i = getint(p);
float x = getint(p)/DMF, y = getint(p)/DMF, z = getint(p)/DMF;
int type = getint(p);
int attr1 = getint(p), attr2 = getint(p), attr3 = getint(p), attr4 = getint(p), attr5 = getint(p);
-
mpeditent(i, vec(x, y, z), type, attr1, attr2, attr3, attr4, attr5, false);
break;
}
- case N_EDITVAR:
- {
+ case N_EDITVAR: {
if(!d) return;
int type = getint(p);
getstring(text, p);
string name;
filtertext(name, text, false);
ident *id = getident(name);
- switch(type)
- {
- case ID_VAR:
- {
+ switch(type) {
+ case ID_VAR: {
int val = getint(p);
if(id && id->flags&IDF_OVERRIDE && !(id->flags&IDF_READONLY)) setvar(name, val);
break;
}
- case ID_FVAR:
- {
+ case ID_FVAR: {
float val = getfloat(p);
if(id && id->flags&IDF_OVERRIDE && !(id->flags&IDF_READONLY)) setfvar(name, val);
break;
}
- case ID_SVAR:
- {
+ case ID_SVAR: {
getstring(text, p);
if(id && id->flags&IDF_OVERRIDE && !(id->flags&IDF_READONLY)) setsvar(name, text);
break;
printvar(d, id);
break;
}
-
case N_PONG:
addmsg(N_CLIENTPING, "i", player1->ping = (player1->ping*5+totalmillis-getint(p))/6);
break;
-
case N_CLIENTPING:
if(!d) return;
d->ping = getint(p);
break;
-
case N_TIMEUP:
timeupdate(getint(p));
break;
-
case N_SERVMSG:
getstring(text, p);
conoutf("%s", text);
break;
-
- case N_SENDDEMOLIST:
- {
+ case N_SENDDEMOLIST: {
int demos = getint(p);
if(demos <= 0) conoutf("no demos available");
- else loopi(demos)
- {
+ else loopi(demos) {
getstring(text, p);
if(p.overread()) break;
conoutf("%d. %s", i+1, text);
}
break;
}
-
- case N_DEMOPLAYBACK:
- {
+ case N_DEMOPLAYBACK: {
int on = getint(p);
if(on) player1->state = CS_SPECTATOR;
else clearclients();
execident(on ? "demostart" : "demoend");
break;
}
-
- case N_CURRENTMASTER:
- {
+ case N_CURRENTMASTER: {
int mm = getint(p), mn;
loopv(players) players[i]->privilege = PRIV_NONE;
- while((mn = getint(p))>=0 && !p.overread())
- {
+ while((mn = getint(p))>=0 && !p.overread()) {
fpsent *m = mn==player1->clientnum ? player1 : newclient(mn);
int priv = getint(p);
if(m) m->privilege = priv;
}
- if(mm != mastermode)
- {
+ if(mm != mastermode) {
mastermode = mm;
conoutf("mastermode is %s (%d)", server::mastermodename(mastermode), mastermode);
}
break;
}
-
- case N_MASTERMODE:
- {
+ case N_MASTERMODE: {
mastermode = getint(p);
conoutf("mastermode is %s (%d)", server::mastermodename(mastermode), mastermode);
break;
}
-
- case N_EDITMODE:
- {
+ case N_EDITMODE: {
int val = getint(p);
if(!d) break;
- if(val)
- {
+ if(val) {
d->editstate = d->state;
d->state = CS_EDITING;
}
- else
- {
+ else {
d->state = d->editstate;
if(d->state==CS_DEAD) deathstate(d, true);
}
break;
}
-
- case N_SPECTATOR:
- {
+ case N_SPECTATOR: {
int sn = getint(p), val = getint(p);
fpsent *s;
- if(sn==player1->clientnum)
- {
+ if(sn==player1->clientnum) {
s = player1;
if(val && remote && !player1->privilege) senditemstoserver = false;
}
else s = newclient(sn);
if(!s) return;
- if(val)
- {
- if(s==player1)
- {
+ if(val) {
+ if(s==player1) {
if(editmode) toggleedit();
if(s->state==CS_DEAD) showscores(false);
disablezoom();
}
s->state = CS_SPECTATOR;
}
- else if(s->state==CS_SPECTATOR)
- {
+ else if(s->state==CS_SPECTATOR) {
if(s==player1) stopfollowing();
deathstate(s, true);
}
break;
}
-
- case N_SETTEAM:
- {
+ case N_SETTEAM: {
int wn = getint(p);
getstring(text, p);
int reason = getint(p);
conoutf(fmt[reason], colorname(w), w->team);
break;
}
-
- case N_ANNOUNCE:
- {
+ case N_ANNOUNCE: {
int t = getint(p);
- if (t==I_QUAD) { playsound(S_V_QUAD10, NULL, NULL, 0, 0, 0, -1, 0, 3000); conoutf(CON_GAMEINFO, "\f2quad damage will spawn in 10 seconds!"); }
+ if (t==I_QUAD) { playsound(S_V_QUAD10, NULL, NULL, 0, 0, 0, -1, 0, 3000); conoutf(CON_GAMEINFO, "\f2quad damage will spawn in 10 seconds!"); }
else if(t==I_BOOST) { playsound(S_V_BOOST10, NULL, NULL, 0, 0, 0, -1, 0, 3000); conoutf(CON_GAMEINFO, "\f2health boost will spawn in 10 seconds!"); }
break;
}
-
- case N_NEWMAP:
- {
+ case N_NEWMAP: {
int size = getint(p);
if(size>=0) emptymap(size, true, NULL);
else enlargemap(true);
- if(d && d!=player1)
- {
+ if(d && d!=player1) {
int newsize = 0;
while(1<<newsize < getworldsize()) newsize++;
conoutf(size>=0 ? "%s started a new map of size %d" : "%s enlarged the map to size %d", colorname(d), newsize);
}
break;
}
-
- case N_REQAUTH:
- {
+ case N_REQAUTH: {
getstring(text, p);
if(autoauth && text[0] && tryauth(text)) conoutf("server requested authkey \"%s\"", text);
break;
}
-
- case N_AUTHCHAL:
- {
+ case N_AUTHCHAL: {
getstring(text, p);
authkey *a = findauthkey(text);
uint id = (uint)getint(p);
getstring(text, p);
- if(a && a->lastauth && lastmillis - a->lastauth < 60*1000)
- {
+ if(a && a->lastauth && lastmillis - a->lastauth < 60*1000) {
vector<char> buf;
answerchallenge(a->key, text, buf);
//conoutf(CON_DEBUG, "answering %u, challenge %s with %s", id, text, buf.getbuf());
}
break;
}
-
- case N_INITAI:
- {
+ case N_INITAI: {
int bn = getint(p), on = getint(p), at = getint(p), sk = clamp(getint(p), 1, 101), pm = getint(p);
string name, team;
getstring(text, p);
ai::init(b, at, on, sk, bn, pm, name, team);
break;
}
-
case N_SERVCMD:
getstring(text, p);
break;
-
default:
neterr("type", cn < 0);
return;
}
}
-
- struct demoreq
- {
+ struct demoreq {
int tag;
string name;
};
vector<demoreq> demoreqs;
enum { MAXDEMOREQS = 7 };
static int lastdemoreq = 0;
-
- void receivefile(packetbuf &p)
- {
+ void receivefile(packetbuf &p) {
int type;
- while(p.remaining()) switch(type = getint(p))
- {
+ while(p.remaining()) switch(type = getint(p)) {
case N_DEMOPACKET: return;
- case N_SENDDEMO:
- {
+ case N_SENDDEMO: {
string fname;
fname[0] = '\0';
int tag = getint(p);
- loopv(demoreqs) if(demoreqs[i].tag == tag)
- {
+ loopv(demoreqs) if(demoreqs[i].tag == tag) {
copystring(fname, demoreqs[i].name);
demoreqs.remove(i);
break;
}
- if(!fname[0])
- {
+ if(!fname[0]) {
time_t t = time(NULL);
size_t len = strftime(fname, sizeof(fname), "%Y-%m-%d_%H.%M.%S", localtime(&t));
fname[min(len, sizeof(fname)-1)] = '\0';
delete demo;
break;
}
-
- case N_SENDMAP:
- {
+ case N_SENDMAP: {
if(!m_edit) return;
string oldname;
copystring(oldname, getclientmap());
}
}
}
-
- void parsepacketclient(int chan, packetbuf &p) // processes any updates from the server
- {
+ void parsepacketclient(int chan, packetbuf &p) { // processes any updates from the server {
if(p.packet->flags&ENET_PACKET_FLAG_UNSEQUENCED) return;
- switch(chan)
- {
+ switch(chan) {
case 0:
parsepositions(p);
break;
-
case 1:
parsemessages(-1, NULL, p);
break;
-
case 2:
receivefile(p);
break;
}
}
-
- void getmap()
- {
+ void getmap() {
if(!m_edit) { conoutf(CON_ERROR, "\"getmap\" only works in coop edit mode"); return; }
conoutf("getting map...");
addmsg(N_GETMAP, "r");
}
COMMAND(getmap, "");
-
- void stopdemo()
- {
- if(remote)
- {
+ void stopdemo() {
+ if(remote) {
if(player1->privilege<PRIV_MASTER) return;
addmsg(N_STOPDEMO, "r");
}
else server::stopdemo();
}
COMMAND(stopdemo, "");
-
- void recorddemo(int val)
- {
+ void recorddemo(int val) {
if(remote && player1->privilege<PRIV_MASTER) return;
addmsg(N_RECORDDEMO, "ri", val);
}
ICOMMAND(recorddemo, "i", (int *val), recorddemo(*val));
-
- void cleardemos(int val)
- {
+ void cleardemos(int val) {
if(remote && player1->privilege<PRIV_MASTER) return;
addmsg(N_CLEARDEMOS, "ri", val);
}
ICOMMAND(cleardemos, "i", (int *val), cleardemos(*val));
-
- void getdemo(char *val, char *name)
- {
+ void getdemo(char *val, char *name) {
int i = 0;
if(isdigit(val[0]) || name[0]) i = parseint(val);
else name = val;
if(i<=0) conoutf("getting demo...");
else conoutf("getting demo %d...", i);
++lastdemoreq;
- if(name[0])
- {
+ if(name[0]) {
if(demoreqs.length() >= MAXDEMOREQS) demoreqs.remove(0);
demoreq &r = demoreqs.add();
r.tag = lastdemoreq;
addmsg(N_GETDEMO, "rii", i, lastdemoreq);
}
ICOMMAND(getdemo, "ss", (char *val, char *name), getdemo(val, name));
-
- void listdemos()
- {
+ void listdemos() {
conoutf("listing demos...");
addmsg(N_LISTDEMOS, "r");
}
COMMAND(listdemos, "");
-
- void sendmap()
- {
+ void sendmap() {
if(!m_edit || (player1->state==CS_SPECTATOR && remote && !player1->privilege)) { conoutf(CON_ERROR, "\"sendmap\" only works in coop edit mode"); return; }
conoutf("sending map...");
defformatstring(mname, "sendmap_%d", lastmillis);
save_world(mname, true);
defformatstring(fname, "packages/maps/%s.ogz", mname);
stream *map = openrawfile(path(fname), "rb");
- if(map)
- {
+ if(map) {
stream::offset len = map->size();
if(len > 4*1024*1024) conoutf(CON_ERROR, "map is too large");
else if(len <= 0) conoutf(CON_ERROR, "could not read map");
- else
- {
+ else {
sendfile(-1, 2, map);
if(needclipboard >= 0) needclipboard++;
}
remove(findfile(fname, "rb"));
}
COMMAND(sendmap, "");
-
- void gotoplayer(const char *arg)
- {
+ void gotoplayer(const char *arg) {
if(player1->state!=CS_SPECTATOR && player1->state!=CS_EDITING) return;
int i = parseplayer(arg);
- if(i>=0)
- {
+ if(i>=0) {
fpsent *d = getclient(i);
if(!d || d==player1) return;
player1->o = d->o;
}
}
COMMANDN(goto, gotoplayer, "s");
-
- void gotosel()
- {
+ void gotosel() {
if(player1->state!=CS_EDITING) return;
player1->o = getselpos();
vec dir;
int pwitemspicked[7] = { 0 };
-namespace entities
-{
+namespace entities {
using namespace game;
-
int extraentinfosize() { return 0; } // size in bytes of what the 2 methods below read/write... so it can be skipped by other games
#ifndef STANDALONE
vector<extentity *> ents;
-
vector<extentity *> &getents() { return ents; }
-
bool mayattach(extentity &e) { return false; }
bool attachent(extentity &e, extentity &a) { return false; }
-
- const char *itemname(int i)
- {
+ const char *itemname(int i) {
int t = ents[i]->type;
if(t<I_SHELLS || t>I_QUAD) return NULL;
return itemstats[t-I_SHELLS].name;
}
-
- int itemicon(int i)
- {
+ int itemicon(int i) {
int t = ents[i]->type;
if(t<I_SHELLS || t>I_QUAD) return -1;
return itemstats[t-I_SHELLS].icon;
}
-
- const char *entmdlname(int type)
- {
- static const char * const entmdlnames[] =
- {
+ const char *entmdlname(int type) {
+ static const char * const entmdlnames[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"ammo/shells", "ammo/bullets", "ammo/rockets", "ammo/rrounds", "ammo/grenades", "ammo/cartridges",
"health", "boost", "tinyhealth", "tinyarmour", "armor/green", "armor/yellow", "quad", "teleporter",
};
return entmdlnames[type];
}
-
- const char *entmodel(const entity &e)
- {
- if(e.type == TELEPORT)
- {
+ const char *entmodel(const entity &e) {
+ if(e.type == TELEPORT) {
if(e.attr2 > 0) return mapmodelname(e.attr2);
if(e.attr2 < 0) return NULL;
}
return e.type < MAXENTTYPES ? entmdlname(e.type) : NULL;
}
-
- void preloadentities()
- {
- loopi(MAXENTTYPES)
- {
- switch(i)
- {
+ void preloadentities() {
+ loopi(MAXENTTYPES) {
+ switch(i) {
case I_SHELLS:
[[fallthrough]];
case I_BULLETS:
if(!mdl) continue;
preloadmodel(mdl);
}
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
- switch(e.type)
- {
+ switch(e.type) {
case TELEPORT:
if(e.attr2 > 0) preloadmodel(mapmodelname(e.attr2));
[[fallthrough]];
-
case JUMPPAD:
if(e.attr4 > 0) preloadmapsound(e.attr4);
break;
}
}
}
-
- void renderentities()
- {
- loopv(ents)
- {
+ void renderentities() {
+ loopv(ents) {
extentity &e = *ents[i];
int revs = 10;
- switch(e.type)
- {
+ switch(e.type) {
case TELEPORT:
if(e.attr2 < 0) continue;
break;
if(!e.spawned() || e.type < I_SHELLS || e.type > I_QUAD) continue;
}
const char *mdlname = entmodel(e);
- if(mdlname)
- {
+ if(mdlname) {
vec p = e.o;
p.z += 1+sinf(lastmillis/100.0+e.o.x+e.o.y)/20;
rendermodel(&e.light, mdlname, ANIM_MAPMODEL|ANIM_LOOP, p, lastmillis/(float)revs, 0, MDL_SHADOW | MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED);
}
}
}
-
- void addammo(int type, int &v, bool local)
- {
+ void addammo(int type, int &v, bool local) {
itemstat &is = itemstats[type-I_SHELLS];
v += is.add;
if(v>is.max) v = is.max;
if(local) msgsound(is.sound);
}
-
- void repammo(fpsent *d, int type, bool local)
- {
+ void repammo(fpsent *d, int type, bool local) {
addammo(type, d->ammo[type-I_SHELLS+GUN_SG], local);
}
-
// these two functions are called when the server acknowledges that you really
// picked up the item (in multiplayer someone may grab it before you).
-
- void pickupeffects(int n, fpsent *d)
- {
+ void pickupeffects(int n, fpsent *d) {
if(!ents.inrange(n)) return;
extentity *e = ents[n];
int type = e->type;
if(!d) return;
itemstat &is = itemstats[type-I_SHELLS];
fpsent *h = followingplayer(player1);
- if(d!=h || isthirdperson())
- {
+ if(d!=h || isthirdperson()) {
//particle_text(d->abovehead(), is.name, PART_TEXT, 2000, 0xFFC864, 4.0f, -8);
particle_icon(d->abovehead(), is.icon%4, is.icon/4, PART_HUD_ICON_GREY, 2000, 0xFFFFFF, 2.0f, -8);
}
case I_BOOST: pwitemspicked[5]++; break;
case I_QUAD: pwitemspicked[6]++; break;
}
- if(d==h) switch(type)
- {
+ if(d==h) switch(type) {
case I_BOOST:
conoutf(CON_GAMEINFO, "\f2you got the health boost!");
playsound(S_V_BOOST, NULL, NULL, 0, 0, 0, -1, 0, 3000);
break;
-
case I_QUAD:
conoutf(CON_GAMEINFO, "\f2you got the quad!");
playsound(S_V_QUAD, NULL, NULL, 0, 0, 0, -1, 0, 3000);
break;
}
}
-
// these functions are called when the client touches the item
-
- void teleporteffects(fpsent *d, int tp, int td, bool local)
- {
- if(ents.inrange(tp) && ents[tp]->type == TELEPORT)
- {
+ void teleporteffects(fpsent *d, int tp, int td, bool local) {
+ if(ents.inrange(tp) && ents[tp]->type == TELEPORT) {
extentity &e = *ents[tp];
- if(e.attr4 >= 0)
- {
+ if(e.attr4 >= 0) {
int snd = S_TELEPORT, flags = 0;
if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; }
fpsent *h = followingplayer(player1);
if(d!=h && ents.inrange(td) && ents[td]->type == TELEDEST) playsound(snd, &ents[td]->o, NULL, flags);
}
}
- if(local && d->clientnum >= 0)
- {
+ if(local && d->clientnum >= 0) {
sendposition(d);
packetbuf p(32, ENET_PACKET_FLAG_RELIABLE);
putint(p, N_TELEPORT);
flushclient();
}
}
-
- void jumppadeffects(fpsent *d, int jp, bool local)
- {
- if(ents.inrange(jp) && ents[jp]->type == JUMPPAD)
- {
+ void jumppadeffects(fpsent *d, int jp, bool local) {
+ if(ents.inrange(jp) && ents[jp]->type == JUMPPAD) {
extentity &e = *ents[jp];
- if(e.attr4 >= 0)
- {
+ if(e.attr4 >= 0) {
int snd = S_JUMPPAD, flags = 0;
if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; }
playsound(snd, d == followingplayer(player1) ? NULL : &e.o, NULL, flags);
}
}
- if(local && d->clientnum >= 0)
- {
+ if(local && d->clientnum >= 0) {
sendposition(d);
packetbuf p(16, ENET_PACKET_FLAG_RELIABLE);
putint(p, N_JUMPPAD);
flushclient();
}
}
-
- void teleport(int n, fpsent *d) // also used by monsters
- {
+ void teleport(int n, fpsent *d) { // also used by monsters {
int e = -1, tag = ents[n]->attr1, beenhere = -1;
- for(;;)
- {
+ for(;;) {
e = findentity(TELEDEST, e+1);
if(e==beenhere || e<0) { conoutf(CON_WARN, "no teleport destination for tag %d", tag); return; }
if(beenhere<0) beenhere = e;
- if(ents[e]->attr2==tag)
- {
+ if(ents[e]->attr2==tag) {
teleporteffects(d, n, e, true);
d->o = ents[e]->o;
d->yaw = ents[e]->attr1;
- if(ents[e]->attr3 > 0)
- {
+ if(ents[e]->attr3 > 0) {
vec dir;
vecfromyawpitch(d->yaw, 0, 1, 0, dir);
float speed = d->vel.magnitude2();
}
}
}
-
- void trypickup(int n, fpsent *d)
- {
+ void trypickup(int n, fpsent *d) {
extentity *e = ents[n];
- switch(e->type)
- {
+ switch(e->type) {
default:
- if(d->canpickup(e->type))
- {
+ if(d->canpickup(e->type)) {
addmsg(N_ITEMPICKUP, "rci", d, n);
e->setnopickup(); // even if someone else gets it first
}
break;
-
- case TELEPORT:
- {
+ case TELEPORT: {
if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<500) break;
- if(e->attr3 > 0)
- {
+ if(e->attr3 > 0) {
defformatstring(hookname, "can_teleport_%d", e->attr3);
if(!execidentbool(hookname, true)) break;
}
teleport(n, d);
break;
}
-
- case JUMPPAD:
- {
+ case JUMPPAD: {
if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<300) break;
d->lastpickup = e->type;
d->lastpickupmillis = lastmillis;
}
}
}
-
- void checkitems(fpsent *d)
- {
+ void checkitems(fpsent *d) {
if(d->state!=CS_ALIVE) return;
vec o = d->feetpos();
- loopv(ents)
- {
+ loopv(ents) {
extentity &e = *ents[i];
if(e.type==NOTUSED) continue;
if((!e.spawned() || e.nopickup()) && e.type!=TELEPORT && e.type!=JUMPPAD) continue;
if(dist<(e.type==TELEPORT ? 16 : 12)) trypickup(i, d);
}
}
-
- void checkquad(int time, fpsent *d)
- {
- if(d->quadmillis && (d->quadmillis -= time)<=0)
- {
+ void checkquad(int time, fpsent *d) {
+ if(d->quadmillis && (d->quadmillis -= time)<=0) {
d->quadmillis = 0;
fpsent *h = followingplayer(player1);
playsound(S_PUPOUT, d==h ? NULL : &d->o);
if(d==h) conoutf(CON_GAMEINFO, "\f2quad damage is over");
}
}
-
- void putitems(packetbuf &p) // puts items in network stream and also spawns them locally
- {
+ void putitems(packetbuf &p) { // puts items in network stream and also spawns them locally {
putint(p, N_ITEMLIST);
- loopv(ents) if(ents[i]->type>=I_SHELLS && ents[i]->type<=I_QUAD && (!m_noammo || ents[i]->type<I_SHELLS || ents[i]->type>I_CARTRIDGES))
- {
+ loopv(ents) if(ents[i]->type>=I_SHELLS && ents[i]->type<=I_QUAD && (!m_noammo || ents[i]->type<I_SHELLS || ents[i]->type>I_CARTRIDGES)) {
putint(p, i);
putint(p, ents[i]->type);
}
putint(p, -1);
}
-
void resetspawns() { loopv(ents) { extentity *e = ents[i]; e->clearspawned(); e->clearnopickup(); } }
-
- void spawnitems(bool force)
- {
+ void spawnitems(bool force) {
if(m_noitems) return;
- loopv(ents)
- {
+ loopv(ents) {
extentity *e = ents[i];
- if(e->type>=I_SHELLS && e->type<=I_QUAD && (!m_noammo || e->type<I_SHELLS || e->type>I_CARTRIDGES))
- {
+ if(e->type>=I_SHELLS && e->type<=I_QUAD && (!m_noammo || e->type<I_SHELLS || e->type>I_CARTRIDGES)) {
e->setspawned(force || !server::delayspawn(e->type));
e->clearnopickup();
}
}
}
-
void setspawn(int i, bool on) { if(ents.inrange(i)) { extentity *e = ents[i]; e->setspawned(on); e->clearnopickup(); } }
-
extentity *newentity() { return new extentity(); }
void deleteentity(extentity *e) { delete e; }
-
- void clearents()
- {
+ void clearents() {
while(ents.length()) deleteentity(ents.pop());
}
-
- void fixentity(extentity &e)
- {
+ void fixentity(extentity &e) {
if(e.type == TELEDEST) e.attr3 = e.attr2;
}
-
- void entradius(extentity &e, bool color)
- {
- switch(e.type)
- {
- case TELEDEST:
- {
+ void entradius(extentity &e, bool color) {
+ switch(e.type) {
+ case TELEDEST: {
vec dir;
vecfromyawpitch(e.attr1, 0, 1, 0, dir);
renderentarrow(e, dir, 4);
break;
}
case TELEPORT:
- loopv(ents) if(ents[i]->type == TELEDEST && e.attr1==ents[i]->attr2)
- {
+ loopv(ents) if(ents[i]->type == TELEDEST && e.attr1==ents[i]->attr2) {
renderentarrow(e, vec(ents[i]->o).sub(e.o).normalize(), e.o.dist(ents[i]->o));
break;
}
break;
-
case JUMPPAD:
renderentarrow(e, vec((int)(char)e.attr3*10.0f, (int)(char)e.attr2*10.0f, e.attr1*12.5f).normalize(), 4);
break;
-
default: break;
}
}
-
- bool printent(extentity &e, char *buf, int len)
- {
+ bool printent(extentity &e, char *buf, int len) {
return false;
}
-
const char *entnameinfo(entity &e) { return ""; }
- const char *entname(int i)
- {
- static const char * const entnames[] =
- {
+ const char *entname(int i) {
+ static const char * const entnames[] = {
"none?", "light", "mapmodel", "playerstart", "none?", "particles", "sound", "spotlight",
"shells", "bullets", "rockets", "riflerounds", "grenades", "cartridges",
"health", "healthboost", "tinyhealth", "tinyarmour", "greenarmour", "yellowarmour", "quaddamage",
};
return i>=0 && size_t(i)<sizeof(entnames)/sizeof(entnames[0]) ? entnames[i] : "";
}
-
- void editent(int i, bool local)
- {
+ void editent(int i, bool local) {
extentity &e = *ents[i];
if(local) addmsg(N_EDITENT, "rii3ii5", i, (int)(e.o.x*DMF), (int)(e.o.y*DMF), (int)(e.o.z*DMF), e.type, e.attr1, e.attr2, e.attr3, e.attr4, e.attr5);
}
A: 0 EXT_UPTIME
B: 0 EXT_PLAYERSTATS cn #a client number or -1 for all players#
C: 0 EXT_TEAMSCORE
-
Server:
--------
A: 0 EXT_UPTIME EXT_ACK EXT_VERSION uptime #in seconds#
EXT_PLAYERSTATS_RESP_IDS pid(s) #1 packet#
EXT_PLAYERSTATS_RESP_STATS pid playerdata #1 packet for each player#
C: 0 EXT_TEAMSCORE EXT_ACK EXT_VERSION 0 or 1 #error, no teammode# remaining_time gamemode loop(teamdata [numbases bases] or -1)
-
Errors:
--------------
B:C:default: 0 command EXT_ACK EXT_VERSION EXT_ERROR
*/
-
VAR(extinfoip, 0, 0, 1);
-
- void extinfoplayer(ucharbuf &p, clientinfo *ci)
- {
+ void extinfoplayer(ucharbuf &p, clientinfo *ci) {
ucharbuf q = p;
putint(q, EXT_PLAYERSTATS_RESP_STATS); // send player stats following
putint(q, ci->clientnum); //add player id
q.put((uchar*)&ip, 3);
sendserverinforeply(q);
}
-
- static inline void extinfoteamscore(ucharbuf &p, const char *team, int score)
- {
+ static inline void extinfoteamscore(ucharbuf &p, const char *team, int score) {
sendstring(team, p);
putint(p, score);
putint(p,-1); //no bases follow
}
-
- void extinfoteams(ucharbuf &p)
- {
+ void extinfoteams(ucharbuf &p) {
putint(p, m_teammode ? 0 : 1);
putint(p, gamemode);
putint(p, max((gamelimit - gamemillis)/1000, 0));
if(!m_teammode) return;
-
vector<teamscore> scores;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
- if(ci->state.state!=CS_SPECTATOR && ci->team[0] && scores.htfind(ci->team) < 0)
- {
+ if(ci->state.state!=CS_SPECTATOR && ci->team[0] && scores.htfind(ci->team) < 0) {
teaminfo *ti = teaminfos.access(ci->team);
scores.add(teamscore(ci->team, ti ? ti->frags : 0));
}
}
loopv(scores) extinfoteamscore(p, scores[i].team, scores[i].score);
}
-
- void extserverinforeply(ucharbuf &req, ucharbuf &p)
- {
+ void extserverinforeply(ucharbuf &req, ucharbuf &p) {
int extcmd = getint(req); // extended commands
-
//Build a new packet
putint(p, EXT_ACK); //send ack
putint(p, EXT_VERSION); //send version of extended info
-
- switch(extcmd)
- {
- case EXT_UPTIME:
- {
+ switch(extcmd) {
+ case EXT_UPTIME: {
putint(p, totalsecs); //in seconds
break;
}
-
- case EXT_PLAYERSTATS:
- {
+ case EXT_PLAYERSTATS: {
int cn = getint(req); //a special player, -1 for all
-
clientinfo *ci = NULL;
- if(cn >= 0)
- {
+ if(cn >= 0) {
loopv(clients) if(clients[i]->clientnum == cn) { ci = clients[i]; break; }
- if(!ci)
- {
+ if(!ci) {
putint(p, EXT_ERROR); //client requested by id was not found
sendserverinforeply(p);
return;
}
}
-
putint(p, EXT_NO_ERROR); //so far no error can happen anymore
-
ucharbuf q = p; //remember buffer position
putint(q, EXT_PLAYERSTATS_RESP_IDS); //send player ids following
if(ci) putint(q, ci->clientnum);
else loopv(clients) putint(q, clients[i]->clientnum);
sendserverinforeply(q);
-
if(ci) extinfoplayer(p, ci);
else loopv(clients) extinfoplayer(p, clients[i]);
return;
}
-
- case EXT_TEAMSCORE:
- {
+ case EXT_TEAMSCORE: {
extinfoteams(p);
break;
}
-
- default:
- {
+ default: {
putint(p, EXT_ERROR);
break;
}
}
sendserverinforeply(p);
}
-
#include "game.h"
-namespace game
-{
+namespace game {
bool intermission = false;
int maptime = 0, maprealtime = 0, maplimit = -1;
int respawnent = -1;
int lasthit = 0, lastspawnattempt = 0;
-
int following = -1, followdir = 0;
-
fpsent *player1 = NULL; // our client
vector<fpsent *> players; // other clients
int savedammo[NUMGUNS];
-
bool clientoption(const char *arg) { return false; }
-
- void taunt()
- {
+ void taunt() {
if(player1->state!=CS_ALIVE || player1->physstate<PHYS_SLOPE) return;
if(lastmillis-player1->lasttaunt<1000) return;
player1->lasttaunt = lastmillis;
addmsg(N_TAUNT, "rc", player1);
}
COMMAND(taunt, "");
-
- ICOMMAND(getfollow, "", (),
- {
+ ICOMMAND(getfollow, "", (), {
fpsent *f = followingplayer();
intret(f ? f->clientnum : -1);
});
-
- void follow(char *arg)
- {
- if(arg[0] ? player1->state==CS_SPECTATOR : following>=0)
- {
+ void follow(char *arg) {
+ if(arg[0] ? player1->state==CS_SPECTATOR : following>=0) {
following = arg[0] ? parseplayer(arg) : -1;
if(following==player1->clientnum) following = -1;
followdir = 0;
}
}
COMMAND(follow, "s");
-
- void nextfollow(int dir)
- {
- if(player1->state!=CS_SPECTATOR || clients.empty())
- {
+ void nextfollow(int dir) {
+ if(player1->state!=CS_SPECTATOR || clients.empty()) {
stopfollowing();
return;
}
int cur = following >= 0 ? following : (dir < 0 ? clients.length() - 1 : 0);
- loopv(clients)
- {
+ loopv(clients) {
cur = (cur + dir + clients.length()) % clients.length();
- if(clients[cur] && clients[cur]->state!=CS_SPECTATOR)
- {
+ if(clients[cur] && clients[cur]->state!=CS_SPECTATOR) {
if(following<0) conoutf("follow on");
following = cur;
followdir = dir;
}
ICOMMAND(nextfollow, "i", (int *dir), nextfollow(*dir < 0 ? -1 : 1));
-
const char *getclientmap() { return clientmap; }
-
- void resetgamestate()
- {
+ void resetgamestate() {
clearprojectiles();
clearbouncers();
}
-
- fpsent *spawnstate(fpsent *d) // reset player state not persistent accross spawns
- {
+ fpsent *spawnstate(fpsent *d) { // reset player state not persistent accross spawns {
d->respawn();
d->spawnstate(gamemode);
return d;
}
-
- void respawnself()
- {
+ void respawnself() {
if(ispaused()) return;
- if(m_mp(gamemode))
- {
+ if(m_mp(gamemode)) {
int seq = (player1->lifesequence<<16)|((lastmillis/1000)&0xFFFF);
if(player1->respawned!=seq) { addmsg(N_TRYSPAWN, "rc", player1); player1->respawned = seq; }
}
- else
- {
+ else {
spawnplayer(player1);
showscores(false);
lasthit = 0;
}
}
-
- fpsent *pointatplayer()
- {
+ fpsent *pointatplayer() {
loopv(players) if(players[i] != player1 && intersect(players[i], player1->o, worldpos)) return players[i];
return NULL;
}
-
- void stopfollowing()
- {
+ void stopfollowing() {
if(following<0) return;
following = -1;
followdir = 0;
conoutf("follow off");
}
-
- fpsent *followingplayer(fpsent *fallback)
- {
+ fpsent *followingplayer(fpsent *fallback) {
if(player1->state!=CS_SPECTATOR || following<0) return fallback;
fpsent *target = getclient(following);
if(target && target->state!=CS_SPECTATOR) return target;
return fallback;
}
-
- fpsent *hudplayer()
- {
+ fpsent *hudplayer() {
if(thirdperson && allowthirdperson()) return player1;
return followingplayer(player1);
}
-
- void setupcamera()
- {
+ void setupcamera() {
fpsent *target = followingplayer();
- if(target)
- {
+ if(target) {
player1->yaw = target->yaw;
player1->pitch = target->state==CS_DEAD ? 0 : target->pitch;
player1->o = target->o;
player1->resetinterp();
}
}
-
- bool allowthirdperson(bool msg)
- {
+ bool allowthirdperson(bool msg) {
return player1->state==CS_SPECTATOR || player1->state==CS_EDITING || m_edit || !multiplayer(msg);
}
ICOMMAND(allowthirdperson, "b", (int *msg), intret(allowthirdperson(*msg!=0) ? 1 : 0));
-
- bool detachcamera()
- {
+ bool detachcamera() {
fpsent *d = hudplayer();
return d->state==CS_DEAD;
}
-
- bool collidecamera()
- {
- switch(player1->state)
- {
+ bool collidecamera() {
+ switch(player1->state) {
case CS_EDITING: return false;
case CS_SPECTATOR: return followingplayer()!=NULL;
}
return true;
}
-
VARP(smoothmove, 0, 75, 100);
VARP(smoothdist, 0, 32, 64);
-
- void predictplayer(fpsent *d, bool move)
- {
+ void predictplayer(fpsent *d, bool move) {
d->o = d->newpos;
d->yaw = d->newyaw;
d->pitch = d->newpitch;
d->roll = d->newroll;
- if(move)
- {
+ if(move) {
moveplayer(d, 1, false);
d->newpos = d->o;
}
float k = 1.0f - float(lastmillis - d->smoothmillis)/smoothmove;
- if(k>0)
- {
+ if(k>0) {
d->o.add(vec(d->deltapos).mul(k));
d->yaw += d->deltayaw*k;
if(d->yaw<0) d->yaw += 360;
d->roll += d->deltaroll*k;
}
}
-
- void otherplayers(int curtime)
- {
- loopv(players)
- {
+ void otherplayers(int curtime) {
+ loopv(players) {
fpsent *d = players[i];
if(d == player1 || d->ai) continue;
-
if(d->state==CS_DEAD && d->ragdoll) moveragdoll(d);
- else if(!intermission)
- {
+ else if(!intermission) {
if(lastmillis - d->lastaction >= d->gunwait) d->gunwait = 0;
if(d->quadmillis) entities::checkquad(curtime, d);
}
-
const int lagtime = totalmillis-d->lastupdate;
if(!lagtime || intermission) continue;
- else if(lagtime>1000 && d->state==CS_ALIVE)
- {
+ else if(lagtime>1000 && d->state==CS_ALIVE) {
d->state = CS_LAGGED;
continue;
}
- if(d->state==CS_ALIVE || d->state==CS_EDITING)
- {
+ if(d->state==CS_ALIVE || d->state==CS_EDITING) {
if(smoothmove && d->smoothmillis>0) predictplayer(d, true);
else moveplayer(d, 1, false);
}
else if(d->state==CS_DEAD && !d->ragdoll && lastmillis-d->lastpain<2000) moveplayer(d, 1, true);
}
}
-
- void checkslowmo()
- {
+ void checkslowmo() {
static int lastslowmohealth = 0;
server::forcegamespeed(intermission ? 100 : clamp(player1->health, 25, 200));
- if(player1->health<player1->maxhealth && lastmillis-max(maptime, lastslowmohealth)>player1->health*player1->health/2)
- {
+ if(player1->health<player1->maxhealth && lastmillis-max(maptime, lastslowmohealth)>player1->health*player1->health/2) {
lastslowmohealth = lastmillis;
player1->health++;
}
}
-
- void updateworld() // main game update loop
- {
+ void updateworld() { // main game update loop {
if(!maptime) { maptime = lastmillis; maprealtime = totalmillis; return; }
if(!curtime) { gets2c(); if(player1->clientnum>=0) c2sinfo(); return; }
-
physicsframe();
ai::navigate();
- if(player1->state != CS_DEAD && !intermission)
- {
+ if(player1->state != CS_DEAD && !intermission) {
if(player1->quadmillis) entities::checkquad(curtime, player1);
}
updateweapons(curtime);
ai::update();
moveragdolls();
gets2c();
- if(connected)
- {
- if(player1->state == CS_DEAD)
- {
+ if(connected) {
+ if(player1->state == CS_DEAD) {
if(player1->ragdoll) moveragdoll(player1);
- else if(lastmillis-player1->lastpain<2000)
- {
+ else if(lastmillis-player1->lastpain<2000) {
player1->move = player1->strafe = 0;
moveplayer(player1, 10, true);
}
}
- else if(!intermission)
- {
+ else if(!intermission) {
if(player1->ragdoll) cleanragdoll(player1);
moveplayer(player1, 10, true);
swayhudgun(curtime);
}
if(player1->clientnum>=0) c2sinfo(); // do this last, to reduce the effective frame lag
}
-
- float proximityscore(float x, float lower, float upper)
- {
+ float proximityscore(float x, float lower, float upper) {
if(x <= lower) return 1.0f;
if(x >= upper) return 0.0f;
float a = x - lower, b = x - upper;
return (b * b) / (a * a + b * b);
}
-
static inline float harmonicmean(float a, float b) { return a + b > 0 ? 2 * a * b / (a + b) : 0.0f; }
-
// avoid spawning near other players
- float ratespawn(dynent *d, const extentity &e)
- {
+ float ratespawn(dynent *d, const extentity &e) {
fpsent *p = (fpsent *)d;
vec loc = vec(e.o).addz(p->eyeheight);
float maxrange = !m_noitems ? 400.0f : 110.0f;
float minplayerdist = maxrange;
- loopv(players)
- {
+ loopv(players) {
const fpsent *o = players[i];
- if(o == p)
- {
+ if(o == p) {
if(m_noitems || (o->state != CS_ALIVE && lastmillis - o->lastpain > 3000)) continue;
}
else if(o->state != CS_ALIVE || isteam(o->team, p->team)) continue;
-
vec dir = vec(o->o).sub(loc);
float dist = dir.squaredlen();
if(dist >= minplayerdist*minplayerdist) continue;
dist = sqrtf(dist);
dir.mul(1/dist);
-
// scale actual distance if not in line of sight
if(raycube(loc, dir, dist) < dist) dist *= 1.5f;
minplayerdist = min(minplayerdist, dist);
}
return 1.0f - proximityscore(minplayerdist, 80.0f, maxrange);
}
-
- void pickgamespawn(fpsent *d)
- {
+ void pickgamespawn(fpsent *d) {
int ent = d == player1 && respawnent >= 0 ? respawnent : -1;
findplayerspawn(d, ent, 0);
}
-
- void spawnplayer(fpsent *d) // place at random spawn
- {
+ void spawnplayer(fpsent *d) { // place at random spawn {
pickgamespawn(d);
spawnstate(d);
- if(d==player1)
- {
+ if(d==player1) {
if(editmode) d->state = CS_EDITING;
else if(d->state != CS_SPECTATOR) d->state = CS_ALIVE;
}
else d->state = CS_ALIVE;
}
-
VARP(spawnwait, 0, 0, 1000);
-
- void respawn()
- {
- if(player1->state==CS_DEAD)
- {
+ void respawn() {
+ if(player1->state==CS_DEAD) {
player1->attacking = false;
respawnself();
}
}
COMMAND(respawn, "");
-
// inputs
-
VARP(attackspawn, 0, 1, 1);
-
- void doattack(bool on)
- {
+ void doattack(bool on) {
if(!connected || intermission) return;
if((player1->attacking = on) && attackspawn) respawn();
}
-
VARP(jumpspawn, 0, 1, 1);
-
- bool canjump()
- {
+ bool canjump() {
if(!connected || intermission) return false;
if(jumpspawn) respawn();
return player1->state!=CS_DEAD;
}
-
- bool allowmove(physent *d)
- {
+ bool allowmove(physent *d) {
if(d->type!=ENT_PLAYER) return true;
return !((fpsent *)d)->lasttaunt || lastmillis-((fpsent *)d)->lasttaunt>=1000;
}
-
VARP(hitsound, 0, 0, 1);
-
- void damaged(int damage, fpsent *d, fpsent *actor, bool local)
- {
+ void damaged(int damage, fpsent *d, fpsent *actor, bool local) {
if((d->state!=CS_ALIVE && d->state != CS_LAGGED && d->state != CS_SPAWNING) || intermission) return;
-
if(local) damage = d->dodamage(damage);
else if(actor==player1) return;
-
fpsent *h = hudplayer();
- if(h!=player1 && actor==h && d!=actor)
- {
+ if(h!=player1 && actor==h && d!=actor) {
if(hitsound && lasthit != lastmillis) playsound(S_HIT);
lasthit = lastmillis;
}
- if(d==h)
- {
+ if(d==h) {
damagecompass(damage, actor->o);
}
damageeffect(damage, d, d!=h);
-
ai::damaged(d, actor);
-
if(d->health<=0) { if(local) killed(d, actor); }
else if(d==h) playsound(S_PAIN6);
else playsound(S_PAIN1+rnd(5), &d->o);
}
-
VARP(deathscore, 0, 1, 1);
-
- void deathstate(fpsent *d, bool restore)
- {
+ void deathstate(fpsent *d, bool restore) {
d->state = CS_DEAD;
d->lastpain = lastmillis;
if(!restore) d->deaths++;
-
- if(d==player1)
- {
+ if(d==player1) {
if(deathscore) showscores(true);
disablezoom();
if(!restore) loopi(NUMGUNS) savedammo[i] = player1->ammo[i];
d->roll = 0;
playsound(S_DIE1+rnd(2));
}
- else
- {
+ else {
d->move = d->strafe = 0;
d->resetinterp();
d->smoothmillis = 0;
playsound(S_DIE1+rnd(2), &d->o);
}
}
-
VARP(teamcolorfrags, 0, 1, 1);
-
/// xolatile: HUD frag messages
#define fragmessageduration (2000)
-
string hudfragger, hudfragged;
int hudfraggun, hudfragmillis;
-
- void sethudfragdata(char *fragger, char *fragged, int gunid)
- {
+ void sethudfragdata(char *fragger, char *fragged, int gunid) {
copystring(hudfragger, fragger ? fragger : "");
copystring(hudfragged, fragged);
hudfraggun = gunid;
hudfragmillis = lastmillis;
}
-
- void killed(fpsent *d, fpsent *actor)
- {
- if(d->state==CS_EDITING)
- {
+ void killed(fpsent *d, fpsent *actor) {
+ if(d->state==CS_EDITING) {
d->editstate = CS_DEAD;
d->deaths++;
if(d!=player1) d->resetinterp();
return;
}
else if((d->state!=CS_ALIVE && d->state != CS_LAGGED && d->state != CS_SPAWNING) || intermission) return;
-
fpsent *h = followingplayer(player1);
int contype = d==h || actor==h ? CON_FRAG_SELF : CON_FRAG_OTHER;
const char *dname = "", *aname = "";
- if(m_teammode && teamcolorfrags)
- {
+ if(m_teammode && teamcolorfrags) {
dname = teamcolorname(d, "you");
aname = teamcolorname(actor, "you");
}
- else
- {
+ else {
dname = colorname(d, NULL, "", "", "you");
aname = colorname(actor, NULL, "", "", "you");
}
conoutf(contype, "\f2%s got killed by %s!", dname, aname);
else if(d==actor || actor->type==ENT_INANIMATE)
conoutf(contype, "\f2%s suicided%s", dname, d==player1 ? "!" : "");
- else if(isteam(d->team, actor->team))
- {
+ else if(isteam(d->team, actor->team)) {
contype |= CON_TEAMKILL;
if(actor==player1) conoutf(contype, "\f6%s fragged a teammate (%s)", aname, dname);
else if(d==player1) conoutf(contype, "\f6%s got fragged by a teammate (%s)", dname, aname);
else conoutf(contype, "\f2%s fragged a teammate (%s)", aname, dname);
}
- else
- {
- if(d==player1)
- {
+ else {
+ if(d==player1) {
conoutf(contype, "\f2%s got fragged by %s", dname, aname);
sethudfragdata(actor->name, d->name, actor->gunselect);
}
- else
- {
+ else {
conoutf(contype, "\f2%s fragged %s", aname, dname);
sethudfragdata(actor->name, d->name, actor->gunselect);
}
deathstate(d);
ai::killed(d, actor);
}
-
- void timeupdate(int secs)
- {
+ void timeupdate(int secs) {
server::timeupdate(secs);
- if(secs > 0)
- {
+ if(secs > 0) {
maplimit = lastmillis + secs*1000;
}
- else
- {
+ else {
intermission = true;
player1->attacking = false;
conoutf(CON_GAMEINFO, "\f2intermission:");
conoutf(CON_GAMEINFO, "\f2player frags: %d, deaths: %d", player1->frags, player1->deaths);
int accuracy = (player1->totaldamage*100)/max(player1->totalshots, 1);
conoutf(CON_GAMEINFO, "\f2player total damage dealt: %d, damage wasted: %d, accuracy(%%): %d", player1->totaldamage, player1->totalshots-player1->totaldamage, accuracy);
-
showscores(true);
disablezoom();
-
execident("intermission");
}
}
-
ICOMMAND(getfrags, "", (), intret(player1->frags));
ICOMMAND(getflags, "", (), intret(player1->flags));
ICOMMAND(getdeaths, "", (), intret(player1->deaths));
ICOMMAND(getaccuracy, "", (), intret((player1->totaldamage*100)/max(player1->totalshots, 1)));
ICOMMAND(gettotaldamage, "", (), intret(player1->totaldamage));
ICOMMAND(gettotalshots, "", (), intret(player1->totalshots));
-
vector<fpsent *> clients;
-
- fpsent *newclient(int cn) // ensure valid entity
- {
- if(cn < 0 || cn > max(0xFF, MAXCLIENTS + MAXBOTS))
- {
+ fpsent *newclient(int cn) { // ensure valid entity {
+ if(cn < 0 || cn > max(0xFF, MAXCLIENTS + MAXBOTS)) {
neterr("clientnum", false);
return NULL;
}
-
if(cn == player1->clientnum) return player1;
-
while(cn >= clients.length()) clients.add(NULL);
- if(!clients[cn])
- {
+ if(!clients[cn]) {
fpsent *d = new fpsent;
d->clientnum = cn;
clients[cn] = d;
}
return clients[cn];
}
-
- fpsent *getclient(int cn) // ensure valid entity
- {
+ fpsent *getclient(int cn) { // ensure valid entity {
if(cn == player1->clientnum) return player1;
return clients.inrange(cn) ? clients[cn] : NULL;
}
-
- void clientdisconnected(int cn, bool notify)
- {
+ void clientdisconnected(int cn, bool notify) {
if(!clients.inrange(cn)) return;
- if(following==cn)
- {
+ if(following==cn) {
if(followdir) nextfollow(followdir);
else stopfollowing();
}
DELETEP(clients[cn]);
cleardynentcache();
}
-
- void clearclients(bool notify)
- {
+ void clearclients(bool notify) {
loopv(clients) if(clients[i]) clientdisconnected(i, notify);
}
-
- void initclient()
- {
+ void initclient() {
player1 = spawnstate(new fpsent);
filtertext(player1->name, "Anonymous", false, false, MAXNAMELEN);
players.add(player1);
}
-
VARP(showmodeinfo, 0, 1, 1);
-
- void startgame()
- {
+ void startgame() {
clearprojectiles();
clearbouncers();
clearragdolls();
-
clearteaminfo();
-
// reset perma-state
- loopv(players)
- {
+ loopv(players) {
fpsent *d = players[i];
d->frags = d->flags = 0;
d->deaths = 0;
d->lifesequence = -1;
d->respawned = d->suicided = -2;
}
-
intermission = false;
maptime = maprealtime = 0;
maplimit = -1;
-
conoutf(CON_GAMEINFO, "\f2game mode is %s", server::modename(gamemode));
-
const char *info = m_valid(gamemode) ? gamemodes[gamemode - STARTGAMEMODE].info : NULL;
if(showmodeinfo && info) conoutf(CON_GAMEINFO, "\f0%s", info);
-
showscores(false);
disablezoom();
lasthit = 0;
-
execident("mapstart");
}
-
- void loadingmap(const char *name)
- {
+ void loadingmap(const char *name) {
execident("playsong");
}
-
- void startmap(const char *name) // called just after a map load
- {
+ void startmap(const char *name) { // called just after a map load {
pwreset();
ai::savewaypoints();
ai::clearwaypoints(true);
-
respawnent = -1; // so we don't respawn at an old spot
if(!m_mp(gamemode)) spawnplayer(player1);
else findplayerspawn(player1, -1);
entities::resetspawns();
copystring(clientmap, name ? name : "");
-
sendmapinfo();
}
-
- const char *getmapinfo()
- {
+ const char *getmapinfo() {
return showmodeinfo && m_valid(gamemode) ? gamemodes[gamemode - STARTGAMEMODE].info : NULL;
}
-
- const char *getscreenshotinfo()
- {
+ const char *getscreenshotinfo() {
return server::modename(gamemode, NULL);
}
-
- void physicstrigger(physent *d, bool local, int floorlevel, int material)
- {
+ void physicstrigger(physent *d, bool local, int floorlevel, int material) {
if(d->type==ENT_INANIMATE) return;
if (floorlevel>0) { if(d==player1 || d->type!=ENT_PLAYER || ((fpsent *)d)->ai) msgsound(S_JUMP, d); }
else if(floorlevel<0) { if(d==player1 || d->type!=ENT_PLAYER || ((fpsent *)d)->ai) msgsound(S_LAND, d); }
}
-
- void dynentcollide(physent *d, physent *o, const vec &dir)
- {
+ void dynentcollide(physent *d, physent *o, const vec &dir) {
return;
}
-
- void msgsound(int n, physent *d)
- {
- if(!d || d==player1)
- {
+ void msgsound(int n, physent *d) {
+ if(!d || d==player1) {
addmsg(N_SOUND, "ci", d, n);
playsound(n);
}
- else
- {
+ else {
if(d->type==ENT_PLAYER && ((fpsent *)d)->ai)
addmsg(N_SOUND, "ci", d, n);
playsound(n, &d->o);
}
}
-
int numdynents() { return players.length(); }
-
- dynent *iterdynents(int i)
- {
+ dynent *iterdynents(int i) {
if(i<players.length()) return players[i];
i -= players.length();
return NULL;
}
-
- bool duplicatename(fpsent *d, const char *name = NULL, const char *alt = NULL)
- {
+ bool duplicatename(fpsent *d, const char *name = NULL, const char *alt = NULL) {
if(!name) name = d->name;
if(alt && d != player1 && !strcmp(name, alt)) return true;
loopv(players) if(d!=players[i] && !strcmp(name, players[i]->name)) return true;
return false;
}
-
static string cname[3];
static int cidx = 0;
-
- const char *colorname(fpsent *d, const char *name, const char *prefix, const char *suffix, const char *alt)
- {
+ const char *colorname(fpsent *d, const char *name, const char *prefix, const char *suffix, const char *alt) {
if(!name) name = alt && d == player1 ? alt : d->name;
bool dup = !name[0] || duplicatename(d, name, alt) || d->aitype != AI_NONE;
- if(dup || prefix[0] || suffix[0])
- {
+ if(dup || prefix[0] || suffix[0]) {
cidx = (cidx+1)%3;
if(dup) formatstring(cname[cidx], d->aitype == AI_NONE ? "%s%s \fs\f5(%d)\fr%s" : "%s%s \fs\f5[%d]\fr%s", prefix, name, d->clientnum, suffix);
else formatstring(cname[cidx], "%s%s%s", prefix, name, suffix);
}
return name;
}
-
VARP(teamcolortext, 0, 1, 1);
-
- const char *teamcolorname(fpsent *d, const char *alt)
- {
+ const char *teamcolorname(fpsent *d, const char *alt) {
if(!teamcolortext || !m_teammode || d->state==CS_SPECTATOR) return colorname(d, NULL, "", "", alt);
return colorname(d, NULL, isteam(d->team, player1->team) ? "\fs\f1" : "\fs\f3", "\fr", alt);
}
-
- const char *teamcolor(const char *name, bool sameteam, const char *alt)
- {
+ const char *teamcolor(const char *name, bool sameteam, const char *alt) {
if(!teamcolortext || !m_teammode) return sameteam || !alt ? name : alt;
cidx = (cidx+1)%3;
formatstring(cname[cidx], sameteam ? "\fs\f1%s\fr" : "\fs\f3%s\fr", sameteam || !alt ? name : alt);
return cname[cidx];
}
-
- const char *teamcolor(const char *name, const char *team, const char *alt)
- {
+ const char *teamcolor(const char *name, const char *team, const char *alt) {
return teamcolor(name, team && isteam(team, player1->team), alt);
}
-
VARP(teamsounds, 0, 1, 1);
-
- void teamsound(bool sameteam, int n, const vec *loc)
- {
+ void teamsound(bool sameteam, int n, const vec *loc) {
playsound(n, loc, NULL, teamsounds ? (m_teammode && sameteam ? SND_USE_ALT : SND_NO_ALT) : 0);
}
-
- void teamsound(fpsent *d, int n, const vec *loc)
- {
+ void teamsound(fpsent *d, int n, const vec *loc) {
teamsound(isteam(d->team, player1->team), n, loc);
}
-
- void suicide(physent *d)
- {
- if(d==player1 || (d->type==ENT_PLAYER && ((fpsent *)d)->ai))
- {
+ void suicide(physent *d) {
+ if(d==player1 || (d->type==ENT_PLAYER && ((fpsent *)d)->ai)) {
if(d->state!=CS_ALIVE) return;
fpsent *pl = (fpsent *)d;
if(!m_mp(gamemode)) killed(pl, pl);
- else
- {
+ else {
int seq = (pl->lifesequence<<16)|((lastmillis/1000)&0xFFFF);
if(pl->suicided!=seq) { addmsg(N_SUICIDE, "rc", pl); pl->suicided = seq; }
}
}
}
ICOMMAND(suicide, "", (), suicide(player1));
-
- void drawicon(int icon, float x, float y, float sz)
- {
+ void drawicon(int icon, float x, float y, float sz) {
settexture("packages/hud/items.png");
float tsz = 0.25f, tx = tsz*(icon%4), ty = tsz*(icon/4);
gle::defvertex(2);
gle::attribf(x+sz, y+sz); gle::attribf(tx+tsz, ty+tsz);
gle::end();
}
-
- float abovegameplayhud(int w, int h)
- {
- switch(hudplayer()->state)
- {
+ float abovegameplayhud(int w, int h) {
+ switch(hudplayer()->state) {
case CS_EDITING:
case CS_SPECTATOR:
return 1;
return 1650.0f/1800.0f;
}
}
-
int ammohudup[3] = { GUN_CG, GUN_RL, GUN_GL },
ammohuddown[3] = { GUN_RIFLE, GUN_SG, GUN_PISTOL },
ammohudcycle[7] = { -1, -1, -1, -1, -1, -1, -1 };
-
- ICOMMAND(ammohudup, "V", (tagval *args, int numargs),
- {
+ ICOMMAND(ammohudup, "V", (tagval *args, int numargs), {
loopi(3) ammohudup[i] = i < numargs ? getweapon(args[i].getstr()) : -1;
});
-
- ICOMMAND(ammohuddown, "V", (tagval *args, int numargs),
- {
+ ICOMMAND(ammohuddown, "V", (tagval *args, int numargs), {
loopi(3) ammohuddown[i] = i < numargs ? getweapon(args[i].getstr()) : -1;
});
-
- ICOMMAND(ammohudcycle, "V", (tagval *args, int numargs),
- {
+ ICOMMAND(ammohudcycle, "V", (tagval *args, int numargs), {
loopi(7) ammohudcycle[i] = i < numargs ? getweapon(args[i].getstr()) : -1;
});
-
VARP(ammohud, 0, 1, 1);
-
- void drawammohud(fpsent *d)
- {
+ void drawammohud(fpsent *d) {
float x = HICON_X + 2*HICON_STEP, y = HICON_Y, sz = HICON_SIZE;
pushhudmatrix();
hudmatrix.scale(1/3.2f, 1/3.2f, 1);
flushhudmatrix();
float xup = (x+sz)*3.2f, yup = y*3.2f + 0.1f*sz;
- loopi(3)
- {
+ loopi(3) {
int gun = ammohudup[i];
if(gun < GUN_FIST || gun > GUN_PISTOL || gun == d->gunselect || !d->ammo[gun]) continue;
drawicon(HICON_FIST+gun, xup, yup, sz);
yup += sz;
}
float xdown = x*3.2f - sz, ydown = (y+sz)*3.2f - 0.1f*sz;
- loopi(3)
- {
+ loopi(3) {
int gun = ammohuddown[3-i-1];
if(gun < GUN_FIST || gun > GUN_PISTOL || gun == d->gunselect || !d->ammo[gun]) continue;
ydown -= sz;
drawicon(HICON_FIST+gun, xdown, ydown, sz);
}
int offset = 0, num = 0;
- loopi(7)
- {
+ loopi(7) {
int gun = ammohudcycle[i];
if(gun < GUN_FIST || gun > GUN_PISTOL) continue;
if(gun == d->gunselect) offset = i + 1;
else if(d->ammo[gun]) num++;
}
float xcycle = (x+sz/2)*3.2f + 0.5f*num*sz, ycycle = y*3.2f-sz;
- loopi(7)
- {
+ loopi(7) {
int gun = ammohudcycle[(i + offset)%7];
if(gun < GUN_FIST || gun > GUN_PISTOL || gun == d->gunselect || !d->ammo[gun]) continue;
xcycle -= sz;
}
pophudmatrix();
}
-
- void hudquad(float x, float y, float w, float h, float r = 1, float g = 1, float b = 1, float tx = 0, float ty = 0, float tw = 1, float th = 1)
- {
+ void hudquad(float x, float y, float w, float h, float r = 1, float g = 1, float b = 1, float tx = 0, float ty = 0, float tw = 1, float th = 1) {
gle::defvertex(2);
gle::deftexcoord0();
gle::colorf(r, g, b);
gle::attribf(x+w, y+h); gle::attribf(tx + tw, ty + th);
gle::end();
}
-
VARP(healthcolors, 0, 1, 1);
-
VARP(hudhealth, 0, 1, 1);
FVARP(hudhealthx, 0, 0, 1);
FVARP(hudhealthy, 0, 1, 1);
FVARP(hudhealthscale, 0.1, 1.0, 1.0);
-
- void drawhudhealth(fpsent *d, int w, int h)
- {
+ void drawhudhealth(fpsent *d, int w, int h) {
pushhudmatrix();
hudmatrix.scale(hudhealthscale, hudhealthscale, 1);
flushhudmatrix();
-
bvec healthcolor = bvec::hexcolor(healthcolors && !m_insta ?
(d->state==CS_DEAD ? 0x808080 :
(d->health<=25 ? 0xc02020 :
defformatstring(health, "%d", d->state==CS_DEAD ? 0 : d->health);
float tw=0, th=0; text_boundsf(health, tw, th);
draw_text(health, offset.x+(125*proportion-tw)/2, offset.y+(healthbarh-th)/2, healthcolor.r, healthcolor.g, healthcolor.b);
-
pophudmatrix();
}
-
VARP(hudmaxhealth, 0, 1, 1);
FVARP(hudmaxhealthx, 0, 0.207, 1);
FVARP(hudmaxhealthy, 0, 0.97, 1);
FVARP(hudmaxhealthscale, 0.1, 1.0, 1.0);
-
- void drawhudmaxhealth(fpsent *d, int w, int h)
- {
+ void drawhudmaxhealth(fpsent *d, int w, int h) {
pushhudmatrix();
hudmatrix.scale(hudmaxhealthscale, hudmaxhealthscale, 1);
flushhudmatrix();
-
const float proportion = (w/15.0f)/160.0f;
const float healthboostw = 160*proportion;
const float healthboosth = 78*proportion;
settexture("packages/hud/health_boost_quad.png");
hudquad(offset.x, offset.y, healthboostw, healthboosth);
}
-
pophudmatrix();
}
-
VARP(armourcolors, 0, 1, 1);
-
VARP(hudarmour, 0, 1, 1);
FVARP(hudarmourx, 0, 1, 1);
FVARP(hudarmoury, 0, 1, 1);
FVARP(hudarmourscale, 0.1, 1.0, 1.0);
-
- void drawhudarmour(fpsent *d, int w, int h)
- {
+ void drawhudarmour(fpsent *d, int w, int h) {
pushhudmatrix();
hudmatrix.scale(hudarmourscale, hudarmourscale, 1);
flushhudmatrix();
-
bvec armourcolor = bvec::hexcolor(d->armourtype == A_BLUE ? 0x83ade5 : (d->armourtype == A_GREEN ? 0x77f29e : (d->armourtype == A_YELLOW ? 0xf5f19b : 0xffffff)));
const float proportion = (w/4.0f)/600.0f;
const float armourbarw = 600*proportion;
defformatstring(armour, "%d", d->state==CS_DEAD ? 0 : d->armour);
float tw=0, th=0; text_boundsf(armour, tw, th);
draw_text(armour, offset.x+(2*(600-63)*proportion-tw)/2, offset.y+(armourbarh-th)/2, armourcolor.r, armourcolor.g, armourcolor.b);
-
pophudmatrix();
}
-
- void drawhudicons(fpsent *d, int w, int h)
- {
+ void drawhudicons(fpsent *d, int w, int h) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
-
if(hudhealth) drawhudhealth(d, w, h);
if(hudmaxhealth) drawhudmaxhealth(d, w, h);
if(hudarmour) drawhudarmour(d, w, h);
-
if(d->state!=CS_DEAD) {
drawicon(HICON_FIST+d->gunselect, HICON_X + 2*HICON_STEP, HICON_Y);
if(ammohud) drawammohud(d);
}
}
-
VARP(gameclock, 0, 0, 1);
FVARP(gameclockscale, 1e-3f, 0.75f, 1e3f);
HVARP(gameclockcolour, 0, 0xFFFFFF, 0xFFFFFF);
VARP(gameclockalign, -1, 0, 1);
FVARP(gameclockx, 0, 0.50f, 1);
FVARP(gameclocky, 0, 0.03f, 1);
-
- void drawgameclock(int w, int h)
- {
+ void drawgameclock(int w, int h) {
int secs = max(maplimit-lastmillis + 999, 0)/1000, mins = secs/60;
secs %= 60;
-
defformatstring(buf, "%d:%02d", mins, secs);
int tw = 0, th = 0;
text_bounds(buf, tw, th);
-
vec2 offset = vec2(gameclockx, gameclocky).mul(vec2(w, h).div(gameclockscale));
if(gameclockalign == 1) offset.x -= tw;
else if(gameclockalign == 0) offset.x -= tw/2.0f;
offset.y -= th/2.0f;
-
pushhudmatrix();
hudmatrix.scale(gameclockscale, gameclockscale, 1);
flushhudmatrix();
-
int color = mins < 1 ? gameclocklowcolour : gameclockcolour;
draw_text(buf, int(offset.x), int(offset.y), (color>>16)&0xFF, (color>>8)&0xFF, color&0xFF, gameclockalpha);
-
pophudmatrix();
}
-
extern int hudscore;
extern void drawhudscore(int w, int h);
-
VARP(ammobar, 0, 0, 1);
VARP(ammobaralign, -1, 0, 1);
VARP(ammobarhorizontal, 0, 0, 1);
FVARP(ammobarx, 0, 0.025f, 1.0f);
FVARP(ammobary, 0, 0.5f, 1.0f);
FVARP(ammobarscale, 0.1f, 0.5f, 1.0f);
-
- void drawammobarcounter(const vec2 ¢er, const fpsent *p, int gun)
- {
+ void drawammobarcounter(const vec2 ¢er, const fpsent *p, int gun) {
vec2 icondrawpos = vec2(center).sub(HICON_SIZE / 2);
int alpha = p->ammo[gun] ? 0xFF : 0x7F;
gle::color(bvec(0xFF, 0xFF, 0xFF), alpha);
drawicon(HICON_FIST + gun, icondrawpos.x, icondrawpos.y);
-
int fw, fh; text_bounds("000", fw, fh);
float labeloffset = HICON_SIZE / 2.0f + ammobarcountsep + ammobarcountscale * (ammobarhorizontal ? fh : fw) / 2.0f;
vec2 offsetdir = (ammobarhorizontal ? vec2(0, 1) : vec2(1, 0)).mul(ammobarflip ? -1 : 1);
vec2 labelorigin = vec2(offsetdir).mul(labeloffset).add(center);
-
pushhudmatrix();
hudmatrix.translate(labelorigin.x, labelorigin.y, 0);
hudmatrix.scale(ammobarcountscale, ammobarcountscale, 1);
flushhudmatrix();
-
defformatstring(label, "%d", p->ammo[gun]);
int tw, th; text_bounds(label, tw, th);
vec2 textdrawpos = vec2(-tw, -th).div(2);
float ammoratio = (float)p->ammo[gun] / itemstats[gun-GUN_SG].add;
bvec color = bvec::hexcolor(p->ammo[gun] == 0 || ammoratio >= 1.0f ? 0xFFFFFF : (ammoratio >= 0.5f ? 0xFFC040 : 0xFF0000));
draw_text(label, textdrawpos.x, textdrawpos.y, color.r, color.g, color.b, alpha);
-
pophudmatrix();
}
-
- static inline bool ammobargunvisible(const fpsent *d, int gun)
- {
+ static inline bool ammobargunvisible(const fpsent *d, int gun) {
return d->ammo[gun] > 0 || d->gunselect == gun;
}
-
- void drawammobar(int w, int h, fpsent *p)
- {
+ void drawammobar(int w, int h, fpsent *p) {
if(m_insta) return;
-
int NUMPLAYERGUNS = GUN_PISTOL - GUN_SG + 1;
int numvisibleguns = NUMPLAYERGUNS;
if(ammobarhideempty) loopi(NUMPLAYERGUNS) if(!ammobargunvisible(p, GUN_SG + i)) numvisibleguns--;
-
vec2 origin = vec2(ammobarx, ammobary).mul(vec2(w, h).div(ammobarscale));
vec2 offsetdir = ammobarhorizontal ? vec2(1, 0) : vec2(0, 1);
float stepsize = HICON_SIZE + ammobarsep;
float initialoffset = (ammobaralign - 1) * (numvisibleguns - 1) * stepsize / 2;
-
pushhudmatrix();
hudmatrix.scale(ammobarscale, ammobarscale, 1);
flushhudmatrix();
-
int numskippedguns = 0;
- loopi(NUMPLAYERGUNS) if(ammobargunvisible(p, GUN_SG + i) || !ammobarhideempty)
- {
+ loopi(NUMPLAYERGUNS) if(ammobargunvisible(p, GUN_SG + i) || !ammobarhideempty) {
float offset = initialoffset + (i - numskippedguns) * stepsize;
vec2 drawpos = vec2(offsetdir).mul(offset).add(origin);
drawammobarcounter(drawpos, p, GUN_SG + i);
}
else numskippedguns++;
-
pophudmatrix();
}
-
VARP(speedometer, 0, 1, 1);
FVARP(speedometerx, 0.0, 0.5, 1.0);
FVARP(speedometery, 0.0, 0.6, 1.0);
FVARP(speedometerscale, 0.1, 0.5, 1.0);
VARP(speedometercolor, 0, 1, 1);
FVARP(speedometeralpha, 0.0, 0.5, 1.0);
-
- void drawspeedometer(fpsent *d, int w, int h)
- {
+ void drawspeedometer(fpsent *d, int w, int h) {
int speedforreal = (int) (sqrtf(d->vel.squaredlen()) + 1.0f);
speedforreal = (speedforreal == 1) ? 0 : speedforreal;
vec colour = vec(255, 255, 255);
else if (speedforreal>180 && speedforreal<=240) colour = vec(90, 180, 60);
else colour = vec(30, 240, 30);
}
-
defformatstring(speedstring, "%d", speedforreal);
text_boundsf(speedstring, realw, realh);
vec2 offset = vec2(speedometerx, speedometery).mul(vec2(w, h).div(speedometerscale));
offset.x -= realw/2.0f;
offset.y -= realh/2.0f;
-
pushhudmatrix();
hudmatrix.scale(speedometerscale, speedometerscale, 1);
flushhudmatrix();
-
const int speedow = 220;
const int speedoh = 101;
settexture("packages/hud/speedometer.png");
hudquad(offset.x+realw/2.0f-speedow/2, offset.y+realh/2.0f-speedoh/2, speedow, speedoh);
-
draw_text(speedstring, int(offset.x), int(offset.y), colour.x, colour.y, colour.z, (int)(speedometeralpha*255.0f));
-
pophudmatrix();
}
-
- void gameplayhud(int w, int h)
- {
+ void gameplayhud(int w, int h) {
pushhudmatrix();
hudmatrix.scale(h/1800.0f, h/1800.0f, 1);
flushhudmatrix();
-
- if(player1->state==CS_SPECTATOR)
- {
+ if(player1->state==CS_SPECTATOR) {
int pw, ph, tw, th, fw, fh;
text_bounds(" ", pw, ph);
text_bounds("SPECTATOR", tw, th);
text_bounds(f ? colorname(f) : " ", fw, fh);
fh = max(fh, ph);
draw_text("SPECTATOR", w*1800/h - tw - pw, 1650 - th - fh);
- if(f)
- {
+ if(f) {
int color = statuscolor(f, 0xFFFFFF);
draw_text(colorname(f), w*1800/h - fw - pw, 1650 - fh, (color>>16)&0xFF, (color>>8)&0xFF, color&0xFF);
}
}
-
fpsent *d = hudplayer();
-
pophudmatrix();
-
if(d->state!=CS_EDITING && d->state!=CS_SPECTATOR) drawhudicons(d, w, h);
-
- if(d->state!=CS_EDITING && d->state!=CS_SPECTATOR && d->state!=CS_DEAD)
- {
+ if(d->state!=CS_EDITING && d->state!=CS_SPECTATOR && d->state!=CS_DEAD) {
if(ammobar) drawammobar(w, h, d);
if(speedometer) drawspeedometer(d, w, h);
}
-
- if(!m_edit)
- {
+ if(!m_edit) {
if(gameclock) drawgameclock(w, h);
if(hudscore) drawhudscore(w, h);
}
-
/// Frag message.
-
- if((hudfragmillis+fragmessageduration > lastmillis) && (lastmillis>fragmessageduration))
- {
+ if((hudfragmillis+fragmessageduration > lastmillis) && (lastmillis>fragmessageduration)) {
vec2 center = vec2(0.5*w, 0.2*h);
float width = 0, height = 0;
pushhudmatrix();
pophudmatrix();
}
}
-
- int clipconsole(int w, int h)
- {
+ int clipconsole(int w, int h) {
return 0;
}
-
VARP(teamcrosshair, 0, 1, 1);
VARP(hitcrosshair, 0, 425, 1000);
-
- const char *defaultcrosshair(int index)
- {
- switch(index)
- {
+ const char *defaultcrosshair(int index) {
+ switch(index) {
case 2: return "data/hit.png";
case 1: return "data/teammate.png";
default: return "data/crosshair.png";
}
}
-
- int selectcrosshair(vec &color)
- {
+ int selectcrosshair(vec &color) {
fpsent *d = hudplayer();
if(d->state==CS_SPECTATOR || d->state==CS_DEAD) return -1;
-
if(d->state!=CS_ALIVE) return 0;
-
int crosshair = 0;
if(lasthit && lastmillis - lasthit < hitcrosshair) crosshair = 2;
- else if(teamcrosshair)
- {
+ else if(teamcrosshair) {
dynent *o = intersectclosest(d->o, worldpos, d);
- if(o && o->type==ENT_PLAYER && isteam(((fpsent *)o)->team, d->team))
- {
+ if(o && o->type==ENT_PLAYER && isteam(((fpsent *)o)->team, d->team)) {
crosshair = 1;
color = vec(0, 0, 1);
}
}
-
- if(crosshair!=1 && !editmode && !m_insta)
- {
+ if(crosshair!=1 && !editmode && !m_insta) {
if(d->health<=25) color = vec(1, 0, 0);
else if(d->health<=50) color = vec(1, 0.5f, 0);
}
if(d->gunwait) color.mul(0.5f);
return crosshair;
}
-
- void lighteffects(dynent *e, vec &color, vec &dir)
- {
+ void lighteffects(dynent *e, vec &color, vec &dir) {
#if 0
fpsent *d = (fpsent *)e;
- if(d->state!=CS_DEAD && d->quadmillis)
- {
+ if(d->state!=CS_DEAD && d->quadmillis) {
float t = 0.5f + 0.5f*sinf(2*M_PI*lastmillis/1000.0f);
color.y = color.y*(1-t) + t;
}
#endif
}
-
- int maxsoundradius(int n)
- {
- switch(n)
- {
+ int maxsoundradius(int n) {
+ switch(n) {
case S_JUMP:
case S_LAND:
case S_WEAPLOAD:
return 500;
}
}
-
- bool serverinfostartcolumn(g3d_gui *g, int i)
- {
+ bool serverinfostartcolumn(g3d_gui *g, int i) {
static const char * const names[] = { "ping ", "players ", "mode ", "map ", "time ", "master ", "host ", "port ", "description " };
- static const float struts[] = { 7, 7, 12.5f, 14, 7, 8, 14, 7, 24.5f };
+ static const float struts[] = { 7, 7, 12.5f, 14, 7, 8, 14, 7, 24.5f };
if(size_t(i) >= sizeof(names)/sizeof(names[0])) return false;
g->pushlist();
g->text(names[i], 0xFFFF80, !i ? " " : NULL);
g->mergehits(true);
return true;
}
-
- void serverinfoendcolumn(g3d_gui *g, int i)
- {
+ void serverinfoendcolumn(g3d_gui *g, int i) {
g->mergehits(false);
g->column(i);
g->poplist();
}
-
- const char *mastermodecolor(int n, const char *unknown)
- {
+ const char *mastermodecolor(int n, const char *unknown) {
return (n>=MM_START && size_t(n-MM_START)<sizeof(mastermodecolors)/sizeof(mastermodecolors[0])) ? mastermodecolors[n-MM_START] : unknown;
}
-
- const char *mastermodeicon(int n, const char *unknown)
- {
+ const char *mastermodeicon(int n, const char *unknown) {
return (n>=MM_START && size_t(n-MM_START)<sizeof(mastermodeicons)/sizeof(mastermodeicons[0])) ? mastermodeicons[n-MM_START] : unknown;
}
-
- bool serverinfoentry(g3d_gui *g, int i, const char *name, int port, const char *sdesc, const char *map, int ping, const vector<int> &attr, int np)
- {
- if(ping < 0 || attr.empty() || attr[0]!=PROTOCOL_VERSION)
- {
- switch(i)
- {
+ bool serverinfoentry(g3d_gui *g, int i, const char *name, int port, const char *sdesc, const char *map, int ping, const vector<int> &attr, int np) {
+ if(ping < 0 || attr.empty() || attr[0]!=PROTOCOL_VERSION) {
+ switch(i) {
case 0:
if(g->button(" ", 0xFFFFDD, "serverunk")&G3D_UP) return true;
break;
-
case 1:
case 2:
case 3:
case 5:
if(g->button(" ", 0xFFFFDD)&G3D_UP) return true;
break;
-
case 6:
if(g->buttonf("%s ", 0xFFFFDD, NULL, name)&G3D_UP) return true;
break;
-
case 7:
if(g->buttonf("%d ", 0xFFFFDD, NULL, port)&G3D_UP) return true;
break;
-
case 8:
- if(ping < 0)
- {
+ if(ping < 0) {
if(g->button(sdesc, 0xFFFFDD)&G3D_UP) return true;
}
else if(g->buttonf("[%s protocol] ", 0xFFFFDD, NULL, attr.empty() ? "unknown" : (attr[0] < PROTOCOL_VERSION ? "older" : "newer"))&G3D_UP) return true;
}
return false;
}
-
- switch(i)
- {
- case 0:
- {
+ switch(i) {
+ case 0: {
const char *icon = attr.inrange(3) && np >= attr[3] ? "serverfull" : (attr.inrange(4) ? mastermodeicon(attr[4], "serverunk") : "serverunk");
if(g->buttonf("%d ", 0xFFFFDD, icon, ping)&G3D_UP) return true;
break;
}
-
case 1:
- if(attr.length()>=4)
- {
+ if(attr.length()>=4) {
if(g->buttonf(np >= attr[3] ? "\f3%d/%d " : "%d/%d ", 0xFFFFDD, NULL, np, attr[3])&G3D_UP) return true;
}
else if(g->buttonf("%d ", 0xFFFFDD, NULL, np)&G3D_UP) return true;
break;
-
case 2:
if(g->buttonf("%s ", 0xFFFFDD, NULL, attr.length()>=2 ? server::modename(attr[1], "") : "")&G3D_UP) return true;
break;
-
case 3:
if(g->buttonf("%.25s ", 0xFFFFDD, NULL, map)&G3D_UP) return true;
break;
-
case 4:
- if(attr.length()>=3 && attr[2] > 0)
- {
+ if(attr.length()>=3 && attr[2] > 0) {
int secs = clamp(attr[2], 0, 59*60+59),
mins = secs/60;
secs %= 60;
case 5:
if(g->buttonf("%s%s ", 0xFFFFDD, NULL, attr.length()>=5 ? mastermodecolor(attr[4], "") : "", attr.length()>=5 ? server::mastermodename(attr[4], "") : "")&G3D_UP) return true;
break;
-
case 6:
if(g->buttonf("%s ", 0xFFFFDD, NULL, name)&G3D_UP) return true;
break;
-
case 7:
if(g->buttonf("%d ", 0xFFFFDD, NULL, port)&G3D_UP) return true;
break;
-
case 8:
if(g->buttonf("%.25s", 0xFFFFDD, NULL, sdesc)&G3D_UP) return true;
break;
}
return false;
}
-
// any data written into this vector will get saved with the map data. Must take care to do own versioning, and endianess if applicable. Will not get called when loading maps from other games, so provide defaults.
void writegamedata(vector<char> &extras) {}
void readgamedata(vector<char> &extras) {}
-
const char *savedconfig() { return "config.cfg"; }
const char *restoreconfig() { return "restore.cfg"; }
const char *defaultconfig() { return "data/defaults.cfg"; }
const char *autoexec() { return "autoexec.cfg"; }
const char *savedservers() { return "servers.cfg"; }
-
- void loadconfigs()
- {
+ void loadconfigs() {
execident("playsong");
-
execfile("auth.cfg", false);
}
}
// console message types
-enum
-{
+enum {
CON_CHAT = 1<<8,
CON_TEAMCHAT = 1<<9,
CON_GAMEINFO = 1<<10,
#define DNF 100.0f // for normalized vectors
#define DVELF 1.0f // for playerspeed based velocity vectors
-enum // static entity types
-{
+enum { // static entity types {
NOTUSED = ET_EMPTY, // entity slot not in use in map
LIGHT = ET_LIGHT, // lightsource, attr1 = radius, attr2 = intensity
MAPMODEL = ET_MAPMODEL, // attr1 = angle, attr2 = idx
};
enum { GUN_FIST = 0, GUN_SG, GUN_CG, GUN_RL, GUN_RIFLE, GUN_GL, GUN_PISTOL, NUMGUNS };
-enum { A_BLUE, A_GREEN, A_YELLOW }; // armour types... take 20/40/60 % off
+enum { A_BLUE, A_GREEN, A_YELLOW }; // armour types... take 20/40/60 % off INCORRECT!
-enum
-{
+enum {
M_TEAM = 1<<0,
M_NOITEMS = 1<<1,
M_NOAMMO = 1<<2,
M_LOBBY = 1<<15
};
-static struct gamemodeinfo
-{
+static struct gamemodeinfo {
const char *name;
int flags;
const char *info;
-} gamemodes[] =
-{
- { "demo", M_DEMO | M_LOCAL, NULL},
- { "ffa", M_LOBBY, "Free For All: Collect items for ammo. Frag everyone to score points." },
- { "coop edit", M_EDIT, "Cooperative Editing: Edit maps with multiple players simultaneously." },
- { "teamplay", M_TEAM, "Teamplay: Collect items for ammo. Frag \fs\f3the enemy team\fr to score points for \fs\f1your team\fr." },
- { "instagib", M_NOITEMS | M_INSTA, "Instagib: You spawn with full rifle ammo and die instantly from one shot. There are no items. Frag everyone to score points." },
- { "insta team", M_NOITEMS | M_INSTA | M_TEAM, "Instagib Team: You spawn with full rifle ammo and die instantly from one shot. There are no items. Frag \fs\f3the enemy team\fr to score points for \fs\f1your team\fr." },
- { "efficiency", M_NOITEMS | M_EFFICIENCY, "Efficiency: You spawn with all weapons and armour. There are no items. Frag everyone to score points." },
- { "effic team", M_NOITEMS | M_EFFICIENCY | M_TEAM, "Efficiency Team: You spawn with all weapons and armour. There are no items. Frag \fs\f3the enemy team\fr to score points for \fs\f1your team\fr." },
+} gamemodes[] = {
+ {
+ "demo", M_DEMO | M_LOCAL, NULL}, {
+ "ffa", M_LOBBY, "Free For All: Collect items for ammo. Frag everyone to score points." }, {
+ "coop edit", M_EDIT, "Cooperative Editing: Edit maps with multiple players simultaneously." }, {
+ "teamplay", M_TEAM, "Teamplay: Collect items for ammo. Frag \fs\f3the enemy team\fr to score points for \fs\f1your team\fr." }, {
+ "instagib", M_NOITEMS | M_INSTA, "Instagib: You spawn with full rifle ammo and die instantly from one shot. There are no items. Frag everyone to score points." }, {
+ "insta team", M_NOITEMS | M_INSTA | M_TEAM, "Instagib Team: You spawn with full rifle ammo and die instantly from one shot. There are no items. Frag \fs\f3the enemy team\fr to score points for \fs\f1your team\fr." }, {
+ "efficiency", M_NOITEMS | M_EFFICIENCY, "Efficiency: You spawn with all weapons and armour. There are no items. Frag everyone to score points." }, {
+ "effic team", M_NOITEMS | M_EFFICIENCY | M_TEAM, "Efficiency Team: You spawn with all weapons and armour. There are no items. Frag \fs\f3the enemy team\fr to score points for \fs\f1your team\fr." },
};
#define STARTGAMEMODE (-1)
enum { MM_AUTH = -1, MM_OPEN = 0, MM_VETO, MM_LOCKED, MM_PRIVATE, MM_PASSWORD, MM_START = MM_AUTH };
-static const char * const mastermodenames[] = { "auth", "open", "veto", "locked", "private", "password" };
+static const char * const mastermodenames[] = { "auth", "open", "veto", "locked", "private", "password" };
static const char * const mastermodecolors[] = { "", "\f0", "\f2", "\f2", "\f3", "\f3" };
-static const char * const mastermodeicons[] = { "server", "server", "serverlock", "serverlock", "serverpriv", "serverpriv" };
+static const char * const mastermodeicons[] = { "server", "server", "serverlock", "serverlock", "serverpriv", "serverpriv" };
// hardcoded sounds, defined in sounds.cfg
-enum
-{
+enum {
S_JUMP = 0, S_LAND, S_RIFLE, S_PUNCH1, S_SG, S_CG,
S_RLFIRE, S_RLHIT, S_WEAPLOAD, S_ITEMAMMO, S_ITEMHEALTH,
S_ITEMARMOUR, S_ITEMPUP, S_ITEMSPAWN, S_TELEPORT, S_NOAMMO, S_PUPOUT,
S_FLAUNCH, S_FEXPLODE,
S_SPLASH1, S_SPLASH2,
S_JUMPPAD, S_PISTOL,
-
S_V_FIGHT,
S_V_BOOST, S_V_BOOST10,
S_V_QUAD, S_V_QUAD10,
-
S_BURN,
S_CHAINSAW_ATTACK,
S_CHAINSAW_IDLE,
-
S_HIT
};
enum { PRIV_NONE = 0, PRIV_MASTER, PRIV_AUTH, PRIV_ADMIN };
-enum
-{
+enum {
N_CONNECT = 0, N_SERVINFO, N_WELCOME, N_INITCLIENT, N_POS, N_TEXT, N_SOUND, N_CDIS,
N_SHOOT, N_EXPLODE, N_SUICIDE,
N_DIED, N_DAMAGE, N_HITPUSH, N_SHOTFX, N_EXPLODEFX,
NUMMSG
};
-static const int msgsizes[] = // size inclusive message token, 0 for variable or not-checked sizes
-{
+static const int msgsizes[] = { // size inclusive message token, 0 for variable or not-checked sizes {
N_CONNECT, 0, N_SERVINFO, 0, N_WELCOME, 1, N_INITCLIENT, 0, N_POS, 0, N_TEXT, 0, N_SOUND, 2, N_CDIS, 2,
N_SHOOT, 0, N_EXPLODE, 0, N_SUICIDE, 1,
N_DIED, 5, N_DAMAGE, 6, N_HITPUSH, 7, N_SHOTFX, 10, N_EXPLODEFX, 4,
#define DEMO_VERSION 1 // bump when demo format changes
#define DEMO_MAGIC "SAUERBRATEN_DEMO"
-struct demoheader
-{
+struct demoheader {
char magic[16];
int version, protocol;
};
#define MAXNAMELEN 15
#define MAXTEAMLEN 4
-enum
-{
+enum {
HICON_BLUE_ARMOUR = 0,
HICON_GREEN_ARMOUR,
HICON_YELLOW_ARMOUR,
-
HICON_HEALTH,
-
HICON_FIST,
HICON_SG,
HICON_CG,
HICON_RIFLE,
HICON_GL,
HICON_PISTOL,
-
HICON_QUAD,
-
HICON_TOKEN,
-
HICON_X = 20,
HICON_Y = 1650,
HICON_TEXTY = 1644,
int add, max, sound;
const char *name;
int icon, info;
-} itemstats[] = {
- {10, 30, S_ITEMAMMO, "SG", HICON_SG, GUN_SG},
- {20, 60, S_ITEMAMMO, "CG", HICON_CG, GUN_CG},
- {5, 15, S_ITEMAMMO, "RL", HICON_RL, GUN_RL},
- {5, 15, S_ITEMAMMO, "RI", HICON_RIFLE, GUN_RIFLE},
- {10, 30, S_ITEMAMMO, "GL", HICON_GL, GUN_GL},
- {30, 120, S_ITEMAMMO, "PI", HICON_PISTOL, GUN_PISTOL},
- {25, 100, S_ITEMHEALTH, "H", HICON_HEALTH, -1},
- {100, 200, S_ITEMHEALTH, "MH", HICON_HEALTH, 50},
- {5, 100, S_ITEMHEALTH, "TH", HICON_HEALTH, -1},
- {5, 50, S_ITEMARMOUR, "TA", HICON_BLUE_ARMOUR, A_BLUE},
- {50, 100, S_ITEMARMOUR, "GA", HICON_GREEN_ARMOUR, A_GREEN},
- {100, 200, S_ITEMARMOUR, "YA", HICON_YELLOW_ARMOUR, A_YELLOW},
- {20000, 30000, S_ITEMPUP, "Q", HICON_QUAD, -1},
+} itemstats[] = { {
+ 10, 30, S_ITEMAMMO, "SG", HICON_SG, GUN_SG}, {
+ 20, 60, S_ITEMAMMO, "CG", HICON_CG, GUN_CG}, {
+ 5, 15, S_ITEMAMMO, "RL", HICON_RL, GUN_RL}, {
+ 5, 15, S_ITEMAMMO, "RI", HICON_RIFLE, GUN_RIFLE}, {
+ 10, 30, S_ITEMAMMO, "GL", HICON_GL, GUN_GL}, {
+ 30, 120, S_ITEMAMMO, "PI", HICON_PISTOL, GUN_PISTOL}, {
+ 25, 100, S_ITEMHEALTH, "H", HICON_HEALTH, -1}, {
+ 100, 200, S_ITEMHEALTH, "MH", HICON_HEALTH, 50}, {
+ 5, 100, S_ITEMHEALTH, "TH", HICON_HEALTH, -1}, {
+ 5, 50, S_ITEMARMOUR, "TA", HICON_BLUE_ARMOUR, A_BLUE}, {
+ 50, 100, S_ITEMARMOUR, "GA", HICON_GREEN_ARMOUR, A_GREEN}, {
+ 100, 200, S_ITEMARMOUR, "YA", HICON_YELLOW_ARMOUR, A_YELLOW}, {
+ 20000, 30000, S_ITEMPUP, "Q", HICON_QUAD, -1},
};
#define MAXRAYS 12
const char *name, *file;
short part;
} guns[NUMGUNS] = {
- // delay| dmg| spr| spd| kck| rng| ray| pus| exp|
+ // delay| dmg| spr| spd| kck| rng| ray| pus| exp| {
{ S_PUNCH1, 100, 30, 0, 0, 0, 30, 1, 80, 0, 0, "fist", "fist", 0 },
{ S_SG, 1000, 20, 280, 0, 20, 1024, MAXRAYS, 100, 0, 0, "shotgun", "shotg", 0 },
{ S_CG, 100, 20, 70, 0, 10, 1024, 1, 80, 0, 0, "chaingun", "chaing", 0 },
#include "ai.h"
// inherited by fpsent and server clients
-struct fpsstate
-{
+struct fpsstate {
int health, maxhealth;
int armour, maxarmour, armourtype;
int quadmillis;
int gunselect, gunwait;
int ammo[NUMGUNS];
int aitype, skill;
-
fpsstate() : maxhealth(100), maxarmour(50), aitype(AI_NONE), skill(0) {}
-
- void baseammo(int gun, int k = 2, int scale = 1)
- {
+ void baseammo(int gun, int k = 2, int scale = 1) {
ammo[gun] = (itemstats[gun-GUN_SG].add*k)/scale;
}
-
- void addammo(int gun, int k = 1, int scale = 1)
- {
+ void addammo(int gun, int k = 1, int scale = 1) {
itemstat &is = itemstats[gun-GUN_SG];
ammo[gun] = min(ammo[gun] + (is.add*k)/scale, is.max);
}
-
- bool hasmaxammo(int type)
- {
+ bool hasmaxammo(int type) {
const itemstat &is = itemstats[type-I_SHELLS];
return ammo[type-I_SHELLS+GUN_SG]>=is.max;
}
-
- bool canpickup(int type)
- {
+ bool canpickup(int type) {
if(type<I_SHELLS || type>I_QUAD) return false;
itemstat &is = itemstats[type-I_SHELLS];
- switch(type)
- {
+ switch(type) {
case I_BOOST: return maxhealth<is.max || health<maxhealth;
case I_TINYHEALTH: return health<maxhealth;
case I_HEALTH: return health<maxhealth;
-
case I_TINYARMOUR:
[[fallthrough]];
case I_GREENARMOUR:
[[fallthrough]];
case I_YELLOWARMOUR: return maxarmour<is.max || armour<maxarmour;
-
case I_QUAD: return quadmillis<is.max;
default: return ammo[is.info]<is.max;
}
}
-
- void pickup(int type)
- {
+ void pickup(int type) {
if(type<I_SHELLS || type>I_QUAD) return;
itemstat &is = itemstats[type-I_SHELLS];
- switch(type)
- {
+ switch(type) {
case I_TINYHEALTH:
health = min(health+is.add, maxhealth);
break;
break;
}
}
-
- void respawn()
- {
+ void respawn() {
maxhealth = 100;
health = maxhealth;
maxarmour = 50;
loopi(NUMGUNS) ammo[i] = 0;
ammo[GUN_FIST] = 1;
}
-
- void spawnstate(int gamemode)
- {
- if(m_demo)
- {
+ void spawnstate(int gamemode) {
+ if(m_demo) {
gunselect = GUN_FIST;
}
- else if(m_insta)
- {
+ else if(m_insta) {
armour = 0;
health = 1;
gunselect = GUN_RIFLE;
ammo[GUN_RIFLE] = 100;
}
- else if(m_efficiency)
- {
+ else if(m_efficiency) {
armourtype = A_GREEN;
armour = 100;
loopi(NUMGUNS-1) baseammo(i+1);
gunselect = GUN_CG;
ammo[GUN_CG] /= 2;
}
- else
- {
+ else {
armourtype = A_BLUE;
armour = 25;
ammo[GUN_PISTOL] = 40;
}
}
-
// just subtract damage here, can set death, etc. later in code calling this
- int dodamage(int damage)
- {
+ int dodamage(int damage) {
int ad = (damage*(armourtype+1)*30)/100; // let armour absorb when possible
if(ad>armour) ad = armour;
armour -= ad;
health -= damage;
return damage;
}
-
- int hasammo(int gun, int exclude = -1)
- {
+ int hasammo(int gun, int exclude = -1) {
return gun >= 0 && gun <= NUMGUNS && gun != exclude && ammo[gun] > 0;
}
};
extern int screenw, screenh;
-struct fpsent : dynent, fpsstate
-{
+struct fpsent : dynent, fpsstate {
int weight; // affects the effectiveness of hitpush
int clientnum, privilege, lastupdate, plag, ping;
int lifesequence; // sequence id for each respawn, used in damage test
editinfo *edit;
float deltayaw, deltapitch, deltaroll, newyaw, newpitch, newroll;
int smoothmillis;
-
string name, team, info;
int playermodel;
ai::aiinfo *ai;
int ownernum, lastnode;
-
vec muzzle;
-
- fpsent() : weight(100), clientnum(-1), privilege(PRIV_NONE), lastupdate(0), plag(0), ping(0), lifesequence(0), respawned(-1), suicided(-1), lastpain(0), attacksound(-1), attackchan(-1), idlesound(-1), idlechan(-1), frags(0), flags(0), deaths(0), totaldamage(0), totalshots(0), edit(NULL), smoothmillis(-1), playermodel(-1), ai(NULL), ownernum(-1), muzzle(-1, -1, -1)
- {
+ fpsent() : weight(100), clientnum(-1), privilege(PRIV_NONE), lastupdate(0), plag(0), ping(0), lifesequence(0), respawned(-1), suicided(-1), lastpain(0), attacksound(-1), attackchan(-1), idlesound(-1), idlechan(-1), frags(0), flags(0), deaths(0), totaldamage(0), totalshots(0), edit(NULL), smoothmillis(-1), playermodel(-1), ai(NULL), ownernum(-1), muzzle(-1, -1, -1) {
name[0] = team[0] = info[0] = 0;
respawn();
}
- ~fpsent()
- {
+ ~fpsent() {
freeeditinfo(edit);
if(attackchan >= 0) stopsound(attacksound, attackchan);
if(idlechan >= 0) stopsound(idlesound, idlechan);
if(ai) delete ai;
}
-
- void hitpush(int damage, const vec &dir, fpsent *actor, int gun)
- {
+ void hitpush(int damage, const vec &dir, fpsent *actor, int gun) {
vec push(dir);
push.mul((actor==this && guns[gun].exprad ? EXP_SELFPUSH : 1.0f)*guns[gun].hitpush*damage/weight);
vel.add(push);
}
-
- void stopattacksound()
- {
+ void stopattacksound() {
if(attackchan >= 0) stopsound(attacksound, attackchan, 250);
attacksound = attackchan = -1;
}
-
- void stopidlesound()
- {
+ void stopidlesound() {
if(idlechan >= 0) stopsound(idlesound, idlechan, 100);
idlesound = idlechan = -1;
}
-
- void respawn()
- {
+ void respawn() {
dynent::reset();
fpsstate::respawn();
respawned = suicided = -1;
stopattacksound();
lastnode = -1;
}
-
- int respawnwait(int secs, int delay = 0)
- {
+ int respawnwait(int secs, int delay = 0) {
return max(0, secs - (::lastmillis - lastpain - delay)/1000);
}
};
-struct teamscore
-{
+struct teamscore {
const char *team;
int score;
teamscore() {}
teamscore(const char *s, int n) : team(s), score(n) {}
-
- static bool compare(const teamscore &x, const teamscore &y)
- {
+ static bool compare(const teamscore &x, const teamscore &y) {
if(x.score > y.score) return true;
if(x.score < y.score) return false;
return strcmp(x.team, y.team) < 0;
#define MAXTEAMS 128
-struct teaminfo
-{
+struct teaminfo {
char team[MAXTEAMLEN+1];
int frags;
};
static inline uint hthash(const teaminfo &t) { return hthash(t.team); }
static inline bool htcmp(const char *team, const teaminfo &t) { return !strcmp(team, t.team); }
-namespace entities
-{
+namespace entities {
extern vector<extentity *> ents;
-
extern const char *entmdlname(int type);
extern const char *itemname(int i);
extern int itemicon(int i);
-
extern void preloadentities();
extern void renderentities();
extern void checkitems(fpsent *d);
extern void pickupeffects(int n, fpsent *d);
extern void teleporteffects(fpsent *d, int tp, int td, bool local = true);
extern void jumppadeffects(fpsent *d, int jp, bool local = true);
-
extern void repammo(fpsent *d, int type, bool local = true);
}
-namespace game
-{
+namespace game {
// fps
extern int gamemode, nextmode;
extern string clientmap;
extern int respawnent;
extern int following;
extern int smoothmove, smoothdist;
-
extern bool clientoption(const char *arg);
extern fpsent *getclient(int cn);
extern fpsent *newclient(int cn);
extern void drawicon(int icon, float x, float y, float sz = 120);
const char *mastermodecolor(int n, const char *unknown);
const char *mastermodeicon(int n, const char *unknown);
-
// client
extern bool connected, remote, demoplayback;
extern string servinfo;
extern vector<uchar> messages;
-
extern int parseplayer(const char *arg);
extern void ignore(int cn);
extern void unignore(int cn);
extern void forceintermission();
extern void c2sinfo(bool force = false);
extern void sendposition(fpsent *d, bool reliable = false);
-
// weapon
extern int getweapon(const char *name);
extern void shoot(fpsent *d, const vec &targ);
extern void gunselect(int gun, fpsent *d);
extern void weaponswitch(fpsent *d);
extern void avoidweapons(ai::avoidset &obstacles, float radius);
-
// scoreboard
extern void showscores(bool on);
extern void getbestplayers(vector<fpsent *> &best);
extern void clearteaminfo();
extern void setteaminfo(const char *team, int frags);
extern int statuscolor(fpsent *d, int color);
-
// render
- struct playermodelinfo
- {
+ struct playermodelinfo {
const char *ffa, *blueteam, *redteam, *hudguns,
*vwep, *quad, *armour[3],
*ffaicon, *blueicon, *redicon;
bool ragdoll;
};
-
extern int playermodel, teamskins, testteam;
-
extern void saveragdoll(fpsent *d);
extern void clearragdolls();
extern void moveragdolls();
extern vec hudgunorigin(int gun, const vec &from, const vec &to, fpsent *d);
}
-namespace server
-{
+namespace server {
extern const char *modename(int n, const char *unknown = "unknown");
extern const char *mastermodename(int n, const char *unknown = "unknown");
extern void startintermission();
struct spawninfo { const extentity *e; float weight; };
extern float gatherspawninfos(dynent *d, int tag, vector<spawninfo> &spawninfos);
-namespace game
-{
+namespace game {
vector<fpsent *> bestplayers;
vector<const char *> bestteams;
-
VARP(ragdoll, 0, 1, 1);
VARP(ragdollmillis, 0, 10000, 300000);
VARP(ragdollfade, 0, 1000, 300000);
VARP(playermodel, 0, 0, 0);
VARP(hidedead, 0, 0, 2);
-
vector<fpsent *> ragdolls;
-
- void saveragdoll(fpsent *d)
- {
+ void saveragdoll(fpsent *d) {
if(!d->ragdoll || !ragdollmillis || (!ragdollfade && lastmillis > d->lastpain + ragdollmillis)) return;
fpsent *r = new fpsent(*d);
r->lastupdate = ragdollfade && lastmillis > d->lastpain + max(ragdollmillis - ragdollfade, 0) ? lastmillis - max(ragdollmillis - ragdollfade, 0) : d->lastpain;
ragdolls.add(r);
d->ragdoll = NULL;
}
-
- void clearragdolls()
- {
+ void clearragdolls() {
ragdolls.deletecontents();
}
-
- void moveragdolls()
- {
- loopv(ragdolls)
- {
+ void moveragdolls() {
+ loopv(ragdolls) {
fpsent *d = ragdolls[i];
- if(lastmillis > d->lastupdate + ragdollmillis)
- {
+ if(lastmillis > d->lastupdate + ragdollmillis) {
delete ragdolls.remove(i--);
continue;
}
moveragdoll(d);
}
}
-
- static const playermodelinfo playermodels[1] =
- {
- { "mrfixit", "mrfixit/blue", "mrfixit/red", "mrfixit/hudguns", NULL, "mrfixit/horns", { "mrfixit/armor/blue", "mrfixit/armor/green", "mrfixit/armor/yellow" }, "mrfixit", "mrfixit_blue", "mrfixit_red", true },
+ static const playermodelinfo playermodels[1] = {
+ {
+ "mrfixit", "mrfixit/blue", "mrfixit/red", "mrfixit/hudguns", NULL, "mrfixit/horns", {
+ "mrfixit/armor/blue", "mrfixit/armor/green", "mrfixit/armor/yellow" },
+ "mrfixit", "mrfixit_blue", "mrfixit_red", true },
};
-
- const playermodelinfo *getplayermodelinfo(int n)
- {
+ const playermodelinfo *getplayermodelinfo(int n) {
(void) n;
return &playermodels[0];
}
-
- const playermodelinfo &getplayermodelinfo(fpsent *d)
- {
+ const playermodelinfo &getplayermodelinfo(fpsent *d) {
+ (void) d;
const playermodelinfo *mdl = getplayermodelinfo(0);
if(!mdl) mdl = getplayermodelinfo(playermodel);
return *mdl;
}
-
- void preloadplayermodel()
- {
+ void preloadplayermodel() {
const playermodelinfo *mdl = getplayermodelinfo(0);
- if(m_teammode)
- {
+ if(m_teammode) {
preloadmodel(mdl->blueteam);
preloadmodel(mdl->redteam);
}
if(mdl->quad) preloadmodel(mdl->quad);
loopj(3) if(mdl->armour[j]) preloadmodel(mdl->armour[j]);
}
-
VAR(testquad, 0, 0, 1);
VAR(testarmour, 0, 0, 1);
VAR(testteam, 0, 0, 3);
-
- void renderplayer(fpsent *d, const playermodelinfo &mdl, int team, float fade, bool mainpass)
- {
+ void renderplayer(fpsent *d, const playermodelinfo &mdl, int team, float fade, bool mainpass) {
int lastaction = d->lastaction, hold = mdl.vwep || d->gunselect==GUN_PISTOL ? 0 : (ANIM_HOLD1+d->gunselect)|ANIM_LOOP, attack = ANIM_ATTACK1+d->gunselect, delay = mdl.vwep ? 300 : guns[d->gunselect].attackdelay+50;
- if(intermission && d->state!=CS_DEAD)
- {
+ if(intermission && d->state!=CS_DEAD) {
lastaction = 0;
hold = attack = ANIM_LOSE|ANIM_LOOP;
delay = 0;
if(m_teammode ? bestteams.htfind(d->team)>=0 : bestplayers.find(d)>=0) hold = attack = ANIM_WIN|ANIM_LOOP;
}
- else if(d->state==CS_ALIVE && d->lasttaunt && lastmillis-d->lasttaunt<1000 && lastmillis-d->lastaction>delay)
- {
+ else if(d->state==CS_ALIVE && d->lasttaunt && lastmillis-d->lasttaunt<1000 && lastmillis-d->lastaction>delay) {
lastaction = d->lasttaunt;
hold = attack = ANIM_TAUNT;
delay = 1000;
modelattach a[5];
static const char * const vweps[] = {"vwep/fist", "vwep/shotg", "vwep/chaing", "vwep/rocket", "vwep/rifle", "vwep/gl", "vwep/pistol"};
int ai = 0;
- if((!mdl.vwep || d->gunselect!=GUN_FIST) && d->gunselect<=GUN_PISTOL)
- {
+ if((!mdl.vwep || d->gunselect!=GUN_FIST) && d->gunselect<=GUN_PISTOL) {
int vanim = ANIM_VWEP_IDLE|ANIM_LOOP, vtime = 0;
- if(lastaction && d->lastattackgun==d->gunselect && lastmillis < lastaction + delay)
- {
+ if(lastaction && d->lastattackgun==d->gunselect && lastmillis < lastaction + delay) {
vanim = ANIM_VWEP_SHOOT;
vtime = lastaction;
}
a[ai++] = modelattach("tag_weapon", mdl.vwep ? mdl.vwep : vweps[d->gunselect], vanim, vtime);
}
- if(d->state==CS_ALIVE)
- {
+ if(d->state==CS_ALIVE) {
if((testquad || d->quadmillis) && mdl.quad)
a[ai++] = modelattach("tag_powerup", mdl.quad, ANIM_POWERUP|ANIM_LOOP, 0);
- if(testarmour || d->armour)
- {
+ if(testarmour || d->armour) {
int type = clamp(d->armourtype, (int)A_BLUE, (int)A_YELLOW);
if(mdl.armour[type])
a[ai++] = modelattach("tag_shield", mdl.armour[type], ANIM_SHIELD|ANIM_LOOP, 0);
}
}
- if(mainpass)
- {
+ if(mainpass) {
d->muzzle = vec(-1, -1, -1);
a[ai++] = modelattach("tag_muzzle", &d->muzzle);
}
const char *mdlname = mdl.ffa;
- switch(testteam ? testteam-1 : team)
- {
+ switch(testteam ? testteam-1 : team) {
case 1: mdlname = mdl.blueteam; break;
case 2: mdlname = mdl.redteam; break;
}
renderclient(d, mdlname, a[0].tag ? a : NULL, hold, attack, delay, lastaction, intermission && d->state!=CS_DEAD ? 0 : d->lastpain, fade, ragdoll && mdl.ragdoll);
}
-
VARP(teamskins, 0, 0, 1);
-
VARP(statusicons, 0, 1, 1);
-
- void renderstatusicons(fpsent *d, int team, float yoffset)///TODO
- {
+ void renderstatusicons(fpsent *d, int team, float yoffset) {///TODO {
vec p = d->abovehead().madd(camup, yoffset);
int icons = 0;
const itemstat &boost = itemstats[I_BOOST-I_SHELLS];
- if(statusicons && (d->state==CS_ALIVE || d->state==CS_LAGGED))
- {
+ if(statusicons && (d->state==CS_ALIVE || d->state==CS_LAGGED)) {
if(d->quadmillis) icons++;
if(d->maxhealth>100) icons += (min(d->maxhealth, boost.max) - 100 + boost.info-1) / boost.info;
if(d->armour>0 && d->armourtype>=A_GREEN && !m_noitems) icons++;
}
if(icons) concatstring(d->info, " ");
particle_text(p, d->info, PART_TEXT, 1, team ? (team==1 ? 0x6496FF : 0xFF4B19) : 0x1EC850, 2.0f, 0, icons);
- if(icons)
- {
+ if(icons) {
float tw, th;
text_boundsf(d->info, tw, th);
float offset = (tw - icons*th)/2;
- if(d->armour>0 && d->armourtype>=A_GREEN && !m_noitems)
- {
+ if(d->armour>0 && d->armourtype>=A_GREEN && !m_noitems) {
int icon = itemstats[(d->armourtype==A_YELLOW ? I_YELLOWARMOUR : I_GREENARMOUR)-I_SHELLS].icon;
particle_texticon(p, icon%4, icon/4, offset, PART_TEXT_ICON, 1, 0xFFFFFF, 2.0f);
offset += th;
}
- for(int i = 100; i < min(d->maxhealth, boost.max); i += boost.info)
- {
+ for(int i = 100; i < min(d->maxhealth, boost.max); i += boost.info) {
particle_texticon(p, boost.icon%4, boost.icon/4, offset, PART_TEXT_ICON, 1, 0xFFFFFF, 2.0f);
offset += th;
}
- if(d->quadmillis)
- {
+ if(d->quadmillis) {
int icon = itemstats[I_QUAD-I_SHELLS].icon;
particle_texticon(p, icon%4, icon/4, offset, PART_TEXT_ICON, 1, 0xFFFFFF, 2.0f);
offset += th;
}
}
}
-
VARP(statusbars, 0, 1, 2);
FVARP(statusbarscale, 0, 1, 2);
-
- float renderstatusbars(fpsent *d, int team)///TODO
- {
+ float renderstatusbars(fpsent *d, int team) {///TODO {
if(!statusbars || m_insta || (player1->state==CS_SPECTATOR ? statusbars <= 1 : team != 1) || (d->state!=CS_ALIVE && d->state!=CS_LAGGED)) return 0;
vec p = d->abovehead().msub(camdir, 50/80.0f).msub(camup, 2.0f);
float offset = 0;
float scale = statusbarscale;
- if(d->armour > 0)
- {
+ if(d->armour > 0) {
int limit = d->armourtype==A_YELLOW ? 200 : (d->armourtype==A_GREEN ? 100 : 50);
int color = d->armourtype==A_YELLOW ? 0xFFC040 : (d->armourtype==A_GREEN ? 0x008C00 : 0x0B5899);
float size = scale*sqrtf(max(d->armour, limit)/100.0f);
particle_meter(vec(p).madd(camup, offset), fill, PART_METER, 1, color, 0, size);
return offset;
}
-
- void rendergame(bool mainpass)
- {
+ void rendergame(bool mainpass) {
if(mainpass) ai::render();
-
- if(intermission)
- {
+ if(intermission) {
bestteams.shrink(0);
bestplayers.shrink(0);
if(m_teammode) getbestteams(bestteams);
else getbestplayers(bestplayers);
}
-
startmodelbatches();
-
fpsent *exclude = isthirdperson() ? NULL : followingplayer();
- loopv(players)
- {
+ loopv(players) {
fpsent *d = players[i];
if(d == player1 || d->state==CS_SPECTATOR || d->state==CS_SPAWNING || d->lifesequence < 0 || d == exclude || (d->state==CS_DEAD && hidedead)) continue;
int team = 0;
if(teamskins || m_teammode) team = isteam(player1->team, d->team) ? 1 : 2;
renderplayer(d, getplayermodelinfo(d), team, 1, mainpass);
-
vec dir = vec(d->o).sub(camera1->o);
float dist = dir.magnitude();
dir.div(dist);
- if(d->state!=CS_EDITING && raycube(camera1->o, dir, dist, 0) < dist)
- {
+ if(d->state!=CS_EDITING && raycube(camera1->o, dir, dist, 0) < dist) {
d->info[0] = '\0';
continue;
}
-
copystring(d->info, colorname(d));
- if(d->state!=CS_DEAD)
- {
+ if(d->state!=CS_DEAD) {
float offset = renderstatusbars(d, team);
renderstatusicons(d, team, offset);
}
}
- loopv(ragdolls)
- {
+ loopv(ragdolls) {
fpsent *d = ragdolls[i];
int team = 0;
if(teamskins || m_teammode) team = isteam(player1->team, d->team) ? 1 : 2;
entities::renderentities();
renderbouncers();
renderprojectiles();
-
endmodelbatches();
}
-
VARP(hudgun, 0, 1, 1);
VARP(hudgunsway, 0, 1, 1);
VARP(teamhudguns, 0, 1, 1);
VARP(chainsawhudgun, 0, 1, 1);
VAR(testhudgun, 0, 0, 1);
-
FVAR(swaystep, 1, 35.0f, 100);
FVAR(swayside, 0, 0.04f, 1);
FVAR(swayup, -1, 0.05f, 1);
-
float swayfade = 0, swayspeed = 0, swaydist = 0;
vec swaydir(0, 0, 0);
-
- void swayhudgun(int curtime)
- {
+ void swayhudgun(int curtime) {
fpsent *d = hudplayer();
- if(d->state != CS_SPECTATOR)
- {
- if(d->physstate >= PHYS_SLOPE)
- {
+ if(d->state != CS_SPECTATOR) {
+ if(d->physstate >= PHYS_SLOPE) {
swayspeed = min(sqrtf(d->vel.x*d->vel.x + d->vel.y*d->vel.y), d->maxspeed);
swaydist += swayspeed*curtime/1000.0f;
swaydist = fmod(swaydist, 2*swaystep);
swayfade = 1;
}
- else if(swayfade > 0)
- {
+ else if(swayfade > 0) {
swaydist += swayspeed*swayfade*curtime/1000.0f;
swaydist = fmod(swaydist, 2*swaystep);
swayfade -= 0.5f*(curtime*d->maxspeed)/(swaystep*1000.0f);
}
-
float k = pow(0.7f, curtime/10.0f);
swaydir.mul(k);
vec vel(d->vel);
swaydir.add(vec(vel).mul((1-k)/(15*max(vel.magnitude(), d->maxspeed))));
}
}
-
- struct hudent : dynent
- {
+ struct hudent : dynent {
hudent() { type = ENT_CAMERA; }
} guninterp;
-
SVARP(hudgunsdir, "");
-
- void drawhudmodel(fpsent *d, int anim, float speed = 0, int base = 0)
- {
+ void drawhudmodel(fpsent *d, int anim, float speed = 0, int base = 0) {
if(d->gunselect>GUN_PISTOL) return;
-
vec sway;
vecfromyawpitch(d->yaw, 0, 0, 1, sway);
float steps = swaydist/swaystep*M_PI;
if(!hudgunsway) sway = d->o;
#if 0
- if(player1->state!=CS_DEAD && player1->quadmillis)
- {
+ if(player1->state!=CS_DEAD && player1->quadmillis) {
float t = 0.5f + 0.5f*sinf(2*M_PI*lastmillis/1000.0f);
color.y = color.y*(1-t) + t;
}
d->muzzle = vec(-1, -1, -1);
a[0] = modelattach("tag_muzzle", &d->muzzle);
dynent *interp = NULL;
- if(d->gunselect==GUN_FIST && chainsawhudgun)
- {
+ if(d->gunselect==GUN_FIST && chainsawhudgun) {
anim |= ANIM_LOOP;
base = 0;
interp = &guninterp;
rendermodel(NULL, gunname, anim, sway, testhudgun ? 0 : d->yaw+90, testhudgun ? 0 : d->pitch, MDL_LIGHT|MDL_HUD, interp, a, base, (int)ceil(speed));
if(d->muzzle.x >= 0) d->muzzle = calcavatarpos(d->muzzle, 12);
}
-
- void drawhudgun()
- {
+ void drawhudgun() {
fpsent *d = hudplayer();
- if(d->state==CS_SPECTATOR || d->state==CS_EDITING || !hudgun || editmode)
- {
+ if(d->state==CS_SPECTATOR || d->state==CS_EDITING || !hudgun || editmode) {
d->muzzle = player1->muzzle = vec(-1, -1, -1);
return;
}
-
int rtime = guns[d->gunselect].attackdelay;
- if(d->lastaction && d->lastattackgun==d->gunselect && lastmillis-d->lastaction<rtime)
- {
+ if(d->lastaction && d->lastattackgun==d->gunselect && lastmillis-d->lastaction<rtime) {
drawhudmodel(d, ANIM_GUN_SHOOT|ANIM_SETSPEED, rtime/17.0f, d->lastaction);
}
- else
- {
+ else {
drawhudmodel(d, ANIM_GUN_IDLE|ANIM_LOOP);
}
}
-
- void renderavatar()
- {
+ void renderavatar() {
drawhudgun();
}
-
- void renderplayerpreview(int model, int team, int weap)
- {
+ void renderplayerpreview(int model, int team, int weap) {
static fpsent *previewent = NULL;
- if(!previewent)
- {
+ if(!previewent) {
previewent = new fpsent;
previewent->light.color = vec(1, 1, 1);
previewent->light.dir = vec(0, -1, 2).normalize();
if(!mdlinfo) return;
renderplayer(previewent, *mdlinfo, team >= 0 && team <= 2 ? team : 0, 1, false);
}
-
- vec hudgunorigin(int gun, const vec &from, const vec &to, fpsent *d)
- {
+ vec hudgunorigin(int gun, const vec &from, const vec &to, fpsent *d) {
+ (void) gun;
if(d->muzzle.x >= 0) return d->muzzle;
vec offset(from);
- if(d!=hudplayer() || isthirdperson())
- {
+ if(d!=hudplayer() || isthirdperson()) {
vec front, right;
vecfromyawpitch(d->yaw, d->pitch, 1, 0, front);
offset.add(front.mul(d->radius));
- if(d->type!=ENT_AI)
- {
+ if(d->type!=ENT_AI) {
offset.z += (d->aboveeye + d->eyeheight)*0.75f - d->eyeheight;
vecfromyawpitch(d->yaw, 0, 0, -1, right);
offset.add(right.mul(0.5f*d->radius));
return offset;
}
offset.add(vec(to).sub(from).normalize().mul(2));
- if(hudgun)
- {
+ if(hudgun) {
offset.sub(vec(camup).mul(1.0f));
offset.add(vec(camright).mul(0.8f));
}
else offset.sub(vec(camup).mul(0.8f));
return offset;
}
-
- void preloadweapons()
- {
+ void preloadweapons() {
const playermodelinfo &mdl = getplayermodelinfo(player1);
- loopi(NUMGUNS)
- {
+ loopi(NUMGUNS) {
const char *file = guns[i].file;
if(!file) continue;
string fname;
- if((m_teammode || teamskins) && teamhudguns)
- {
+ if((m_teammode || teamskins) && teamhudguns) {
formatstring(fname, "%s/%s/blue", hudgunsdir[0] ? hudgunsdir : mdl.hudguns, file);
preloadmodel(fname);
}
- else
- {
+ else {
formatstring(fname, "%s/%s", hudgunsdir[0] ? hudgunsdir : mdl.hudguns, file);
preloadmodel(fname);
}
preloadmodel(fname);
}
}
-
- void preloadsounds()
- {
+ void preloadsounds() {
for(int i = S_JUMP; i <= S_HIT; i++) preloadsound(i);
}
-
- void preload()
- {
+ void preload() {
if(hudgun) preloadweapons();
preloadbouncers();
preloadplayermodel();
// creation of scoreboard
#include "game.h"
-namespace game
-{
+namespace game {
VARP(scoreboard2d, 0, 1, 1);
VARP(showservinfo, 0, 1, 1);
VARP(showclientnum, 0, 1, 1);
VARP(hidefrags, 0, 0, 1);
VARP(showdeaths, 0, 1, 1);
VARP(showdamagedealt, 0, 1, 1);
-
static hashset<teaminfo> teaminfos;
-
- void clearteaminfo()
- {
+ void clearteaminfo() {
teaminfos.clear();
}
-
- void setteaminfo(const char *team, int frags)
- {
+ void setteaminfo(const char *team, int frags) {
teaminfo *t = teaminfos.access(team);
if(!t) { t = &teaminfos[team]; copystring(t->team, team, sizeof(t->team)); }
t->frags = frags;
}
-
- static inline bool playersort(const fpsent *a, const fpsent *b)
- {
- if(a->state==CS_SPECTATOR)
- {
+ static inline bool playersort(const fpsent *a, const fpsent *b) {
+ if(a->state==CS_SPECTATOR) {
if(b->state==CS_SPECTATOR) return strcmp(a->name, b->name) < 0;
else return false;
}
if(a->frags < b->frags) return false;
return strcmp(a->name, b->name) < 0;
}
-
- void getbestplayers(vector<fpsent *> &best)
- {
- loopv(players)
- {
+ void getbestplayers(vector<fpsent *> &best) {
+ loopv(players) {
fpsent *o = players[i];
if(o->state!=CS_SPECTATOR) best.add(o);
}
best.sort(playersort);
while(best.length() > 1 && best.last()->frags < best[0]->frags) best.drop();
}
-
- void getbestteams(vector<const char *> &best)
- {
- if(!hidefrags)
- {
+ void getbestteams(vector<const char *> &best) {
+ if(!hidefrags) {
vector<teamscore> teamscores;
teamscores.sort(teamscore::compare);
while(teamscores.length() > 1 && teamscores.last().score < teamscores[0].score) teamscores.drop();
loopv(teamscores) best.add(teamscores[i].team);
}
- else
- {
+ else {
int bestfrags = INT_MIN;
enumerate(teaminfos, teaminfo, t, bestfrags = max(bestfrags, t.frags));
- if(bestfrags <= 0) loopv(players)
- {
+ if(bestfrags <= 0) loopv(players) {
fpsent *o = players[i];
if(o->state!=CS_SPECTATOR && !teaminfos.access(o->team) && best.htfind(o->team) < 0) { bestfrags = 0; best.add(o->team); }
}
enumerate(teaminfos, teaminfo, t, if(t.frags >= bestfrags) best.add(t.team));
}
}
-
- struct scoregroup : teamscore
- {
+ struct scoregroup : teamscore {
vector<fpsent *> players;
};
static vector<scoregroup *> groups;
static vector<fpsent *> spectators;
-
- static inline bool scoregroupcmp(const scoregroup *x, const scoregroup *y)
- {
- if(!x->team)
- {
+ static inline bool scoregroupcmp(const scoregroup *x, const scoregroup *y) {
+ if(!x->team) {
if(y->team) return false;
}
else if(!y->team) return true;
if(x->players.length() < y->players.length()) return false;
return x->team && y->team && strcmp(x->team, y->team) < 0;
}
-
- static int groupplayers()
- {
+ static int groupplayers() {
int numgroups = 0;
spectators.setsize(0);
- loopv(players)
- {
+ loopv(players) {
fpsent *o = players[i];
if(!showconnecting && !o->name[0]) continue;
if(o->state==CS_SPECTATOR) { spectators.add(o); continue; }
const char *team = m_teammode && o->team[0] ? o->team : NULL;
bool found = false;
- loopj(numgroups)
- {
+ loopj(numgroups) {
scoregroup &g = *groups[j];
if(team!=g.team && (!team || !g.team || strcmp(team, g.team))) continue;
g.players.add(o);
groups.sort(scoregroupcmp, 0, numgroups);
return numgroups;
}
-
- int statuscolor(fpsent *d, int color)
- {
- if(d->privilege)
- {
+ int statuscolor(fpsent *d, int color) {
+ if(d->privilege) {
color = d->privilege>=PRIV_ADMIN ? 0xFF8000 : (d->privilege>=PRIV_AUTH ? 0xC040C0 : 0x40FF80);
if(d->state==CS_DEAD) color = (color>>1)&0x7F7F7F;
}
else if(d->state==CS_DEAD) color = 0x606060;
return color;
}
-
- void renderscoreboard(g3d_gui &g, bool firstpass)
- {
+ void renderscoreboard(g3d_gui &g, bool firstpass) {
const ENetAddress *address = connectedpeer();
- if(showservinfo && address)
- {
+ if(showservinfo && address) {
string hostname;
- if(enet_address_get_host_ip(address, hostname, sizeof(hostname)) >= 0)
- {
+ if(enet_address_get_host_ip(address, hostname, sizeof(hostname)) >= 0) {
if(servinfo[0]) g.titlef("%.25s", 0xFFFF80, NULL, servinfo);
else g.titlef("%s:%d", 0xFFFF80, NULL, hostname, address->port);
}
}
-
g.pushlist();
g.spring();
g.text(server::modename(gamemode), 0xFFFF80);
g.text(mname[0] ? mname : "[new map]", 0xFFFF80);
extern int gamespeed;
if(gamespeed != 100) { g.separator(); g.textf("%d.%02dx", 0xFFFF80, NULL, gamespeed/100, gamespeed%100); }
- if(m_timed && mname[0] && (maplimit >= 0 || intermission))
- {
+ if(m_timed && mname[0] && (maplimit >= 0 || intermission)) {
g.separator();
if(intermission) g.text("intermission", 0xFFFF80);
- else
- {
+ else {
int secs = max(maplimit-lastmillis+999, 0)/1000, mins = secs/60;
secs %= 60;
g.pushlist();
if(ispaused()) { g.separator(); g.text("paused", 0xFFFF80); }
g.spring();
g.poplist();
-
g.separator();
-
int numgroups = groupplayers();
- loopk(numgroups)
- {
+ loopk(numgroups) {
if((k%2)==0) g.pushlist(); // horizontal
-
scoregroup &sg = *groups[k];
int bgcolor = sg.team && m_teammode ? (isteam(player1->team, sg.team) ? 0x3030C0 : 0xC03030) : 0,
fgcolor = 0xFFFF80;
-
g.pushlist(); // vertical
g.pushlist(); // horizontal
-
#define loopscoregroup(o, b) \
- loopv(sg.players) \
- { \
+ loopv(sg.players) { \
+ \
fpsent *o = sg.players[i]; \
b; \
}
-
g.pushlist();
- if(sg.team && m_teammode)
- {
+ if(sg.team && m_teammode) {
g.pushlist();
g.background(bgcolor, numgroups>1 ? 3 : 5);
g.strut(1);
g.poplist();
}
g.text("", 0, " ");
- loopscoregroup(o,
- {
- if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1))
- {
+ loopscoregroup(o, {
+ if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) {
g.pushlist();
g.background(0x808080, numgroups>1 ? 3 : 5);
}
if(o==player1 && highlightscore && (multiplayer(false) || demoplayback || players.length() > 1)) g.poplist();
});
g.poplist();
-
- if(sg.team && m_teammode)
- {
+ if(sg.team && m_teammode) {
g.pushlist(); // vertical
-
if(sg.score>=10000) g.textf("%s: WIN", fgcolor, NULL, sg.team);
else g.textf("%s: %d", fgcolor, NULL, sg.team, sg.score);
-
g.pushlist(); // horizontal
}
-
- if(!hidefrags)
- {
+ if(!hidefrags) {
g.pushlist();
g.strut(6);
g.text("frags", fgcolor);
loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->frags));
g.poplist();
}
-
- if(showdeaths)
- {
+ if(showdeaths) {
g.pushlist();
g.strut(6);
g.text("deaths", fgcolor);
loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->deaths));
g.poplist();
}
-
- if(showdamagedealt)
- {
+ if(showdamagedealt) {
g.pushlist();
g.strut(7);
g.text("damage", fgcolor);
loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->totaldamage));
g.poplist();
}
-
g.pushlist();
g.text("name", fgcolor);
g.strut(12);
loopscoregroup(o, { g.textf("%s ", statuscolor(o, 0xFFFFDD), NULL, colorname(o)); });
g.poplist();
-
- if(multiplayer(false) || demoplayback)
- {
+ if(multiplayer(false) || demoplayback) {
if(showpj || showping) g.space(1);
-
- if(showpj && showping <= 1)
- {
+ if(showpj && showping <= 1) {
g.pushlist();
g.strut(6);
g.text("pj", fgcolor);
- loopscoregroup(o,
- {
+ loopscoregroup(o, {
if(o->state==CS_LAGGED) g.text("LAG", 0xFFFFDD);
else g.textf("%d", 0xFFFFDD, NULL, o->plag);
});
g.poplist();
}
-
- if(showping > 1)
- {
+ if(showping > 1) {
g.pushlist();
g.strut(6);
-
g.pushlist();
g.text("ping", fgcolor);
g.space(1);
g.spring();
g.text("pj", fgcolor);
g.poplist();
-
- loopscoregroup(o,
- {
+ loopscoregroup(o, {
fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o;
if(!p) p = o;
g.pushlist();
if(p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD);
- else
- {
+ else {
g.textf("%d", 0xFFFFDD, NULL, p->ping);
g.space(1);
g.spring();
g.textf("%d", 0xFFFFDD, NULL, o->plag);
}
g.poplist();
-
});
g.poplist();
}
- else if(showping)
- {
+ else if(showping) {
g.pushlist();
g.text("ping", fgcolor);
g.strut(6);
- loopscoregroup(o,
- {
+ loopscoregroup(o, {
fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o;
if(!p) p = o;
if(!showpj && p->state==CS_LAGGED) g.text("LAG", 0xFFFFDD);
g.poplist();
}
}
-
- if(showclientnum || player1->privilege>=PRIV_MASTER)
- {
+ if(showclientnum || player1->privilege>=PRIV_MASTER) {
g.space(1);
g.pushlist();
g.text("cn", fgcolor);
loopscoregroup(o, g.textf("%d", 0xFFFFDD, NULL, o->clientnum));
g.poplist();
}
-
- if(sg.team && m_teammode)
- {
+ if(sg.team && m_teammode) {
g.poplist(); // horizontal
g.poplist(); // vertical
}
-
g.poplist(); // horizontal
g.poplist(); // vertical
-
if(k+1<numgroups && (k+1)%2) g.space(2);
else g.poplist(); // horizontal
}
-
- if(showspectators && spectators.length())
- {
- if(showclientnum || player1->privilege>=PRIV_MASTER)
- {
+ if(showspectators && spectators.length()) {
+ if(showclientnum || player1->privilege>=PRIV_MASTER) {
g.pushlist();
-
g.pushlist();
g.text("spectator", 0xFFFF80, " ");
g.strut(12);
- loopv(spectators)
- {
+ loopv(spectators) {
fpsent *o = spectators[i];
- if(o==player1 && highlightscore)
- {
+ if(o==player1 && highlightscore) {
g.pushlist();
g.background(0x808080, 3);
}
if(o==player1 && highlightscore) g.poplist();
}
g.poplist();
-
- if((multiplayer(false) || demoplayback) && showspectatorping)
- {
+ if((multiplayer(false) || demoplayback) && showspectatorping) {
g.space(1);
g.pushlist();
g.text("ping", 0xFFFF80);
g.strut(6);
- loopv(spectators)
- {
+ loopv(spectators) {
fpsent *o = spectators[i];
fpsent *p = o->ownernum >= 0 ? getclient(o->ownernum) : o;
if(!p) p = o;
}
g.poplist();
}
-
g.space(1);
g.pushlist();
g.text("cn", 0xFFFF80);
loopv(spectators) g.textf("%d", 0xFFFFDD, NULL, spectators[i]->clientnum);
g.poplist();
-
g.poplist();
}
- else
- {
+ else {
g.textf("%d spectator%s", 0xFFFF80, " ", spectators.length(), spectators.length()!=1 ? "s" : "");
- loopv(spectators)
- {
- if((i%3)==0)
- {
+ loopv(spectators) {
+ if((i%3)==0) {
g.pushlist();
g.text("", 0xFFFFDD, "spectator");
}
fpsent *o = spectators[i];
- if(o==player1 && highlightscore)
- {
+ if(o==player1 && highlightscore) {
g.pushlist();
g.background(0x808080);
}
}
}
}
-
/// PW
g.separator();
g.pushlist();
g.textf(" x %d ", 0xffffff, "quad_damage.png", pwitemspicked[6]);
g.poplist();
}
-
- struct scoreboardgui : g3d_callback
- {
+ struct scoreboardgui : g3d_callback {
bool showing;
vec menupos;
int menustart;
-
scoreboardgui() : showing(false) {}
-
- void show(bool on)
- {
- if(!showing && on)
- {
+ void show(bool on) {
+ if(!showing && on) {
menupos = menuinfrontofplayer();
menustart = starttime();
}
showing = on;
}
-
- void gui(g3d_gui &g, bool firstpass)
- {
+ void gui(g3d_gui &g, bool firstpass) {
g.start(menustart, 0.03f, NULL, false);
renderscoreboard(g, firstpass);
g.end();
}
-
- void render()
- {
+ void render() {
if(showing) g3d_addgui(this, menupos, (scoreboard2d ? GUI_FORCE_2D : GUI_2D | GUI_FOLLOW) | GUI_BOTTOM);
}
-
} scoreboard;
-
- void g3d_gamemenus()
- {
+ void g3d_gamemenus() {
scoreboard.render();
}
-
VARFN(scoreboard, showscoreboard, 0, 0, 1, scoreboard.show(showscoreboard!=0));
-
- void showscores(bool on)
- {
+ void showscores(bool on) {
showscoreboard = on ? 1 : 0;
scoreboard.show(on);
}
ICOMMAND(showscores, "D", (int *down), showscores(*down!=0));
-
VARP(hudscore, 0, 0, 1);
FVARP(hudscorescale, 1e-3f, 1.0f, 1e3f);
VARP(hudscorealign, -1, 0, 1);
HVARP(hudscoreenemycolour, 0, 0xFF4040, 0xFFFFFF);
VARP(hudscorealpha, 0, 255, 255);
VARP(hudscoresep, 0, 200, 1000);
-
- void drawhudscore(int w, int h)
- {
+ void drawhudscore(int w, int h) {
int numgroups = groupplayers();
if(!numgroups) return;
-
scoregroup *g = groups[0];
int score = INT_MIN, score2 = INT_MIN;
bool best = false;
- if(m_teammode)
- {
+ if(m_teammode) {
score = g->score;
best = isteam(player1->team, g->team);
- if(numgroups > 1)
- {
+ if(numgroups > 1) {
if(best) score2 = groups[1]->score;
else for(int i = 1; i < groups.length(); ++i) if(isteam(player1->team, groups[i]->team)) { score2 = groups[i]->score; break; }
- if(score2 == INT_MIN)
- {
+ if(score2 == INT_MIN) {
fpsent *p = followingplayer(player1);
if(p->state==CS_SPECTATOR) score2 = groups[1]->score;
}
}
}
- else
- {
+ else {
fpsent *p = followingplayer(player1);
score = g->players[0]->frags;
best = p == g->players[0];
- if(g->players.length() > 1)
- {
+ if(g->players.length() > 1) {
if(best || p->state==CS_SPECTATOR) score2 = g->players[1]->frags;
else score2 = p->frags;
}
}
if(score == score2 && !best) best = true;
-
score = clamp(score, -999, 9999);
defformatstring(buf, "%d", score);
int tw = 0, th = 0;
text_bounds(buf, tw, th);
-
string buf2;
int tw2 = 0, th2 = 0;
- if(score2 > INT_MIN)
- {
+ if(score2 > INT_MIN) {
score2 = clamp(score2, -999, 9999);
formatstring(buf2, "%d", score2);
text_bounds(buf2, tw2, th2);
}
-
int fw = 0, fh = 0;
text_bounds("00", fw, fh);
fw = max(fw, max(tw, tw2));
-
vec2 offset = vec2(hudscorex, hudscorey).mul(vec2(w, h).div(hudscorescale));
if(hudscorealign == 1) offset.x -= 2*fw + hudscoresep;
else if(hudscorealign == 0) offset.x -= (2*fw + hudscoresep) / 2.0f;
offset.y -= th/2.0f;
offset2.x += fw + hudscoresep + (fw-tw2)/2.0f;
offset2.y -= th2/2.0f;
-
pushhudmatrix();
hudmatrix.scale(hudscorescale, hudscorescale, 1);
flushhudmatrix();
-
int color = hudscoreplayercolour, color2 = hudscoreenemycolour;
if(!best) swap(color, color2);
-
draw_text(buf, int(offset.x), int(offset.y), (color>>16)&0xFF, (color>>8)&0xFF, color&0xFF, hudscorealpha);
if(score2 > INT_MIN) draw_text(buf2, int(offset2.x), int(offset2.y), (color2>>16)&0xFF, (color2>>8)&0xFF, color2&0xFF, hudscorealpha);
-
pophudmatrix();
}
}
#include "game.h"
-namespace game
-{
- void parseoptions(vector<const char *> &args)
- {
+namespace game {
+ void parseoptions(vector<const char *> &args) {
loopv(args)
#ifndef STANDALONE
if(!game::clientoption(args[i]))
if(!server::serveroption(args[i]))
conoutf(CON_ERROR, "unknown command-line option: %s", args[i]);
}
-
const char *gameident() { return "fps"; }
}
extern ENetAddress masteraddress;
-namespace server
-{
- struct server_entity // server side version of "entity" type
- {
+namespace server {
+ struct server_entity { // server side version of "entity" type {
int type;
int spawntime;
bool spawned;
};
-
static const int DEATHMILLIS = 300;
-
struct clientinfo;
-
- struct gameevent
- {
+ struct gameevent {
virtual ~gameevent() {}
-
virtual bool flush(clientinfo *ci, int fmillis);
- virtual void process(clientinfo *ci) {}
-
+ virtual void process(clientinfo *) {}
virtual bool keepable() const { return false; }
};
-
- struct timedevent : gameevent
- {
+ struct timedevent : gameevent {
int millis;
-
bool flush(clientinfo *ci, int fmillis);
};
-
- struct hitinfo
- {
+ struct hitinfo {
int target;
int lifesequence;
int rays;
float dist;
vec dir;
};
-
- struct shotevent : timedevent
- {
+ struct shotevent : timedevent {
int id, gun;
vec from, to;
vector<hitinfo> hits;
-
void process(clientinfo *ci);
};
-
- struct explodeevent : timedevent
- {
+ struct explodeevent : timedevent {
int id, gun;
vector<hitinfo> hits;
-
bool keepable() const { return true; }
-
void process(clientinfo *ci);
};
-
- struct suicideevent : gameevent
- {
+ struct suicideevent : gameevent {
void process(clientinfo *ci);
};
-
- struct pickupevent : gameevent
- {
+ struct pickupevent : gameevent {
int ent;
-
void process(clientinfo *ci);
};
-
template <int N>
- struct projectilestate
- {
+ struct projectilestate {
int projs[N];
int numprojs;
-
projectilestate() : numprojs(0) {}
-
void reset() { numprojs = 0; }
-
- void add(int val)
- {
+ void add(int val) {
if(numprojs>=N) numprojs = 0;
projs[numprojs++] = val;
}
-
- bool remove(int val)
- {
- loopi(numprojs) if(projs[i]==val)
- {
+ bool remove(int val) {
+ loopi(numprojs) if(projs[i]==val) {
projs[i] = projs[--numprojs];
return true;
}
return false;
}
};
-
- struct gamestate : fpsstate
- {
+ struct gamestate : fpsstate {
vec o;
int state, editstate;
int lastdeath, deadflush, lastspawn, lifesequence;
int frags, flags, deaths, teamkills, shotdamage, damage, tokens;
int lasttimeplayed, timeplayed;
float effectiveness;
-
gamestate() : state(CS_DEAD), editstate(CS_DEAD), lifesequence(0) {}
-
- bool isalive(int gamemillis)
- {
+ bool isalive(int gamemillis) {
return state==CS_ALIVE || (state==CS_DEAD && gamemillis - lastdeath <= DEATHMILLIS);
}
-
- bool waitexpired(int gamemillis)
- {
+ bool waitexpired(int gamemillis) {
return gamemillis - lastshot >= gunwait;
}
-
- void reset()
- {
+ void reset() {
if(state!=CS_SPECTATOR) state = editstate = CS_DEAD;
maxhealth = 100;
maxarmour = 50;
rockets.reset();
grenades.reset();
-
timeplayed = 0;
effectiveness = 0;
frags = flags = deaths = teamkills = shotdamage = damage = tokens = 0;
-
lastdeath = 0;
-
respawn();
}
-
- void respawn()
- {
+ void respawn() {
fpsstate::respawn();
o = vec(-1e10f, -1e10f, -1e10f);
deadflush = 0;
lastshot = 0;
tokens = 0;
}
-
- void reassign()
- {
+ void reassign() {
respawn();
rockets.reset();
grenades.reset();
}
};
-
- struct savedscore
- {
+ struct savedscore {
uint ip;
string name;
int frags, flags, deaths, teamkills, shotdamage, damage;
int timeplayed;
float effectiveness;
-
- void save(gamestate &gs)
- {
+ void save(gamestate &gs) {
frags = gs.frags;
flags = gs.flags;
deaths = gs.deaths;
timeplayed = gs.timeplayed;
effectiveness = gs.effectiveness;
}
-
- void restore(gamestate &gs)
- {
+ void restore(gamestate &gs) {
gs.frags = frags;
gs.flags = flags;
gs.deaths = deaths;
gs.effectiveness = effectiveness;
}
};
-
extern int gamemillis, nextexceeded;
-
- struct clientinfo
- {
+ struct clientinfo {
int clientnum, ownernum, connectmillis, sessionid, overflow;
string name, team, mapvote;
int playermodel;
void *authchallenge;
int authkickvictim;
char *authkickreason;
-
clientinfo() : getdemo(NULL), getmap(NULL), clipboard(NULL), authchallenge(NULL), authkickreason(NULL) { reset(); }
~clientinfo() { events.deletecontents(); cleanclipboard(); cleanauth(); }
-
- void addevent(gameevent *e)
- {
+ void addevent(gameevent *e) {
if(state.state==CS_SPECTATOR || events.length()>100) delete e;
else events.add(e);
}
-
- enum
- {
+ enum {
PUSHMILLIS = 3000
};
-
- int calcpushrange()
- {
+ int calcpushrange() {
ENetPeer *peer = getclientpeer(ownernum);
return PUSHMILLIS + ((peer) ? (int) (peer->roundTripTime + peer->roundTripTimeVariance) : (int) ENET_PEER_DEFAULT_ROUND_TRIP_TIME);
}
-
- bool checkpushed(int millis, int range)
- {
+ bool checkpushed(int millis, int range) {
return millis >= pushed - range && millis <= pushed + range;
}
-
- void scheduleexceeded()
- {
+ void scheduleexceeded() {
if(state.state!=CS_ALIVE || !exceeded) return;
int range = calcpushrange();
if(!nextexceeded || exceeded + range < nextexceeded) nextexceeded = exceeded + range;
}
-
- void setexceeded()
- {
+ void setexceeded() {
if(state.state==CS_ALIVE && !exceeded && !checkpushed(gamemillis, calcpushrange())) exceeded = gamemillis;
scheduleexceeded();
}
-
- void setpushed()
- {
+ void setpushed() {
pushed = max(pushed, gamemillis);
if(exceeded && checkpushed(exceeded, calcpushrange())) exceeded = 0;
}
-
- bool checkexceeded()
- {
+ bool checkexceeded() {
return state.state==CS_ALIVE && exceeded && gamemillis > exceeded + calcpushrange();
}
-
- void mapchange()
- {
+ void mapchange() {
mapvote[0] = 0;
modevote = INT_MAX;
state.reset();
warned = false;
gameclip = false;
}
-
- void reassign()
- {
+ void reassign() {
state.reassign();
events.deletecontents();
timesync = false;
lastevent = 0;
}
-
- void cleanclipboard(bool fullclean = true)
- {
+ void cleanclipboard(bool fullclean = true) {
if(clipboard) { if(--clipboard->referenceCount <= 0) enet_packet_destroy(clipboard); clipboard = NULL; }
if(fullclean) lastclipboard = 0;
}
-
- void cleanauthkick()
- {
+ void cleanauthkick() {
authkickvictim = -1;
DELETEA(authkickreason);
}
-
- void cleanauth(bool full = true)
- {
+ void cleanauth(bool full = true) {
authreq = 0;
if(authchallenge) { freechallenge(authchallenge); authchallenge = NULL; }
if(full) cleanauthkick();
}
-
- void reset()
- {
+ void reset() {
name[0] = team[0] = 0;
playermodel = -1;
privilege = PRIV_NONE;
cleanauth();
mapchange();
}
-
- int geteventmillis(int servmillis, int clientmillis)
- {
- if(!timesync || (events.empty() && state.waitexpired(servmillis)))
- {
+ int geteventmillis(int servmillis, int clientmillis) {
+ if(!timesync || (events.empty() && state.waitexpired(servmillis))) {
timesync = true;
gameoffset = servmillis - clientmillis;
return servmillis;
else return gameoffset + clientmillis;
}
};
-
- struct ban
- {
+ struct ban {
int time, expire;
uint ip;
};
-
- namespace aiman
- {
+ namespace aiman {
extern void removeai(clientinfo *ci);
extern void clearai();
extern void checkai();
extern void addclient(clientinfo *ci);
extern void changeteam(clientinfo *ci);
}
-
#define MM_MODE 0xF
#define MM_AUTOAPPROVE 0x1000
#define MM_PRIVSERV (MM_MODE | MM_AUTOAPPROVE)
#define MM_PUBSERV ((1<<MM_OPEN) | (1<<MM_VETO))
#define MM_COOPSERV (MM_AUTOAPPROVE | MM_PUBSERV | (1<<MM_LOCKED))
-
bool notgotitems = true; // true when map has changed and waiting for clients to send item
int gamemode = 0;
int gamemillis = 0, gamelimit = 0, nextexceeded = 0, gamespeed = 100;
bool gamepaused = false, shouldstep = true;
-
string smapname = "";
int interm = 0;
enet_uint32 lastsend = 0;
int mastermode = MM_OPEN, mastermask = MM_PRIVSERV;
stream *mapdata = NULL;
-
vector<uint> allowedips;
vector<ban> bannedips;
-
- void addban(uint ip, int expire)
- {
+ void addban(uint ip, int expire) {
allowedips.removeobj(ip);
ban b;
b.time = totalmillis;
loopv(bannedips) if(bannedips[i].expire - b.expire > 0) { bannedips.insert(i, b); return; }
bannedips.add(b);
}
-
vector<clientinfo *> connects, clients, bots;
-
- void kickclients(uint ip, clientinfo *actor = NULL, int priv = PRIV_NONE)
- {
- loopvrev(clients)
- {
+ void kickclients(clientinfo *actor = NULL, int priv = PRIV_NONE) {
+ loopvrev(clients) {
clientinfo &c = *clients[i];
if(c.state.aitype != AI_NONE || c.privilege >= PRIV_ADMIN || c.local) continue;
if(actor && ((c.privilege > priv && !actor->local) || c.clientnum == actor->clientnum)) continue;
- //~if(getclientip(c.clientnum) == ip) disconnect_client(c.clientnum, DISC_KICK);
}
}
-
- struct maprotation
- {
+ struct maprotation {
static int exclude;
int modes;
string map;
-
int calcmodemask() const { return modes&(1<<NUMGAMEMODES) ? modes & ~exclude : modes; }
bool hasmode(int mode, int offset = STARTGAMEMODE) const { return (calcmodemask() & (1 << (mode-offset))) != 0; }
-
- int findmode(int mode) const
- {
+ int findmode(int mode) const {
if(!hasmode(mode)) loopi(NUMGAMEMODES) if(hasmode(i, 0)) return i+STARTGAMEMODE;
return mode;
}
-
- bool match(int reqmode, const char *reqmap) const
- {
+ bool match(int reqmode, const char *reqmap) const {
return hasmode(reqmode) && (!map[0] || !reqmap[0] || !strcmp(map, reqmap));
}
-
- bool includes(const maprotation &rot) const
- {
+ bool includes(const maprotation &rot) const {
return rot.modes == modes ? rot.map[0] && !map[0] : (rot.modes & modes) == rot.modes;
}
};
int maprotation::exclude = 0;
vector<maprotation> maprotations;
int curmaprotation = 0;
-
VAR(lockmaprotation, 0, 0, 2);
-
- void maprotationreset()
- {
+ void maprotationreset() {
maprotations.setsize(0);
curmaprotation = 0;
maprotation::exclude = 0;
}
-
- void nextmaprotation()
- {
+ void nextmaprotation() {
curmaprotation++;
if(maprotations.inrange(curmaprotation) && maprotations[curmaprotation].modes) return;
do curmaprotation--;
while(maprotations.inrange(curmaprotation) && maprotations[curmaprotation].modes);
curmaprotation++;
}
-
- int findmaprotation(int mode, const char *map)
- {
- for(int i = max(curmaprotation, 0); i < maprotations.length(); i++)
- {
+ int findmaprotation(int mode, const char *map) {
+ for(int i = max(curmaprotation, 0); i < maprotations.length(); i++) {
maprotation &rot = maprotations[i];
if(!rot.modes) break;
if(rot.match(mode, map)) return i;
int start;
for(start = max(curmaprotation, 0) - 1; start >= 0; start--) if(!maprotations[start].modes) break;
start++;
- for(int i = start; i < curmaprotation; i++)
- {
+ for(int i = start; i < curmaprotation; i++) {
maprotation &rot = maprotations[i];
if(!rot.modes) break;
if(rot.match(mode, map)) return i;
}
int best = -1;
- loopv(maprotations)
- {
+ loopv(maprotations) {
maprotation &rot = maprotations[i];
if(rot.match(mode, map) && (best < 0 || maprotations[best].includes(rot))) best = i;
}
return best;
}
-
- bool searchmodename(const char *haystack, const char *needle)
- {
+ bool searchmodename(const char *haystack, const char *needle) {
if(!needle[0]) return true;
- do
- {
- if(needle[0] != '.')
- {
+ do {
+ if(needle[0] != '.') {
haystack = strchr(haystack, needle[0]);
if(!haystack) break;
haystack++;
}
const char *h = haystack, *n = needle+1;
- for(; *h && *n; h++)
- {
+ for(; *h && *n; h++) {
if(*h == *n) n++;
else if(*h != ' ') break;
}
} while(needle[0] != '.');
return false;
}
-
- int genmodemask(vector<char *> &modes)
- {
+ int genmodemask(vector<char *> &modes) {
int modemask = 0;
- loopv(modes)
- {
+ loopv(modes) {
const char *mode = modes[i];
int op = mode[0];
- switch(mode[0])
- {
+ switch(mode[0]) {
case '*':
modemask |= 1<<NUMGAMEMODES;
loopk(NUMGAMEMODES) if(m_checknot(k+STARTGAMEMODE, M_DEMO|M_EDIT|M_LOCAL)) modemask |= 1<<k;
[[fallthrough]];
case '?':
mode++;
- loopk(NUMGAMEMODES) if(searchmodename(gamemodes[k].name, mode))
- {
+ loopk(NUMGAMEMODES) if(searchmodename(gamemodes[k].name, mode)) {
if(op == '!') modemask &= ~(1<<k);
else modemask |= 1<<k;
}
if(isdigit(mode[0])) modenum = atoi(mode);
else loopk(NUMGAMEMODES) if(searchmodename(gamemodes[k].name, mode)) { modenum = k+STARTGAMEMODE; break; }
if(!m_valid(modenum)) continue;
- switch(op)
- {
+ switch(op) {
case '!': modemask &= ~(1 << (modenum - STARTGAMEMODE)); break;
default: modemask |= 1 << (modenum - STARTGAMEMODE); break;
}
}
return modemask;
}
-
- bool addmaprotation(int modemask, const char *map)
- {
+ bool addmaprotation(int modemask, const char *map) {
if(!map[0]) loopk(NUMGAMEMODES) if(modemask&(1<<k) && !m_check(k+STARTGAMEMODE, M_EDIT)) modemask &= ~(1<<k);
if(!modemask) return false;
if(!(modemask&(1<<NUMGAMEMODES))) maprotation::exclude |= modemask;
copystring(rot.map, map);
return true;
}
-
- void addmaprotations(tagval *args, int numargs)
- {
+ void addmaprotations(tagval *args, int numargs) {
vector<char *> modes, maps;
- for(int i = 0; i + 1 < numargs; i += 2)
- {
+ for(int i = 0; i + 1 < numargs; i += 2) {
explodelist(args[i].getstr(), modes);
explodelist(args[i+1].getstr(), maps);
int modemask = genmodemask(modes);
modes.deletearrays();
maps.deletearrays();
}
- if(maprotations.length() && maprotations.last().modes)
- {
+ if(maprotations.length() && maprotations.last().modes) {
maprotation &rot = maprotations.add();
rot.modes = 0;
rot.map[0] = '\0';
}
}
-
COMMAND(maprotationreset, "");
COMMANDN(maprotation, addmaprotations, "ss2V");
-
- struct demofile
- {
+ struct demofile {
string info;
uchar *data;
int len;
};
-
vector<demofile> demos;
-
bool demonextmatch = false;
stream *demotmp = NULL, *demorecord = NULL, *demoplayback = NULL;
int nextplayback = 0;
-
VAR(maxdemos, 0, 5, 25);
VAR(maxdemosize, 0, 16, 31);
VAR(restrictdemos, 0, 1, 1);
VARF(autorecorddemo, 0, 0, 1, demonextmatch = autorecorddemo!=0);
-
VAR(restrictpausegame, 0, 1, 1);
VAR(restrictgamespeed, 0, 1, 1);
-
SVAR(serverdesc, "");
SVAR(serverpass, "");
SVAR(adminpass, "");
VARF(publicserver, 0, 0, 2, {
- switch(publicserver)
- {
+ switch(publicserver) {
case 0: default: mastermask = MM_PRIVSERV; break;
case 1: mastermask = MM_PUBSERV; break;
case 2: mastermask = MM_COOPSERV; break;
}
});
SVAR(servermotd, "");
-
- struct teamkillkick
- {
+ struct teamkillkick {
int modes, limit, ban;
-
- bool match(int mode) const
- {
+ bool match(int mode) const {
return (modes&(1<<(mode-STARTGAMEMODE)))!=0;
}
-
- bool includes(const teamkillkick &tk) const
- {
+ bool includes(const teamkillkick &tk) const {
return tk.modes != modes && (tk.modes & modes) == tk.modes;
}
};
vector<teamkillkick> teamkillkicks;
-
- void teamkillkickreset()
- {
+ void teamkillkickreset() {
teamkillkicks.setsize(0);
}
-
- void addteamkillkick(char *modestr, int *limit, int *ban)
- {
+ void addteamkillkick(char *modestr, int *limit, int *ban) {
vector<char *> modes;
explodelist(modestr, modes);
teamkillkick &kick = teamkillkicks.add();
kick.ban = *ban > 0 ? *ban*60000 : (*ban < 0 ? 0 : 30*60000);
modes.deletearrays();
}
-
COMMAND(teamkillkickreset, "");
COMMANDN(teamkillkick, addteamkillkick, "sii");
-
- struct teamkillinfo
- {
+ struct teamkillinfo {
uint ip;
int teamkills;
};
vector<teamkillinfo> teamkills;
bool shouldcheckteamkills = false;
-
- void addteamkill(clientinfo *actor, clientinfo *victim, int n)
- {
+ void addteamkill(clientinfo *actor, clientinfo *victim, int n) {
if(!m_timed || actor->state.aitype != AI_NONE || actor->local || actor->privilege || (victim && victim->state.aitype != AI_NONE)) return;
shouldcheckteamkills = true;
uint ip = getclientip(actor->clientnum);
- loopv(teamkills) if(teamkills[i].ip == ip)
- {
+ loopv(teamkills) if(teamkills[i].ip == ip) {
teamkills[i].teamkills += n;
return;
}
tk.ip = ip;
tk.teamkills = n;
}
-
- void checkteamkills()
- {
+ void checkteamkills() {
teamkillkick *kick = NULL;
if(m_timed) loopv(teamkillkicks) if(teamkillkicks[i].match(gamemode) && (!kick || kick->includes(teamkillkicks[i])))
kick = &teamkillkicks[i];
- if(kick) loopvrev(teamkills)
- {
+ if(kick) loopvrev(teamkills) {
teamkillinfo &tk = teamkills[i];
- if(tk.teamkills >= kick->limit)
- {
+ if(tk.teamkills >= kick->limit) {
if(kick->ban > 0) addban(tk.ip, kick->ban);
- kickclients(tk.ip);
+ kickclients();
teamkills.removeunordered(i);
}
}
shouldcheckteamkills = false;
}
-
void *newclientinfo() { return new clientinfo; }
void deleteclientinfo(void *ci) { delete (clientinfo *)ci; }
-
- clientinfo *getinfo(int n)
- {
+ clientinfo *getinfo(int n) {
if(n < MAXCLIENTS) return (clientinfo *)getclientinfo(n);
n -= MAXCLIENTS;
return bots.inrange(n) ? bots[n] : NULL;
}
-
uint mcrc = 0;
vector<entity> ments;
vector<server_entity> sents;
vector<savedscore> scores;
-
- int msgsizelookup(int msg)
- {
+ int msgsizelookup(int msg) {
static int sizetable[NUMMSG] = { -1 };
- if(sizetable[0] < 0)
- {
+ if(sizetable[0] < 0) {
memset(sizetable, -1, sizeof(sizetable));
for(const int *p = msgsizes; *p >= 0; p += 2) sizetable[p[0]] = p[1];
}
return msg >= 0 && msg < NUMMSG ? sizetable[msg] : -1;
}
-
- const char *modename(int n, const char *unknown)
- {
+ const char *modename(int n, const char *unknown) {
if(m_valid(n)) return gamemodes[n - STARTGAMEMODE].name;
return unknown;
}
-
- const char *mastermodename(int n, const char *unknown)
- {
+ const char *mastermodename(int n, const char *unknown) {
return (n>=MM_START && size_t(n-MM_START)<sizeof(mastermodenames)/sizeof(mastermodenames[0])) ? mastermodenames[n-MM_START] : unknown;
}
-
- const char *privname(int type)
- {
- switch(type)
- {
+ const char *privname(int type) {
+ switch(type) {
case PRIV_ADMIN: return "admin";
case PRIV_AUTH: return "auth";
case PRIV_MASTER: return "master";
default: return "unknown";
}
}
-
void sendservmsg(const char *s) { sendf(-1, 1, "ris", N_SERVMSG, s); }
- void sendservmsgf(const char *fmt, ...)
- {
+ void sendservmsgf(const char *fmt, ...) {
defvformatstring(s, fmt, fmt);
sendf(-1, 1, "ris", N_SERVMSG, s);
}
-
- void resetitems()
- {
+ void resetitems() {
mcrc = 0;
ments.setsize(0);
sents.setsize(0);
//cps.reset();
}
-
- bool serveroption(const char *arg)
- {
- if(arg[0]=='-') switch(arg[1])
- {
+ bool serveroption(const char *arg) {
+ if(arg[0]=='-') switch(arg[1]) {
case 'n': setsvar("serverdesc", &arg[2]); return true;
case 'y': setsvar("serverpass", &arg[2]); return true;
case 'p': setsvar("adminpass", &arg[2]); return true;
}
return false;
}
-
- void serverinit()
- {
+ void serverinit() {
smapname[0] = '\0';
resetitems();
}
-
- int numclients(int exclude = -1, bool nospec = true, bool noai = true, bool priv = false)
- {
+ int numclients(int exclude = -1, bool nospec = true, bool noai = true, bool priv = false) {
int n = 0;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->clientnum!=exclude && (!nospec || ci->state.state!=CS_SPECTATOR || (priv && (ci->privilege || ci->local))) && (!noai || ci->state.aitype == AI_NONE)) n++;
}
return n;
}
-
- bool duplicatename(clientinfo *ci, const char *name)
- {
+ bool duplicatename(clientinfo *ci, const char *name) {
if(!name) name = ci->name;
loopv(clients) if(clients[i]!=ci && !strcmp(name, clients[i]->name)) return true;
return false;
}
-
- const char *colorname(clientinfo *ci, const char *name = NULL)
- {
+ const char *colorname(clientinfo *ci, const char *name = NULL) {
if(!name) name = ci->name;
if(name[0] && !duplicatename(ci, name) && ci->state.aitype == AI_NONE) return name;
static string cname[3];
formatstring(cname[cidx], ci->state.aitype == AI_NONE ? "%s \fs\f5(%d)\fr" : "%s \fs\f5[%d]\fr", name, ci->clientnum);
return cname[cidx];
}
-
bool canspawnitem(int type) { return !m_noitems && (type>=I_SHELLS && type<=I_QUAD && (!m_noammo || type<I_SHELLS || type>I_CARTRIDGES)); }
-
- int spawntime(int type)
- {
+ int spawntime(int type) {
int np = numclients(-1, true, false);
np = np<3 ? 4 : (np>4 ? 2 : 3); // spawn times are dependent on number of players
int sec = 0;
- switch(type)
- {
+ switch(type) {
case I_SHELLS:
case I_BULLETS:
case I_ROCKETS:
}
return sec*1000;
}
-
- bool delayspawn(int type)
- {
- switch(type)
- {
+ bool delayspawn(int type) {
+ switch(type) {
case I_GREENARMOUR:
case I_YELLOWARMOUR:
case I_BOOST:
return false;
}
}
-
- bool pickup(int i, int sender) // server side item pickup, acknowledge first client that gets it
- {
+ bool pickup(int i, int sender) { // server side item pickup, acknowledge first client that gets it {
if((m_timed && gamemillis>=gamelimit) || !sents.inrange(i) || !sents[i].spawned) return false;
clientinfo *ci = getinfo(sender);
if(!ci) return false;
- if(!ci->local && !ci->state.canpickup(sents[i].type))
- {
+ if(!ci->local && !ci->state.canpickup(sents[i].type)) {
sendf(sender, 1, "ri3", N_ITEMACC, i, -1);
return false;
}
ci->state.pickup(sents[i].type);
return true;
}
-
static hashset<teaminfo> teaminfos;
-
- void clearteaminfo()
- {
+ void clearteaminfo() {
teaminfos.clear();
}
-
bool teamhasplayers(const char *team) { loopv(clients) if(!strcmp(clients[i]->team, team)) return true; return false; }
-
- bool pruneteaminfo()
- {
+ bool pruneteaminfo() {
int oldteams = teaminfos.numelems;
enumerate(teaminfos, teaminfo, old,
if(!old.frags && !teamhasplayers(old.team)) teaminfos.remove(old.team);
);
return teaminfos.numelems < oldteams;
}
-
- teaminfo *addteaminfo(const char *team)
- {
+ teaminfo *addteaminfo(const char *team) {
teaminfo *t = teaminfos.access(team);
- if(!t)
- {
+ if(!t) {
if(teaminfos.numelems >= MAXTEAMS && !pruneteaminfo()) return NULL;
t = &teaminfos[team];
copystring(t->team, team, sizeof(t->team));
}
return t;
}
-
- clientinfo *choosebestclient(float &bestrank)
- {
+ clientinfo *choosebestclient(float &bestrank) {
clientinfo *best = NULL;
bestrank = -1;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->state.timeplayed<0) continue;
float rank = ci->state.state!=CS_SPECTATOR ? ci->state.effectiveness/max(ci->state.timeplayed, 1) : -1;
}
return best;
}
-
VAR(persistteams, 0, 0, 1);
-
- void autoteam()
- {
+ void autoteam() {
static const char * const teamnames[2] = {"good", "evil"};
vector<clientinfo *> team[2];
float teamrank[2] = {0, 0};
- for(int round = 0, remaining = clients.length(); remaining>=0; round++)
- {
+ for(int round = 0, remaining = clients.length(); remaining>=0; round++) {
int first = round&1, second = (round+1)&1, selected = 0;
- while(teamrank[first] <= teamrank[second])
- {
+ while(teamrank[first] <= teamrank[second]) {
float rank;
clientinfo *ci = choosebestclient(rank);
if(!ci) break;
if(!selected) break;
remaining -= selected;
}
- loopi(sizeof(team)/sizeof(team[0]))
- {
+ loopi(sizeof(team)/sizeof(team[0])) {
addteaminfo(teamnames[i]);
- loopvj(team[i])
- {
+ loopvj(team[i]) {
clientinfo *ci = team[i][j];
if(!strcmp(ci->team, teamnames[i])) continue;
- if(persistteams && ci->team[0])
- {
+ if(persistteams && ci->team[0]) {
addteaminfo(ci->team);
continue;
}
}
}
}
-
- struct teamrank
- {
+ struct teamrank {
const char *name;
float rank;
int clients;
-
teamrank(const char *name) : name(name), rank(0), clients(0) {}
};
-
- const char *chooseworstteam(const char *suggest = NULL, clientinfo *exclude = NULL)
- {
+ const char *chooseworstteam(clientinfo *exclude = NULL) {
teamrank teamranks[2] = { teamrank("good"), teamrank("evil") };
const int numteams = sizeof(teamranks)/sizeof(teamranks[0]);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci==exclude || ci->state.aitype!=AI_NONE || ci->state.state==CS_SPECTATOR || !ci->team[0]) continue;
ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed;
ci->state.lasttimeplayed = lastmillis;
-
- loopj(numteams) if(!strcmp(ci->team, teamranks[j].name))
- {
+ loopj(numteams) if(!strcmp(ci->team, teamranks[j].name)) {
teamrank &ts = teamranks[j];
ts.rank += ci->state.effectiveness/max(ci->state.timeplayed, 1);
ts.clients++;
}
}
teamrank *worst = &teamranks[numteams-1];
- loopi(numteams-1)
- {
+ loopi(numteams-1) {
teamrank &ts = teamranks[i];
if(ts.rank < worst->rank || (ts.rank == worst->rank && ts.clients < worst->clients)) worst = &ts;
}
return worst->name;
}
-
- void prunedemos(int extra = 0)
- {
+ void prunedemos(int extra = 0) {
int n = clamp(demos.length() + extra - maxdemos, 0, demos.length());
if(n <= 0) return;
loopi(n) delete[] demos[i].data;
demos.remove(0, n);
}
-
- void adddemo()
- {
+ void adddemo() {
if(!demotmp) return;
int len = (int)min(demotmp->size(), stream::offset((maxdemosize<<20) + 0x10000));
demofile &d = demos.add();
demotmp->read(d.data, len);
DELETEP(demotmp);
}
-
- void enddemorecord()
- {
+ void enddemorecord() {
if(!demorecord) return;
-
DELETEP(demorecord);
-
if(!demotmp) return;
if(!maxdemos || !maxdemosize) { DELETEP(demotmp); return; }
-
prunedemos(1);
adddemo();
}
-
- void writedemo(int chan, void *data, int len)
- {
+ void writedemo(int chan, void *data, int len) {
if(!demorecord) return;
int stamp[3] = { gamemillis, chan, len };
lilswap(stamp, 3);
demorecord->write(data, len);
if(demorecord->rawtell() >= (maxdemosize<<20)) enddemorecord();
}
-
- void recordpacket(int chan, void *data, int len)
- {
+ void recordpacket(int chan, void *data, int len) {
writedemo(chan, data, len);
}
-
int welcomepacket(packetbuf &p, clientinfo *ci);
void sendwelcome(clientinfo *ci);
-
- void setupdemorecord()
- {
+ void setupdemorecord() {
if(!m_mp(gamemode) || m_edit) return;
-
demotmp = opentempfile("demorecord", "w+b");
if(!demotmp) return;
-
stream *f = opengzfile(NULL, "wb", demotmp);
if(!f) { DELETEP(demotmp); return; }
-
sendservmsg("recording demo");
-
demorecord = f;
-
demoheader hdr;
memcpy(hdr.magic, DEMO_MAGIC, sizeof(hdr.magic));
hdr.version = DEMO_VERSION;
hdr.protocol = PROTOCOL_VERSION;
lilswap(&hdr.version, 2);
demorecord->write(&hdr, sizeof(demoheader));
-
packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
welcomepacket(p, NULL);
writedemo(1, p.buf, p.len);
}
-
- void listdemos(int cn)
- {
+ void listdemos(int cn) {
packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
putint(p, N_SENDDEMOLIST);
putint(p, demos.length());
loopv(demos) sendstring(demos[i].info, p);
sendpacket(cn, 1, p.finalize());
}
-
- void cleardemos(int n)
- {
- if(!n)
- {
+ void cleardemos(int n) {
+ if(!n) {
loopv(demos) delete[] demos[i].data;
demos.shrink(0);
sendservmsg("cleared all demos");
}
- else if(demos.inrange(n-1))
- {
+ else if(demos.inrange(n-1)) {
delete[] demos[n-1].data;
demos.remove(n-1);
sendservmsgf("cleared demo %d", n);
}
}
-
- static void freegetmap(ENetPacket *packet)
- {
- loopv(clients)
- {
+ static void freegetmap(ENetPacket *packet) {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->getmap == packet) ci->getmap = NULL;
}
}
-
- static void freegetdemo(ENetPacket *packet)
- {
- loopv(clients)
- {
+ static void freegetdemo(ENetPacket *packet) {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->getdemo == packet) ci->getdemo = NULL;
}
}
-
- void senddemo(clientinfo *ci, int num, int tag)
- {
+ void senddemo(clientinfo *ci, int num, int tag) {
if(ci->getdemo) return;
if(!num) num = demos.length();
if(!demos.inrange(num-1)) return;
if((ci->getdemo = sendf(ci->clientnum, 2, "riim", N_SENDDEMO, tag, d.len, d.data)))
ci->getdemo->freeCallback = freegetdemo;
}
-
- void enddemoplayback()
- {
+ void enddemoplayback() {
if(!demoplayback) return;
DELETEP(demoplayback);
-
loopv(clients) sendf(clients[i]->clientnum, 1, "ri3", N_DEMOPLAYBACK, 0, clients[i]->clientnum);
-
sendservmsg("demo playback finished");
-
loopv(clients) sendwelcome(clients[i]);
}
-
SVARP(demodir, "demo");
-
- const char *getdemofile(const char *file, bool init)
- {
+ const char *getdemofile(const char *file, bool init) {
if(!demodir[0]) return NULL;
static string buf;
copystring(buf, demodir);
int dirlen = strlen(buf);
if(buf[dirlen] != '/' && buf[dirlen] != '\\' && dirlen+1 < (int)sizeof(buf)) { buf[dirlen++] = '/'; buf[dirlen] = '\0'; }
- if(init)
- {
+ if(init) {
const char *dir = findfile(buf, "w");
if(!fileexists(dir, "w")) createdir(dir);
}
concatstring(buf, file);
return buf;
}
-
- void setupdemoplayback()
- {
+ void setupdemoplayback() {
if(demoplayback) return;
demoheader hdr;
string msg;
if(!demoplayback) formatstring(msg, "could not read demo \"%s\"", file);
else if(demoplayback->read(&hdr, sizeof(demoheader))!=sizeof(demoheader) || memcmp(hdr.magic, DEMO_MAGIC, sizeof(hdr.magic)))
formatstring(msg, "\"%s\" is not a demo file", file);
- else
- {
+ else {
lilswap(&hdr.version, 2);
if(hdr.version!=DEMO_VERSION) formatstring(msg, "demo \"%s\" requires an %s version of Cube 2: Sauerbraten", file, hdr.version<DEMO_VERSION ? "older" : "newer");
else if(hdr.protocol!=PROTOCOL_VERSION) formatstring(msg, "demo \"%s\" requires an %s version of Cube 2: Sauerbraten", file, hdr.protocol<PROTOCOL_VERSION ? "older" : "newer");
}
- if(msg[0])
- {
+ if(msg[0]) {
DELETEP(demoplayback);
sendservmsg(msg);
return;
}
-
sendservmsgf("playing demo \"%s\"", file);
-
sendf(-1, 1, "ri3", N_DEMOPLAYBACK, 1, -1);
-
- if(demoplayback->read(&nextplayback, sizeof(nextplayback))!=sizeof(nextplayback))
- {
+ if(demoplayback->read(&nextplayback, sizeof(nextplayback))!=sizeof(nextplayback)) {
enddemoplayback();
return;
}
lilswap(&nextplayback, 1);
}
-
- void readdemo()
- {
+ void readdemo() {
if(!demoplayback) return;
- while(gamemillis>=nextplayback)
- {
+ while(gamemillis>=nextplayback) {
int chan, len;
if(demoplayback->read(&chan, sizeof(chan))!=sizeof(chan) ||
- demoplayback->read(&len, sizeof(len))!=sizeof(len))
- {
+ demoplayback->read(&len, sizeof(len))!=sizeof(len)) {
enddemoplayback();
return;
}
lilswap(&chan, 1);
lilswap(&len, 1);
ENetPacket *packet = enet_packet_create(NULL, len+1, 0);
- if(!packet || demoplayback->read(packet->data+1, len)!=size_t(len))
- {
+ if(!packet || demoplayback->read(packet->data+1, len)!=size_t(len)) {
if(packet) enet_packet_destroy(packet);
enddemoplayback();
return;
sendpacket(-1, chan, packet);
if(!packet->referenceCount) enet_packet_destroy(packet);
if(!demoplayback) break;
- if(demoplayback->read(&nextplayback, sizeof(nextplayback))!=sizeof(nextplayback))
- {
+ if(demoplayback->read(&nextplayback, sizeof(nextplayback))!=sizeof(nextplayback)) {
enddemoplayback();
return;
}
lilswap(&nextplayback, 1);
}
}
-
- void timeupdate(int secs)
- {
+ void timeupdate(int secs) {
if(!demoplayback) return;
if(secs <= 0) interm = -1;
else gamelimit = max(gamelimit, nextplayback + secs*1000);
}
-
- void seekdemo(char *t)
- {
+ void seekdemo(char *t) {
if(!demoplayback) return;
bool rev = *t == '-';
if(rev) t++;
else { secs = mins; mins = 0; }
if(*t == '.') millis = strtoul(t+1, &t, 10);
int offset = max(millis + (mins*60 + secs)*1000, 0), prevmillis = gamemillis;
- if(rev) while(gamelimit - offset > gamemillis)
- {
+ if(rev) while(gamelimit - offset > gamemillis) {
gamemillis = gamelimit - offset;
readdemo();
}
- else if(offset > gamemillis)
- {
+ else if(offset > gamemillis) {
gamemillis = offset;
readdemo();
}
- if(gamemillis > prevmillis)
- {
+ if(gamemillis > prevmillis) {
if(!interm) sendf(-1, 1, "ri2", N_TIMEUP, max((gamelimit - gamemillis)/1000, 1));
}
}
-
- ICOMMAND(seekdemo, "sN$", (char *t, int *numargs, ident *id),
- {
+ ICOMMAND(seekdemo, "sN$", (char *t, int *numargs, ident *id), {
if(*numargs > 0) seekdemo(t);
- else
- {
+ else {
int secs = gamemillis/1000;
defformatstring(str, "%d:%02d.%03d", secs/60, secs%60, gamemillis%1000);
if(*numargs < 0) result(str);
else printsvar(id, str);
}
});
-
- void stopdemo()
- {
+ void stopdemo() {
if(m_demo) enddemoplayback();
else enddemorecord();
}
-
- void pausegame(bool val, clientinfo *ci = NULL)
- {
+ void pausegame(bool val, clientinfo *ci = NULL) {
if(gamepaused==val) return;
gamepaused = val;
sendf(-1, 1, "riii", N_PAUSEGAME, gamepaused ? 1 : 0, ci ? ci->clientnum : -1);
}
-
- void checkpausegame()
- {
+ void checkpausegame() {
if(!gamepaused) return;
int admins = 0;
loopv(clients) if(clients[i]->privilege >= (restrictpausegame ? PRIV_ADMIN : PRIV_MASTER) || clients[i]->local) admins++;
if(!admins) pausegame(false);
}
-
- void forcepaused(bool paused)
- {
+ void forcepaused(bool paused) {
pausegame(paused);
}
-
bool ispaused() { return gamepaused; }
-
- void changegamespeed(int val, clientinfo *ci = NULL)
- {
+ void changegamespeed(int val, clientinfo *ci = NULL) {
val = clamp(val, 10, 1000);
if(gamespeed==val) return;
gamespeed = val;
sendf(-1, 1, "riii", N_GAMESPEED, gamespeed, ci ? ci->clientnum : -1);
}
-
- void forcegamespeed(int speed)
- {
+ void forcegamespeed(int speed) {
changegamespeed(speed);
}
-
int scaletime(int t) { return t*gamespeed; }
-
SVAR(serverauth, "");
-
- struct userkey
- {
+ struct userkey {
char *name;
char *desc;
-
userkey() : name(NULL), desc(NULL) {}
userkey(char *name, char *desc) : name(name), desc(desc) {}
};
-
static inline uint hthash(const userkey &k) { return ::hthash(k.name); }
static inline bool htcmp(const userkey &x, const userkey &y) { return !strcmp(x.name, y.name) && !strcmp(x.desc, y.desc); }
-
- struct userinfo : userkey
- {
+ struct userinfo : userkey {
void *pubkey;
int privilege;
-
userinfo() : pubkey(NULL), privilege(PRIV_NONE) {}
~userinfo() { delete[] name; delete[] desc; if(pubkey) freepubkey(pubkey); }
};
hashset<userinfo> users;
-
- void adduser(char *name, char *desc, char *pubkey, char *priv)
- {
+ void adduser(char *name, char *desc, char *pubkey, char *priv) {
userkey key(name, desc);
userinfo &u = users[key];
if(u.pubkey) { freepubkey(u.pubkey); u.pubkey = NULL; }
if(!u.name) u.name = newstring(name);
if(!u.desc) u.desc = newstring(desc);
u.pubkey = parsepubkey(pubkey);
- switch(priv[0])
- {
+ switch(priv[0]) {
case 'a': case 'A': u.privilege = PRIV_ADMIN; break;
case 'm': case 'M': default: u.privilege = PRIV_AUTH; break;
case 'n': case 'N': u.privilege = PRIV_NONE; break;
}
}
COMMAND(adduser, "ssss");
-
- void clearusers()
- {
+ void clearusers() {
users.clear();
}
COMMAND(clearusers, "");
-
- void hashpassword(int cn, int sessionid, const char *pwd, char *result, int maxlen)
- {
+ void hashpassword(int cn, int sessionid, const char *pwd, char *result, int maxlen) {
char buf[2*sizeof(string)];
formatstring(buf, "%d %d ", cn, sessionid);
concatstring(buf, pwd, sizeof(buf));
if(!hashstring(buf, result, maxlen)) *result = '\0';
}
-
- bool checkpassword(clientinfo *ci, const char *wanted, const char *given)
- {
+ bool checkpassword(clientinfo *ci, const char *wanted, const char *given) {
string hash;
hashpassword(ci->clientnum, ci->sessionid, wanted, hash, sizeof(hash));
return !strcmp(hash, given);
}
-
- void revokemaster(clientinfo *ci)
- {
+ void revokemaster(clientinfo *ci) {
ci->privilege = PRIV_NONE;
if(ci->state.state==CS_SPECTATOR && !ci->local) aiman::removeai(ci);
}
-
extern void connected(clientinfo *ci);
-
- bool setmaster(clientinfo *ci, bool val, const char *pass = "", const char *authname = NULL, const char *authdesc = NULL, int authpriv = PRIV_MASTER, bool force = false, bool trial = false)
- {
+ bool setmaster(clientinfo *ci, bool val, const char *pass = "", const char *authname = NULL, const char *authdesc = NULL, int authpriv = PRIV_MASTER, bool force = false, bool trial = false) {
if(authname && !val) return false;
const char *name = "";
- if(val)
- {
+ if(val) {
bool haspass = adminpass[0] && checkpassword(ci, adminpass, pass);
int wantpriv = ci->local || haspass ? PRIV_ADMIN : authpriv;
if(wantpriv <= ci->privilege) return true;
- else if(wantpriv <= PRIV_MASTER && !force)
- {
- if(ci->state.state==CS_SPECTATOR)
- {
+ else if(wantpriv <= PRIV_MASTER && !force) {
+ if(ci->state.state==CS_SPECTATOR) {
sendf(ci->clientnum, 1, "ris", N_SERVMSG, "Spectators may not claim master.");
return false;
}
- loopv(clients) if(ci!=clients[i] && clients[i]->privilege)
- {
+ loopv(clients) if(ci!=clients[i] && clients[i]->privilege) {
sendf(ci->clientnum, 1, "ris", N_SERVMSG, "Master is already claimed.");
return false;
}
- if(!authname && !(mastermask&MM_AUTOAPPROVE) && !ci->privilege && !ci->local)
- {
+ if(!authname && !(mastermask&MM_AUTOAPPROVE) && !ci->privilege && !ci->local) {
sendf(ci->clientnum, 1, "ris", N_SERVMSG, "This server requires you to use the \"/auth\" command to claim master.");
return false;
}
ci->privilege = wantpriv;
name = privname(ci->privilege);
}
- else
- {
+ else {
if(!ci->privilege) return false;
if(trial) return true;
name = privname(ci->privilege);
}
bool hasmaster = false;
loopv(clients) if(clients[i]->local || clients[i]->privilege >= PRIV_MASTER) hasmaster = true;
- if(!hasmaster)
- {
+ if(!hasmaster) {
mastermode = MM_OPEN;
allowedips.shrink(0);
}
string msg;
- if(val && authname)
- {
+ if(val && authname) {
if(authdesc && authdesc[0]) formatstring(msg, "%s claimed %s as '\fs\f5%s\fr' [\fs\f0%s\fr]", colorname(ci), name, authname, authdesc);
else formatstring(msg, "%s claimed %s as '\fs\f5%s\fr'", colorname(ci), name, authname);
}
sendstring(msg, p);
putint(p, N_CURRENTMASTER);
putint(p, mastermode);
- loopv(clients) if(clients[i]->privilege >= PRIV_MASTER)
- {
+ loopv(clients) if(clients[i]->privilege >= PRIV_MASTER) {
putint(p, clients[i]->clientnum);
putint(p, clients[i]->privilege);
}
checkpausegame();
return true;
}
-
- bool trykick(clientinfo *ci, int victim, const char *reason = NULL, const char *authname = NULL, const char *authdesc = NULL, int authpriv = PRIV_NONE, bool trial = false)
- {
+ bool trykick(clientinfo *ci, int victim, const char *reason = NULL, const char *authname = NULL, const char *authdesc = NULL, int authpriv = PRIV_NONE, bool trial = false) {
int priv = ci->privilege;
- if(authname)
- {
+ if(authname) {
if(priv >= authpriv || ci->local) authname = authdesc = NULL;
else priv = authpriv;
}
- if((priv || ci->local) && ci->clientnum!=victim)
- {
+ if((priv || ci->local) && ci->clientnum!=victim) {
clientinfo *vinfo = (clientinfo *)getclientinfo(victim);
- if(vinfo && vinfo->connected && (priv >= vinfo->privilege || ci->local) && vinfo->privilege < PRIV_ADMIN && !vinfo->local)
- {
+ if(vinfo && vinfo->connected && (priv >= vinfo->privilege || ci->local) && vinfo->privilege < PRIV_ADMIN && !vinfo->local) {
if(trial) return true;
string kicker;
- if(authname)
- {
+ if(authname) {
if(authdesc && authdesc[0]) formatstring(kicker, "%s as '\fs\f5%s\fr' [\fs\f0%s\fr]", colorname(ci), authname, authdesc);
else formatstring(kicker, "%s as '\fs\f5%s\fr'", colorname(ci), authname);
}
else sendservmsgf("%s kicked %s", kicker, colorname(vinfo));
uint ip = getclientip(victim);
addban(ip, 4*60*60000);
- kickclients(ip, ci, priv);
+ kickclients(ci, priv);
}
}
return false;
}
-
- savedscore *findscore(clientinfo *ci, bool insert)
- {
+ savedscore *findscore(clientinfo *ci, bool insert) {
uint ip = getclientip(ci->clientnum);
if(!ip && !ci->local) return 0;
- if(!insert)
- {
- loopv(clients)
- {
+ if(!insert) {
+ loopv(clients) {
clientinfo *oi = clients[i];
- if(oi->clientnum != ci->clientnum && getclientip(oi->clientnum) == ip && !strcmp(oi->name, ci->name))
- {
+ if(oi->clientnum != ci->clientnum && getclientip(oi->clientnum) == ip && !strcmp(oi->name, ci->name)) {
oi->state.timeplayed += lastmillis - oi->state.lasttimeplayed;
oi->state.lasttimeplayed = lastmillis;
static savedscore curscore;
}
}
}
- loopv(scores)
- {
+ loopv(scores) {
savedscore &sc = scores[i];
if(sc.ip == ip && !strcmp(sc.name, ci->name)) return ≻
}
copystring(sc.name, ci->name);
return ≻
}
-
- void savescore(clientinfo *ci)
- {
+ void savescore(clientinfo *ci) {
savedscore *sc = findscore(ci, true);
if(sc) sc->save(ci->state);
}
-
- static struct msgfilter
- {
+ static struct msgfilter {
uchar msgmask[NUMMSG];
-
- msgfilter(int msg, ...)
- {
+ msgfilter(int msg, ...) {
memset(msgmask, 0, sizeof(msgmask));
va_list msgs;
va_start(msgs, msg);
- for(uchar val = 1; msg < NUMMSG; msg = va_arg(msgs, int))
- {
+ for(uchar val = 1; msg < NUMMSG; msg = va_arg(msgs, int)) {
if(msg < 0) val = uchar(-msg);
else msgmask[msg] = val;
}
va_end(msgs);
}
-
uchar operator[](int msg) const { return msg >= 0 && msg < NUMMSG ? msgmask[msg] : 0; }
} msgfilter(-1, N_CONNECT, N_SERVINFO, N_INITCLIENT, N_WELCOME, N_MAPCHANGE, N_SERVMSG, N_DAMAGE, N_HITPUSH, N_SHOTFX, N_EXPLODEFX, N_DIED,
N_SPAWNSTATE, N_FORCEDEATH, N_TEAMINFO, N_ITEMACC, N_ITEMSPAWN, N_TIMEUP, N_CDIS, N_CURRENTMASTER, N_PONG, N_RESUME,
N_NEWMAP, N_GETMAP, N_SENDMAP, N_CLIPBOARD, -3, N_EDITENT, N_EDITF, N_EDITT, N_EDITM, N_FLIP, N_COPY, N_PASTE, N_ROTATE, N_REPLACE,
N_DELCUBE, N_EDITVAR, N_EDITVSLOT, N_UNDO, N_REDO, -4, N_POS, NUMMSG),
connectfilter(-1, N_CONNECT, -2, N_AUTHANS, -3, N_PING, NUMMSG);
-
- int checktype(int type, clientinfo *ci)
- {
- if(ci)
- {
- if(!ci->connected) switch(connectfilter[type])
- {
+ int checktype(int type, clientinfo *ci) {
+ if(ci) {
+ if(!ci->connected) switch(connectfilter[type]) {
// allow only before authconnect
case 1: return !ci->connectauth ? type : -1;
// allow only during authconnect
}
if(ci->local) return type;
}
- switch(msgfilter[type])
- {
+ switch(msgfilter[type]) {
// server-only messages
case 1: return ci ? -1 : type;
// only allowed in coop-edit
if(ci && ++ci->overflow >= 200) return -2;
return type;
}
-
- struct worldstate
- {
+ struct worldstate {
int uses, len;
uchar *data;
-
worldstate() : uses(0), len(0), data(NULL) {}
-
void setup(int n) { len = n; data = new uchar[n]; }
void cleanup() { DELETEA(data); len = 0; }
bool contains(const uchar *p) const { return p >= data && p < &data[len]; }
};
vector<worldstate> worldstates;
bool reliablemessages = false;
-
- void cleanworldstate(ENetPacket *packet)
- {
- loopv(worldstates)
- {
+ void cleanworldstate(ENetPacket *packet) {
+ loopv(worldstates) {
worldstate &ws = worldstates[i];
if(!ws.contains(packet->data)) continue;
ws.uses--;
- if(ws.uses <= 0)
- {
+ if(ws.uses <= 0) {
ws.cleanup();
worldstates.removeunordered(i);
}
break;
}
}
-
- void flushclientposition(clientinfo &ci)
- {
+ void flushclientposition(clientinfo &ci) {
if(ci.position.empty() || (!hasnonlocalclients() && !demorecord)) return;
packetbuf p(ci.position.length(), 0);
p.put(ci.position.getbuf(), ci.position.length());
ci.position.setsize(0);
sendpacket(-1, 0, p.finalize(), ci.ownernum);
}
-
- static void sendpositions(worldstate &ws, ucharbuf &wsbuf)
- {
+ static void sendpositions(worldstate &ws, ucharbuf &wsbuf) {
if(wsbuf.empty()) return;
int wslen = wsbuf.length();
recordpacket(0, wsbuf.buf, wslen);
wsbuf.put(wsbuf.buf, wslen);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo &ci = *clients[i];
if(ci.state.aitype != AI_NONE) continue;
uchar *data = wsbuf.buf;
}
wsbuf.offset(wsbuf.length());
}
-
- static inline void addposition(worldstate &ws, ucharbuf &wsbuf, int mtu, clientinfo &bi, clientinfo &ci)
- {
+ static inline void addposition(worldstate &ws, ucharbuf &wsbuf, int mtu, clientinfo &bi, clientinfo &ci) {
if(bi.position.empty()) return;
if(wsbuf.length() + bi.position.length() > mtu) sendpositions(ws, wsbuf);
int offset = wsbuf.length();
if(ci.wsdata < wsbuf.buf) { ci.wsdata = &wsbuf.buf[offset]; ci.wslen = len; }
else ci.wslen += len;
}
-
- static void sendmessages(worldstate &ws, ucharbuf &wsbuf)
- {
+ static void sendmessages(worldstate &ws, ucharbuf &wsbuf) {
if(wsbuf.empty()) return;
int wslen = wsbuf.length();
recordpacket(1, wsbuf.buf, wslen);
wsbuf.put(wsbuf.buf, wslen);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo &ci = *clients[i];
if(ci.state.aitype != AI_NONE) continue;
uchar *data = wsbuf.buf;
}
wsbuf.offset(wsbuf.length());
}
-
- static inline void addmessages(worldstate &ws, ucharbuf &wsbuf, int mtu, clientinfo &bi, clientinfo &ci)
- {
+ static inline void addmessages(worldstate &ws, ucharbuf &wsbuf, int mtu, clientinfo &bi, clientinfo &ci) {
if(bi.messages.empty()) return;
if(wsbuf.length() + 10 + bi.messages.length() > mtu) sendmessages(ws, wsbuf);
int offset = wsbuf.length();
if(ci.wsdata < wsbuf.buf) { ci.wsdata = &wsbuf.buf[offset]; ci.wslen = len; }
else ci.wslen += len;
}
-
- bool buildworldstate()
- {
+ bool buildworldstate() {
int wsmax = 0;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo &ci = *clients[i];
ci.overflow = 0;
ci.wsdata = NULL;
wsmax += ci.position.length();
if(ci.messages.length()) wsmax += 10 + ci.messages.length();
}
- if(wsmax <= 0)
- {
+ if(wsmax <= 0) {
reliablemessages = false;
return false;
}
int mtu = getservermtu() - 100;
if(mtu <= 0) mtu = ws.len;
ucharbuf wsbuf(ws.data, ws.len);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo &ci = *clients[i];
if(ci.state.aitype != AI_NONE) continue;
addposition(ws, wsbuf, mtu, ci, ci);
loopvj(ci.bots) addposition(ws, wsbuf, mtu, *ci.bots[j], ci);
}
sendpositions(ws, wsbuf);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo &ci = *clients[i];
if(ci.state.aitype != AI_NONE) continue;
addmessages(ws, wsbuf, mtu, ci, ci);
worldstates.drop();
return false;
}
-
- bool sendpackets(bool force)
- {
+ bool sendpackets(bool force) {
if(clients.empty() || (!hasnonlocalclients() && !demorecord)) return false;
enet_uint32 curtime = enet_time_get()-lastsend;
if(curtime<33 && !force) return false;
lastsend += curtime - (curtime%33);
return flush;
}
-
template<class T>
- void sendstate(gamestate &gs, T &p)
- {
+ void sendstate(gamestate &gs, T &p) {
putint(p, gs.lifesequence);
putint(p, gs.health);
putint(p, gs.maxhealth);
putint(p, gs.gunselect);
loopi(GUN_PISTOL-GUN_SG+1) putint(p, gs.ammo[GUN_SG+i]);
}
-
- void spawnstate(clientinfo *ci)
- {
+ void spawnstate(clientinfo *ci) {
gamestate &gs = ci->state;
gs.spawnstate(gamemode);
gs.lifesequence = (gs.lifesequence + 1)&0x7F;
}
-
- void sendspawn(clientinfo *ci)
- {
+ void sendspawn(clientinfo *ci) {
gamestate &gs = ci->state;
spawnstate(ci);
sendf(ci->ownernum, 1, "rii8v", N_SPAWNSTATE, ci->clientnum, gs.lifesequence,
gs.gunselect, GUN_PISTOL-GUN_SG+1, &gs.ammo[GUN_SG]);
gs.lastspawn = gamemillis;
}
-
- void sendwelcome(clientinfo *ci)
- {
+ void sendwelcome(clientinfo *ci) {
packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
int chan = welcomepacket(p, ci);
sendpacket(ci->clientnum, chan, p.finalize());
}
-
- void putinitclient(clientinfo *ci, packetbuf &p)
- {
- if(ci->state.aitype != AI_NONE)
- {
+ void putinitclient(clientinfo *ci, packetbuf &p) {
+ if(ci->state.aitype != AI_NONE) {
putint(p, N_INITAI);
putint(p, ci->clientnum);
putint(p, ci->ownernum);
sendstring(ci->name, p);
sendstring(ci->team, p);
}
- else
- {
+ else {
putint(p, N_INITCLIENT);
putint(p, ci->clientnum);
sendstring(ci->name, p);
putint(p, ci->playermodel);
}
}
-
- void welcomeinitclient(packetbuf &p, int exclude = -1)
- {
- loopv(clients)
- {
+ void welcomeinitclient(packetbuf &p, int exclude = -1) {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(!ci->connected || ci->clientnum == exclude) continue;
-
putinitclient(ci, p);
}
}
-
- bool hasmap(clientinfo *ci)
- {
+ bool hasmap(clientinfo *ci) {
return (m_edit && (clients.length() > 0 || ci->local)) ||
(smapname[0] && (!m_timed || gamemillis < gamelimit || (ci->state.state==CS_SPECTATOR && !ci->privilege && !ci->local) || numclients(ci->clientnum, true, true, true)));
}
-
- int welcomepacket(packetbuf &p, clientinfo *ci)
- {
+ int welcomepacket(packetbuf &p, clientinfo *ci) {
putint(p, N_WELCOME);
putint(p, N_MAPCHANGE);
sendstring(smapname, p);
putint(p, gamemode);
putint(p, notgotitems ? 1 : 0);
- if(!ci || (m_timed && smapname[0]))
- {
+ if(!ci || (m_timed && smapname[0])) {
putint(p, N_TIMEUP);
putint(p, gamemillis < gamelimit && !interm ? max((gamelimit - gamemillis)/1000, 1) : 0);
}
- if(!notgotitems)
- {
+ if(!notgotitems) {
putint(p, N_ITEMLIST);
- loopv(sents) if(sents[i].spawned)
- {
+ loopv(sents) if(sents[i].spawned) {
putint(p, i);
putint(p, sents[i].type);
}
putint(p, -1);
}
bool hasmaster = false;
- if(mastermode != MM_OPEN)
- {
+ if(mastermode != MM_OPEN) {
putint(p, N_CURRENTMASTER);
putint(p, mastermode);
hasmaster = true;
}
- loopv(clients) if(clients[i]->privilege >= PRIV_MASTER)
- {
- if(!hasmaster)
- {
+ loopv(clients) if(clients[i]->privilege >= PRIV_MASTER) {
+ if(!hasmaster) {
putint(p, N_CURRENTMASTER);
putint(p, mastermode);
hasmaster = true;
putint(p, clients[i]->privilege);
}
if(hasmaster) putint(p, -1);
- if(gamepaused)
- {
+ if(gamepaused) {
putint(p, N_PAUSEGAME);
putint(p, 1);
putint(p, -1);
}
- if(gamespeed != 100)
- {
+ if(gamespeed != 100) {
putint(p, N_GAMESPEED);
putint(p, gamespeed);
putint(p, -1);
}
- if(m_teammode)
- {
+ if(m_teammode) {
putint(p, N_TEAMINFO);
enumerate(teaminfos, teaminfo, t,
if(t.frags) { sendstring(t.team, p); putint(p, t.frags); }
);
sendstring("", p);
}
- if(ci)
- {
+ if(ci) {
putint(p, N_SETTEAM);
putint(p, ci->clientnum);
sendstring(ci->team, p);
putint(p, -1);
}
- if(ci && (m_demo || m_mp(gamemode)) && ci->state.state!=CS_SPECTATOR)
- {
+ if(ci && (m_demo || m_mp(gamemode)) && ci->state.state!=CS_SPECTATOR) {
gamestate &gs = ci->state;
spawnstate(ci);
putint(p, N_SPAWNSTATE);
sendstate(gs, p);
gs.lastspawn = gamemillis;
}
- if(ci && ci->state.state==CS_SPECTATOR)
- {
+ if(ci && ci->state.state==CS_SPECTATOR) {
putint(p, N_SPECTATOR);
putint(p, ci->clientnum);
putint(p, 1);
sendf(-1, 1, "ri3x", N_SPECTATOR, ci->clientnum, 1, ci->clientnum);
}
- if(!ci || clients.length()>1)
- {
+ if(!ci || clients.length()>1) {
putint(p, N_RESUME);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *oi = clients[i];
if(ci && oi->clientnum==ci->clientnum) continue;
putint(p, oi->clientnum);
}
return 1;
}
-
- bool restorescore(clientinfo *ci)
- {
+ bool restorescore(clientinfo *ci) {
//if(ci->local) return false;
savedscore *sc = findscore(ci, false);
- if(sc)
- {
+ if(sc) {
sc->restore(ci->state);
return true;
}
return false;
}
-
- void sendresume(clientinfo *ci)
- {
+ void sendresume(clientinfo *ci) {
gamestate &gs = ci->state;
sendf(-1, 1, "ri3i5i6vi", N_RESUME, ci->clientnum, gs.state,
gs.frags, gs.flags, gs.deaths, gs.quadmillis,
gs.armour, gs.maxarmour, gs.armourtype,
gs.gunselect, GUN_PISTOL-GUN_SG+1, &gs.ammo[GUN_SG], -1);
}
-
- void sendinitclient(clientinfo *ci)
- {
+ void sendinitclient(clientinfo *ci) {
packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
putinitclient(ci, p);
sendpacket(-1, 1, p.finalize(), ci->clientnum);
}
-
- void loaditems()
- {
+ void loaditems() {
resetitems();
notgotitems = true;
if(m_edit || !loadents(smapname, ments, &mcrc))
return;
- loopv(ments) if(canspawnitem(ments[i].type))
- {
+ loopv(ments) if(canspawnitem(ments[i].type)) {
server_entity se = { NOTUSED, 0, false };
while(sents.length()<=i) sents.add(se);
sents[i].type = ments[i].type;
}
notgotitems = false;
}
-
- void changemap(const char *s, int mode)
- {
+ void changemap(const char *s, int mode) {
stopdemo();
pausegame(false);
changegamespeed(100);
aiman::clearai();
-
gamemode = mode;
gamemillis = 0;
gamelimit = 10*60000;
scores.shrink(0);
shouldcheckteamkills = false;
teamkills.shrink(0);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed;
}
-
if(!m_mp(gamemode)) kicknonlocalclients(DISC_LOCAL);
-
sendf(-1, 1, "risii", N_MAPCHANGE, smapname, gamemode, 1);
-
clearteaminfo();
if(m_teammode) autoteam();
-
if(m_timed && smapname[0]) sendf(-1, 1, "ri2", N_TIMEUP, gamemillis < gamelimit && !interm ? max((gamelimit - gamemillis)/1000, 1) : 0);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
ci->mapchange();
ci->state.lasttimeplayed = lastmillis;
if(m_mp(gamemode) && ci->state.state!=CS_SPECTATOR) sendspawn(ci);
}
-
aiman::changemap();
-
- if(m_demo)
- {
+ if(m_demo) {
if(clients.length()) setupdemoplayback();
}
- else
- {
+ else {
if(demonextmatch) setupdemorecord();
demonextmatch = autorecorddemo!=0;
}
}
-
- void rotatemap(bool next)
- {
- if(!maprotations.inrange(curmaprotation))
- {
+ void rotatemap(bool next) {
+ if(!maprotations.inrange(curmaprotation)) {
changemap("", 1);
return;
}
- if(next)
- {
+ if(next) {
curmaprotation = findmaprotation(gamemode, smapname);
if(curmaprotation >= 0) nextmaprotation();
else curmaprotation = smapname[0] ? max(findmaprotation(gamemode, ""), 0) : 0;
maprotation &rot = maprotations[curmaprotation];
changemap(rot.map, rot.findmode(gamemode));
}
-
- struct votecount
- {
+ struct votecount {
char *map;
int mode, count;
votecount() {}
votecount(char *s, int n) : map(s), mode(n), count(0) {}
};
-
- void checkvotes(bool force = false)
- {
+ void checkvotes(bool force = false) {
vector<votecount> votes;
int maxvotes = 0;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *oi = clients[i];
if(oi->state.state==CS_SPECTATOR && !oi->privilege && !oi->local) continue;
if(oi->state.aitype!=AI_NONE) continue;
maxvotes++;
if(!m_valid(oi->modevote)) continue;
votecount *vc = NULL;
- loopvj(votes) if(!strcmp(oi->mapvote, votes[j].map) && oi->modevote==votes[j].mode)
- {
+ loopvj(votes) if(!strcmp(oi->mapvote, votes[j].map) && oi->modevote==votes[j].mode) {
vc = &votes[j];
break;
}
}
votecount *best = NULL;
loopv(votes) if(!best || votes[i].count > best->count || (votes[i].count == best->count && rnd(2))) best = &votes[i];
- if(force || (best && best->count > maxvotes/2))
- {
+ if(force || (best && best->count > maxvotes/2)) {
sendpackets(true);
if(demorecord) enddemorecord();
- if(best && (best->count > (force ? 1 : maxvotes/2)))
- {
+ if(best && (best->count > (force ? 1 : maxvotes/2))) {
sendservmsg(force ? "vote passed by default" : "vote passed by majority");
changemap(best->map, best->mode);
}
else rotatemap(true);
}
}
-
- void forcemap(const char *map, int mode)
- {
+ void forcemap(const char *map, int mode) {
stopdemo();
- if(!map[0] && !m_check(mode, M_EDIT))
- {
+ if(!map[0] && !m_check(mode, M_EDIT)) {
int idx = findmaprotation(mode, smapname);
if(idx < 0 && smapname[0]) idx = findmaprotation(mode, "");
if(idx < 0) return;
if(hasnonlocalclients()) sendservmsgf("local player forced %s on map %s", modename(mode), map[0] ? map : "[new map]");
changemap(map, mode);
}
-
- void vote(const char *map, int reqmode, int sender)
- {
+ void vote(const char *map, int reqmode, int sender) {
clientinfo *ci = getinfo(sender);
if(!ci || (ci->state.state==CS_SPECTATOR && !ci->privilege && !ci->local) || (!ci->local && !m_mp(reqmode))) return;
if(!m_valid(reqmode)) return;
- if(!map[0] && !m_check(reqmode, M_EDIT))
- {
+ if(!map[0] && !m_check(reqmode, M_EDIT)) {
int idx = findmaprotation(reqmode, smapname);
if(idx < 0 && smapname[0]) idx = findmaprotation(reqmode, "");
if(idx < 0) return;
map = maprotations[idx].map;
}
- if(lockmaprotation && !ci->local && ci->privilege < (lockmaprotation > 1 ? PRIV_ADMIN : PRIV_MASTER) && findmaprotation(reqmode, map) < 0)
- {
+ if(lockmaprotation && !ci->local && ci->privilege < (lockmaprotation > 1 ? PRIV_ADMIN : PRIV_MASTER) && findmaprotation(reqmode, map) < 0) {
sendf(sender, 1, "ris", N_SERVMSG, "This server has locked the map rotation.");
return;
}
copystring(ci->mapvote, map);
ci->modevote = reqmode;
- if(ci->local || (ci->privilege && mastermode>=MM_VETO))
- {
+ if(ci->local || (ci->privilege && mastermode>=MM_VETO)) {
sendpackets(true);
if(demorecord) enddemorecord();
if(!ci->local || hasnonlocalclients())
sendservmsgf("%s forced %s on map %s", colorname(ci), modename(ci->modevote), ci->mapvote[0] ? ci->mapvote : "[new map]");
changemap(ci->mapvote, ci->modevote);
}
- else
- {
+ else {
sendservmsgf("%s suggests %s on map %s (select map to vote)", colorname(ci), modename(reqmode), map[0] ? map : "[new map]");
checkvotes();
}
}
-
VAR(overtime, 0, 0, 1);
-
- bool checkovertime()
- {
+ bool checkovertime() {
if(!m_timed || !overtime) return false;
const char* topteam = NULL;
int topscore = INT_MIN;
bool tied = false;
- if(m_teammode)
- {
+ if(m_teammode) {
vector<teamscore> scores;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->state.state==CS_SPECTATOR || !ci->team[0]) continue;
int score = 0;
else if(score == topscore && strcmp(ci->team, topteam)) tied = true;
}
}
- else
- {
- loopv(clients)
- {
+ else {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->state.state==CS_SPECTATOR) continue;
int score = ci->state.frags;
sendf(-1, 1, "ri2", N_TIMEUP, max((gamelimit - gamemillis)/1000, 1));
return true;
}
-
- void checkintermission(bool force = false)
- {
- if(gamemillis >= gamelimit && !interm && (force || !checkovertime()))
- {
+ void checkintermission(bool force = false) {
+ if(gamemillis >= gamelimit && !interm && (force || !checkovertime())) {
sendf(-1, 1, "ri2", N_TIMEUP, 0);
changegamespeed(100);
interm = gamemillis + 10000;
}
}
-
void startintermission() { gamelimit = min(gamelimit, gamemillis); checkintermission(true); }
-
- void dodamage(clientinfo *target, clientinfo *actor, int damage, int gun, const vec &hitpush = vec(0, 0, 0))
- {
+ void dodamage(clientinfo *target, clientinfo *actor, int damage, int gun, const vec &hitpush = vec(0, 0, 0)) {
gamestate &ts = target->state;
ts.dodamage(damage);
if(target!=actor && !isteam(target->team, actor->team)) actor->state.damage += damage;
sendf(-1, 1, "ri6", N_DAMAGE, target->clientnum, actor->clientnum, damage, ts.armour, ts.health);
if(target==actor) target->setpushed();
- else if(!hitpush.iszero())
- {
+ else if(!hitpush.iszero()) {
ivec v(vec(hitpush).rescale(DNF));
sendf(ts.health<=0 ? -1 : target->ownernum, 1, "ri7", N_HITPUSH, target->clientnum, gun, damage, v.x, v.y, v.z);
target->setpushed();
}
- if(ts.health<=0)
- {
+ if(ts.health<=0) {
target->state.deaths++;
int fragvalue = (target==actor || isteam(target->team, actor->team) ? -1 : 1);
actor->state.frags += fragvalue;
- if(fragvalue>0)
- {
+ if(fragvalue>0) {
int friends = 0, enemies = 0; // note: friends also includes the fragger
if(m_teammode) loopv(clients) if(strcmp(clients[i]->team, actor->team)) enemies++; else friends++;
else { friends = 1; enemies = clients.length()-1; }
target->position.setsize(0);
ts.state = CS_DEAD;
ts.lastdeath = gamemillis;
- if(actor!=target && isteam(actor->team, target->team))
- {
+ if(actor!=target && isteam(actor->team, target->team)) {
actor->state.teamkills++;
addteamkill(actor, target, 1);
}
// ts.respawn();
}
}
-
- void suicide(clientinfo *ci)
- {
+ void suicide(clientinfo *ci) {
gamestate &gs = ci->state;
if(gs.state!=CS_ALIVE) return;
int fragvalue = -1;
gs.lastdeath = gamemillis;
gs.respawn();
}
-
- void suicideevent::process(clientinfo *ci)
- {
+ void suicideevent::process(clientinfo *ci) {
suicide(ci);
}
-
- void explodeevent::process(clientinfo *ci)
- {
+ void explodeevent::process(clientinfo *ci) {
gamestate &gs = ci->state;
- switch(gun)
- {
+ switch(gun) {
case GUN_RL:
if(!gs.rockets.remove(id)) return;
break;
-
case GUN_GL:
if(!gs.grenades.remove(id)) return;
break;
-
default:
return;
}
sendf(-1, 1, "ri4x", N_EXPLODEFX, ci->clientnum, gun, id, ci->ownernum);
- loopv(hits)
- {
+ loopv(hits) {
hitinfo &h = hits[i];
clientinfo *target = getinfo(h.target);
if(!target || target->state.state!=CS_ALIVE || h.lifesequence!=target->state.lifesequence || h.dist<0 || h.dist>guns[gun].exprad) continue;
-
bool dup = false;
loopj(i) if(hits[j].target==h.target) { dup = true; break; }
if(dup) continue;
-
int damage = guns[gun].damage;
if(gs.quadmillis) damage *= 4;
damage = int(damage*(1-h.dist/EXP_DISTSCALE/guns[gun].exprad));
dodamage(target, ci, damage, gun, h.dir);
}
}
-
- void shotevent::process(clientinfo *ci)
- {
+ void shotevent::process(clientinfo *ci) {
gamestate &gs = ci->state;
int wait = millis - gs.lastshot;
if(!gs.isalive(gamemillis) ||
int(to.x*DMF), int(to.y*DMF), int(to.z*DMF),
ci->ownernum);
gs.shotdamage += guns[gun].damage*(gs.quadmillis ? 4 : 1)*guns[gun].rays;
- switch(gun)
- {
+ switch(gun) {
case GUN_RL: gs.rockets.add(id); break;
case GUN_GL: gs.grenades.add(id); break;
- default:
- {
+ default: {
int totalrays = 0, maxrays = guns[gun].rays;
- loopv(hits)
- {
+ loopv(hits) {
hitinfo &h = hits[i];
clientinfo *target = getinfo(h.target);
if(!target || target->state.state!=CS_ALIVE || h.lifesequence!=target->state.lifesequence || h.rays<1 || h.dist > guns[gun].range + 1) continue;
-
totalrays += h.rays;
if(totalrays>maxrays) continue;
int damage = h.rays*guns[gun].damage;
}
}
}
-
- void pickupevent::process(clientinfo *ci)
- {
+ void pickupevent::process(clientinfo *ci) {
gamestate &gs = ci->state;
if(m_mp(gamemode) && !gs.isalive(gamemillis)) return;
pickup(ent, ci->clientnum);
}
-
- bool gameevent::flush(clientinfo *ci, int fmillis)
- {
+ bool gameevent::flush(clientinfo *ci, int fmillis) {
+ (void) fmillis;
process(ci);
return true;
}
-
- bool timedevent::flush(clientinfo *ci, int fmillis)
- {
+ bool timedevent::flush(clientinfo *ci, int fmillis) {
if(millis > fmillis) return false;
- else if(millis >= ci->lastevent)
- {
+ else if(millis >= ci->lastevent) {
ci->lastevent = millis;
process(ci);
}
return true;
}
-
- void clearevent(clientinfo *ci)
- {
+ void clearevent(clientinfo *ci) {
delete ci->events.remove(0);
}
-
- void flushevents(clientinfo *ci, int millis)
- {
- while(ci->events.length())
- {
+ void flushevents(clientinfo *ci, int millis) {
+ while(ci->events.length()) {
gameevent *ev = ci->events[0];
if(ev->flush(ci, millis)) clearevent(ci);
else break;
}
}
-
- void processevents()
- {
- loopv(clients)
- {
+ void processevents() {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(curtime>0 && ci->state.quadmillis) ci->state.quadmillis = max(ci->state.quadmillis-curtime, 0);
flushevents(ci, gamemillis);
}
}
-
- void cleartimedevents(clientinfo *ci)
- {
+ void cleartimedevents(clientinfo *ci) {
int keep = 0;
- loopv(ci->events)
- {
- if(ci->events[i]->keepable())
- {
- if(keep < i)
- {
+ loopv(ci->events) {
+ if(ci->events[i]->keepable()) {
+ if(keep < i) {
for(int j = keep; j < i; j++) delete ci->events[j];
ci->events.remove(keep, i - keep);
i = keep;
while(ci->events.length() > keep) delete ci->events.pop();
ci->timesync = false;
}
-
- void serverupdate()
- {
- if(shouldstep && !gamepaused)
- {
+ void serverupdate() {
+ if(shouldstep && !gamepaused) {
gamemillis += curtime;
-
if(m_demo) readdemo();
- else if(!m_timed || gamemillis < gamelimit)
- {
+ else if(!m_timed || gamemillis < gamelimit) {
processevents();
- if(curtime)
- {
- loopv(sents) if(sents[i].spawntime) // spawn entities when timer reached
- {
+ if(curtime) {
+ loopv(sents) if(sents[i].spawntime) { // spawn entities when timer reached {
int oldtime = sents[i].spawntime;
sents[i].spawntime -= curtime;
- if(sents[i].spawntime<=0)
- {
+ if(sents[i].spawntime<=0) {
sents[i].spawntime = 0;
sents[i].spawned = true;
sendf(-1, 1, "ri2", N_ITEMSPAWN, i);
}
- else if(sents[i].spawntime<=10000 && oldtime>10000 && (sents[i].type==I_QUAD || sents[i].type==I_BOOST))
- {
+ else if(sents[i].spawntime<=10000 && oldtime>10000 && (sents[i].type==I_QUAD || sents[i].type==I_BOOST)) {
sendf(-1, 1, "ri2", N_ANNOUNCE, sents[i].type);
}
}
aiman::checkai();
}
}
-
while(bannedips.length() && bannedips[0].expire-totalmillis <= 0) bannedips.remove(0);
//~loopv(connects) if(totalmillis-connects[i]->connectmillis>15000) disconnect_client(connects[i]->clientnum, DISC_TIMEOUT);
-
- if(nextexceeded && gamemillis > nextexceeded && (!m_timed || gamemillis < gamelimit))
- {
+ if(nextexceeded && gamemillis > nextexceeded && (!m_timed || gamemillis < gamelimit)) {
nextexceeded = 0;
- loopvrev(clients)
- {
+ loopvrev(clients) {
clientinfo &c = *clients[i];
if(c.state.aitype != AI_NONE) continue;
//~if(c.checkexceeded()) disconnect_client(c.clientnum, DISC_MSGERR);
else c.scheduleexceeded();
}
}
-
if(shouldcheckteamkills) checkteamkills();
-
- if(shouldstep && !gamepaused)
- {
+ if(shouldstep && !gamepaused) {
if(m_timed && smapname[0] && gamemillis-curtime>0) checkintermission();
- if(interm > 0 && gamemillis>interm)
- {
+ if(interm > 0 && gamemillis>interm) {
if(demorecord) enddemorecord();
interm = -1;
checkvotes(true);
}
}
-
shouldstep = clients.length() > 0;
}
-
- void forcespectator(clientinfo *ci)
- {
+ void forcespectator(clientinfo *ci) {
if(ci->state.state==CS_ALIVE) suicide(ci);
ci->state.state = CS_SPECTATOR;
ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed;
if(!ci->local && (!ci->privilege || ci->warned)) aiman::removeai(ci);
sendf(-1, 1, "ri3", N_SPECTATOR, ci->clientnum, 1);
}
-
- struct crcinfo
- {
+ struct crcinfo {
int crc, matches;
-
crcinfo() {}
crcinfo(int crc, int matches) : crc(crc), matches(matches) {}
-
static bool compare(const crcinfo &x, const crcinfo &y) { return x.matches > y.matches; }
};
-
VAR(modifiedmapspectator, 0, 1, 2);
-
- void checkmaps(int req = -1)
- {
+ void checkmaps(int req = -1) {
if(m_edit || !smapname[0]) return;
vector<crcinfo> crcs;
int total = 0, unsent = 0, invalid = 0;
if(mcrc) crcs.add(crcinfo(mcrc, clients.length() + 1));
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->state.state==CS_SPECTATOR || ci->state.aitype != AI_NONE) continue;
total++;
- if(!ci->clientmap[0])
- {
+ if(!ci->clientmap[0]) {
if(ci->mapcrc < 0) invalid++;
else if(!ci->mapcrc) unsent++;
}
- else
- {
+ else {
crcinfo *match = NULL;
loopvj(crcs) if(crcs[j].crc == ci->mapcrc) { match = &crcs[j]; break; }
if(!match) crcs.add(crcinfo(ci->mapcrc, 1));
if(!mcrc && total - unsent < min(total, 4)) return;
crcs.sort(crcinfo::compare);
string msg;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *ci = clients[i];
if(ci->state.state==CS_SPECTATOR || ci->state.aitype != AI_NONE || ci->clientmap[0] || ci->mapcrc >= 0 || (req < 0 && ci->warned)) continue;
formatstring(msg, "%s has modified map \"%s\"", colorname(ci), smapname);
sendf(req, 1, "ris", N_SERVMSG, msg);
if(req < 0) ci->warned = true;
}
- if(crcs.length() >= 2) loopv(crcs)
- {
+ if(crcs.length() >= 2) loopv(crcs) {
crcinfo &info = crcs[i];
- if(i || info.matches <= crcs[i+1].matches) loopvj(clients)
- {
+ if(i || info.matches <= crcs[i+1].matches) loopvj(clients) {
clientinfo *ci = clients[j];
if(ci->state.state==CS_SPECTATOR || ci->state.aitype != AI_NONE || !ci->clientmap[0] || ci->mapcrc != info.crc || (req < 0 && ci->warned)) continue;
formatstring(msg, "%s has modified map \"%s\"", colorname(ci), smapname);
if(req < 0) ci->warned = true;
}
}
- if(req < 0 && modifiedmapspectator && (mcrc || modifiedmapspectator > 1)) loopv(clients)
- {
+ if(req < 0 && modifiedmapspectator && (mcrc || modifiedmapspectator > 1)) loopv(clients) {
clientinfo *ci = clients[i];
if(!ci->local && ci->warned && ci->state.state != CS_SPECTATOR) forcespectator(ci);
}
}
-
- bool shouldspectate(clientinfo *ci)
- {
+ bool shouldspectate(clientinfo *ci) {
return !ci->local && ci->warned && modifiedmapspectator && (mcrc || modifiedmapspectator > 1);
}
-
- void unspectate(clientinfo *ci)
- {
+ void unspectate(clientinfo *ci) {
if(shouldspectate(ci)) return;
ci->state.state = CS_DEAD;
ci->state.respawn();
if(ci->clientmap[0] || ci->mapcrc) checkmaps();
if(!hasmap(ci)) rotatemap(true);
}
-
- void sendservinfo(clientinfo *ci)
- {
+ void sendservinfo(clientinfo *ci) {
sendf(ci->clientnum, 1, "ri5ss", N_SERVINFO, ci->clientnum, PROTOCOL_VERSION, ci->sessionid, serverpass[0] ? 1 : 0, serverdesc, serverauth);
}
-
- void noclients()
- {
+ void noclients() {
bannedips.shrink(0);
aiman::clearai();
}
-
- void localconnect(int n)
- {
+ void localconnect(int n) {
clientinfo *ci = getinfo(n);
ci->clientnum = ci->ownernum = n;
ci->connectmillis = totalmillis;
ci->sessionid = (rnd(0x1000000)*((totalmillis%10000)+1))&0xFFFFFF;
ci->local = true;
-
connects.add(ci);
sendservinfo(ci);
}
-
- void localdisconnect(int n)
- {
+ void localdisconnect(int n) {
if(m_demo) enddemoplayback();
clientdisconnect(n);
}
-
- int clientconnect(int n)
- {
+ int clientconnect(int n) {
clientinfo *ci = getinfo(n);
ci->clientnum = ci->ownernum = n;
ci->connectmillis = totalmillis;
ci->sessionid = (rnd(0x1000000)*((totalmillis%10000)+1))&0xFFFFFF;
-
connects.add(ci);
if(!m_mp(gamemode)) return DISC_LOCAL;
sendservinfo(ci);
return DISC_NONE;
}
-
- void clientdisconnect(int n)
- {
+ void clientdisconnect(int n) {
clientinfo *ci = getinfo(n);
loopv(clients) if(clients[i]->authkickvictim == ci->clientnum) clients[i]->cleanauth();
- if(ci->connected)
- {
+ if(ci->connected) {
if(ci->privilege) setmaster(ci, false);
ci->state.timeplayed += lastmillis - ci->state.lasttimeplayed;
savescore(ci);
}
else connects.removeobj(ci);
}
-
int reserveclients() { return 3; }
-
extern void verifybans();
-
- struct banlist
- {
+ struct banlist {
vector<ipmask> bans;
-
void clear() { bans.shrink(0); }
-
- bool check(uint ip)
- {
+ bool check(uint ip) {
loopv(bans) if(bans[i].check(ip)) return true;
return false;
}
-
- void add(const char *ipname)
- {
+ void add(const char *ipname) {
ipmask ban;
ban.parse(ipname);
bans.add(ban);
-
verifybans();
}
} ipbans, gbans;
-
- bool checkbans(uint ip)
- {
+ bool checkbans(uint ip) {
loopv(bannedips) if(bannedips[i].ip==ip) return true;
return ipbans.check(ip) || gbans.check(ip);
}
-
- void verifybans()
- {
- loopvrev(clients)
- {
+ void verifybans() {
+ loopvrev(clients) {
clientinfo *ci = clients[i];
if(ci->state.aitype != AI_NONE || ci->local || ci->privilege >= PRIV_ADMIN) continue;
//~if(checkbans(getclientip(ci->clientnum))) disconnect_client(ci->clientnum, DISC_IPBAN);
}
}
-
ICOMMAND(clearipbans, "", (), ipbans.clear());
ICOMMAND(ipban, "s", (const char *ipname), ipbans.add(ipname));
-
- int allowconnect(clientinfo *ci, const char *pwd = "")
- {
+ int allowconnect(clientinfo *ci, const char *pwd = "") {
if(ci->local) return DISC_NONE;
if(!m_mp(gamemode)) return DISC_LOCAL;
- if(serverpass[0])
- {
+ if(serverpass[0]) {
if(!checkpassword(ci, serverpass, pwd)) return DISC_PASSWORD;
return DISC_NONE;
}
if(mastermode>=MM_PRIVATE && allowedips.find(ip)<0) return DISC_PRIVATE;
return DISC_NONE;
}
-
- bool allowbroadcast(int n)
- {
+ bool allowbroadcast(int n) {
clientinfo *ci = getinfo(n);
return ci && ci->connected;
}
-
- clientinfo *findauth(uint id)
- {
+ clientinfo *findauth(uint id) {
loopv(clients) if(clients[i]->authreq == id) return clients[i];
return NULL;
}
-
- void authfailed(clientinfo *ci)
- {
+ void authfailed(clientinfo *ci) {
if(!ci) return;
ci->cleanauth();
//~if(ci->connectauth) disconnect_client(ci->clientnum, ci->connectauth);
}
-
- void authfailed(uint id)
- {
+ void authfailed(uint id) {
authfailed(findauth(id));
}
-
- void authsucceeded(uint id)
- {
+ void authsucceeded(uint id) {
clientinfo *ci = findauth(id);
if(!ci) return;
ci->cleanauth(ci->connectauth!=0);
if(ci->connectauth) connected(ci);
- if(ci->authkickvictim >= 0)
- {
+ if(ci->authkickvictim >= 0) {
if(setmaster(ci, true, "", ci->authname, NULL, PRIV_AUTH, false, true))
trykick(ci, ci->authkickvictim, ci->authkickreason, ci->authname, NULL, PRIV_AUTH);
ci->cleanauthkick();
}
else setmaster(ci, true, "", ci->authname, NULL, PRIV_AUTH);
}
-
- void authchallenged(uint id, const char *val, const char *desc = "")
- {
+ void authchallenged(uint id, const char *val, const char *desc = "") {
clientinfo *ci = findauth(id);
if(!ci) return;
sendf(ci->clientnum, 1, "risis", N_AUTHCHAL, desc, id, val);
}
-
uint nextauthreq = 0;
-
- bool tryauth(clientinfo *ci, const char *user, const char *desc)
- {
+ bool tryauth(clientinfo *ci, const char *user, const char *desc) {
ci->cleanauth();
if(!nextauthreq) nextauthreq = 1;
ci->authreq = nextauthreq++;
filtertext(ci->authname, user, false, false, 100);
copystring(ci->authdesc, desc);
- if(ci->authdesc[0])
- {
+ if(ci->authdesc[0]) {
userinfo *u = users.access(userkey(ci->authname, ci->authdesc));
- if(u)
- {
+ if(u) {
uint seed[3] = { ::hthash(serverauth) + detrnd(size_t(ci) + size_t(user) + size_t(desc), 0x10000), uint(totalmillis), randomMT() };
vector<char> buf;
ci->authchallenge = genchallenge(u->pubkey, seed, sizeof(seed), buf);
}
else ci->cleanauth();
}
- else if(!requestmasterf("reqauth %u %s\n", ci->authreq, ci->authname))
- {
+ else if(!requestmasterf("reqauth %u %s\n", ci->authreq, ci->authname)) {
ci->cleanauth();
sendf(ci->clientnum, 1, "ris", N_SERVMSG, "not connected to authentication server");
}
//~if(ci->connectauth) disconnect_client(ci->clientnum, ci->connectauth);
return false;
}
-
- bool answerchallenge(clientinfo *ci, uint id, char *val, const char *desc)
- {
- if(ci->authreq != id || strcmp(ci->authdesc, desc))
- {
+ bool answerchallenge(clientinfo *ci, uint id, char *val, const char *desc) {
+ if(ci->authreq != id || strcmp(ci->authdesc, desc)) {
ci->cleanauth();
return !ci->connectauth;
}
- for(char *s = val; *s; s++)
- {
+ for(char *s = val; *s; s++) {
if(!isxdigit(*s)) { *s = '\0'; break; }
}
- if(desc[0])
- {
- if(ci->authchallenge && checkchallenge(val, ci->authchallenge))
- {
+ if(desc[0]) {
+ if(ci->authchallenge && checkchallenge(val, ci->authchallenge)) {
userinfo *u = users.access(userkey(ci->authname, ci->authdesc));
- if(u)
- {
+ if(u) {
if(ci->connectauth) connected(ci);
- if(ci->authkickvictim >= 0)
- {
+ if(ci->authkickvictim >= 0) {
if(setmaster(ci, true, "", ci->authname, ci->authdesc, u->privilege, false, true))
trykick(ci, ci->authkickvictim, ci->authkickreason, ci->authname, ci->authdesc, u->privilege);
}
}
ci->cleanauth();
}
- else if(!requestmasterf("confauth %u %s\n", id, val))
- {
+ else if(!requestmasterf("confauth %u %s\n", id, val)) {
ci->cleanauth();
sendf(ci->clientnum, 1, "ris", N_SERVMSG, "not connected to authentication server");
}
return ci->authreq || !ci->connectauth;
}
-
- void masterconnected()
- {
+ void masterconnected() {
}
-
- void masterdisconnected()
- {
- loopvrev(clients)
- {
+ void masterdisconnected() {
+ loopvrev(clients) {
clientinfo *ci = clients[i];
if(ci->authreq) authfailed(ci);
}
}
-
- void processmasterinput(const char *cmd, int cmdlen, const char *args)
- {
+ void processmasterinput(const char *cmd, int cmdlen) {
uint id;
string val;
if(sscanf(cmd, "failauth %u", &id) == 1)
else if(sscanf(cmd, "addgban %100s", val) == 1)
gbans.add(val);
}
-
- void receivefile(int sender, uchar *data, int len)
- {
+ void receivefile(int sender, uchar *data, int len) {
if(!m_edit || len <= 0 || len > 4*1024*1024) return;
clientinfo *ci = getinfo(sender);
if(ci->state.state==CS_SPECTATOR && !ci->privilege && !ci->local) return;
mapdata->write(data, len);
sendservmsgf("[%s sent a map to server, \"/getmap\" to receive it]", colorname(ci));
}
-
- void sendclipboard(clientinfo *ci)
- {
+ void sendclipboard(clientinfo *ci) {
if(!ci->lastclipboard || !ci->clipboard) return;
bool flushed = false;
- loopv(clients)
- {
+ loopv(clients) {
clientinfo &e = *clients[i];
- if(e.clientnum != ci->clientnum && e.needclipboard - ci->lastclipboard >= 0)
- {
+ if(e.clientnum != ci->clientnum && e.needclipboard - ci->lastclipboard >= 0) {
if(!flushed) { flushserver(true); flushed = true; }
sendpacket(e.clientnum, 1, ci->clipboard);
}
}
}
-
- void connected(clientinfo *ci)
- {
+ void connected(clientinfo *ci) {
if(m_demo) enddemoplayback();
-
if(!hasmap(ci)) rotatemap(false);
-
shouldstep = true;
-
connects.removeobj(ci);
clients.add(ci);
-
ci->connectauth = 0;
ci->connected = true;
ci->needclipboard = totalmillis ? totalmillis : 1;
if(mastermode>=MM_LOCKED) ci->state.state = CS_SPECTATOR;
ci->state.lasttimeplayed = lastmillis;
-
- const char *worst = m_teammode ? chooseworstteam(NULL, ci) : NULL;
+ const char *worst = m_teammode ? chooseworstteam(ci) : NULL;
copystring(ci->team, worst ? worst : "good", MAXTEAMLEN+1);
-
sendwelcome(ci);
if(restorescore(ci)) sendresume(ci);
sendinitclient(ci);
-
aiman::addclient(ci);
-
if(m_demo) setupdemoplayback();
-
if(servermotd[0]) sendf(ci->clientnum, 1, "ris", N_SERVMSG, servermotd);
}
-
- void parsepacket(int sender, int chan, packetbuf &p) // has to parse exactly each byte of the packet
- {
+ void parsepacket(int sender, int chan, packetbuf &p) { // has to parse exactly each byte of the packet {
if(sender<0 || p.packet->flags&ENET_PACKET_FLAG_UNSEQUENCED || chan > 2) return;
char text[MAXTRANS];
int type;
clientinfo *ci = sender>=0 ? getinfo(sender) : NULL, *cq = ci, *cm = ci;
- if(ci && !ci->connected)
- {
+ if(ci && !ci->connected) {
if(chan==0) return;
//~else if(chan!=1) { disconnect_client(sender, DISC_MSGERR); return; }
- else while(p.length() < p.maxlen) switch(checktype(getint(p), ci))
- {
- case N_CONNECT:
- {
+ else while(p.length() < p.maxlen) switch(checktype(getint(p), ci)) {
+ case N_CONNECT: {
getstring(text, p);
filtertext(text, text, false, false, MAXNAMELEN);
if(!text[0]) copystring(text, "Anonymous");
copystring(ci->name, text, MAXNAMELEN+1);
ci->playermodel = 0;
-
string password, authdesc, authname;
getstring(password, p, sizeof(password));
getstring(authdesc, p, sizeof(authdesc));
getstring(authname, p, sizeof(authname));
int disc = allowconnect(ci, password);
- if(disc)
- {
- if(disc == DISC_LOCAL || !serverauth[0] || strcmp(serverauth, authdesc) || !tryauth(ci, authname, authdesc))
- {
+ if(disc) {
+ if(disc == DISC_LOCAL || !serverauth[0] || strcmp(serverauth, authdesc) || !tryauth(ci, authname, authdesc)) {
//~disconnect_client(sender, disc);
return;
}
else connected(ci);
break;
}
-
- case N_AUTHANS:
- {
+ case N_AUTHANS: {
string desc, ans;
getstring(desc, p, sizeof(desc));
uint id = (uint)getint(p);
getstring(ans, p, sizeof(ans));
- if(!answerchallenge(ci, id, ans, desc))
- {
+ if(!answerchallenge(ci, id, ans, desc)) {
//~disconnect_client(sender, ci->connectauth);
return;
}
break;
}
-
case N_PING:
getint(p);
break;
-
default:
//~disconnect_client(sender, DISC_MSGERR);
return;
}
return;
}
- else if(chan==2)
- {
+ else if(chan==2) {
receivefile(sender, p.buf, p.maxlen);
return;
}
-
if(p.packet->flags&ENET_PACKET_FLAG_RELIABLE) reliablemessages = true;
#define QUEUE_AI clientinfo *cm = cq;
#define QUEUE_MSG { if(cm && (!cm->local || demorecord || hasnonlocalclients())) while(curmsg<p.length()) cm->messages.add(p.buf[curmsg++]); }
#define QUEUE_BUF(body) { \
- if(cm && (!cm->local || demorecord || hasnonlocalclients())) \
- { \
- curmsg = p.length(); \
- { body; } \
+ if(cm && (!cm->local || demorecord || hasnonlocalclients())) { \
+ \
+ curmsg = p.length(); { \
+ body; } \
} \
}
#define QUEUE_INT(n) QUEUE_BUF(putint(cm->messages, n))
#define QUEUE_UINT(n) QUEUE_BUF(putuint(cm->messages, n))
#define QUEUE_STR(text) QUEUE_BUF(sendstring(text, cm->messages))
int curmsg;
- while((curmsg = p.length()) < p.maxlen) switch(type = checktype(getint(p), ci))
- {
- case N_POS:
- {
+ while((curmsg = p.length()) < p.maxlen) switch(type = checktype(getint(p), ci)) {
+ case N_POS: {
int pcn = getuint(p);
p.get();
uint flags = getuint(p);
clientinfo *cp = getinfo(pcn);
if(cp && pcn != sender && cp->ownernum != sender) cp = NULL;
vec pos;
- loopk(3)
- {
+ loopk(3) {
int n = p.get(); n |= p.get()<<8; if(flags&(1<<k)) { n |= p.get()<<16; if(n&0x800000) n |= ~0U<<24; }
pos[k] = n/DMF;
}
int mag = p.get(); if(flags&(1<<3)) mag |= p.get()<<8;
int dir = p.get(); dir |= p.get()<<8;
vec vel = vec((dir%360)*RAD, (clamp(dir/360, 0, 180)-90)*RAD).mul(mag/DVELF);
- if(flags&(1<<4))
- {
+ if(flags&(1<<4)) {
p.get(); if(flags&(1<<5)) p.get();
if(flags&(1<<6)) loopk(2) p.get();
}
- if(cp)
- {
- if((!ci->local || demorecord || hasnonlocalclients()) && (cp->state.state==CS_ALIVE || cp->state.state==CS_EDITING))
- {
+ if(cp) {
+ if((!ci->local || demorecord || hasnonlocalclients()) && (cp->state.state==CS_ALIVE || cp->state.state==CS_EDITING)) {
if(!ci->local && !m_edit && max(vel.magnitude2(), (float)fabs(vel.z)) >= 180)
cp->setexceeded();
cp->position.setsize(0);
}
break;
}
-
- case N_TELEPORT:
- {
+ case N_TELEPORT: {
int pcn = getint(p), teleport = getint(p), teledest = getint(p);
clientinfo *cp = getinfo(pcn);
if(cp && pcn != sender && cp->ownernum != sender) cp = NULL;
- if(cp && (!ci->local || demorecord || hasnonlocalclients()) && (cp->state.state==CS_ALIVE || cp->state.state==CS_EDITING))
- {
+ if(cp && (!ci->local || demorecord || hasnonlocalclients()) && (cp->state.state==CS_ALIVE || cp->state.state==CS_EDITING)) {
flushclientposition(*cp);
sendf(-1, 0, "ri4x", N_TELEPORT, pcn, teleport, teledest, cp->ownernum);
}
break;
}
-
- case N_JUMPPAD:
- {
+ case N_JUMPPAD: {
int pcn = getint(p), jumppad = getint(p);
clientinfo *cp = getinfo(pcn);
if(cp && pcn != sender && cp->ownernum != sender) cp = NULL;
- if(cp && (!ci->local || demorecord || hasnonlocalclients()) && (cp->state.state==CS_ALIVE || cp->state.state==CS_EDITING))
- {
+ if(cp && (!ci->local || demorecord || hasnonlocalclients()) && (cp->state.state==CS_ALIVE || cp->state.state==CS_EDITING)) {
cp->setpushed();
flushclientposition(*cp);
sendf(-1, 0, "ri3x", N_JUMPPAD, pcn, jumppad, cp->ownernum);
}
break;
}
-
- case N_FROMAI:
- {
+ case N_FROMAI: {
int qcn = getint(p);
if(qcn < 0) cq = ci;
- else
- {
+ else {
cq = getinfo(qcn);
if(cq && qcn != sender && cq->ownernum != sender) cq = NULL;
}
break;
}
-
- case N_EDITMODE:
- {
+ case N_EDITMODE: {
int val = getint(p);
if(!ci->local && !m_edit) break;
if(val ? ci->state.state!=CS_ALIVE && ci->state.state!=CS_DEAD : ci->state.state!=CS_EDITING) break;
- if(val)
- {
+ if(val) {
ci->state.editstate = ci->state.state;
ci->state.state = CS_EDITING;
ci->events.setsize(0);
QUEUE_MSG;
break;
}
-
- case N_MAPCRC:
- {
+ case N_MAPCRC: {
getstring(text, p);
int crc = getint(p);
if(!ci) break;
- if(strcmp(text, smapname))
- {
- if(ci->clientmap[0])
- {
+ if(strcmp(text, smapname)) {
+ if(ci->clientmap[0]) {
ci->clientmap[0] = '\0';
ci->mapcrc = 0;
}
if(cq && cq != ci && cq->ownernum != ci->clientnum) cq = NULL;
break;
}
-
case N_CHECKMAPS:
checkmaps(sender);
break;
-
case N_TRYSPAWN:
if(!ci || !cq || cq->state.state!=CS_DEAD || cq->state.lastspawn>=0) break;
- if(!ci->clientmap[0] && !ci->mapcrc)
- {
+ if(!ci->clientmap[0] && !ci->mapcrc) {
ci->mapcrc = -1;
checkmaps();
if(ci == cq) { if(ci->state.state != CS_DEAD) break; }
else if(cq->ownernum != ci->clientnum) { cq = NULL; break; }
}
- if(cq->state.deadflush)
- {
+ if(cq->state.deadflush) {
flushevents(cq, cq->state.deadflush);
cq->state.respawn();
}
cleartimedevents(cq);
sendspawn(cq);
break;
-
- case N_GUNSELECT:
- {
+ case N_GUNSELECT: {
int gunselect = getint(p);
if(!cq || cq->state.state!=CS_ALIVE) break;
cq->state.gunselect = gunselect >= GUN_FIST && gunselect <= GUN_PISTOL ? gunselect : GUN_FIST;
QUEUE_MSG;
break;
}
-
- case N_SPAWN:
- {
+ case N_SPAWN: {
int ls = getint(p), gunselect = getint(p);
if(!cq || (cq->state.state!=CS_ALIVE && cq->state.state!=CS_DEAD && cq->state.state!=CS_EDITING) || ls!=cq->state.lifesequence || cq->state.lastspawn<0) break;
cq->state.lastspawn = -1;
});
break;
}
-
- case N_SUICIDE:
- {
+ case N_SUICIDE: {
if(cq) cq->addevent(new suicideevent);
break;
}
-
- case N_SHOOT:
- {
+ case N_SHOOT: {
shotevent *shot = new shotevent;
shot->id = getint(p);
shot->millis = cq ? cq->geteventmillis(gamemillis, shot->id) : 0;
loopk(3) shot->from[k] = getint(p)/DMF;
loopk(3) shot->to[k] = getint(p)/DMF;
int hits = getint(p);
- loopk(hits)
- {
+ loopk(hits) {
if(p.overread()) break;
hitinfo &hit = shot->hits.add();
hit.target = getint(p);
hit.rays = getint(p);
loopk(3) hit.dir[k] = getint(p)/DNF;
}
- if(cq)
- {
+ if(cq) {
cq->addevent(shot);
cq->setpushed();
}
else delete shot;
break;
}
-
- case N_EXPLODE:
- {
+ case N_EXPLODE: {
explodeevent *exp = new explodeevent;
int cmillis = getint(p);
exp->millis = cq ? cq->geteventmillis(gamemillis, cmillis) : 0;
exp->gun = getint(p);
exp->id = getint(p);
int hits = getint(p);
- loopk(hits)
- {
+ loopk(hits) {
if(p.overread()) break;
hitinfo &hit = exp->hits.add();
hit.target = getint(p);
else delete exp;
break;
}
-
- case N_ITEMPICKUP:
- {
+ case N_ITEMPICKUP: {
int n = getint(p);
if(!cq) break;
pickupevent *pickup = new pickupevent;
cq->addevent(pickup);
break;
}
-
- case N_TEXT:
- {
+ case N_TEXT: {
QUEUE_AI;
QUEUE_MSG;
getstring(text, p);
if(isdedicatedserver() && cq) logoutf("%s: %s", colorname(cq), text);
break;
}
-
- case N_SAYTEAM:
- {
+ case N_SAYTEAM: {
getstring(text, p);
if(!ci || !cq || (ci->state.state==CS_SPECTATOR && !ci->local && !ci->privilege) || !m_teammode || !cq->team[0]) break;
filtertext(text, text, true, true);
- loopv(clients)
- {
+ loopv(clients) {
clientinfo *t = clients[i];
if(t==cq || t->state.state==CS_SPECTATOR || t->state.aitype != AI_NONE || strcmp(cq->team, t->team)) continue;
sendf(t->clientnum, 1, "riis", N_SAYTEAM, cq->clientnum, text);
if(isdedicatedserver() && cq) logoutf("%s <%s>: %s", colorname(cq), cq->team, text);
break;
}
-
- case N_SWITCHNAME:
- {
+ case N_SWITCHNAME: {
QUEUE_MSG;
getstring(text, p);
filtertext(ci->name, text, false, false, MAXNAMELEN);
QUEUE_STR(ci->name);
break;
}
-
- case N_SWITCHMODEL:
- {
+ case N_SWITCHMODEL: {
ci->playermodel = 0;
QUEUE_MSG;
break;
}
-
- case N_SWITCHTEAM:
- {
+ case N_SWITCHTEAM: {
getstring(text, p);
filtertext(text, text, false, false, MAXTEAMLEN);
- if(m_teammode && text[0] && strcmp(ci->team, text) && addteaminfo(text))
- {
+ if(m_teammode && text[0] && strcmp(ci->team, text) && addteaminfo(text)) {
if(ci->state.state==CS_ALIVE) suicide(ci);
copystring(ci->team, text);
aiman::changeteam(ci);
}
break;
}
-
- case N_MAPVOTE:
- {
+ case N_MAPVOTE: {
getstring(text, p);
filtertext(text, text, false);
fixmapname(text);
vote(text, reqmode, sender);
break;
}
-
- case N_ITEMLIST:
- {
+ case N_ITEMLIST: {
if((ci->state.state==CS_SPECTATOR && !ci->privilege && !ci->local) || !notgotitems || strcmp(ci->clientmap, smapname)) { while(getint(p)>=0 && !p.overread()) getint(p); break; }
int n;
- while((n = getint(p))>=0 && n<MAXENTS && !p.overread())
- {
+ while((n = getint(p))>=0 && n<MAXENTS && !p.overread()) {
server_entity se = { NOTUSED, 0, false };
while(sents.length()<=n) sents.add(se);
sents[n].type = getint(p);
- if(canspawnitem(sents[n].type))
- {
+ if(canspawnitem(sents[n].type)) {
if(m_mp(gamemode) && delayspawn(sents[n].type)) sents[n].spawntime = spawntime(sents[n].type);
else sents[n].spawned = true;
}
notgotitems = false;
break;
}
-
- case N_EDITENT:
- {
+ case N_EDITENT: {
int i = getint(p);
loopk(3) getint(p);
int type = getint(p);
if(!ci || ci->state.state==CS_SPECTATOR) break;
QUEUE_MSG;
bool canspawn = canspawnitem(type);
- if(i<MAXENTS && (sents.inrange(i) || canspawnitem(type)))
- {
+ if(i<MAXENTS && (sents.inrange(i) || canspawnitem(type))) {
server_entity se = { NOTUSED, 0, false };
while(sents.length()<=i) sents.add(se);
sents[i].type = type;
- if(canspawn ? !sents[i].spawned : (sents[i].spawned || sents[i].spawntime))
- {
+ if(canspawn ? !sents[i].spawned : (sents[i].spawned || sents[i].spawntime)) {
sents[i].spawntime = canspawn ? 1 : 0;
sents[i].spawned = false;
}
}
break;
}
-
- case N_EDITVAR:
- {
+ case N_EDITVAR: {
int type = getint(p);
getstring(text, p);
- switch(type)
- {
+ switch(type) {
case ID_VAR: getint(p); break;
case ID_FVAR: getfloat(p); break;
case ID_SVAR: getstring(text, p);
if(ci && ci->state.state!=CS_SPECTATOR) QUEUE_MSG;
break;
}
-
case N_PING:
sendf(sender, 1, "i2", N_PONG, getint(p));
break;
-
- case N_CLIENTPING:
- {
+ case N_CLIENTPING: {
int ping = getint(p);
- if(ci)
- {
+ if(ci) {
ci->ping = ping;
loopv(ci->bots) ci->bots[i]->ping = ping;
}
QUEUE_MSG;
break;
}
-
- case N_MASTERMODE:
- {
+ case N_MASTERMODE: {
int mm = getint(p);
- if((ci->privilege || ci->local) && mm>=MM_OPEN && mm<=MM_PRIVATE)
- {
- if((ci->privilege>=PRIV_ADMIN || ci->local) || (mastermask&(1<<mm)))
- {
+ if((ci->privilege || ci->local) && mm>=MM_OPEN && mm<=MM_PRIVATE) {
+ if((ci->privilege>=PRIV_ADMIN || ci->local) || (mastermask&(1<<mm))) {
mastermode = mm;
allowedips.shrink(0);
- if(mm>=MM_PRIVATE)
- {
+ if(mm>=MM_PRIVATE) {
loopv(clients) allowedips.add(getclientip(clients[i]->clientnum));
}
sendf(-1, 1, "rii", N_MASTERMODE, mastermode);
//sendservmsgf("mastermode is now %s (%d)", mastermodename(mastermode), mastermode);
}
- else
- {
+ else {
defformatstring(s, "mastermode %d is disabled on this server", mm);
sendf(sender, 1, "ris", N_SERVMSG, s);
}
}
break;
}
-
- case N_CLEARBANS:
- {
- if(ci->privilege || ci->local)
- {
+ case N_CLEARBANS: {
+ if(ci->privilege || ci->local) {
bannedips.shrink(0);
sendservmsg("cleared all bans");
}
break;
}
-
- case N_KICK:
- {
+ case N_KICK: {
int victim = getint(p);
getstring(text, p);
filtertext(text, text);
trykick(ci, victim, text);
break;
}
-
- case N_SPECTATOR:
- {
+ case N_SPECTATOR: {
int spectator = getint(p), val = getint(p);
if(!ci->privilege && !ci->local && (spectator!=sender || (ci->state.state==CS_SPECTATOR && mastermode>=MM_LOCKED))) break;
clientinfo *spinfo = (clientinfo *)getclientinfo(spectator); // no bots
if(!spinfo || !spinfo->connected || (spinfo->state.state==CS_SPECTATOR ? val : !val)) break;
-
if(spinfo->state.state!=CS_SPECTATOR && val) forcespectator(spinfo);
else if(spinfo->state.state==CS_SPECTATOR && !val) unspectate(spinfo);
-
if(cq && cq != ci && cq->ownernum != ci->clientnum) cq = NULL;
break;
}
-
- case N_SETTEAM:
- {
+ case N_SETTEAM: {
int who = getint(p);
getstring(text, p);
filtertext(text, text, false, false, MAXTEAMLEN);
if(!ci->privilege && !ci->local) break;
clientinfo *wi = getinfo(who);
if(!m_teammode || !text[0] || !wi || !wi->connected || !strcmp(wi->team, text)) break;
- if(addteaminfo(text))
- {
+ if(addteaminfo(text)) {
if(wi->state.state==CS_ALIVE) suicide(wi);
copystring(wi->team, text, MAXTEAMLEN+1);
}
sendf(-1, 1, "riisi", N_SETTEAM, who, wi->team, 1);
break;
}
-
case N_FORCEINTERMISSION:
if(ci->local && !hasnonlocalclients()) startintermission();
break;
-
- case N_RECORDDEMO:
- {
+ case N_RECORDDEMO: {
int val = getint(p);
if(ci->privilege < (restrictdemos ? PRIV_ADMIN : PRIV_MASTER) && !ci->local) break;
- if(!maxdemos || !maxdemosize)
- {
+ if(!maxdemos || !maxdemosize) {
sendf(ci->clientnum, 1, "ris", N_SERVMSG, "the server has disabled demo recording");
break;
}
sendservmsgf("demo recording is %s for next match", demonextmatch ? "enabled" : "disabled");
break;
}
-
- case N_STOPDEMO:
- {
+ case N_STOPDEMO: {
if(ci->privilege < (restrictdemos ? PRIV_ADMIN : PRIV_MASTER) && !ci->local) break;
stopdemo();
break;
}
-
- case N_CLEARDEMOS:
- {
+ case N_CLEARDEMOS: {
int demo = getint(p);
if(ci->privilege < (restrictdemos ? PRIV_ADMIN : PRIV_MASTER) && !ci->local) break;
cleardemos(demo);
break;
}
-
case N_LISTDEMOS:
if(!ci->privilege && !ci->local && ci->state.state==CS_SPECTATOR) break;
listdemos(sender);
break;
-
- case N_GETDEMO:
- {
+ case N_GETDEMO: {
int n = getint(p), tag = getint(p);
if(!ci->privilege && !ci->local && ci->state.state==CS_SPECTATOR) break;
senddemo(ci, n, tag);
break;
}
-
case N_GETMAP:
if(!mapdata) sendf(sender, 1, "ris", N_SERVMSG, "no map to send");
else if(ci->getmap) sendf(sender, 1, "ris", N_SERVMSG, "already sending map");
- else
- {
+ else {
sendservmsgf("[%s is getting the map]", colorname(ci));
if((ci->getmap = sendfile(sender, 2, mapdata, "ri", N_SENDMAP)))
ci->getmap->freeCallback = freegetmap;
ci->needclipboard = totalmillis ? totalmillis : 1;
}
break;
-
- case N_NEWMAP:
- {
+ case N_NEWMAP: {
int size = getint(p);
if(!ci->privilege && !ci->local && ci->state.state==CS_SPECTATOR) break;
- if(size>=0)
- {
+ if(size>=0) {
smapname[0] = '\0';
resetitems();
notgotitems = false;
QUEUE_MSG;
break;
}
-
- case N_SETMASTER:
- {
+ case N_SETMASTER: {
int mn = getint(p), val = getint(p);
getstring(text, p);
- if(mn != ci->clientnum)
- {
+ if(mn != ci->clientnum) {
if(!ci->privilege && !ci->local) break;
clientinfo *minfo = (clientinfo *)getclientinfo(mn);
if(!minfo || !minfo->connected || (!ci->local && minfo->privilege >= ci->privilege) || (val && minfo->privilege)) break;
// don't broadcast the master password
break;
}
-
- case N_ADDBOT:
- {
+ case N_ADDBOT: {
aiman::reqadd(ci, getint(p));
break;
}
-
- case N_DELBOT:
- {
+ case N_DELBOT: {
aiman::reqdel(ci);
break;
}
-
- case N_BOTLIMIT:
- {
+ case N_BOTLIMIT: {
int limit = getint(p);
if(ci) aiman::setbotlimit(ci, limit);
break;
}
-
- case N_BOTBALANCE:
- {
+ case N_BOTBALANCE: {
int balance = getint(p);
if(ci) aiman::setbotbalance(ci, balance!=0);
break;
}
-
- case N_AUTHTRY:
- {
+ case N_AUTHTRY: {
string desc, name;
getstring(desc, p, sizeof(desc));
getstring(name, p, sizeof(name));
tryauth(ci, name, desc);
break;
}
-
- case N_AUTHKICK:
- {
+ case N_AUTHKICK: {
string desc, name;
getstring(desc, p, sizeof(desc));
getstring(name, p, sizeof(name));
getstring(text, p);
filtertext(text, text);
int authpriv = PRIV_AUTH;
- if(desc[0])
- {
+ if(desc[0]) {
userinfo *u = users.access(userkey(name, desc));
if(u) authpriv = u->privilege; else break;
}
if(ci->local || ci->privilege >= authpriv) trykick(ci, victim, text);
- else if(trykick(ci, victim, text, name, desc, authpriv, true) && tryauth(ci, name, desc))
- {
+ else if(trykick(ci, victim, text, name, desc, authpriv, true) && tryauth(ci, name, desc)) {
ci->authkickvictim = victim;
ci->authkickreason = newstring(text);
}
break;
}
-
- case N_AUTHANS:
- {
+ case N_AUTHANS: {
string desc, ans;
getstring(desc, p, sizeof(desc));
uint id = (uint)getint(p);
answerchallenge(ci, id, ans, desc);
break;
}
-
- case N_PAUSEGAME:
- {
+ case N_PAUSEGAME: {
int val = getint(p);
if(ci->privilege < (restrictpausegame ? PRIV_ADMIN : PRIV_MASTER) && !ci->local) break;
pausegame(val > 0, ci);
break;
}
-
- case N_GAMESPEED:
- {
+ case N_GAMESPEED: {
int val = getint(p);
if(ci->privilege < (restrictgamespeed ? PRIV_ADMIN : PRIV_MASTER) && !ci->local) break;
changegamespeed(val, ci);
break;
}
-
case N_COPY:
ci->cleanclipboard();
ci->lastclipboard = totalmillis ? totalmillis : 1;
goto genericmsg;
-
case N_PASTE:
if(ci->state.state!=CS_SPECTATOR) sendclipboard(ci);
goto genericmsg;
-
- case N_CLIPBOARD:
- {
+ case N_CLIPBOARD: {
int unpacklen = getint(p), packlen = getint(p);
ci->cleanclipboard(false);
- if(ci->state.state==CS_SPECTATOR)
- {
+ if(ci->state.state==CS_SPECTATOR) {
if(packlen > 0) p.subbuf(packlen);
break;
}
- if(packlen <= 0 || packlen > (1<<16) || unpacklen <= 0)
- {
+ if(packlen <= 0 || packlen > (1<<16) || unpacklen <= 0) {
if(packlen > 0) p.subbuf(packlen);
packlen = unpacklen = 0;
}
ci->clipboard->referenceCount++;
break;
}
-
case N_EDITT:
case N_REPLACE:
- case N_EDITVSLOT:
- {
+ case N_EDITVSLOT: {
int size = server::msgsizelookup(type);
//~if(size<=0) { disconnect_client(sender, DISC_MSGERR); return; }
loopi(size-1) getint(p);
if(ci && ci->state.state!=CS_SPECTATOR) QUEUE_MSG;
break;
}
-
case N_UNDO:
- case N_REDO:
- {
+ case N_REDO: {
int unpacklen = getint(p), packlen = getint(p);
- if(!ci || ci->state.state==CS_SPECTATOR || packlen <= 0 || packlen > (1<<16) || unpacklen <= 0)
- {
+ if(!ci || ci->state.state==CS_SPECTATOR || packlen <= 0 || packlen > (1<<16) || unpacklen <= 0) {
if(packlen > 0) p.subbuf(packlen);
break;
}
sendpacket(-1, 1, q.finalize(), ci->clientnum);
break;
}
-
case N_SERVCMD:
getstring(text, p);
break;
-
case -1:
//~disconnect_client(sender, DISC_MSGERR);
return;
-
case -2:
//~disconnect_client(sender, DISC_OVERFLOW);
return;
-
- default: genericmsg:
- {
+ default: genericmsg: {
int size = server::msgsizelookup(type);
//~if(size<=0) { disconnect_client(sender, DISC_MSGERR); return; }
loopi(size-1) getint(p);
- if(ci) switch(msgfilter[type])
- {
+ if(ci) switch(msgfilter[type]) {
case 2: case 3: if(ci->state.state != CS_SPECTATOR) QUEUE_MSG; break;
default: if(cq && (ci != cq || ci->state.state!=CS_SPECTATOR)) { QUEUE_AI; QUEUE_MSG; } break;
}
}
}
}
-
int laninfoport() { return SAUERBRATEN_LANINFO_PORT; }
int serverinfoport(int servport) { return servport < 0 ? SAUERBRATEN_SERVINFO_PORT : servport+1; }
int serverport(int infoport) { return infoport < 0 ? SAUERBRATEN_SERVER_PORT : infoport-1; }
const char *defaultmaster() { return "master.sauerbraten.org"; }
int masterport() { return SAUERBRATEN_MASTER_PORT; }
int numchannels() { return 3; }
-
#include "extinfo.h"
-
- void serverinforeply(ucharbuf &req, ucharbuf &p)
- {
- if(req.remaining() && !getint(req))
- {
+ void serverinforeply(ucharbuf &req, ucharbuf &p) {
+ if(req.remaining() && !getint(req)) {
extserverinforeply(req, p);
return;
}
-
putint(p, numclients(-1, false, true));
putint(p, gamepaused || gamespeed != 100 ? 7 : 5); // number of attrs following
putint(p, PROTOCOL_VERSION); // generic attributes, passed back below
putint(p, m_timed ? max((gamelimit - gamemillis)/1000, 0) : 0);
putint(p, maxclients);
putint(p, serverpass[0] ? MM_PASSWORD : (!m_mp(gamemode) ? MM_PRIVATE : (mastermode || mastermask&MM_AUTOAPPROVE ? mastermode : MM_AUTH)));
- if(gamepaused || gamespeed != 100)
- {
+ if(gamepaused || gamespeed != 100) {
putint(p, gamepaused ? 1 : 0);
putint(p, gamespeed);
}
sendstring(serverdesc, p);
sendserverinforeply(p);
}
-
#include "aiman.h"
}
extern selinfo sel;
-namespace ai
-{
+namespace ai {
using namespace game;
-
vector<waypoint> waypoints;
-
- bool clipped(const vec &o)
- {
+ bool clipped(const vec &o) {
int material = lookupmaterial(o), clipmat = material&MATF_CLIP;
return clipmat == MAT_CLIP || material&MAT_DEATH;
}
-
- int getweight(const vec &o)
- {
+ int getweight(const vec &o) {
vec pos = o; pos.z += ai::JUMPMIN;
if(!insideworld(vec(pos.x, pos.y, min(pos.z, getworldsize() - 1e-3f)))) return -2;
float dist = raycube(pos, vec(0, 0, -1), 0, RAY_CLIPMAT);
int weight = 1;
- if(dist >= 0)
- {
+ if(dist >= 0) {
weight = int(dist/ai::JUMPMIN);
pos.z -= clamp(dist-8.0f, 0.0f, pos.z);
int trgmat = lookupmaterial(pos);
}
return weight;
}
-
- enum
- {
+ enum {
WPCACHE_STATIC = 0,
WPCACHE_DYNAMIC,
NUMWPCACHES
};
-
- struct wpcache
- {
- struct node
- {
+ struct wpcache {
+ struct node {
float split[2];
uint child[2];
-
int axis() const { return child[0]>>30; }
int childindex(int which) const { return child[which]&0x3FFFFFFF; }
bool isleaf(int which) const { return (child[1]&(1<<(30+which)))!=0; }
};
-
vector<node> nodes;
int firstwp, lastwp;
vec bbmin, bbmax;
-
wpcache() { clear(); }
-
- void clear()
- {
+ void clear() {
nodes.setsize(0);
firstwp = lastwp = -1;
bbmin = vec(1e16f, 1e16f, 1e16f);
bbmax = vec(-1e16f, -1e16f, -1e16f);
}
-
- void build(int first = 0, int last = -1)
- {
+ void build(int first = 0, int last = -1) {
if(last < 0) last = waypoints.length();
vector<int> indices;
- for(int i = first; i < last; i++)
- {
+ for(int i = first; i < last; i++) {
waypoint &w = waypoints[i];
indices.add(i);
if(firstwp < 0) firstwp = i;
bbmax.max(vec(w.o).add(radius));
}
if(first < last) lastwp = max(lastwp, last-1);
- if(indices.length())
- {
+ if(indices.length()) {
nodes.reserve(indices.length());
build(indices.getbuf(), indices.length(), bbmin, bbmax);
}
}
-
- void build(int *indices, int numindices, const vec &vmin, const vec &vmax)
- {
+ void build(int *indices, int numindices, const vec &vmin, const vec &vmax) {
int axis = 2;
loopk(2) if(vmax[k] - vmin[k] > vmax[axis] - vmin[axis]) axis = k;
-
vec leftmin(1e16f, 1e16f, 1e16f), leftmax(-1e16f, -1e16f, -1e16f), rightmin(1e16f, 1e16f, 1e16f), rightmax(-1e16f, -1e16f, -1e16f);
float split = 0.5f*(vmax[axis] + vmin[axis]), splitleft = -1e16f, splitright = 1e16f;
int left, right;
- for(left = 0, right = numindices; left < right;)
- {
+ for(left = 0, right = numindices; left < right;) {
waypoint &w = waypoints[indices[left]];
float radius = WAYPOINTRADIUS;
- if(max(split - (w.o[axis]-radius), 0.0f) > max((w.o[axis]+radius) - split, 0.0f))
- {
+ if(max(split - (w.o[axis]-radius), 0.0f) > max((w.o[axis]+radius) - split, 0.0f)) {
++left;
splitleft = max(splitleft, w.o[axis]+radius);
leftmin.min(vec(w.o).sub(radius));
leftmax.max(vec(w.o).add(radius));
}
- else
- {
+ else {
--right;
swap(indices[left], indices[right]);
splitright = min(splitright, w.o[axis]-radius);
rightmax.max(vec(w.o).add(radius));
}
}
-
- if(!left || right==numindices)
- {
+ if(!left || right==numindices) {
leftmin = rightmin = vec(1e16f, 1e16f, 1e16f);
leftmax = rightmax = vec(-1e16f, -1e16f, -1e16f);
left = right = numindices/2;
splitleft = -1e16f;
splitright = 1e16f;
- loopi(numindices)
- {
+ loopi(numindices) {
waypoint &w = waypoints[indices[i]];
float radius = WAYPOINTRADIUS;
- if(i < left)
- {
+ if(i < left) {
splitleft = max(splitleft, w.o[axis]+radius);
leftmin.min(vec(w.o).sub(radius));
leftmax.max(vec(w.o).add(radius));
}
- else
- {
+ else {
splitright = min(splitright, w.o[axis]-radius);
rightmin.min(vec(w.o).sub(radius));
rightmax.max(vec(w.o).add(radius));
}
}
}
-
int offset = nodes.length();
node &curnode = nodes.add();
curnode.split[0] = splitleft;
curnode.split[1] = splitright;
-
if(left<=1) curnode.child[0] = (axis<<30) | (left>0 ? indices[0] : 0x3FFFFFFF);
- else
- {
+ else {
curnode.child[0] = (axis<<30) | (nodes.length()-offset);
if(left) build(indices, left, leftmin, leftmax);
}
-
if(numindices-right<=1) curnode.child[1] = (1<<31) | (left<=1 ? 1<<30 : 0) | (numindices-right>0 ? indices[right] : 0x3FFFFFFF);
- else
- {
+ else {
curnode.child[1] = (left<=1 ? 1<<30 : 0) | (nodes.length()-offset);
if(numindices-right) build(&indices[right], numindices-right, rightmin, rightmax);
}
}
} wpcaches[NUMWPCACHES];
-
static int invalidatedwpcaches = 0, clearedwpcaches = (1<<NUMWPCACHES)-1, numinvalidatewpcaches = 0, lastwpcache = 0;
-
- static inline void invalidatewpcache(int wp)
- {
+ static inline void invalidatewpcache(int wp) {
if(++numinvalidatewpcaches >= 1000) { numinvalidatewpcaches = 0; invalidatedwpcaches = (1<<NUMWPCACHES)-1; }
- else
- {
+ else {
loopi(WPCACHE_DYNAMIC) if(wp >= wpcaches[i].firstwp && wp <= wpcaches[i].lastwp) { invalidatedwpcaches |= 1<<i; return; }
invalidatedwpcaches |= 1<<WPCACHE_DYNAMIC;
}
}
-
- void clearwpcache(bool full = true)
- {
+ void clearwpcache(bool full = true) {
loopi(NUMWPCACHES) if(full || invalidatedwpcaches&(1<<i)) { wpcaches[i].clear(); clearedwpcaches |= 1<<i; }
- if(full || invalidatedwpcaches == (1<<NUMWPCACHES)-1)
- {
+ if(full || invalidatedwpcaches == (1<<NUMWPCACHES)-1) {
numinvalidatewpcaches = 0;
lastwpcache = 0;
}
invalidatedwpcaches = 0;
}
ICOMMAND(clearwpcache, "", (), clearwpcache());
-
avoidset wpavoid;
-
- void buildwpcache()
- {
+ void buildwpcache() {
loopi(NUMWPCACHES) if(wpcaches[i].firstwp < 0)
wpcaches[i].build(i > 0 ? wpcaches[i-1].lastwp+1 : 1, i+1 >= NUMWPCACHES || wpcaches[i+1].firstwp < 0 ? -1 : wpcaches[i+1].firstwp);
clearedwpcaches = 0;
lastwpcache = waypoints.length();
-
wpavoid.clear();
loopv(waypoints) if(waypoints[i].weight < 0) wpavoid.avoidnear(NULL, waypoints[i].o.z + WAYPOINTRADIUS, waypoints[i].o, WAYPOINTRADIUS);
}
-
- struct wpcachestack
- {
+ struct wpcachestack {
wpcache::node *node;
float tmin, tmax;
};
-
vector<wpcache::node *> wpcachestack;
-
- int closestwaypoint(const vec &pos, float mindist, bool links, fpsent *d)
- {
+ int closestwaypoint(const vec &pos, float mindist, bool links) {
if(waypoints.empty()) return -1;
if(clearedwpcaches) buildwpcache();
-
#define CHECKCLOSEST(index) do { \
int n = (index); \
- if(n < waypoints.length()) \
- { \
+ if(n < waypoints.length()) { \
+ \
const waypoint &w = waypoints[n]; \
- if(!links || w.links[0]) \
- { \
+ if(!links || w.links[0]) { \
+ \
float dist = w.o.squaredist(pos); \
if(dist < mindist*mindist) { closest = n; mindist = sqrtf(dist); } \
} \
} while(0)
int closest = -1;
wpcache::node *curnode;
- loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;)
- {
+ loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;) {
int axis = curnode->axis();
float dist1 = pos[axis] - curnode->split[0], dist2 = curnode->split[1] - pos[axis];
- if(dist1 >= mindist)
- {
- if(dist2 < mindist)
- {
+ if(dist1 >= mindist) {
+ if(dist2 < mindist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKCLOSEST(curnode->childindex(1));
}
}
- else if(curnode->isleaf(0))
- {
+ else if(curnode->isleaf(0)) {
CHECKCLOSEST(curnode->childindex(0));
- if(dist2 < mindist)
- {
+ if(dist2 < mindist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKCLOSEST(curnode->childindex(1));
}
}
- else
- {
- if(dist2 < mindist)
- {
+ else {
+ if(dist2 < mindist) {
if(!curnode->isleaf(1)) wpcachestack.add(curnode + curnode->childindex(1));
else CHECKCLOSEST(curnode->childindex(1));
}
for(int i = lastwpcache; i < waypoints.length(); i++) { CHECKCLOSEST(i); }
return closest;
}
-
- void findwaypointswithin(const vec &pos, float mindist, float maxdist, vector<int> &results)
- {
+ void findwaypointswithin(const vec &pos, float mindist, float maxdist, vector<int> &results) {
if(waypoints.empty()) return;
if(clearedwpcaches) buildwpcache();
-
float mindist2 = mindist*mindist, maxdist2 = maxdist*maxdist;
#define CHECKWITHIN(index) do { \
int n = (index); \
- if(n < waypoints.length()) \
- { \
+ if(n < waypoints.length()) { \
+ \
const waypoint &w = waypoints[n]; \
float dist = w.o.squaredist(pos); \
if(dist > mindist2 && dist < maxdist2) results.add(n); \
} \
} while(0)
wpcache::node *curnode;
- loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;)
- {
+ loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;) {
int axis = curnode->axis();
float dist1 = pos[axis] - curnode->split[0], dist2 = curnode->split[1] - pos[axis];
- if(dist1 >= maxdist)
- {
- if(dist2 < maxdist)
- {
+ if(dist1 >= maxdist) {
+ if(dist2 < maxdist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKWITHIN(curnode->childindex(1));
}
}
- else if(curnode->isleaf(0))
- {
+ else if(curnode->isleaf(0)) {
CHECKWITHIN(curnode->childindex(0));
- if(dist2 < maxdist)
- {
+ if(dist2 < maxdist) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKWITHIN(curnode->childindex(1));
}
}
- else
- {
- if(dist2 < maxdist)
- {
+ else {
+ if(dist2 < maxdist) {
if(!curnode->isleaf(1)) wpcachestack.add(curnode + curnode->childindex(1));
else CHECKWITHIN(curnode->childindex(1));
}
}
for(int i = lastwpcache; i < waypoints.length(); i++) { CHECKWITHIN(i); }
}
-
- void avoidset::avoidnear(void *owner, float above, const vec &pos, float limit)
- {
+ void avoidset::avoidnear(void *owner, float above, const vec &pos, float limit) {
if(ai::waypoints.empty()) return;
if(clearedwpcaches) buildwpcache();
-
float limit2 = limit*limit;
#define CHECKNEAR(index) do { \
int n = (index); \
- if(n < ai::waypoints.length()) \
- { \
+ if(n < ai::waypoints.length()) { \
+ \
const waypoint &w = ai::waypoints[n]; \
if(w.o.squaredist(pos) < limit2) add(owner, above, n); \
} \
} while(0)
wpcache::node *curnode;
- loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;)
- {
+ loop(which, NUMWPCACHES) if(wpcaches[which].firstwp >= 0) for(curnode = &wpcaches[which].nodes[0], wpcachestack.setsize(0);;) {
int axis = curnode->axis();
float dist1 = pos[axis] - curnode->split[0], dist2 = curnode->split[1] - pos[axis];
- if(dist1 >= limit)
- {
- if(dist2 < limit)
- {
+ if(dist1 >= limit) {
+ if(dist2 < limit) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKNEAR(curnode->childindex(1));
}
}
- else if(curnode->isleaf(0))
- {
+ else if(curnode->isleaf(0)) {
CHECKNEAR(curnode->childindex(0));
- if(dist2 < limit)
- {
+ if(dist2 < limit) {
if(!curnode->isleaf(1)) { curnode += curnode->childindex(1); continue; }
CHECKNEAR(curnode->childindex(1));
}
}
- else
- {
- if(dist2 < limit)
- {
+ else {
+ if(dist2 < limit) {
if(!curnode->isleaf(1)) wpcachestack.add(curnode + curnode->childindex(1));
else CHECKNEAR(curnode->childindex(1));
}
}
for(int i = lastwpcache; i < waypoints.length(); i++) { CHECKNEAR(i); }
}
-
- int avoidset::remap(fpsent *d, int n, vec &pos, bool retry)
- {
- if(!obstacles.empty())
- {
+ int avoidset::remap(fpsent *d, int n, vec &pos, bool retry) {
+ if(!obstacles.empty()) {
int cur = 0;
- loopv(obstacles)
- {
+ loopv(obstacles) {
obstacle &ob = obstacles[i];
int next = cur + ob.numwaypoints;
- if(ob.owner != d)
- {
- for(; cur < next; cur++) if(waypoints[cur] == n)
- {
+ if(ob.owner != d) {
+ for(; cur < next; cur++) if(waypoints[cur] == n) {
if(ob.above < 0) return retry ? n : -1;
vec above(pos.x, pos.y, ob.above);
if(above.z-d->o.z >= ai::JUMPMAX)
return retry ? n : -1; // too much scotty
- int node = closestwaypoint(above, ai::SIGHTMIN, true, d);
- if(ai::iswaypoint(node) && node != n)
- { // try to reroute above their head?
+ int node = closestwaypoint(above, ai::SIGHTMIN, true);
+ if(ai::iswaypoint(node) && node != n) {
+ // try to reroute above their head?
if(!find(node, d))
{
pos = ai::waypoints[node].o;
}
else return retry ? n : -1;
}
- else
- {
+ else {
vec old = d->o;
d->o = vec(above).add(vec(0, 0, d->eyeheight));
bool col = collide(d, vec(0, 0, 1));
}
return n;
}
-
static inline float heapscore(waypoint *q) { return q->score(); }
-
- bool route(fpsent *d, int node, int goal, vector<int> &route, const avoidset &obstacles, int retries)
- {
+ bool route(fpsent *d, int node, int goal, vector<int> &route, const avoidset &obstacles, int retries) {
if(waypoints.empty() || !iswaypoint(node) || !iswaypoint(goal) || goal == node || !waypoints[node].links[0])
return false;
-
static ushort routeid = 1;
static vector<waypoint *> queue;
-
- if(!routeid)
- {
+ if(!routeid) {
loopv(waypoints) waypoints[i].route = 0;
routeid = 1;
}
-
- if(d)
- {
- if(retries <= 1 && d->ai) loopi(ai::NUMPREVNODES) if(d->ai->prevnodes[i] != node && iswaypoint(d->ai->prevnodes[i]))
- {
+ if(d) {
+ if(retries <= 1 && d->ai) loopi(ai::NUMPREVNODES) if(d->ai->prevnodes[i] != node && iswaypoint(d->ai->prevnodes[i])) {
waypoints[d->ai->prevnodes[i]].route = routeid;
waypoints[d->ai->prevnodes[i]].curscore = -1;
waypoints[d->ai->prevnodes[i]].estscore = 0;
}
- if(retries <= 0)
- {
- loopavoid(obstacles, d,
- {
- if(iswaypoint(wp) && wp != node && wp != goal && waypoints[node].find(wp) < 0 && waypoints[goal].find(wp) < 0)
- {
+ if(retries <= 0) {
+ loopavoid(obstacles, d, {
+ if(iswaypoint(wp) && wp != node && wp != goal && waypoints[node].find(wp) < 0 && waypoints[goal].find(wp) < 0) {
waypoints[wp].route = routeid;
waypoints[wp].curscore = -1;
waypoints[wp].estscore = 0;
});
}
}
-
waypoints[node].route = routeid;
waypoints[node].curscore = waypoints[node].estscore = 0;
waypoints[node].prev = 0;
queue.setsize(0);
queue.add(&waypoints[node]);
route.setsize(0);
-
int lowest = -1;
- while(!queue.empty())
- {
+ while(!queue.empty()) {
waypoint &m = *queue.removeheap();
float prevscore = m.curscore;
m.curscore = -1;
- loopi(MAXWAYPOINTLINKS)
- {
+ loopi(MAXWAYPOINTLINKS) {
int link = m.links[i];
if(!link) break;
- if(iswaypoint(link) && (link == node || link == goal || waypoints[link].links[0]))
- {
+ if(iswaypoint(link) && (link == node || link == goal || waypoints[link].links[0])) {
waypoint &n = waypoints[link];
int weight = max(n.weight, 1);
float curscore = prevscore + n.o.dist(m.o)*weight;
if(n.route == routeid && curscore >= n.curscore) continue;
n.curscore = curscore;
n.prev = ushort(&m - &waypoints[0]);
- if(n.route != routeid)
- {
+ if(n.route != routeid) {
n.estscore = n.o.dist(waypoints[goal].o)*weight;
if(n.estscore <= WAYPOINTRADIUS*4 && (lowest < 0 || n.estscore <= waypoints[lowest].estscore))
lowest = link;
}
}
foundgoal:
-
routeid++;
-
- if(lowest >= 0) // otherwise nothing got there
- {
+ if(lowest >= 0) { // otherwise nothing got there {
for(waypoint *m = &waypoints[lowest]; m > &waypoints[0]; m = &waypoints[m->prev])
route.add(m - &waypoints[0]); // just keep it stored backward
}
-
return !route.empty();
}
-
VARF(dropwaypoints, 0, 0, 1, { player1->lastnode = -1; });
-
- int addwaypoint(const vec &o, int weight = -1)
- {
+ int addwaypoint(const vec &o, int weight = -1) {
if(waypoints.length() > MAXWAYPOINTS) return -1;
int n = waypoints.length();
waypoints.add(waypoint(o, weight >= 0 ? weight : getweight(o)));
invalidatewpcache(n);
return n;
}
-
- void linkwaypoint(waypoint &a, int n)
- {
- loopi(MAXWAYPOINTLINKS)
- {
+ void linkwaypoint(waypoint &a, int n) {
+ loopi(MAXWAYPOINTLINKS) {
if(a.links[i] == n) return;
if(!a.links[i]) { a.links[i] = n; return; }
}
a.links[rnd(MAXWAYPOINTLINKS)] = n;
}
-
string loadedwaypoints = "";
-
- static inline bool shouldnavigate()
- {
+ static inline bool shouldnavigate() {
if(dropwaypoints) return true;
loopvrev(players) if(players[i]->aitype != AI_NONE) return true;
return false;
}
-
- static inline bool shoulddrop(fpsent *d)
- {
+ static inline bool shoulddrop(fpsent *d) {
return !d->ai && (dropwaypoints || !loadedwaypoints[0]);
}
-
- void inferwaypoints(fpsent *d, const vec &o, const vec &v, float mindist)
- {
+ void inferwaypoints(fpsent *d, const vec &o, const vec &v, float mindist) {
if(!shouldnavigate()) return;
- if(shoulddrop(d))
- {
+ if(shoulddrop(d)) {
if(waypoints.empty()) seedwaypoints();
int from = closestwaypoint(o, mindist, false), to = closestwaypoint(v, mindist, false);
if(!iswaypoint(from)) from = addwaypoint(o);
if(!iswaypoint(to)) to = addwaypoint(v);
if(d->lastnode != from && iswaypoint(d->lastnode) && iswaypoint(from))
linkwaypoint(waypoints[d->lastnode], from);
- if(iswaypoint(to))
- {
+ if(iswaypoint(to)) {
if(from != to && iswaypoint(from) && iswaypoint(to))
linkwaypoint(waypoints[from], to);
d->lastnode = to;
}
}
- else d->lastnode = closestwaypoint(v, WAYPOINTRADIUS*2, false, d);
+ else d->lastnode = closestwaypoint(v, WAYPOINTRADIUS*2, false);
}
-
- void navigate(fpsent *d)
- {
+ void navigate(fpsent *d) {
vec v(d->feetpos());
if(d->state != CS_ALIVE) { d->lastnode = -1; return; }
bool dropping = shoulddrop(d);
int mat = lookupmaterial(v);
if((mat&MATF_CLIP) == MAT_CLIP || mat&MAT_DEATH) dropping = false;
float dist = dropping ? WAYPOINTRADIUS : (d->ai ? WAYPOINTRADIUS : SIGHTMIN);
- int curnode = closestwaypoint(v, dist, false, d), prevnode = d->lastnode;
- if(!iswaypoint(curnode) && dropping)
- {
+ int curnode = closestwaypoint(v, dist, false), prevnode = d->lastnode;
+ if(!iswaypoint(curnode) && dropping) {
if(waypoints.empty()) seedwaypoints();
curnode = addwaypoint(v);
}
- if(iswaypoint(curnode))
- {
- if(dropping && d->lastnode != curnode && iswaypoint(d->lastnode))
- {
+ if(iswaypoint(curnode)) {
+ if(dropping && d->lastnode != curnode && iswaypoint(d->lastnode)) {
linkwaypoint(waypoints[d->lastnode], curnode);
if(!d->timeinair) linkwaypoint(waypoints[curnode], d->lastnode);
}
if(d->ai && iswaypoint(prevnode) && d->lastnode != prevnode) d->ai->addprevnode(prevnode);
}
else if(!iswaypoint(d->lastnode) || waypoints[d->lastnode].o.squaredist(v) > SIGHTMIN*SIGHTMIN)
- d->lastnode = closestwaypoint(v, SIGHTMAX, false, d);
+ d->lastnode = closestwaypoint(v, SIGHTMAX, false);
}
-
- void navigate()
- {
+ void navigate() {
if(shouldnavigate()) loopv(players) ai::navigate(players[i]);
if(invalidatedwpcaches) clearwpcache(false);
}
-
- void clearwaypoints(bool full)
- {
+ void clearwaypoints(bool full) {
waypoints.setsize(0);
clearwpcache();
- if(full)
- {
+ if(full) {
loadedwaypoints[0] = '\0';
dropwaypoints = 0;
}
}
ICOMMAND(clearwaypoints, "", (), clearwaypoints());
-
- void seedwaypoints()
- {
+ void seedwaypoints() {
if(waypoints.empty()) addwaypoint(vec(0, 0, 0));
- loopv(entities::ents)
- {
+ loopv(entities::ents) {
extentity &e = *entities::ents[i];
- switch(e.type)
- {
+ switch(e.type) {
case PLAYERSTART: case TELEPORT: case JUMPPAD:
addwaypoint(e.o);
break;
}
}
}
-
- void remapwaypoints()
- {
+ void remapwaypoints() {
vector<ushort> remap;
int total = 0;
loopv(waypoints) remap.add(waypoints[i].links[1] == 0xFFFF ? 0 : total++);
total = 0;
- loopvj(waypoints)
- {
+ loopvj(waypoints) {
if(waypoints[j].links[1] == 0xFFFF) continue;
waypoint &w = waypoints[total];
if(j != total) w = waypoints[j];
int k = 0;
- loopi(MAXWAYPOINTLINKS)
- {
+ loopi(MAXWAYPOINTLINKS) {
int link = w.links[i];
if(!link) break;
if((w.links[k] = remap[link])) k++;
}
waypoints.setsize(total);
}
-
- bool cleanwaypoints()
- {
+ bool cleanwaypoints() {
int cleared = 0;
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
- if(clipped(w.o))
- {
+ if(clipped(w.o)) {
w.links[0] = 0;
w.links[1] = 0xFFFF;
cleared++;
}
}
- if(cleared)
- {
+ if(cleared) {
player1->lastnode = -1;
loopv(players) if(players[i]) players[i]->lastnode = -1;
remapwaypoints();
}
return false;
}
-
- bool getwaypointfile(const char *mname, char *wptname)
- {
+ bool getwaypointfile(const char *mname, char *wptname) {
if(!mname || !*mname) mname = getclientmap();
if(!*mname) return false;
-
string pakname, mapname, cfgname;
getmapfilenames(mname, NULL, pakname, mapname, cfgname);
nformatstring(wptname, MAXSTRLEN, "packages/%s.wpt", mapname);
path(wptname);
return true;
}
-
- void loadwaypoints(bool force, const char *mname)
- {
+ void loadwaypoints(bool force, const char *mname) {
string wptname;
if(!getwaypointfile(mname, wptname)) return;
if(!force && (waypoints.length() || !strcmp(loadedwaypoints, wptname))) return;
-
stream *f = opengzfile(wptname, "rb");
if(!f) return;
char magic[4];
if(f->read(magic, 4) < 4 || memcmp(magic, "OWPT", 4)) { delete f; return; }
-
copystring(loadedwaypoints, wptname);
-
waypoints.setsize(0);
waypoints.add(vec(0, 0, 0));
ushort numwp = f->getlil<ushort>();
- loopi(numwp)
- {
+ loopi(numwp) {
if(f->end()) break;
vec o;
o.x = f->getlil<float>();
o.z = f->getlil<float>();
waypoint &w = waypoints.add(waypoint(o, getweight(o)));
int numlinks = f->getchar(), k = 0;
- loopi(numlinks)
- {
- if((w.links[k] = f->getlil<ushort>()))
- {
+ loopi(numlinks) {
+ if((w.links[k] = f->getlil<ushort>())) {
if(++k >= MAXWAYPOINTLINKS) break;
}
}
}
-
delete f;
conoutf("loaded %d waypoints from %s", numwp, wptname);
-
if(!cleanwaypoints()) clearwpcache();
}
ICOMMAND(loadwaypoints, "s", (char *mname), loadwaypoints(true, mname));
-
- void savewaypoints(bool force, const char *mname)
- {
+ void savewaypoints(bool force, const char *mname) {
if((!dropwaypoints && !force) || waypoints.empty()) return;
-
string wptname;
if(!getwaypointfile(mname, wptname)) return;
-
stream *f = opengzfile(wptname, "wb");
if(!f) return;
f->write("OWPT", 4);
f->putlil<ushort>(waypoints.length()-1);
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
f->putlil<float>(w.o.x);
f->putlil<float>(w.o.y);
f->putchar(numlinks);
loopj(numlinks) f->putlil<ushort>(w.links[j]);
}
-
delete f;
conoutf("saved %d waypoints to %s", waypoints.length()-1, wptname);
}
-
ICOMMAND(savewaypoints, "s", (char *mname), savewaypoints(true, mname));
-
- void delselwaypoints()
- {
+ void delselwaypoints() {
if(noedit(true)) return;
vec o = vec(sel.o).sub(0.1f), s = vec(sel.s).mul(sel.grid).add(o).add(0.1f);
int cleared = 0;
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
- if(w.o.x >= o.x && w.o.x <= s.x && w.o.y >= o.y && w.o.y <= s.y && w.o.z >= o.z && w.o.z <= s.z)
- {
+ if(w.o.x >= o.x && w.o.x <= s.x && w.o.y >= o.y && w.o.y <= s.y && w.o.z >= o.z && w.o.z <= s.z) {
w.links[0] = 0;
w.links[1] = 0xFFFF;
cleared++;
}
}
- if(cleared)
- {
+ if(cleared) {
player1->lastnode = -1;
remapwaypoints();
clearwpcache();
}
}
COMMAND(delselwaypoints, "");
-
- void movewaypoints(const vec &d)
- {
+ void movewaypoints(const vec &d) {
if(noedit(true)) return;
int worldsize = getworldsize();
- if(d.x < -worldsize || d.x > worldsize || d.y < -worldsize || d.y > worldsize || d.z < -worldsize || d.z > worldsize)
- {
+ if(d.x < -worldsize || d.x > worldsize || d.y < -worldsize || d.y > worldsize || d.z < -worldsize || d.z > worldsize) {
clearwaypoints();
return;
}
int cleared = 0;
- for(int i = 1; i < waypoints.length(); i++)
- {
+ for(int i = 1; i < waypoints.length(); i++) {
waypoint &w = waypoints[i];
w.o.add(d);
if(!insideworld(w.o)) { w.links[0] = 0; w.links[1] = 0xFFFF; cleared++; }
}
- if(cleared)
- {
+ if(cleared) {
player1->lastnode = -1;
remapwaypoints();
}
// weapon.cpp: all shooting and effects code, projectile management
#include "game.h"
-namespace game
-{
+namespace game {
static const int OFFSETMILLIS = 500;
vec rays[MAXRAYS];
-
- struct hitmsg
- {
+ struct hitmsg {
int target, lifesequence, info1, info2;
ivec dir;
};
vector<hitmsg> hits;
-
ICOMMAND(getweapon, "", (), intret(player1->gunselect));
-
- void gunselect(int gun, fpsent *d)
- {
- if(gun!=d->gunselect)
- {
+ void gunselect(int gun, fpsent *d) {
+ if(gun!=d->gunselect) {
addmsg(N_GUNSELECT, "rci", d, gun);
playsound(S_WEAPLOAD, d == player1 ? NULL : &d->o);
}
d->gunselect = gun;
}
-
- void nextweapon(int dir, bool force = false)
- {
+ void nextweapon(int dir, bool force = false) {
if(player1->state!=CS_ALIVE) return;
dir = (dir < 0 ? NUMGUNS-1 : 1);
int gun = player1->gunselect;
- loopi(NUMGUNS)
- {
+ loopi(NUMGUNS) {
gun = (gun + dir)%NUMGUNS;
if(force || player1->ammo[gun]) break;
}
else playsound(S_NOAMMO);
}
ICOMMAND(nextweapon, "ii", (int *dir, int *force), nextweapon(*dir, *force!=0));
-
- int getweapon(const char *name)
- {
+ int getweapon(const char *name) {
const char *abbrevs[] = { "FI", "SG", "CG", "RL", "RI", "GL", "PI" };
if(isdigit(name[0])) return parseint(name);
else loopi(sizeof(abbrevs)/sizeof(abbrevs[0])) if(!strcasecmp(abbrevs[i], name)) return i;
return -1;
}
-
- void setweapon(const char *name, bool force = false)
- {
+ void setweapon(const char *name, bool force = false) {
int gun = getweapon(name);
if(player1->state!=CS_ALIVE || gun<GUN_FIST || gun>GUN_PISTOL) return;
if(force || player1->ammo[gun]) gunselect(gun, player1);
else playsound(S_NOAMMO);
}
ICOMMAND(setweapon, "si", (char *name, int *force), setweapon(name, *force!=0));
-
- void cycleweapon(int numguns, int *guns, bool force = false)
- {
+ void cycleweapon(int numguns, int *guns, bool force = false) {
if(numguns<=0 || player1->state!=CS_ALIVE) return;
int offset = 0;
loopi(numguns) if(guns[i] == player1->gunselect) { offset = i+1; break; }
- loopi(numguns)
- {
+ loopi(numguns) {
int gun = guns[(i+offset)%numguns];
- if(gun>=0 && gun<NUMGUNS && (force || player1->ammo[gun]))
- {
+ if(gun>=0 && gun<NUMGUNS && (force || player1->ammo[gun])) {
gunselect(gun, player1);
return;
}
}
playsound(S_NOAMMO);
}
- ICOMMAND(cycleweapon, "V", (tagval *args, int numargs),
- {
+ ICOMMAND(cycleweapon, "V", (tagval *args, int numargs), {
int numguns = min(numargs, 7);
int guns[7];
loopi(numguns) guns[i] = getweapon(args[i].getstr());
cycleweapon(numguns, guns);
});
-
- void weaponswitch(fpsent *d)
- {
+ void weaponswitch(fpsent *d) {
if(d->state!=CS_ALIVE) return;
int s = d->gunselect;
if (s!=GUN_CG && d->ammo[GUN_CG]) s = GUN_CG;
else if(s!=GUN_GL && d->ammo[GUN_GL]) s = GUN_GL;
else if(s!=GUN_PISTOL && d->ammo[GUN_PISTOL]) s = GUN_PISTOL;
else s = GUN_FIST;
-
gunselect(s, d);
}
-
- ICOMMAND(weapon, "V", (tagval *args, int numargs),
- {
+ ICOMMAND(weapon, "V", (tagval *args, int numargs), {
if(player1->state!=CS_ALIVE) return;
- loopi(7)
- {
+ loopi(7) {
const char *name = i < numargs ? args[i].getstr() : "";
- if(name[0])
- {
+ if(name[0]) {
int gun = getweapon(name);
if(gun >= GUN_FIST && gun <= GUN_PISTOL && gun != player1->gunselect && player1->ammo[gun]) { gunselect(gun, player1); return; }
} else { weaponswitch(player1); return; }
}
playsound(S_NOAMMO);
});
-
- void offsetray(const vec &from, const vec &to, int spread, float range, vec &dest)
- {
+ void offsetray(const vec &from, const vec &to, int spread, float range, vec &dest) {
vec offset;
do offset = vec(rndscale(1), rndscale(1), rndscale(1)).sub(0.5f);
while(offset.squaredlen() > 0.5f*0.5f);
offset.mul((to.dist(from)/1024)*spread);
offset.z /= 2;
dest = vec(offset).add(to);
- if(dest != from)
- {
+ if(dest != from) {
vec dir = vec(dest).sub(from).normalize();
raycubepos(from, dir, dest, range, RAY_CLIPMAT|RAY_ALPHAPOLY);
}
}
-
- void createrays(int gun, const vec &from, const vec &to) // create random spread of rays
- {
+ void createrays(int gun, const vec &from, const vec &to) { // create random spread of rays {
loopi(guns[gun].rays) offsetray(from, to, guns[gun].spread, guns[gun].range, rays[i]);
}
-
enum { BNC_GRENADE };
-
- struct bouncer : physent
- {
+ struct bouncer : physent {
int lifetime, bounces;
float lastyaw, roll;
bool local;
float offsetheight;
int id;
entitylight light;
-
- bouncer() : bounces(0), roll(0), variant(0)
- {
+ bouncer() : bounces(0), roll(0), variant(0) {
type = ENT_BOUNCE;
}
-
- vec offsetpos()
- {
+ vec offsetpos() {
vec pos(o);
- if(offsetmillis > 0)
- {
+ if(offsetmillis > 0) {
pos.add(vec(offset).mul(offsetmillis/float(OFFSETMILLIS)));
if(offsetheight >= 0) pos.z = max(pos.z, o.z - max(offsetheight - eyeheight, 0.0f));
}
return pos;
}
-
- void limitoffset()
- {
+ void limitoffset() {
if(bouncetype == BNC_GRENADE && offsetmillis > 0 && offset.z < 0)
offsetheight = raycube(vec(o.x + offset.x, o.y + offset.y, o.z), vec(0, 0, -1), -offset.z);
else offsetheight = -1;
}
};
-
vector<bouncer *> bouncers;
-
vec hudgunorigin(int gun, const vec &from, const vec &to, fpsent *d);
-
- void newbouncer(const vec &from, const vec &to, bool local, int id, fpsent *owner, int type, int lifetime, int speed, entitylight *light = NULL)
- {
+ void newbouncer(const vec &from, const vec &to, bool local, int id, fpsent *owner, int type, int lifetime, int speed, entitylight *light = NULL) {
bouncer &bnc = *bouncers.add(new bouncer);
bnc.o = from;
bnc.radius = bnc.xradius = bnc.yradius = 1.5f;
bnc.bouncetype = type;
bnc.id = local ? lastmillis : id;
if(light) bnc.light = *light;
-
bnc.collidetype = COLLIDE_ELLIPSE_PRECISE;
-
vec dir(to);
dir.sub(from).safenormalize();
bnc.vel = dir;
bnc.vel.mul(speed);
-
avoidcollision(&bnc, dir, owner, 0.1f);
-
- if(type==BNC_GRENADE)
- {
+ if(type==BNC_GRENADE) {
bnc.offset = hudgunorigin(GUN_GL, from, to, owner);
if(owner==followingplayer(player1) && !isthirdperson()) bnc.offset.sub(owner->o).rescale(16).add(owner->o);
}
bnc.offset.sub(bnc.o);
bnc.offsetmillis = OFFSETMILLIS;
bnc.limitoffset();
-
bnc.resetinterp();
}
-
- void bounced(physent *d, const vec &surface)
- {
+ void bounced(physent *d, const vec &surface) {
if(d->type != ENT_BOUNCE) return;
bouncer *b = (bouncer *)d;
if(b->bounces >= 2) return;
b->bounces++;
adddecal(DECAL_BLOOD, vec(b->o).sub(vec(surface).mul(b->radius)), surface, 2.96f/b->bounces, bvec(0x60, 0xFF, 0xFF), rnd(4));
}
-
- void updatebouncers(int time)
- {
- loopv(bouncers)
- {
+ void updatebouncers(int time) {
+ loopv(bouncers) {
bouncer &bnc = *bouncers[i];
- if(bnc.bouncetype==BNC_GRENADE && bnc.vel.magnitude() > 50.0f)
- {
+ if(bnc.bouncetype==BNC_GRENADE && bnc.vel.magnitude() > 50.0f) {
vec pos = bnc.offsetpos();
regular_particle_splash(PART_SMOKE, 1, 150, pos, 0x404040, 2.4f, 50, -20);
}
vec old(bnc.o);
bool stopped = false;
if(bnc.bouncetype==BNC_GRENADE) stopped = bounce(&bnc, 0.6f, 0.5f, 0.8f) || (bnc.lifetime -= time)<0;
-
- if(stopped)
- {
- if(bnc.bouncetype==BNC_GRENADE)
- {
+ if(stopped) {
+ if(bnc.bouncetype==BNC_GRENADE) {
int qdam = guns[GUN_GL].damage*(bnc.owner->quadmillis ? 4 : 1);
hits.setsize(0);
explode(bnc.local, bnc.owner, bnc.o, NULL, qdam, GUN_GL);
}
delete bouncers.remove(i--);
}
- else
- {
+ else {
bnc.roll += old.sub(bnc.o).magnitude()/(4*RAD);
bnc.offsetmillis = max(bnc.offsetmillis-time, 0);
bnc.limitoffset();
}
}
}
-
- void removebouncers(fpsent *owner)
- {
+ void removebouncers(fpsent *owner) {
loopv(bouncers) if(bouncers[i]->owner==owner) { delete bouncers[i]; bouncers.remove(i--); }
}
-
void clearbouncers() { bouncers.deletecontents(); }
-
- struct projectile
- {
+ struct projectile {
vec dir, o, to, offset;
float speed;
fpsent *owner;
entitylight light;
};
vector<projectile> projs;
-
void clearprojectiles() { projs.shrink(0); }
-
- void newprojectile(const vec &from, const vec &to, float speed, bool local, int id, fpsent *owner, int gun)
- {
+ void newprojectile(const vec &from, const vec &to, float speed, bool local, int id, fpsent *owner, int gun) {
projectile &p = projs.add();
p.dir = vec(to).sub(from).safenormalize();
p.o = from;
p.offsetmillis = OFFSETMILLIS;
p.id = local ? lastmillis : id;
}
-
- void removeprojectiles(fpsent *owner)
- {
+ void removeprojectiles(fpsent *owner) {
// can't use loopv here due to strange GCC optimizer bug
int len = projs.length();
loopi(len) if(projs[i].owner==owner) { projs.remove(i--); len--; }
}
-
VARP(blood, 0, 1, 1);
-
- void damageeffect(int damage, fpsent *d, bool thirdperson)
- {
+ void damageeffect(int damage, fpsent *d, bool thirdperson) {
vec p = d->o;
p.z += 0.6f*(d->eyeheight + d->aboveeye) - d->eyeheight;
if(blood) particle_splash(PART_BLOOD, damage/10, 1000, p, 0x60FFFF, 2.96f);
- if(thirdperson)
- {
+ if(thirdperson) {
defformatstring(ds, "%d", damage);
particle_textcopy(d->abovehead(), ds, PART_TEXT, 2000, 0xFF4B19, 4.0f, -8);
}
}
-
- void spawnbouncer(const vec &p, const vec &vel, fpsent *d, int type, entitylight *light = NULL)
- {
- vec to(rnd(100)-50, rnd(100)-50, rnd(100)-50);
- if(to.iszero()) to.z += 1;
- to.normalize();
- to.add(p);
- newbouncer(p, to, true, 0, d, type, rnd(1000)+1000, rnd(100)+20, light);
- }
-
- void hit(int damage, dynent *d, fpsent *at, const vec &vel, int gun, float info1, int info2 = 1)
- {
- if(at==player1 && d!=at)
- {
+ //~void spawnbouncer(const vec &p, const vec &vel, fpsent *d, int type, entitylight *light = NULL)
+ //~{
+ //~vec to(rnd(100)-50, rnd(100)-50, rnd(100)-50);
+ //~if(to.iszero()) to.z += 1;
+ //~to.normalize();
+ //~to.add(p);
+ //~newbouncer(p, to, true, 0, d, type, rnd(1000)+1000, rnd(100)+20, light);
+ //~}
+ void hit(int damage, dynent *d, fpsent *at, const vec &vel, int gun, float info1, int info2 = 1) {
+ if(at==player1 && d!=at) {
extern int hitsound;
if(hitsound && lasthit != lastmillis) playsound(S_HIT);
lasthit = lastmillis;
}
-
fpsent *f = (fpsent *)d;
-
f->lastpain = lastmillis;
if(at->type==ENT_PLAYER && !isteam(at->team, f->team)) at->totaldamage += damage;
-
if(f->type==ENT_AI || !m_mp(gamemode) || f==at) f->hitpush(damage, vel, at, gun);
-
pwhit(gun, damage);
-
if(!m_mp(gamemode)) damaged(damage, f, at);
- else
- {
+ else {
hitmsg &h = hits.add();
h.target = f->clientnum;
h.lifesequence = f->lifesequence;
h.info1 = int(info1*DMF);
h.info2 = info2;
h.dir = f==at ? ivec(0, 0, 0) : ivec(vec(vel).mul(DNF));
- if(at==player1)
- {
+ if(at==player1) {
damageeffect(damage, f);
- if(f==player1)
- {
+ if(f==player1) {
damagecompass(damage, at ? at->o : f->o);
playsound(S_PAIN6);
}
}
}
}
-
- void hitpush(int damage, dynent *d, fpsent *at, vec &from, vec &to, int gun, int rays)
- {
+ void hitpush(int damage, dynent *d, fpsent *at, vec &from, vec &to, int gun, int rays) {
hit(damage, d, at, vec(to).sub(from).safenormalize(), gun, from.dist(to), rays);
}
-
- float projdist(dynent *o, vec &dir, const vec &v)
- {
+ float projdist(dynent *o, vec &dir, const vec &v) {
vec middle = o->o;
middle.z += (o->aboveeye-o->eyeheight)/2;
float dist = middle.dist(v, dir);
if(dist<0) dist = 0;
return dist;
}
-
- void radialeffect(dynent *o, const vec &v, int qdam, fpsent *at, int gun)
- {
+ void radialeffect(dynent *o, const vec &v, int qdam, fpsent *at, int gun) {
if(o->state!=CS_ALIVE) return;
vec dir;
float dist = projdist(o, dir, v);
- if(dist<guns[gun].exprad)
- {
+ if(dist<guns[gun].exprad) {
int damage = (int)(qdam*(1-dist/EXP_DISTSCALE/guns[gun].exprad));
if(o==at) damage /= EXP_SELFDAMDIV;
hit(damage, o, at, dir, gun, dist);
}
}
-
FVARP(explodebright, 0, 1, 1);
-
- void explode(bool local, fpsent *owner, const vec &v, dynent *safe, int damage, int gun)
- {
+ void explode(bool local, fpsent *owner, const vec &v, dynent *safe, int damage, int gun) {
particle_splash(PART_SPARK, 200, 300, v, 0xB49B4B, 0.24f);
playsound(gun!=GUN_GL ? S_RLHIT : S_FEXPLODE, &v);
int color = gun!=GUN_GL ? 0xFF8080 : 0x80FFFF;
if((gun==GUN_RL || gun==GUN_GL) && explodebright < 1) color = vec::hexcolor(color).mul(explodebright).tohexcolor();
- particle_fireball(v, guns[gun].exprad, gun!=GUN_GL ? PART_EXPLOSION : PART_EXPLOSION_BLUE, gun!=GUN_GL ? -1 : int((guns[gun].exprad-4.0f)*15), color, 4.0f);
+ /// REPLACE THIS SHIT WITH SMOKE AND FIRE EFFECT LIKE IN XONOTIC
+ //~particle_fireball(v, guns[gun].exprad, gun!=GUN_GL ? PART_EXPLOSION : PART_EXPLOSION_BLUE, gun!=GUN_GL ? -1 : int((guns[gun].exprad-4.0f)*15), color, 4.0f);
if(gun==GUN_RL) adddynlight(v, 1.15f*guns[gun].exprad, vec(2, 1.5f, 1), 700, 100, 0, guns[gun].exprad/2, vec(1, 0.75f, 0.5f));
else if(gun==GUN_GL) adddynlight(v, 1.15f*guns[gun].exprad, vec(0.5f, 1.5f, 2), 600, 100, 0, 8, vec(0.25f, 1, 1));
else adddynlight(v, 1.15f*guns[gun].exprad, vec(2, 1.5f, 1), 700, 100);
if(!local) return;
int numdyn = numdynents();
- loopi(numdyn)
- {
+ loopi(numdyn) {
dynent *o = iterdynents(i);
if(o->o.reject(v, o->radius + guns[gun].exprad) || o==safe) continue;
radialeffect(o, v, damage, owner, gun);
}
}
-
- void projsplash(projectile &p, vec &v, dynent *safe, int damage)
- {
- if(guns[p.gun].part)
- {
+ void projsplash(projectile &p, vec &v, dynent *safe, int damage) {
+ if(guns[p.gun].part) {
particle_splash(PART_SPARK, 100, 200, v, 0xB49B4B, 0.24f);
playsound(S_FEXPLODE, &v);
// no push?
}
- else
- {
+ else {
explode(p.local, p.owner, v, safe, damage, GUN_RL);
adddecal(DECAL_SCORCH, v, vec(p.dir).neg(), guns[p.gun].exprad/2);
}
}
-
- void explodeeffects(int gun, fpsent *d, bool local, int id)
- {
+ void explodeeffects(int gun, fpsent *d, bool local, int id) {
if(local) return;
- switch(gun)
- {
+ switch(gun) {
case GUN_RL:
- loopv(projs)
- {
+ loopv(projs) {
projectile &p = projs[i];
- if(p.gun == gun && p.owner == d && p.id == id && !p.local)
- {
+ if(p.gun == gun && p.owner == d && p.id == id && !p.local) {
vec pos(p.o);
pos.add(vec(p.offset).mul(p.offsetmillis/float(OFFSETMILLIS)));
explode(p.local, p.owner, pos, NULL, 0, GUN_RL);
}
break;
case GUN_GL:
- loopv(bouncers)
- {
+ loopv(bouncers) {
bouncer &b = *bouncers[i];
- if(b.bouncetype == BNC_GRENADE && b.owner == d && b.id == id && !b.local)
- {
+ if(b.bouncetype == BNC_GRENADE && b.owner == d && b.id == id && !b.local) {
vec pos = b.offsetpos();
explode(b.local, b.owner, pos, NULL, 0, GUN_GL);
adddecal(DECAL_SCORCH, pos, vec(0, 0, 1), guns[gun].exprad/2);
break;
}
}
-
- bool projdamage(dynent *o, projectile &p, vec &v, int qdam)
- {
+ bool projdamage(dynent *o, projectile &p, vec &v, int qdam) {
if(o->state!=CS_ALIVE) return false;
if(!intersect(o, p.o, v)) return false;
projsplash(p, v, o, qdam);
hit(qdam, o, p.owner, dir, p.gun, 0);
return true;
}
-
- void updateprojectiles(int time)
- {
- loopv(projs)
- {
+ void updateprojectiles(int time) {
+ loopv(projs) {
projectile &p = projs[i];
p.offsetmillis = max(p.offsetmillis-time, 0);
int qdam = guns[p.gun].damage*(p.owner->quadmillis ? 4 : 1);
vec v = vec(p.o).add(dv);
bool exploded = false;
hits.setsize(0);
- if(p.local)
- {
+ if(p.local) {
vec halfdv = vec(dv).mul(0.5f), bo = vec(p.o).add(halfdv);
float br = max(fabs(halfdv.x), fabs(halfdv.y)) + 1;
- loopj(numdynents())
- {
+ loopj(numdynents()) {
dynent *o = iterdynents(j);
if(p.owner==o || o->o.reject(bo, o->radius + br)) continue;
if(projdamage(o, p, v, qdam)) { exploded = true; break; }
}
}
- if(!exploded)
- {
- if(dist<4)
- {
- if(p.o!=p.to) // if original target was moving, reevaluate endpoint
- {
+ if(!exploded) {
+ if(dist<4) {
+ if(p.o!=p.to) { // if original target was moving, reevaluate endpoint {
if(raycubepos(p.o, p.dir, p.to, 0, RAY_CLIPMAT|RAY_ALPHAPOLY)>=4) continue;
}
projsplash(p, v, NULL, qdam);
exploded = true;
}
- else
- {
+ else {
vec pos(v);
pos.add(vec(p.offset).mul(p.offsetmillis/float(OFFSETMILLIS)));
regular_particle_splash(PART_SMOKE, 2, 300, pos, 0x404040, 2.4f, 50, -20);
}
}
- if(exploded)
- {
+ if(exploded) {
if(p.local)
addmsg(N_EXPLODE, "rci3iv", p.owner, lastmillis-maptime, p.gun, p.id-maptime,
hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf());
else p.o = v;
}
}
-
extern int chainsawhudgun;
-
VARP(muzzleflash, 0, 1, 1);
VARP(muzzlelight, 0, 1, 1);
-
- void shoteffects(int gun, const vec &from, const vec &to, fpsent *d, bool local, int id, int prevaction) // create visual effect from a shot
- {
+ void shoteffects(int gun, const vec &from, const vec &to, fpsent *d, bool local, int id, int prevaction) { // create visual effect from a shot {
int sound = guns[gun].sound, pspeed = 25;
- switch(gun)
- {
+ switch(gun) {
case GUN_FIST:
if(d->type==ENT_PLAYER && chainsawhudgun) sound = S_CHAINSAW_ATTACK;
break;
-
- case GUN_SG:
- {
+ case GUN_SG: {
if(!local) createrays(gun, from, to);
if(muzzleflash && d->muzzle.x >= 0)
particle_flare(d->muzzle, d->muzzle, 200, PART_MUZZLE_FLASH3, 0xFFFFFF, 2.75f, d);
- loopi(guns[gun].rays)
- {
+ loopi(guns[gun].rays) {
if(d->quadmillis)
particle_trail(PART_FLAME, 400, hudgunorigin(gun, from, rays[i], d), rays[i], 0x802010, 0.6f, 36);
particle_splash(PART_SPARK, 20, 250, rays[i], 0xB49B4B, 0.24f);
if(muzzlelight) adddynlight(hudgunorigin(gun, d->o, to, d), 30, vec(0.5f, 0.375f, 0.25f), 100, 100, DL_FLASH, 0, vec(0, 0, 0), d);
break;
}
-
case GUN_CG:
- case GUN_PISTOL:
- {
+ case GUN_PISTOL: {
particle_splash(PART_SPARK, 200, 250, to, 0xB49B4B, 0.24f);
if(d->quadmillis)
particle_trail(PART_FLAME, 400, hudgunorigin(gun, from, to, d), to, 0x802010, 0.6f, 36);
if(muzzlelight) adddynlight(hudgunorigin(gun, d->o, to, d), gun==GUN_CG ? 30 : 15, vec(0.5f, 0.375f, 0.25f), gun==GUN_CG ? 50 : 100, gun==GUN_CG ? 50 : 100, DL_FLASH, 0, vec(0, 0, 0), d);
break;
}
-
case GUN_RL:
if(d->quadmillis)
particle_trail(PART_FLAME, 400, hudgunorigin(gun, from, to, d), to, 0x802010, 0.6f, 36);
pspeed = guns[gun].projspeed;
newprojectile(from, to, (float)pspeed, local, id, d, gun);
break;
-
- case GUN_GL:
- {
+ case GUN_GL: {
float dist = from.dist(to);
vec up = to;
up.z += dist/8;
newbouncer(from, up, local, id, d, BNC_GRENADE, guns[gun].ttl, guns[gun].projspeed);
break;
}
-
case GUN_RIFLE:
particle_splash(PART_SPARK, 200, 250, to, 0xB49B4B, 0.24f);
if(d->quadmillis)
if(muzzlelight) adddynlight(hudgunorigin(gun, d->o, to, d), 25, vec(0.5f, 0.375f, 0.25f), 75, 75, DL_FLASH, 0, vec(0, 0, 0), d);
break;
}
-
bool looped = false;
if(d->attacksound >= 0 && d->attacksound != sound) d->stopattacksound();
if(d->idlesound >= 0) d->stopidlesound();
fpsent *h = followingplayer(player1);
- switch(sound)
- {
+ switch(sound) {
case S_CHAINSAW_ATTACK:
if(d->attacksound >= 0) looped = true;
d->attacksound = sound;
}
if(d->quadmillis && lastmillis-prevaction>200 && !looped) playsound(S_ITEMPUP, d==h ? NULL : &d->o);
}
-
- void particletrack(physent *owner, vec &o, vec &d)
- {
+ void particletrack(physent *owner, vec &o, vec &d) {
if(owner->type!=ENT_PLAYER && owner->type!=ENT_AI) return;
fpsent *pl = (fpsent *)owner;
if(pl->muzzle.x < 0 || pl->lastattackgun != pl->gunselect) return;
float dist = o.dist(d);
o = pl->muzzle;
if(dist <= 0) d = o;
- else
- {
+ else {
vecfromyawpitch(owner->yaw, owner->pitch, 1, 0, d);
float newdist = raycube(owner->o, d, dist, RAY_CLIPMAT|RAY_ALPHAPOLY);
d.mul(min(newdist, dist)).add(owner->o);
}
}
-
- void dynlighttrack(physent *owner, vec &o, vec &hud)
- {
+ void dynlighttrack(physent *owner, vec &o, vec &hud) {
if(owner->type!=ENT_PLAYER && owner->type!=ENT_AI) return;
fpsent *pl = (fpsent *)owner;
if(pl->muzzle.x < 0 || pl->lastattackgun != pl->gunselect) return;
o = pl->muzzle;
hud = owner == followingplayer(player1) ? vec(pl->o).add(vec(0, 0, 2)) : pl->muzzle;
}
-
float intersectdist = 1e16f;
-
- bool intersect(dynent *d, const vec &from, const vec &to, float &dist) // if lineseg hits entity bounding box
- {
+ bool intersect(dynent *d, const vec &from, const vec &to, float &dist) { // if lineseg hits entity bounding box {
vec bottom(d->o), top(d->o);
bottom.z -= d->eyeheight;
top.z += d->aboveeye;
return linecylinderintersect(from, to, bottom, top, d->radius, dist);
}
-
- dynent *intersectclosest(const vec &from, const vec &to, fpsent *at, float &bestdist)
- {
+ dynent *intersectclosest(const vec &from, const vec &to, fpsent *at, float &bestdist) {
dynent *best = NULL;
bestdist = 1e16f;
- loopi(numdynents())
- {
+ loopi(numdynents()) {
dynent *o = iterdynents(i);
if(o==at || o->state!=CS_ALIVE) continue;
float dist;
if(!intersect(o, from, to, dist)) continue;
- if(dist<bestdist)
- {
+ if(dist<bestdist) {
best = o;
bestdist = dist;
}
}
return best;
}
-
- void shorten(vec &from, vec &target, float dist)
- {
+ void shorten(vec &from, vec &target, float dist) {
target.sub(from).mul(min(1.0f, dist)).add(from);
}
-
- void raydamage(vec &from, vec &to, fpsent *d)
- {
+ void raydamage(vec &from, vec &to, fpsent *d) {
int qdam = guns[d->gunselect].damage;
if(d->quadmillis) qdam *= 4;
dynent *o;
float dist;
- if(guns[d->gunselect].rays > 1)
- {
+ if(guns[d->gunselect].rays > 1) {
dynent *hits[MAXRAYS];
int maxrays = guns[d->gunselect].rays;
- loopi(maxrays)
- {
+ loopi(maxrays) {
if((hits[i] = intersectclosest(from, rays[i], d, dist))) shorten(from, rays[i], dist);
else adddecal(DECAL_BULLET, rays[i], vec(from).sub(rays[i]).safenormalize(), 2.0f);
}
- loopi(maxrays) if(hits[i])
- {
+ loopi(maxrays) if(hits[i]) {
o = hits[i];
hits[i] = NULL;
int numhits = 1;
- for(int j = i+1; j < maxrays; j++) if(hits[j] == o)
- {
+ for(int j = i+1; j < maxrays; j++) if(hits[j] == o) {
hits[j] = NULL;
numhits++;
}
hitpush(numhits*qdam, o, d, from, to, d->gunselect, numhits);
}
}
- else if((o = intersectclosest(from, to, d, dist)))
- {
+ else if((o = intersectclosest(from, to, d, dist))) {
shorten(from, to, dist);
hitpush(qdam, o, d, from, to, d->gunselect, 1);
}
else if(d->gunselect!=GUN_FIST) adddecal(DECAL_BULLET, to, vec(from).sub(to).safenormalize(), d->gunselect==GUN_RIFLE ? 3.0f : 2.0f);
}
-
- void shoot(fpsent *d, const vec &targ)
- {
+ void shoot(fpsent *d, const vec &targ) {
int prevaction = d->lastaction, attacktime = lastmillis-prevaction;
if(attacktime<d->gunwait) return;
d->gunwait = 0;
if((d==player1 || d->ai) && !d->attacking) return;
d->lastaction = lastmillis;
d->lastattackgun = d->gunselect;
- if(!d->ammo[d->gunselect])
- {
- if(d==player1)
- {
+ if(!d->ammo[d->gunselect]) {
+ if(d==player1) {
msgsound(S_NOAMMO, d);
d->gunwait = 600;
d->lastattackgun = -1;
return;
}
if(d->gunselect) d->ammo[d->gunselect]--;
-
pwshot(d->gunselect); /// PW
-
vec from = d->o, to = targ, dir = vec(to).sub(from).safenormalize();
float dist = to.dist(from);
vec kickback = vec(dir).mul(guns[d->gunselect].kickamount*-2.5f);
if(barrier > 0 && barrier < dist && (!shorten || barrier < shorten))
shorten = barrier;
if(shorten) to = vec(dir).mul(shorten).add(from);
-
if(guns[d->gunselect].rays > 1) createrays(d->gunselect, from, to);
else if(guns[d->gunselect].spread) offsetray(from, to, guns[d->gunselect].spread, guns[d->gunselect].range, to);
-
hits.setsize(0);
-
if(!guns[d->gunselect].projspeed) raydamage(from, to, d);
-
shoteffects(d->gunselect, from, to, d, true, 0, prevaction);
-
- if(d==player1 || d->ai)
- {
+ if(d==player1 || d->ai) {
addmsg(N_SHOOT, "rci2i6iv", d, lastmillis-maptime, d->gunselect,
(int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF),
(int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF),
hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf());
}
-
d->gunwait = guns[d->gunselect].attackdelay;
if(d->gunselect == GUN_PISTOL && d->ai) d->gunwait += int(d->gunwait*(((101-d->skill)+rnd(111-d->skill))/100.f));
d->totalshots += guns[d->gunselect].damage*(d->quadmillis ? 4 : 1)*guns[d->gunselect].rays;
}
-
- void adddynlights()
- {
- loopv(projs)
- {
+ void adddynlights() {
+ loopv(projs) {
projectile &p = projs[i];
if(p.gun!=GUN_RL) continue;
vec pos(p.o);
pos.add(vec(p.offset).mul(p.offsetmillis/float(OFFSETMILLIS)));
adddynlight(pos, 20, vec(1, 0.75f, 0.5f));
}
- loopv(bouncers)
- {
+ loopv(bouncers) {
bouncer &bnc = *bouncers[i];
if(bnc.bouncetype!=BNC_GRENADE) continue;
vec pos = bnc.offsetpos();
adddynlight(pos, 8, vec(0.25f, 1, 1));
}
}
-
static const char * const projnames[2] = { "projectiles/grenade", "projectiles/rocket" };
-
void preloadbouncers() {
loopi(sizeof(projnames)/sizeof(projnames[0])) preloadmodel(projnames[i]);
}
-
- void renderbouncers()
- {
+ void renderbouncers() {
float yaw, pitch;
- loopv(bouncers)
- {
+ loopv(bouncers) {
bouncer &bnc = *bouncers[i];
vec pos = bnc.offsetpos();
vec vel(bnc.vel);
if(vel.magnitude() <= 25.0f) yaw = bnc.lastyaw;
- else
- {
+ else {
vectoyawpitch(vel, yaw, pitch);
yaw += 90;
bnc.lastyaw = yaw;
pitch = -bnc.roll;
if(bnc.bouncetype==BNC_GRENADE)
rendermodel(&bnc.light, "projectiles/grenade", ANIM_MAPMODEL|ANIM_LOOP, pos, yaw, pitch, MDL_CULL_VFC|MDL_CULL_OCCLUDED|MDL_LIGHT|MDL_LIGHT_FAST|MDL_DYNSHADOW);
- else
- {
+ else {
const char *mdl = NULL;
int cull = MDL_CULL_VFC|MDL_CULL_DIST|MDL_CULL_OCCLUDED;
float fade = 1;
}
}
}
-
- void renderprojectiles()
- {
+ void renderprojectiles() {
float yaw, pitch;
- loopv(projs)
- {
+ loopv(projs) {
projectile &p = projs[i];
if(p.gun!=GUN_RL) continue;
float dist = min(p.o.dist(p.to)/32.0f, 1.0f);
rendermodel(&p.light, "projectiles/rocket", ANIM_MAPMODEL|ANIM_LOOP, v, yaw, pitch, MDL_CULL_VFC|MDL_CULL_OCCLUDED|MDL_LIGHT|MDL_LIGHT_FAST);
}
}
-
- void checkattacksound(fpsent *d, bool local)
- {
+ void checkattacksound(fpsent *d, bool local) {
int gun = -1;
- switch(d->attacksound)
- {
+ switch(d->attacksound) {
case S_CHAINSAW_ATTACK:
if(chainsawhudgun) gun = GUN_FIST;
break;
}
if(gun >= 0 && gun < NUMGUNS &&
d->clientnum >= 0 && d->state == CS_ALIVE &&
- d->lastattackgun == gun && lastmillis - d->lastaction < guns[gun].attackdelay + 50)
- {
+ d->lastattackgun == gun && lastmillis - d->lastaction < guns[gun].attackdelay + 50) {
d->attackchan = playsound(d->attacksound, local ? NULL : &d->o, NULL, 0, -1, -1, d->attackchan);
if(d->attackchan < 0) d->attacksound = -1;
}
else d->stopattacksound();
}
-
- void checkidlesound(fpsent *d, bool local)
- {
+ void checkidlesound(fpsent *d, bool local) {
int sound = -1, radius = 0;
- if(d->clientnum >= 0 && d->state == CS_ALIVE) switch(d->gunselect)
- {
+ if(d->clientnum >= 0 && d->state == CS_ALIVE) switch(d->gunselect) {
case GUN_FIST:
- if(chainsawhudgun && d->attacksound < 0)
- {
+ if(chainsawhudgun && d->attacksound < 0) {
sound = S_CHAINSAW_IDLE;
radius = 50;
}
break;
}
- if(d->idlesound != sound)
- {
+ if(d->idlesound != sound) {
if(d->idlesound >= 0) d->stopidlesound();
- if(sound >= 0)
- {
+ if(sound >= 0) {
d->idlechan = playsound(sound, local ? NULL : &d->o, NULL, 0, -1, 100, d->idlechan, radius);
if(d->idlechan >= 0) d->idlesound = sound;
}
}
- else if(sound >= 0)
- {
+ else if(sound >= 0) {
d->idlechan = playsound(sound, local ? NULL : &d->o, NULL, 0, -1, -1, d->idlechan, radius);
if(d->idlechan < 0) d->idlesound = -1;
}
}
-
- void removeweapons(fpsent *d)
- {
+ void removeweapons(fpsent *d) {
removebouncers(d);
removeprojectiles(d);
}
-
- void updateweapons(int curtime)
- {
+ void updateweapons(int curtime) {
updateprojectiles(curtime);
pwcalcaccuracy();
if(player1->clientnum>=0 && player1->state==CS_ALIVE) shoot(player1, worldpos); // only shoot when connected to server
updatebouncers(curtime); // need to do this after the player shoots so grenades don't end up inside player's BB next frame
fpsent *following = followingplayer();
if(!following) following = player1;
- loopv(players)
- {
+ loopv(players) {
fpsent *d = players[i];
checkattacksound(d, d==following);
checkidlesound(d, d==following);
}
}
-
- void avoidweapons(ai::avoidset &obstacles, float radius)
- {
- loopv(projs)
- {
+ void avoidweapons(ai::avoidset &obstacles, float radius) {
+ loopv(projs) {
projectile &p = projs[i];
obstacles.avoidnear(NULL, p.o.z + guns[p.gun].exprad + 1, p.o, radius + guns[p.gun].exprad);
}
- loopv(bouncers)
- {
+ loopv(bouncers) {
bouncer &bnc = *bouncers[i];
if(bnc.bouncetype != BNC_GRENADE) continue;
obstacles.avoidnear(NULL, bnc.o.z + guns[GUN_GL].exprad + 1, bnc.o, radius + guns[GUN_GL].exprad);
enum { VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR, VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT };
-enum
-{
+enum {
CODE_START = 0,
CODE_OFFSET,
CODE_POP,
CODE_LOOKUP, CODE_LOOKUPU, CODE_LOOKUPARG, CODE_ALIAS, CODE_ALIASU, CODE_ALIASARG, CODE_CALL, CODE_CALLU, CODE_CALLARG,
CODE_PRINT,
CODE_LOCAL,
-
CODE_OP_MASK = 0x3F,
CODE_RET = 6,
CODE_RET_MASK = 0xC0,
-
/* return type flags */
RET_NULL = VAL_NULL<<CODE_RET,
RET_STR = VAL_STR<<CODE_RET,
struct ident;
-struct identval
-{
- union
- {
+struct identval {
+ union {
int i; // ID_VAR, VAL_INT
float f; // ID_FVAR, VAL_FLOAT
char *s; // ID_SVAR, VAL_STR
};
};
-struct tagval : identval
-{
+struct tagval : identval {
int type;
-
void setint(int val) { type = VAL_INT; i = val; }
void setfloat(float val) { type = VAL_FLOAT; f = val; }
void setstr(char *val) { type = VAL_STR; s = val; }
void setcode(const uint *val) { type = VAL_CODE; code = val; }
void setmacro(const uint *val) { type = VAL_MACRO; code = val; }
void setident(ident *val) { type = VAL_IDENT; id = val; }
-
const char *getstr() const;
int getint() const;
float getfloat() const;
bool getbool() const;
-
void cleanup();
};
-struct identstack
-{
+struct identstack {
identval val;
int valtype;
identstack *next;
};
-union identvalptr
-{
+union identvalptr {
int *i; // ID_VAR
float *f; // ID_FVAR
char **s; // ID_SVAR
typedef void (__cdecl *identfun)();
-struct ident
-{
+struct ident {
uchar type; // one of ID_* above
- union
- {
+ union {
uchar valtype; // ID_ALIAS
uchar numargs; // ID_COMMAND
};
ushort flags;
int index;
const char *name;
- union
- {
- struct // ID_VAR, ID_FVAR, ID_SVAR
- {
- union
- {
+ union {
+ struct { // ID_VAR, ID_FVAR, ID_SVAR {
+ union {
struct { int minval, maxval; }; // ID_VAR
struct { float minvalf, maxvalf; }; // ID_FVAR
};
identvalptr storage;
identval overrideval;
};
- struct // ID_ALIAS
- {
+ struct { // ID_ALIAS {
uint *code;
identval val;
identstack *stack;
};
- struct // ID_COMMAND
- {
+ struct { // ID_COMMAND {
const char *args;
uint argmask;
};
};
identfun fun; // ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND
-
ident() {}
// ID_VAR
ident(int t, const char *n, int m, int x, int *s, void *f = NULL, int flags = 0)
- : type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minval(m), maxval(x), fun((identfun)f)
- { storage.i = s; }
+ : type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minval(m), maxval(x), fun((identfun)f) {
+ storage.i = s; }
// ID_FVAR
ident(int t, const char *n, float m, float x, float *s, void *f = NULL, int flags = 0)
- : type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minvalf(m), maxvalf(x), fun((identfun)f)
- { storage.f = s; }
+ : type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minvalf(m), maxvalf(x), fun((identfun)f) {
+ storage.f = s; }
// ID_SVAR
ident(int t, const char *n, char **s, void *f = NULL, int flags = 0)
- : type(t), flags(flags), name(n), fun((identfun)f)
- { storage.s = s; }
+ : type(t), flags(flags), name(n), fun((identfun)f) {
+ storage.s = s; }
// ID_ALIAS
ident(int t, const char *n, char *a, int flags)
- : type(t), valtype(VAL_STR), flags(flags), name(n), code(NULL), stack(NULL)
- { val.s = a; }
+ : type(t), valtype(VAL_STR), flags(flags), name(n), code(NULL), stack(NULL) {
+ val.s = a; }
ident(int t, const char *n, int a, int flags)
- : type(t), valtype(VAL_INT), flags(flags), name(n), code(NULL), stack(NULL)
- { val.i = a; }
+ : type(t), valtype(VAL_INT), flags(flags), name(n), code(NULL), stack(NULL) {
+ val.i = a; }
ident(int t, const char *n, float a, int flags)
- : type(t), valtype(VAL_FLOAT), flags(flags), name(n), code(NULL), stack(NULL)
- { val.f = a; }
+ : type(t), valtype(VAL_FLOAT), flags(flags), name(n), code(NULL), stack(NULL) {
+ val.f = a; }
ident(int t, const char *n, int flags)
- : type(t), valtype(VAL_NULL), flags(flags), name(n), code(NULL), stack(NULL)
- {}
+ : type(t), valtype(VAL_NULL), flags(flags), name(n), code(NULL), stack(NULL) {
+ }
ident(int t, const char *n, const tagval &v, int flags)
- : type(t), valtype(v.type), flags(flags), name(n), code(NULL), stack(NULL)
- { val = v; }
+ : type(t), valtype(v.type), flags(flags), name(n), code(NULL), stack(NULL) {
+ val = v; }
// ID_COMMAND
ident(int t, const char *n, const char *args, uint argmask, int numargs, void *f = NULL, int flags = 0)
- : type(t), numargs(numargs), flags(flags), name(n), args(args), argmask(argmask), fun((identfun)f)
- {}
-
+ : type(t), numargs(numargs), flags(flags), name(n), args(args), argmask(argmask), fun((identfun)f) {
+ }
void changed() { if(fun) fun(); }
-
- void setval(const tagval &v)
- {
+ void setval(const tagval &v) {
valtype = v.type;
val = v;
}
-
- void setval(const identstack &v)
- {
+ void setval(const identstack &v) {
valtype = v.valtype;
val = v.val;
}
-
- void forcenull()
- {
+ void forcenull() {
if(valtype==VAL_STR) delete[] val.s;
valtype = VAL_NULL;
}
-
float getfloat() const;
int getint() const;
const char *getstr() const;
extern void result(tagval &v);
extern void result(const char *s);
-static inline int parseint(const char *s)
-{
+static inline int parseint(const char *s) {
return int(strtoul(s, NULL, 0));
}
-static inline float parsefloat(const char *s)
-{
+static inline float parsefloat(const char *s) {
// not all platforms (windows) can parse hexadecimal integers via strtod
char *end;
double val = strtod(s, &end);
static inline void intformat(char *buf, int v, int len = 20) { nformatstring(buf, len, "%d", v); }
static inline void floatformat(char *buf, float v, int len = 20) { nformatstring(buf, len, v==int(v) ? "%.1f" : "%.6g", v); }
-static inline const char *getstr(const identval &v, int type)
-{
- switch(type)
- {
+static inline const char *getstr(const identval &v, int type) {
+ switch(type) {
case VAL_STR: case VAL_MACRO: return v.s;
case VAL_INT: return intstr(v.i);
case VAL_FLOAT: return floatstr(v.f);
inline const char *tagval::getstr() const { return ::getstr(*this, type); }
inline const char *ident::getstr() const { return ::getstr(val, valtype); }
-static inline int getint(const identval &v, int type)
-{
- switch(type)
- {
+static inline int getint(const identval &v, int type) {
+ switch(type) {
case VAL_INT: return v.i;
case VAL_FLOAT: return int(v.f);
case VAL_STR: case VAL_MACRO: return parseint(v.s);
inline int tagval::getint() const { return ::getint(*this, type); }
inline int ident::getint() const { return ::getint(val, valtype); }
-static inline float getfloat(const identval &v, int type)
-{
- switch(type)
- {
+static inline float getfloat(const identval &v, int type) {
+ switch(type) {
case VAL_FLOAT: return v.f;
case VAL_INT: return float(v.i);
case VAL_STR: case VAL_MACRO: return parsefloat(v.s);
inline float tagval::getfloat() const { return ::getfloat(*this, type); }
inline float ident::getfloat() const { return ::getfloat(val, valtype); }
-inline void ident::getval(tagval &v) const
-{
- switch(valtype)
- {
+inline void ident::getval(tagval &v) const {
+ switch(valtype) {
case VAL_STR: case VAL_MACRO: v.setstr(newstring(val.s)); break;
case VAL_INT: v.setint(val.i); break;
case VAL_FLOAT: v.setfloat(val.f); break;
#define SVARFR(name, cur, body) _SVARF(name, name, cur, body, IDF_OVERRIDE)
// anonymous inline commands, uses nasty template trick with line numbers to keep names unique
-#define ICOMMANDNS(name, cmdname, nargs, proto, b) template<int N> struct cmdname; template<> struct cmdname<__LINE__> { static bool init; static void run proto; }; bool cmdname<__LINE__>::init = addcommand(name, (identfun)cmdname<__LINE__>::run, nargs); void cmdname<__LINE__>::run proto \
- { b; }
+#define ICOMMANDNS(name, cmdname, nargs, proto, b) template<int N> struct cmdname; template<> struct cmdname<__LINE__> { static bool init; static void run proto; }; bool cmdname<__LINE__>::init = addcommand(name, (identfun)cmdname<__LINE__>::run, nargs); void cmdname<__LINE__>::run proto { b; }
#define ICOMMANDN(name, cmdname, nargs, proto, b) ICOMMANDNS(#name, cmdname, nargs, proto, b)
#define ICOMMANDNAME(name) _icmd_##name
#define ICOMMAND(name, nargs, proto, b) ICOMMANDN(name, ICOMMANDNAME(name), nargs, proto, b)
#define TIGER_PASSES 3
-namespace tiger
-{
+namespace tiger {
typedef unsigned long long int chunk;
-
- union hashval
- {
+ union hashval {
uchar bytes[3*8];
chunk chunks[3];
};
-
chunk sboxes[4*256];
-
- void compress(const chunk *str, chunk state[3])
- {
+ void compress(const chunk *str, chunk state[3]) {
chunk a, b, c;
chunk aa, bb, cc;
chunk x0, x1, x2, x3, x4, x5, x6, x7;
-
a = state[0];
b = state[1];
c = state[2];
-
x0=str[0]; x1=str[1]; x2=str[2]; x3=str[3];
x4=str[4]; x5=str[5]; x6=str[6]; x7=str[7];
-
aa = a;
bb = b;
cc = c;
-
- loop(pass_no, TIGER_PASSES)
- {
- if(pass_no)
- {
+ loop(pass_no, TIGER_PASSES) {
+ if(pass_no) {
x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5ULL; x1 ^= x0; x2 += x1; x3 -= x2 ^ ((~x1)<<19);
x4 ^= x3; x5 += x4; x6 -= x5 ^ ((~x4)>>23); x7 ^= x6;
x0 += x7; x1 -= x0 ^ ((~x7)<<19); x2 ^= x1; x3 += x2;
b += sb4[((c)>>(1*8))&0xFF] ^ sb3[((c)>>(3*8))&0xFF] ^ \
sb2[((c)>>(5*8))&0xFF] ^ sb1[((c)>>(7*8))&0xFF] ; \
b *= mul;
-
uint mul = !pass_no ? 5 : (pass_no==1 ? 7 : 9);
round(a, b, c, x0) round(b, c, a, x1) round(c, a, b, x2) round(a, b, c, x3)
round(b, c, a, x4) round(c, a, b, x5) round(a, b, c, x6) round(b, c, a, x7)
-
chunk tmp = a; a = c; c = b; b = tmp;
}
-
a ^= aa;
b -= bb;
c += cc;
-
state[0] = a;
state[1] = b;
state[2] = c;
}
-
- void gensboxes()
- {
+ void gensboxes() {
const char *str = "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham";
chunk state[3] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL, 0xF096A5B4C3B2E187ULL };
uchar temp[64];
-
if(!*(const uchar *)&islittleendian) loopj(64) temp[j^7] = str[j];
else loopj(64) temp[j] = str[j];
loopi(1024) loop(col, 8) ((uchar *)&sboxes[i])[col] = i&0xFF;
-
int abc = 2;
- loop(pass, 5) loopi(256) for(int sb = 0; sb < 1024; sb += 256)
- {
+ loop(pass, 5) loopi(256) for(int sb = 0; sb < 1024; sb += 256) {
abc++;
if(abc >= 3) { abc = 0; compress((chunk *)temp, state); }
- loop(col, 8)
- {
+ loop(col, 8) {
uchar val = ((uchar *)&sboxes[sb+i])[col];
((uchar *)&sboxes[sb+i])[col] = ((uchar *)&sboxes[sb + ((uchar *)&state[abc])[col]])[col];
((uchar *)&sboxes[sb + ((uchar *)&state[abc])[col]])[col] = val;
}
}
}
-
- void hash(const uchar *str, int length, hashval &val)
- {
+ void hash(const uchar *str, int length, hashval &val) {
static bool init = false;
if(!init) { gensboxes(); init = true; }
-
uchar temp[65];
-
val.chunks[0] = 0x0123456789ABCDEFULL;
val.chunks[1] = 0xFEDCBA9876543210ULL;
val.chunks[2] = 0xF096A5B4C3B2E187ULL;
-
int i = length;
- for(; i >= 64; i -= 64, str += 64)
- {
- if(!*(const uchar *)&islittleendian)
- {
+ for(; i >= 64; i -= 64, str += 64) {
+ if(!*(const uchar *)&islittleendian) {
loopj(64) temp[j^7] = str[j];
compress((chunk *)temp, val.chunks);
}
else compress((chunk *)str, val.chunks);
}
-
int j;
- if(!*(const uchar *)&islittleendian)
- {
+ if(!*(const uchar *)&islittleendian) {
for(j = 0; j < i; j++) temp[j^7] = str[j];
temp[j^7] = 0x01;
while(++j&7) temp[j^7] = 0;
}
- else
- {
+ else {
for(j = 0; j < i; j++) temp[j] = str[j];
temp[j] = 0x01;
while(++j&7) temp[j] = 0;
}
-
- if(j > 56)
- {
+ if(j > 56) {
while(j < 64) temp[j++] = 0;
compress((chunk *)temp, val.chunks);
j = 0;
while(j < 56) temp[j++] = 0;
*(chunk *)(temp+56) = (chunk)length<<3;
compress((chunk *)temp, val.chunks);
- if(!*(const uchar *)&islittleendian)
- {
- loopk(3)
- {
+ if(!*(const uchar *)&islittleendian) {
+ loopk(3) {
uchar *c = &val.bytes[k*sizeof(chunk)];
loopl(sizeof(chunk)/2) swap(c[l], c[sizeof(chunk)-1-l]);
}
#define BI_DIGIT_BITS 16
#define BI_DIGIT_MASK ((1<<BI_DIGIT_BITS)-1)
-template<int BI_DIGITS> struct bigint
-{
+template<int BI_DIGITS> struct bigint {
typedef ushort digit;
typedef uint dbldigit;
-
int len;
digit digits[BI_DIGITS];
-
bigint() {}
bigint(digit n) { if(n) { len = 1; digits[0] = n; } else len = 0; }
bigint(const char *s) { parse(s); }
template<int Y_DIGITS> bigint(const bigint<Y_DIGITS> &y) { *this = y; }
-
- static int parsedigits(ushort *digits, int maxlen, const char *s)
- {
+ static int parsedigits(ushort *digits, int maxlen, const char *s) {
int slen = 0;
while(isxdigit(s[slen])) slen++;
int len = (slen+2*sizeof(ushort)-1)/(2*sizeof(ushort));
if(len>maxlen) return 0;
memset(digits, 0, len*sizeof(ushort));
- loopi(slen)
- {
+ loopi(slen) {
int c = s[slen-i-1];
if(isalpha(c)) c = toupper(c) - 'A' + 10;
else if(isdigit(c)) c -= '0';
}
return len;
}
-
- void parse(const char *s)
- {
+ void parse(const char *s) {
len = parsedigits(digits, BI_DIGITS, s);
shrink();
}
-
void zero() { len = 0; }
-
- void print(stream *out) const
- {
+ void print(stream *out) const {
vector<char> buf;
printdigits(buf);
out->write(buf.getbuf(), buf.length());
}
-
- void printdigits(vector<char> &buf) const
- {
- loopi(len)
- {
+ void printdigits(vector<char> &buf) const {
+ loopi(len) {
digit d = digits[len-i-1];
- loopj(BI_DIGIT_BITS/4)
- {
+ loopj(BI_DIGIT_BITS/4) {
uint shift = BI_DIGIT_BITS - (j+1)*4;
int val = (d >> shift) & 0xF;
if(val < 10) buf.add('0' + val);
}
}
}
-
- template<int Y_DIGITS> bigint &operator=(const bigint<Y_DIGITS> &y)
- {
+ template<int Y_DIGITS> bigint &operator=(const bigint<Y_DIGITS> &y) {
len = y.len;
memcpy(digits, y.digits, len*sizeof(digit));
return *this;
}
-
bool iszero() const { return !len; }
bool isone() const { return len==1 && digits[0]==1; }
-
- int numbits() const
- {
+ int numbits() const {
if(!len) return 0;
int bits = len*BI_DIGIT_BITS;
digit last = digits[len-1], mask = 1<<(BI_DIGIT_BITS-1);
- while(mask)
- {
+ while(mask) {
if(last&mask) return bits;
bits--;
mask >>= 1;
}
return 0;
}
-
bool hasbit(int n) const { return n/BI_DIGIT_BITS < len && ((digits[n/BI_DIGIT_BITS]>>(n%BI_DIGIT_BITS))&1); }
-
bool morebits(int n) const { return len > n/BI_DIGIT_BITS; }
-
- template<int X_DIGITS, int Y_DIGITS> bigint &add(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
+ template<int X_DIGITS, int Y_DIGITS> bigint &add(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
dbldigit carry = 0;
int maxlen = max(x.len, y.len), i;
- for(i = 0; i < y.len || carry; i++)
- {
+ for(i = 0; i < y.len || carry; i++) {
carry += (i < x.len ? (dbldigit)x.digits[i] : 0) + (i < y.len ? (dbldigit)y.digits[i] : 0);
digits[i] = (digit)carry;
carry >>= BI_DIGIT_BITS;
return *this;
}
template<int Y_DIGITS> bigint &add(const bigint<Y_DIGITS> &y) { return add(*this, y); }
-
- template<int X_DIGITS, int Y_DIGITS> bigint &sub(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
+ template<int X_DIGITS, int Y_DIGITS> bigint &sub(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
ASSERT(x >= y);
dbldigit borrow = 0;
int i;
- for(i = 0; i < y.len || borrow; i++)
- {
+ for(i = 0; i < y.len || borrow; i++) {
borrow = (1<<BI_DIGIT_BITS) + (dbldigit)x.digits[i] - (i<y.len ? (dbldigit)y.digits[i] : 0) - borrow;
digits[i] = (digit)borrow;
borrow = (borrow>>BI_DIGIT_BITS)^1;
return *this;
}
template<int Y_DIGITS> bigint &sub(const bigint<Y_DIGITS> &y) { return sub(*this, y); }
-
void shrink() { while(len > 0 && !digits[len-1]) len--; }
void shrinkdigits(int n) { len = n; shrink(); }
void shrinkbits(int n) { shrinkdigits(n/BI_DIGIT_BITS); }
-
- template<int Y_DIGITS> void copyshrinkdigits(const bigint<Y_DIGITS> &y, int n)
- {
+ template<int Y_DIGITS> void copyshrinkdigits(const bigint<Y_DIGITS> &y, int n) {
len = clamp(y.len, 0, n);
memcpy(digits, y.digits, len*sizeof(digit));
shrink();
}
- template<int Y_DIGITS> void copyshrinkbits(const bigint<Y_DIGITS> &y, int n)
- {
+ template<int Y_DIGITS> void copyshrinkbits(const bigint<Y_DIGITS> &y, int n) {
copyshrinkdigits(y, n/BI_DIGIT_BITS);
}
-
- template<int X_DIGITS, int Y_DIGITS> bigint &mul(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
+ template<int X_DIGITS, int Y_DIGITS> bigint &mul(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
if(!x.len || !y.len) { len = 0; return *this; }
memset(digits, 0, y.len*sizeof(digit));
- loopi(x.len)
- {
+ loopi(x.len) {
dbldigit carry = 0;
- loopj(y.len)
- {
+ loopj(y.len) {
carry += (dbldigit)x.digits[i] * (dbldigit)y.digits[j] + (dbldigit)digits[i+j];
digits[i+j] = (digit)carry;
carry >>= BI_DIGIT_BITS;
shrink();
return *this;
}
-
- bigint &rshift(int n)
- {
+ bigint &rshift(int n) {
assert(len <= BI_DIGITS);
if(!len || n<=0) return *this;
if(n >= len*BI_DIGIT_BITS) { len = 0; return *this; }
int dig = (n-1)/BI_DIGIT_BITS;
n = ((n-1) % BI_DIGIT_BITS)+1;
digit carry = digit(digits[dig]>>n);
- for(int i = dig+1; i < len; i++)
- {
+ for(int i = dig+1; i < len; i++) {
digit tmp = digits[i];
digits[i-dig-1] = digit((tmp<<(BI_DIGIT_BITS-n)) | carry);
carry = digit(tmp>>n);
shrink();
return *this;
}
-
- bigint &lshift(int n)
- {
+ bigint &lshift(int n) {
if(!len || n<=0) return *this;
int dig = n/BI_DIGIT_BITS;
n %= BI_DIGIT_BITS;
digit carry = 0;
- loopirev(len)
- {
+ loopirev(len) {
digit tmp = digits[i];
digits[i+dig] = digit((tmp<<n) | carry);
carry = digit(tmp>>(BI_DIGIT_BITS-n));
if(dig) memset(digits, 0, dig*sizeof(digit));
return *this;
}
-
- void zerodigits(int i, int n)
- {
+ void zerodigits(int i, int n) {
memset(&digits[i], 0, n*sizeof(digit));
}
- void zerobits(int i, int n)
- {
+ void zerobits(int i, int n) {
zerodigits(i/BI_DIGIT_BITS, n/BI_DIGIT_BITS);
}
-
- template<int Y_DIGITS> void copydigits(int to, const bigint<Y_DIGITS> &y, int from, int n)
- {
+ template<int Y_DIGITS> void copydigits(int to, const bigint<Y_DIGITS> &y, int from, int n) {
int avail = clamp(y.len-from, 0, n);
memcpy(&digits[to], &y.digits[from], avail*sizeof(digit));
if(avail < n) memset(&digits[to+avail], 0, (n-avail)*sizeof(digit));
}
- template<int Y_DIGITS> void copybits(int to, const bigint<Y_DIGITS> &y, int from, int n)
- {
+ template<int Y_DIGITS> void copybits(int to, const bigint<Y_DIGITS> &y, int from, int n) {
copydigits(to/BI_DIGIT_BITS, y, from/BI_DIGIT_BITS, n/BI_DIGIT_BITS);
}
-
- void dupdigits(int to, int from, int n)
- {
+ void dupdigits(int to, int from, int n) {
memcpy(&digits[to], &digits[from], n*sizeof(digit));
}
- void dupbits(int to, int from, int n)
- {
+ void dupbits(int to, int from, int n) {
dupdigits(to/BI_DIGIT_BITS, from/BI_DIGIT_BITS, n/BI_DIGIT_BITS);
}
-
- template<int Y_DIGITS> bool operator==(const bigint<Y_DIGITS> &y) const
- {
+ template<int Y_DIGITS> bool operator==(const bigint<Y_DIGITS> &y) const {
if(len!=y.len) return false;
loopirev(len) if(digits[i]!=y.digits[i]) return false;
return true;
}
template<int Y_DIGITS> bool operator!=(const bigint<Y_DIGITS> &y) const { return !(*this==y); }
- template<int Y_DIGITS> bool operator<(const bigint<Y_DIGITS> &y) const
- {
+ template<int Y_DIGITS> bool operator<(const bigint<Y_DIGITS> &y) const {
if(len<y.len) return true;
if(len>y.len) return false;
- loopirev(len)
- {
+ loopirev(len) {
if(digits[i]<y.digits[i]) return true;
if(digits[i]>y.digits[i]) return false;
}
/* NIST prime Galois fields.
* Currently only supports NIST P-192, where P=2^192-2^64-1, and P-256, where P=2^256-2^224+2^192+2^96-1.
*/
-struct gfield : gfint
-{
+struct gfield : gfint {
static const gfield P;
-
gfield() {}
gfield(digit n) : gfint(n) {}
gfield(const char *s) : gfint(s) {}
-
template<int Y_DIGITS> gfield(const bigint<Y_DIGITS> &y) : gfint(y) {}
-
- template<int Y_DIGITS> gfield &operator=(const bigint<Y_DIGITS> &y)
- {
+ template<int Y_DIGITS> gfield &operator=(const bigint<Y_DIGITS> &y) {
gfint::operator=(y);
return *this;
}
-
- template<int X_DIGITS, int Y_DIGITS> gfield &add(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
+ template<int X_DIGITS, int Y_DIGITS> gfield &add(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
gfint::add(x, y);
if(*this >= P) gfint::sub(*this, P);
return *this;
}
template<int Y_DIGITS> gfield &add(const bigint<Y_DIGITS> &y) { return add(*this, y); }
-
template<int X_DIGITS> gfield &mul2(const bigint<X_DIGITS> &x) { return add(x, x); }
gfield &mul2() { return mul2(*this); }
-
- gfield &div2()
- {
+ gfield &div2() {
if(hasbit(0)) gfint::add(*this, P);
rshift(1);
return *this;
}
-
- template<int X_DIGITS, int Y_DIGITS> gfield &sub(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
- if(x < y)
- {
+ template<int X_DIGITS, int Y_DIGITS> gfield &sub(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
+ if(x < y) {
gfint tmp; /* necessary if this==&y, using this instead would clobber y */
tmp.add(x, P);
gfint::sub(tmp, y);
return *this;
}
template<int Y_DIGITS> gfield &sub(const bigint<Y_DIGITS> &y) { return sub(*this, y); }
-
- template<int X_DIGITS> gfield &neg(const bigint<X_DIGITS> &x)
- {
+ template<int X_DIGITS> gfield &neg(const bigint<X_DIGITS> &x) {
gfint::sub(P, x);
return *this;
}
gfield &neg() { return neg(*this); }
-
template<int X_DIGITS> gfield &square(const bigint<X_DIGITS> &x) { return mul(x, x); }
gfield &square() { return square(*this); }
-
- template<int X_DIGITS, int Y_DIGITS> gfield &mul(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
+ template<int X_DIGITS, int Y_DIGITS> gfield &mul(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
bigint<X_DIGITS+Y_DIGITS> result;
result.mul(x, y);
reduce(result);
return *this;
}
template<int Y_DIGITS> gfield &mul(const bigint<Y_DIGITS> &y) { return mul(*this, y); }
-
- template<int RESULT_DIGITS> void reduce(const bigint<RESULT_DIGITS> &result)
- {
+ template<int RESULT_DIGITS> void reduce(const bigint<RESULT_DIGITS> &result) {
#if GF_BITS==192
// B = T + S1 + S2 + S3 mod p
copyshrinkdigits(result, GF_DIGITS); // T
-
- if(result.morebits(192))
- {
+ if(result.morebits(192)) {
gfield s;
s.copybits(0, result, 192, 64);
s.dupbits(64, 0, 64);
s.shrinkbits(128);
add(s); // S1
-
- if(result.morebits(256))
- {
+ if(result.morebits(256)) {
s.zerobits(0, 64);
s.copybits(64, result, 256, 64);
s.dupbits(128, 64, 64);
s.shrinkdigits(GF_DIGITS);
add(s); // S2
-
- if(result.morebits(320))
- {
+ if(result.morebits(320)) {
s.copybits(0, result, 320, 64);
s.dupbits(64, 0, 64);
s.dupbits(128, 0, 64);
#elif GF_BITS==256
// B = T + 2*S1 + 2*S2 + S3 + S4 - D1 - D2 - D3 - D4 mod p
copyshrinkdigits(result, GF_DIGITS); // T
-
- if(result.morebits(256))
- {
+ if(result.morebits(256)) {
gfield s;
- if(result.morebits(352))
- {
+ if(result.morebits(352)) {
s.zerobits(0, 96);
s.copybits(96, result, 352, 160);
s.shrinkdigits(GF_DIGITS);
add(s); add(s); // S1
-
- if(result.morebits(384))
- {
+ if(result.morebits(384)) {
//s.zerobits(0, 96);
s.copybits(96, result, 384, 128);
s.shrinkbits(224);
add(s); add(s); // S2
}
}
-
s.copybits(0, result, 256, 96);
s.zerobits(96, 96);
s.copybits(192, result, 448, 64);
s.shrinkdigits(GF_DIGITS);
add(s); // S3
-
s.copybits(0, result, 288, 96);
s.copybits(96, result, 416, 96);
s.dupbits(192, 96, 32);
s.copybits(224, result, 256, 32);
s.shrinkdigits(GF_DIGITS);
add(s); // S4
-
s.copybits(0, result, 352, 96);
s.zerobits(96, 96);
s.copybits(192, result, 256, 32);
s.copybits(224, result, 320, 32);
s.shrinkdigits(GF_DIGITS);
sub(s); // D1
-
s.copybits(0, result, 384, 128);
//s.zerobits(128, 64);
s.copybits(192, result, 288, 32);
s.copybits(224, result, 352, 32);
s.shrinkdigits(GF_DIGITS);
sub(s); // D2
-
s.copybits(0, result, 416, 96);
s.copybits(96, result, 256, 96);
s.zerobits(192, 32);
s.copybits(224, result, 384, 32);
s.shrinkdigits(GF_DIGITS);
sub(s); // D3
-
s.copybits(0, result, 448, 64);
s.zerobits(64, 32);
s.copybits(96, result, 288, 96);
#error Unsupported GF
#endif
}
-
- template<int X_DIGITS, int Y_DIGITS> gfield &pow(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y)
- {
+ template<int X_DIGITS, int Y_DIGITS> gfield &pow(const bigint<X_DIGITS> &x, const bigint<Y_DIGITS> &y) {
gfield a(x);
if(y.hasbit(0)) *this = a;
- else
- {
+ else {
len = 1;
digits[0] = 1;
if(!y.len) return *this;
}
- for(int i = 1, j = y.numbits(); i < j; i++)
- {
+ for(int i = 1, j = y.numbits(); i < j; i++) {
a.square();
if(y.hasbit(i)) mul(a);
}
return *this;
}
template<int Y_DIGITS> gfield &pow(const bigint<Y_DIGITS> &y) { return pow(*this, y); }
-
- bool invert(const gfield &x)
- {
+ bool invert(const gfield &x) {
if(!x.len) return false;
gfint u(x), v(P), A((gfint::digit)1), C((gfint::digit)0);
- while(!u.iszero())
- {
+ while(!u.iszero()) {
int ushift = 0, ashift = 0;
- while(!u.hasbit(ushift))
- {
+ while(!u.hasbit(ushift)) {
ushift++;
- if(A.hasbit(ashift))
- {
+ if(A.hasbit(ashift)) {
if(ashift) { A.rshift(ashift); ashift = 0; }
A.add(P);
}
if(ushift) u.rshift(ushift);
if(ashift) A.rshift(ashift);
int vshift = 0, cshift = 0;
- while(!v.hasbit(vshift))
- {
+ while(!v.hasbit(vshift)) {
vshift++;
- if(C.hasbit(cshift))
- {
+ if(C.hasbit(cshift)) {
if(cshift) { C.rshift(cshift); cshift = 0; }
C.add(P);
}
}
if(vshift) v.rshift(vshift);
if(cshift) C.rshift(cshift);
- if(u >= v)
- {
+ if(u >= v) {
u.sub(v);
if(A < C) A.add(P);
A.sub(C);
}
- else
- {
+ else {
v.sub(v, u);
if(C < A) C.add(P);
C.sub(A);
return true;
}
void invert() { invert(*this); }
-
- template<int X_DIGITS> static int legendre(const bigint<X_DIGITS> &x)
- {
+ template<int X_DIGITS> static int legendre(const bigint<X_DIGITS> &x) {
static const gfint Psub1div2(gfint(P).sub(bigint<1>(1)).rshift(1));
gfield L;
L.pow(x, Psub1div2);
return -1;
}
int legendre() const { return legendre(*this); }
-
- bool sqrt(const gfield &x)
- {
+ bool sqrt(const gfield &x) {
if(!x.len) { len = 0; return true; }
#if GF_BITS==224
#error Unsupported GF
#else
ASSERT((P.digits[0]%4)==3);
static const gfint Padd1div4(gfint(P).add(bigint<1>(1)).rshift(2));
- switch(legendre(x))
- {
+ switch(legendre(x)) {
case 0: len = 0; return true;
case -1: return false;
default: pow(x, Padd1div4); return true;
bool sqrt() { return sqrt(*this); }
};
-struct ecjacobian
-{
+struct ecjacobian {
static const gfield B;
static const ecjacobian base;
static const ecjacobian origin;
-
gfield x, y, z;
-
ecjacobian() {}
ecjacobian(const gfield &x, const gfield &y) : x(x), y(y), z(bigint<1>(1)) {}
ecjacobian(const gfield &x, const gfield &y, const gfield &z) : x(x), y(y), z(z) {}
-
- void mul2()
- {
+ void mul2() {
if(z.iszero()) return;
else if(y.iszero()) { *this = origin; return; }
gfield a, b, c, d;
a.square(b).add(a);
y.sub(d, x).mul(c).sub(a);
}
-
- void add(const ecjacobian &q)
- {
+ void add(const ecjacobian &q) {
if(q.z.iszero()) return;
else if(z.iszero()) { *this = q; return; }
gfield a, b, c, d, e, f;
a.square(z);
b.mul(q.y, a).mul(z);
a.mul(q.x);
- if(q.z.isone())
- {
+ if(q.z.isone()) {
c.add(x, a);
d.add(y, b);
a.sub(x, a);
b.sub(y, b);
}
- else
- {
+ else {
f.mul(y, e.square(q.z)).mul(q.z);
e.mul(x);
c.add(e, a);
x.square(b).sub(f.mul(c, e.square(a)));
y.sub(f, x).sub(x).mul(b).sub(e.mul(a).mul(d)).div2();
}
-
- template<int Q_DIGITS> void mul(const ecjacobian &p, const bigint<Q_DIGITS> &q)
- {
+ template<int Q_DIGITS> void mul(const ecjacobian &p, const bigint<Q_DIGITS> &q) {
*this = origin;
- loopirev(q.numbits())
- {
+ loopirev(q.numbits()) {
mul2();
if(q.hasbit(i)) add(p);
}
}
template<int Q_DIGITS> void mul(const bigint<Q_DIGITS> &q) { ecjacobian tmp(*this); mul(tmp, q); }
-
- void normalize()
- {
+ void normalize() {
if(z.iszero() || z.isone()) return;
gfield tmp;
z.invert();
y.mul(tmp).mul(z);
z = bigint<1>(1);
}
-
- bool calcy(bool ybit)
- {
+ bool calcy(bool ybit) {
gfield y2, tmp;
y2.square(x).mul(x).sub(tmp.add(x, x).add(x)).add(B);
if(!y.sqrt(y2)) { y.zero(); return false; }
if(y.hasbit(0) != ybit) y.neg();
return true;
}
-
- void print(vector<char> &buf)
- {
+ void print(vector<char> &buf) {
normalize();
buf.add(y.hasbit(0) ? '-' : '+');
x.printdigits(buf);
}
-
- void parse(const char *s)
- {
+ void parse(const char *s) {
bool ybit = *s++ == '-';
x.parse(s);
calcy(ybit);
#error Unsupported GF
#endif
-void calcpubkey(gfint privkey, vector<char> &pubstr)
-{
+void calcpubkey(gfint privkey, vector<char> &pubstr) {
ecjacobian c(ecjacobian::base);
c.mul(privkey);
c.normalize();
pubstr.add('\0');
}
-bool calcpubkey(const char *privstr, vector<char> &pubstr)
-{
+bool calcpubkey(const char *privstr, vector<char> &pubstr) {
if(!privstr[0]) return false;
gfint privkey;
privkey.parse(privstr);
return true;
}
-void genprivkey(const char *seed, vector<char> &privstr, vector<char> &pubstr)
-{
+void genprivkey(const char *seed, vector<char> &privstr, vector<char> &pubstr) {
tiger::hashval hash;
tiger::hash((const uchar *)seed, (int)strlen(seed), hash);
bigint<8*sizeof(hash.bytes)/BI_DIGIT_BITS> privkey;
privkey.shrink();
privkey.printdigits(privstr);
privstr.add('\0');
-
calcpubkey(privkey, pubstr);
}
-bool hashstring(const char *str, char *result, int maxlen)
-{
+bool hashstring(const char *str, char *result, int maxlen) {
tiger::hashval hv;
if(maxlen < 2*(int)sizeof(hv.bytes) + 1) return false;
tiger::hash((uchar *)str, strlen(str), hv);
- loopi(sizeof(hv.bytes))
- {
+ loopi(sizeof(hv.bytes)) {
uchar c = hv.bytes[i];
*result++ = "0123456789abcdef"[c&0xF];
*result++ = "0123456789abcdef"[c>>4];
return true;
}
-void answerchallenge(const char *privstr, const char *challenge, vector<char> &answerstr)
-{
+void answerchallenge(const char *privstr, const char *challenge, vector<char> &answerstr) {
gfint privkey;
privkey.parse(privstr);
ecjacobian answer;
answerstr.add('\0');
}
-void *parsepubkey(const char *pubstr)
-{
+void *parsepubkey(const char *pubstr) {
ecjacobian *pubkey = new ecjacobian;
pubkey->parse(pubstr);
return pubkey;
}
-void freepubkey(void *pubkey)
-{
+void freepubkey(void *pubkey) {
delete (ecjacobian *)pubkey;
}
-void *genchallenge(void *pubkey, const void *seed, int seedlen, vector<char> &challengestr)
-{
+void *genchallenge(void *pubkey, const void *seed, int seedlen, vector<char> &challengestr) {
tiger::hashval hash;
tiger::hash((const uchar *)seed, seedlen, hash);
gfint challenge;
memcpy(challenge.digits, hash.bytes, sizeof(hash.bytes));
challenge.len = 8*sizeof(hash.bytes)/BI_DIGIT_BITS;
challenge.shrink();
-
ecjacobian answer(*(ecjacobian *)pubkey);
answer.mul(challenge);
answer.normalize();
-
ecjacobian secret(ecjacobian::base);
secret.mul(challenge);
secret.normalize();
-
secret.print(challengestr);
challengestr.add('\0');
-
return new gfield(answer.x);
}
-void freechallenge(void *answer)
-{
+void freechallenge(void *answer) {
delete (gfint *)answer;
}
-bool checkchallenge(const char *answerstr, void *correct)
-{
+bool checkchallenge(const char *answerstr, void *correct) {
gfint answer(answerstr);
return answer == *(gfint *)correct;
}
int imin(int a, int b) { return a < b ? a : b; }\r
int imax(int a, int b) { return a > b ? a : b; }\r
\r
-void fatal(const char *fmt, ...)\r
-{\r
+void fatal(const char *fmt, ...)\r {
+\r
va_list v;\r
va_start(v, fmt);\r
vfprintf(stderr, fmt, v);\r
exit(EXIT_FAILURE);\r
}\r
\r
-uint bigswap(uint n)\r
-{\r
+uint bigswap(uint n)\r {
+\r
const int islittleendian = 1;\r
return *(const uchar *)&islittleendian ? (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000) : n;\r
}\r
\r
-size_t writebig(FILE *f, uint n)\r
-{\r
+size_t writebig(FILE *f, uint n)\r {
+\r
n = bigswap(n);\r
return fwrite(&n, 1, sizeof(n), f);\r
}\r
\r
-void writepngchunk(FILE *f, const char *type, uchar *data, uint len)\r
-{\r
+void writepngchunk(FILE *f, const char *type, uchar *data, uint len)\r {
+\r
uint crc;\r
writebig(f, len);\r
fwrite(type, 1, 4, f);\r
writebig(f, crc);\r
}\r
\r
-struct pngihdr\r
-{\r
+struct pngihdr\r {
+\r
uint width, height;\r
uchar bitdepth, colortype, compress, filter, interlace;\r
};\r
\r
-void savepng(const char *filename, uchar *data, int w, int h, int bpp, int flip)\r
-{\r
+void savepng(const char *filename, uchar *data, int w, int h, int bpp, int flip)\r {
+\r
const uchar signature[] = { 137, 80, 78, 71, 13, 10, 26, 10 };\r
struct pngihdr ihdr;\r
FILE *f;\r
ihdr.width = bigswap(w);\r
ihdr.height = bigswap(h);\r
ihdr.bitdepth = 8;\r
- switch(bpp)\r
- {\r
+ switch(bpp)\r {
+\r
case 1: ihdr.colortype = 0; break;\r
case 2: ihdr.colortype = 4; break;\r
case 3: ihdr.colortype = 2; break;\r
z.next_out = (Bytef *)buf;\r
z.avail_out = sizeof(buf);\r
\r
- for(i = 0; i < h; i++)\r
- {\r
+ for(i = 0; i < h; i++)\r {
+\r
uchar filter = 0;\r
- for(j = 0; j < 2; j++)\r
- {\r
+ for(j = 0; j < 2; j++)\r {
+\r
z.next_in = j ? (Bytef *)data + (flip ? h-i-1 : i)*w*bpp : (Bytef *)&filter;\r
z.avail_in = j ? w*bpp : 1;\r
- while(z.avail_in > 0)\r
- {\r
+ while(z.avail_in > 0)\r {
+\r
if(deflate(&z, Z_NO_FLUSH) != Z_OK) goto cleanuperror;\r
#define FLUSHZ do { \\r
int flush = sizeof(buf) - z.avail_out; \\r
}\r
}\r
\r
- for(;;)\r
- {\r
+ for(;;)\r {
+\r
int err = deflate(&z, Z_FINISH);\r
if(err != Z_OK && err != Z_STREAM_END) goto cleanuperror;\r
FLUSHZ;\r
fatal("cube2font: failed saving PNG to %s", filename);\r
}\r
\r
-enum\r
-{\r
+enum\r {
+\r
CT_PRINT = 1<<0,\r
CT_SPACE = 1<<1,\r
CT_DIGIT = 1<<2,\r
U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, \\r
U, U, U, U, u, u, u, u, u, u, u, u, u, u, u, u, \\r
u, u, u, u, u, u, u, u, u, u, u, u, u, u, U, u\r
-const uchar cubectype[256] =\r
-{\r
+const uchar cubectype[256] =\r {
+\r
CUBECTYPE(CT_SPACE,\r
CT_PRINT,\r
CT_PRINT|CT_DIGIT,\r
int iscubealnum(uchar c) { return cubectype[c]&(CT_ALPHA|CT_DIGIT); }\r
int iscubelower(uchar c) { return cubectype[c]&CT_LOWER; }\r
int iscubeupper(uchar c) { return cubectype[c]&CT_UPPER; }\r
-const int cube2unichars[256] =\r
-{\r
+const int cube2unichars[256] =\r {
+\r
0, 192, 193, 194, 195, 196, 197, 198, 199, 9, 10, 11, 12, 13, 200, 201,\r
202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,\r
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\r
0x42C, 0x42D, 0x42E, 0x42F, 0x431, 0x432, 0x433, 0x434, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D,\r
0x43F, 0x442, 0x444, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x454, 0x490, 0x491\r
};\r
-int cube2uni(uchar c)\r
-{\r
+int cube2uni(uchar c)\r {
+\r
return cube2unichars[c];\r
}\r
\r
-const char *encodeutf8(int uni)\r
-{\r
+const char *encodeutf8(int uni)\r {
+\r
static char buf[7];\r
char *dst = buf;\r
if(uni <= 0x7F) { *dst++ = uni; goto uni1; }\r
\r
const char *texdir = "";\r
\r
-const char *texfilename(const char *name, int texnum)\r
-{\r
+const char *texfilename(const char *name, int texnum)\r {
+\r
static char file[256];\r
snprintf(file, sizeof(file), "%s%d.png", name, texnum);\r
return file;\r
}\r
\r
-const char *texname(const char *name, int texnum)\r
-{\r
+const char *texname(const char *name, int texnum)\r {
+\r
static char file[512];\r
snprintf(file, sizeof(file), "<grey>%s%s", texdir, texfilename(name, texnum));\r
return file;\r
}\r
\r
-void writetexs(const char *name, struct fontchar *chars, int numchars, int numtexs, int tw, int th)\r
-{\r
+void writetexs(const char *name, struct fontchar *chars, int numchars, int numtexs, int tw, int th)\r {
+\r
int tex;\r
uchar *pixels = (uchar *)malloc(tw*th*2);\r
if(!pixels) fatal("cube2font: failed allocating textures");\r
- for(tex = 0; tex < numtexs; tex++)\r
- {\r
+ for(tex = 0; tex < numtexs; tex++)\r {
+\r
const char *file = texfilename(name, tex);\r
int texchars = 0, i;\r
uchar *dst, *src;\r
memset(pixels, 0, tw*th*2);\r
- for(i = 0; i < numchars; i++)\r
- {\r
+ for(i = 0; i < numchars; i++)\r {
+\r
struct fontchar *c = &chars[i];\r
int x, y;\r
if(c->tex != tex) continue;\r
texchars++;\r
dst = &pixels[2*((c->y + c->offy - c->color->top)*tw + c->x + c->color->left - c->offx)];\r
src = (uchar *)c->color->bitmap.buffer;\r
- for(y = 0; y < c->color->bitmap.rows; y++)\r
- {\r
+ for(y = 0; y < c->color->bitmap.rows; y++)\r {
+\r
for(x = 0; x < c->color->bitmap.width; x++)\r
dst[2*x] = src[x];\r
src += c->color->bitmap.pitch;\r
}\r
dst = &pixels[2*((c->y + c->offy - c->alpha->top)*tw + c->x + c->alpha->left - c->offx)];\r
src = (uchar *)c->alpha->bitmap.buffer;\r
- for(y = 0; y < c->alpha->bitmap.rows; y++)\r
- {\r
+ for(y = 0; y < c->alpha->bitmap.rows; y++)\r {
+\r
for(x = 0; x < c->alpha->bitmap.width; x++)\r
dst[2*x+1] = src[x];\r
src += c->alpha->bitmap.pitch;\r
free(pixels);\r
}\r
\r
-void writecfg(const char *name, struct fontchar *chars, int numchars, int x1, int y1, int x2, int y2, int sw, int sh, int argc, char **argv)\r
-{\r
+void writecfg(const char *name, struct fontchar *chars, int numchars, int x1, int y1, int x2, int y2, int sw, int sh, int argc, char **argv)\r {
+\r
FILE *f;\r
char file[256];\r
int i, lastcode = 0, lasttex = 0;\r
fprintf(f, " %s", argv[i]);\r
fprintf(f, "\n");\r
fprintf(f, "font \"%s\" \"%s\" %d %d\n", name, texname(name, 0), sw, sh);\r
- for(i = 0; i < numchars; i++)\r
- {\r
+ for(i = 0; i < numchars; i++)\r {
+\r
struct fontchar *c = &chars[i];\r
- if(!lastcode && lastcode < c->code)\r
- {\r
+ if(!lastcode && lastcode < c->code)\r {
+\r
fprintf(f, "fontoffset \"%s\"\n", encodeutf8(c->uni));\r
lastcode = c->code;\r
}\r
- else if(lastcode < c->code)\r
- {\r
+ else if(lastcode < c->code)\r {
+\r
if(lastcode + 1 == c->code)\r
fprintf(f, "fontskip // %d\n", lastcode);\r
else\r
fprintf(f, "fontskip %d // %d .. %d\n", c->code - lastcode, lastcode, c->code-1);\r
lastcode = c->code;\r
}\r
- if(lasttex != c->tex)\r
- {\r
+ if(lasttex != c->tex)\r {
+\r
fprintf(f, "\nfonttex \"%s\"\n", texname(name, c->tex));\r
lasttex = c->tex;\r
}\r
fclose(f);\r
}\r
\r
-int groupchar(int c)\r
-{\r
- switch(c)\r
- {\r
+int groupchar(int c)\r {
+\r
+ switch(c)\r {
+\r
case 0x152: case 0x153: case 0x178: return 1;\r
}\r
if(c < 127 || c >= 0x2000) return 0;\r
return 3;\r
}\r
\r
-int sortchars(const void *x, const void *y)\r
-{\r
+int sortchars(const void *x, const void *y)\r {
+\r
const struct fontchar *xc = *(const struct fontchar **)x, *yc = *(const struct fontchar **)y;\r
int xg = groupchar(xc->uni), yg = groupchar(yc->uni);\r
if(xg < yg) return -1;\r
return yc->uni - xc->uni;\r
}\r
\r
-int scorechar(struct fontchar *f, int pad, int tw, int th, int rw, int rh, int ry)\r
-{\r
+int scorechar(struct fontchar *f, int pad, int tw, int th, int rw, int rh, int ry)\r {
+\r
int score = 0;\r
if(rw + f->w > tw) { ry += rh + pad; score = 1; }\r
if(ry + f->h > th) score = 2;\r
return score;\r
}\r
\r
-int main(int argc, char **argv)\r
-{\r
+int main(int argc, char **argv)\r {
+\r
FT_Library l;\r
FT_Face f;\r
FT_Stroker s, s2;\r
fatal("cube2font: failed loading font %s", argv[1]);\r
if(outborder > 0) FT_Stroker_Set(s, (FT_Fixed)(outborder * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);\r
if(inborder > 0) FT_Stroker_Set(s2, (FT_Fixed)(inborder * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);\r
- for(c = 0; c < 256; c++) if(iscubeprint(c))\r
- {\r
+ for(c = 0; c < 256; c++) if(iscubeprint(c))\r {
+\r
FT_Glyph p, p2;\r
FT_BitmapGlyph b, b2;\r
struct fontchar *dst = &chars[numchars];\r
order[numchars++] = dst;\r
}\r
qsort(order, numchars, sizeof(order[0]), sortchars);\r
- for(i = 0; i < numchars;)\r
- {\r
+ for(i = 0; i < numchars;)\r {
+\r
struct fontchar *dst;\r
int j, k, trial0, prevscore, dstscore, fitscore;\r
- for(trial0 = trial, prevscore = -1; (trial -= 2) >= trial0-512;)\r
- {\r
+ for(trial0 = trial, prevscore = -1; (trial -= 2) >= trial0-512;)\r {
+\r
int g, fw = rw, fh = rh, fy = ry, curscore = 0, reused = 0;\r
- for(j = i; j < numchars; j++)\r
- {\r
+ for(j = i; j < numchars; j++)\r {
+\r
dst = order[j];\r
if(dst->tex >= 0 || dst->tex <= trial) continue;\r
g = groupchar(dst->uni);\r
dstscore = scorechar(dst, pad, tw, th, fw, fh, fy);\r
- for(k = j; k < numchars; k++)\r
- {\r
+ for(k = j; k < numchars; k++)\r {
+\r
struct fontchar *fit = order[k];\r
if(fit->tex >= 0 || fit->tex <= trial) continue;\r
if(fit->tex >= trial0 && groupchar(fit->uni) != g) break;\r
fitscore = scorechar(fit, pad, tw, th, fw, fh, fy);\r
- if(fitscore < dstscore || (fitscore == dstscore && fit->h > dst->h))\r
- {\r
+ if(fitscore < dstscore || (fitscore == dstscore && fit->h > dst->h))\r {
+\r
dst = fit;\r
dstscore = fitscore;\r
}\r
}\r
- if(fw + dst->w > tw)\r
- {\r
+ if(fw + dst->w > tw)\r {
+\r
fy += fh + pad;\r
fw = fh = 0;\r
}\r
- if(fy + dst->h > th)\r
- {\r
+ if(fy + dst->h > th)\r {
+\r
fy = fw = fh = 0;\r
if(curscore > 0) break;\r
}\r
if(reused < prevscore || curscore <= prevscore) break;\r
prevscore = curscore;\r
}\r
- for(; i < numchars; i++)\r
- {\r
+ for(; i < numchars; i++)\r {
+\r
dst = order[i];\r
if(dst->tex >= 0) continue;\r
dstscore = scorechar(dst, pad, tw, th, rw, rh, ry);\r
- for(j = i; j < numchars; j++)\r
- {\r
+ for(j = i; j < numchars; j++)\r {
+\r
struct fontchar *fit = order[j];\r
if(fit->tex < trial || fit->tex > trial+2) continue;\r
fitscore = scorechar(fit, pad, tw, th, rw, rh, ry);\r
- if(fitscore < dstscore || (fitscore == dstscore && fit->h > dst->h))\r
- {\r
+ if(fitscore < dstscore || (fitscore == dstscore && fit->h > dst->h))\r {
+\r
dst = fit;\r
dstscore = fitscore;\r
}\r
}\r
if(dst->tex < trial || dst->tex > trial+2) break;\r
- if(rw + dst->w > tw)\r
- {\r
+ if(rw + dst->w > tw)\r {
+\r
ry += rh + pad;\r
rw = rh = 0;\r
}\r
- if(ry + dst->h > th)\r
- {\r
+ if(ry + dst->h > th)\r {
+\r
ry = rw = rh = 0;\r
numtex++;\r
}\r
}\r
if(rh > 0) numtex++;\r
#if 0\r
- if(sw <= 0)\r
- {\r
+ if(sw <= 0)\r {
+\r
if(FT_Load_Char(f, ' ', FT_LOAD_DEFAULT))\r
fatal("cube2font: failed loading space character");\r
sw = (f->glyph->advance.x+0x3F)>>6;\r
if(sw <= 0) sw = sh/3;\r
writetexs(argv[2], chars, numchars, numtex, tw, th);\r
writecfg(argv[2], chars, numchars, x1, y1, x2, y2, sw, sh, argc, argv);\r
- for(i = 0; i < numchars; i++)\r
- {\r
+ for(i = 0; i < numchars; i++)\r {
+\r
if(chars[i].alpha != chars[i].color) FT_Done_Glyph((FT_Glyph)chars[i].alpha);\r
FT_Done_Glyph((FT_Glyph)chars[i].color);\r
}\r
enum { ET_EMPTY=0, ET_LIGHT, ET_MAPMODEL, ET_PLAYERSTART, ET_PARTICLES, ET_SOUND, ET_SPOTLIGHT, ET_GAMESPECIFIC };
-struct entity // persistent map entity
-{
+// persistent map entity
+struct entity {
vec o; // position
short attr1, attr2, attr3, attr4, attr5;
uchar type; // type is one of the above
uchar reserved;
};
-struct entitylight
-{
+struct entitylight {
vec color, dir;
int millis;
-
entitylight() : color(1, 1, 1), dir(0, 0, 1), millis(-1) {}
};
-enum
-{
+enum {
EF_NOVIS = 1<<0,
EF_NOSHADOW = 1<<1,
EF_NOCOLLIDE = 1<<2,
EF_NOPICKUP = 1<<8
};
-struct extentity : entity // part of the entity that doesn't get saved to disk
-{
+// part of the entity that doesn't get saved to disk
+struct extentity : entity {
int flags; // the only dynamic state of a map entity
entitylight light;
extentity *attached;
-
extentity() : flags(0), attached(NULL) {}
-
bool spawned() const { return (flags&EF_SPAWNED) != 0; }
void setspawned(bool val) { if(val) flags |= EF_SPAWNED; else flags &= ~EF_SPAWNED; }
void setspawned() { flags |= EF_SPAWNED; }
void clearspawned() { flags &= ~EF_SPAWNED; }
-
bool nopickup() const { return (flags&EF_NOPICKUP) != 0; }
void setnopickup(bool val) { if(val) flags |= EF_NOPICKUP; else flags &= ~EF_NOPICKUP; }
void setnopickup() { flags |= EF_NOPICKUP; }
enum { COLLIDE_NONE = 0, COLLIDE_ELLIPSE, COLLIDE_OBB, COLLIDE_ELLIPSE_PRECISE };
-struct physent // base entity type, can be affected by physics
-{
+struct physent { // base entity type, can be affected by physics {
vec o, vel, falling; // origin, velocity
vec deltapos, newpos; // movement interpolation
float yaw, pitch, roll;
float radius, eyeheight, aboveeye; // bounding box size
float xradius, yradius, zmargin;
vec floor; // the normal of floor the dynent is on
-
ushort timeinair;
uchar inwater;
bool jumping;
schar move, strafe;
-
uchar physstate; // one of PHYS_* above
uchar state, editstate; // one of CS_* above
uchar type; // one of ENT_* above
uchar collidetype; // one of COLLIDE_* above
-
bool blocked; // used by physics to signal ai
-
physent() : o(0, 0, 0), deltapos(0, 0, 0), newpos(0, 0, 0), yaw(0), pitch(0), roll(0), maxspeed(100),
radius(4.1f), eyeheight(14), aboveeye(1), xradius(4.1f), yradius(4.1f), zmargin(0),
state(CS_ALIVE), editstate(CS_ALIVE), type(ENT_PLAYER),
collidetype(COLLIDE_ELLIPSE),
blocked(false)
- { reset(); }
-
- void resetinterp()
- {
+ { reset(); }
+ void resetinterp() {
newpos = o;
deltapos = vec(0, 0, 0);
}
-
- void reset()
- {
+ void reset() {
inwater = 0;
timeinair = 0;
jumping = false;
vel = falling = vec(0, 0, 0);
floor = vec(0, 0, 1);
}
-
vec feetpos(float offset = 0) const { return vec(o).add(vec(0, 0, offset - eyeheight)); }
vec headpos(float offset = 0) const { return vec(o).add(vec(0, 0, offset)); }
-
bool maymove() const { return timeinair || physstate < PHYS_FLOOR || vel.squaredlen() > 1e-4f || deltapos.squaredlen() > 1e-4f; }
};
-enum
-{
+enum {
ANIM_DEAD = 0, ANIM_DYING, ANIM_IDLE,
ANIM_FORWARD, ANIM_BACKWARD, ANIM_LEFT, ANIM_RIGHT,
ANIM_HOLD1, ANIM_HOLD2, ANIM_HOLD3, ANIM_HOLD4, ANIM_HOLD5, ANIM_HOLD6, ANIM_HOLD7,
NUMANIMS
};
-static const char * const animnames[] =
-{
+static const char * const animnames[] = {
"dead", "dying", "idle",
"forward", "backward", "left", "right",
"hold 1", "hold 2", "hold 3", "hold 4", "hold 5", "hold 6", "hold 7",
#define ANIM_GHOST (1<<30)
#define ANIM_FLAGS (0x1FF<<22)
-struct animinfo // description of a character's animation
-{
+struct animinfo { // description of a character's animation {
int anim, frame, range, basetime;
float speed;
uint varseed;
-
animinfo() : anim(0), frame(0), range(0), basetime(0), speed(100.0f), varseed(0) { }
-
bool operator==(const animinfo &o) const { return frame==o.frame && range==o.range && (anim&(ANIM_SETTIME|ANIM_DIR))==(o.anim&(ANIM_SETTIME|ANIM_DIR)) && (anim&ANIM_SETTIME || basetime==o.basetime) && speed==o.speed; }
bool operator!=(const animinfo &o) const { return frame!=o.frame || range!=o.range || (anim&(ANIM_SETTIME|ANIM_DIR))!=(o.anim&(ANIM_SETTIME|ANIM_DIR)) || (!(anim&ANIM_SETTIME) && basetime!=o.basetime) || speed!=o.speed; }
};
-struct animinterpinfo // used for animation blending of animated characters
-{
+struct animinterpinfo { // used for animation blending of animated characters {
animinfo prev, cur;
int lastswitch;
void *lastmodel;
-
animinterpinfo() : lastswitch(-1), lastmodel(NULL) {}
-
void reset() { lastswitch = -1; }
};
struct occludequery;
struct ragdolldata;
-struct dynent : physent // animated characters, or characters that can receive input
-{
+struct dynent : physent { // animated characters, or characters that can receive input {
bool k_left, k_right, k_up, k_down; // see input code
-
entitylight light;
animinterpinfo animinterp[MAXANIMPARTS];
ragdolldata *ragdoll;
occludequery *query;
int lastrendered;
uchar occluded;
-
- dynent() : ragdoll(NULL), query(NULL), lastrendered(0), occluded(0)
- {
+ dynent() : ragdoll(NULL), query(NULL), lastrendered(0), occluded(0) {
reset();
}
-
- ~dynent()
- {
+ ~dynent() {
#ifndef STANDALONE
extern void cleanragdoll(dynent *d);
if(ragdoll) cleanragdoll(this);
#endif
}
-
- void stopmoving()
- {
+ void stopmoving() {
k_left = k_right = k_up = k_down = jumping = false;
move = strafe = 0;
}
-
- void reset()
- {
+ void reset() {
physent::reset();
stopmoving();
loopi(MAXANIMPARTS) animinterp[i].reset();
}
-
vec abovehead() { return vec(o).add(vec(0, 0, aboveeye+4)); }
};
-
-
static inline double det2x2(double a, double b, double c, double d) { return a*d - b*c; }
static inline double det3x3(double a1, double a2, double a3,
double b1, double b2, double b3,
- double c1, double c2, double c3)
-{
+ double c1, double c2, double c3) {
return a1 * det2x2(b2, b3, c2, c3)
- b1 * det2x2(a2, a3, c2, c3)
+ c1 * det2x2(a2, a3, b2, b3);
}
-bool matrix4::invert(const matrix4 &m, double mindet)
-{
+bool matrix4::invert(const matrix4 &m, double mindet) {
double a1 = m.a.x, a2 = m.a.y, a3 = m.a.z, a4 = m.a.w,
b1 = m.b.x, b2 = m.b.y, b3 = m.b.z, b4 = m.b.w,
c1 = m.c.x, c2 = m.c.y, c3 = m.c.z, c4 = m.c.w,
det3 = det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4),
det4 = -det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4),
det = a1*det1 + b1*det2 + c1*det3 + d1*det4;
-
if(fabs(det) < mindet) return false;
-
double invdet = 1/det;
-
a.x = det1 * invdet;
a.y = det2 * invdet;
a.z = det3 * invdet;
a.w = det4 * invdet;
-
b.x = -det3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4) * invdet;
b.y = det3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4) * invdet;
b.z = -det3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4) * invdet;
b.w = det3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4) * invdet;
-
c.x = det3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4) * invdet;
c.y = -det3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4) * invdet;
c.z = det3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4) * invdet;
c.w = -det3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4) * invdet;
-
d.x = -det3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3) * invdet;
d.y = det3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3) * invdet;
d.z = -det3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3) * invdet;
d.w = det3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3) * invdet;
-
return true;
}
-bool raysphereintersect(const vec ¢er, float radius, const vec &o, const vec &ray, float &dist)
-{
+bool raysphereintersect(const vec ¢er, float radius, const vec &o, const vec &ray, float &dist) {
vec c(center);
c.sub(o);
float v = c.dot(ray),
return true;
}
-bool rayboxintersect(const vec &b, const vec &s, const vec &o, const vec &ray, float &dist, int &orient)
-{
- loop(d, 3) if(ray[d])
- {
+bool rayboxintersect(const vec &b, const vec &s, const vec &o, const vec &ray, float &dist, int &orient) {
+ loop(d, 3) if(ray[d]) {
int dc = ray[d]<0 ? 1 : 0;
float pdist = (b[d]+s[d]*dc - o[d]) / ray[d];
vec v(ray);
v.mul(pdist).add(o);
if(v[R[d]] >= b[R[d]] && v[R[d]] <= b[R[d]]+s[R[d]]
- && v[C[d]] >= b[C[d]] && v[C[d]] <= b[C[d]]+s[C[d]])
- {
+ && v[C[d]] >= b[C[d]] && v[C[d]] <= b[C[d]]+s[C[d]]) {
dist = pdist;
orient = 2*d+dc;
return true;
return false;
}
-bool linecylinderintersect(const vec &from, const vec &to, const vec &start, const vec &end, float radius, float &dist)
-{
+bool linecylinderintersect(const vec &from, const vec &to, const vec &start, const vec &end, float radius, float &dist) {
vec d(end), m(from), n(to);
d.sub(start);
m.sub(start);
a = dd*nn - nd*nd,
k = m.squaredlen() - radius*radius,
c = dd*k - md*md;
- if(fabs(a) < 0.005f)
- {
+ if(fabs(a) < 0.005f) {
if(c > 0) return false;
if(md < 0) dist = -mn / nn;
else if(md > dd) dist = (nd - mn) / nn;
else dist = 0;
return true;
}
- else if(c > 0)
- {
+ else if(c > 0) {
float b = dd*mn - nd*md,
discrim = b*b - a*c;
if(discrim < 0) return false;
}
else dist = 0;
float offset = md + dist*nd;
- if(offset < 0)
- {
+ if(offset < 0) {
if(nd <= 0) return false;
dist = -md / nd;
if(k + dist*(2*mn + dist*nn) > 0) return false;
}
- else if(offset > dd)
- {
+ else if(offset > dd) {
if(nd >= 0) return false;
dist = (dd - md) / nd;
if(k + dd - 2*md + dist*(2*(mn-nd) + dist*nn) > 0) return false;
return dist >= 0 && dist <= 1;
}
-extern const vec2 sincos360[721] =
-{
+extern const vec2 sincos360[721] = {
vec2(1.00000000, 0.00000000), vec2(0.99984770, 0.01745241), vec2(0.99939083, 0.03489950), vec2(0.99862953, 0.05233596), vec2(0.99756405, 0.06975647), vec2(0.99619470, 0.08715574), // 0
vec2(0.99452190, 0.10452846), vec2(0.99254615, 0.12186934), vec2(0.99026807, 0.13917310), vec2(0.98768834, 0.15643447), vec2(0.98480775, 0.17364818), vec2(0.98162718, 0.19080900), // 6
vec2(0.97814760, 0.20791169), vec2(0.97437006, 0.22495105), vec2(0.97029573, 0.24192190), vec2(0.96592583, 0.25881905), vec2(0.96126170, 0.27563736), vec2(0.95630476, 0.29237170), // 12
struct vec;
struct vec4;
-struct vec2
-{
- union
- {
+struct vec2 {
+ union {
struct { float x, y; };
float v[2];
};
-
vec2() {}
vec2(float x, float y) : x(x), y(y) {}
explicit vec2(const vec &v);
explicit vec2(const vec4 &v);
-
- float &operator[](int i) { return v[i]; }
+ float &operator[](int i) { return v[i]; }
float operator[](int i) const { return v[i]; }
-
bool operator==(const vec2 &o) const { return x == o.x && y == o.y; }
bool operator!=(const vec2 &o) const { return x != o.x || y != o.y; }
-
bool iszero() const { return x==0 && y==0; }
- float dot(const vec2 &o) const { return x*o.x + y*o.y; }
+ float dot(const vec2 &o) const { return x*o.x + y*o.y; }
float squaredlen() const { return dot(*this); }
- float magnitude() const { return sqrtf(squaredlen()); }
+ float magnitude() const { return sqrtf(squaredlen()); }
vec2 &normalize() { mul(1/magnitude()); return *this; }
vec2 &safenormalize() { float m = magnitude(); if(m) mul(1/m); return *this; }
float cross(const vec2 &o) const { return x*o.y - y*o.x; }
-
- vec2 &mul(float f) { x *= f; y *= f; return *this; }
+ vec2 &mul(float f) { x *= f; y *= f; return *this; }
vec2 &mul(const vec2 &o) { x *= o.x; y *= o.y; return *this; }
- vec2 &square() { mul(*this); return *this; }
- vec2 &div(float f) { x /= f; y /= f; return *this; }
+ vec2 &square() { mul(*this); return *this; }
+ vec2 &div(float f) { x /= f; y /= f; return *this; }
vec2 &div(const vec2 &o) { x /= o.x; y /= o.y; return *this; }
vec2 &recip() { x = 1/x; y = 1/y; return *this; }
- vec2 &add(float f) { x += f; y += f; return *this; }
+ vec2 &add(float f) { x += f; y += f; return *this; }
vec2 &add(const vec2 &o) { x += o.x; y += o.y; return *this; }
- vec2 &sub(float f) { x -= f; y -= f; return *this; }
+ vec2 &sub(float f) { x -= f; y -= f; return *this; }
vec2 &sub(const vec2 &o) { x -= o.x; y -= o.y; return *this; }
- vec2 &neg() { x = -x; y = -y; return *this; }
+ vec2 &neg() { x = -x; y = -y; return *this; }
vec2 &min(const vec2 &o) { x = ::min(x, o.x); y = ::min(y, o.y); return *this; }
vec2 &max(const vec2 &o) { x = ::max(x, o.x); y = ::max(y, o.y); return *this; }
- vec2 &min(float f) { x = ::min(x, f); y = ::min(y, f); return *this; }
- vec2 &max(float f) { x = ::max(x, f); y = ::max(y, f); return *this; }
+ vec2 &min(float f) { x = ::min(x, f); y = ::min(y, f); return *this; }
+ vec2 &max(float f) { x = ::max(x, f); y = ::max(y, f); return *this; }
vec2 &abs() { x = fabs(x); y = fabs(y); return *this; }
vec2 &clamp(float l, float h) { x = ::clamp(x, l, h); y = ::clamp(y, l, h); return *this; }
vec2 &reflect(const vec2 &n) { float k = 2*dot(n); x -= k*n.x; y -= k*n.y; return *this; }
template<class B> vec2 &msub(const vec2 &a, const B &b) { return sub(vec2(a).mul(b)); }
};
-static inline bool htcmp(const vec2 &x, const vec2 &y)
-{
+static inline bool htcmp(const vec2 &x, const vec2 &y) {
return x == y;
}
-static inline uint hthash(const vec2 &k)
-{
+static inline uint hthash(const vec2 &k) {
union { uint i; float f; } x, y;
x.f = k.x; y.f = k.y;
uint v = x.i^y.i;
struct ivec;
-struct vec
-{
- union
- {
+struct vec {
+ union {
struct { float x, y, z; };
struct { float r, g, b; };
float v[3];
};
-
vec() {}
explicit vec(int a) : x(a), y(a), z(a) {}
explicit vec(float a) : x(a), y(a), z(a) {}
explicit vec(const vec2 &v, float z = 0) : x(v.x), y(v.y), z(z) {}
explicit vec(const vec4 &v);
explicit vec(const ivec &v);
-
vec(float yaw, float pitch) : x(-sinf(yaw)*cosf(pitch)), y(cosf(yaw)*cosf(pitch)), z(sinf(pitch)) {}
-
- float &operator[](int i) { return v[i]; }
+ float &operator[](int i) { return v[i]; }
float operator[](int i) const { return v[i]; }
-
vec &set(int i, float f) { v[i] = f; return *this; }
-
bool operator==(const vec &o) const { return x == o.x && y == o.y && z == o.z; }
bool operator!=(const vec &o) const { return x != o.x || y != o.y || z != o.z; }
-
bool iszero() const { return x==0 && y==0 && z==0; }
float squaredlen() const { return x*x + y*y + z*z; }
template<class T> float dot2(const T &o) const { return x*o.x + y*o.y; }
float dot(const vec &o) const { return x*o.x + y*o.y + z*o.z; }
float absdot(const vec &o) const { return fabs(x*o.x) + fabs(y*o.y) + fabs(z*o.z); }
vec &pow(float f) { x = ::pow(x, f); y = ::pow(y, f); z = ::pow(z, f); return *this; }
- vec &exp() { x = ::exp(x); y = ::exp(y); z = ::exp(z); return *this; }
- vec &exp2() { x = ::exp2(x); y = ::exp2(y); z = ::exp2(z); return *this; }
- vec &sqrt() { x = sqrtf(x); y = sqrtf(y); z = sqrtf(z); return *this; }
- vec &mul(const vec &o) { x *= o.x; y *= o.y; z *= o.z; return *this; }
+ vec &exp() { x = ::exp(x); y = ::exp(y); z = ::exp(z); return *this; }
+ vec &exp2() { x = ::exp2(x); y = ::exp2(y); z = ::exp2(z); return *this; }
+ vec &sqrt() { x = sqrtf(x); y = sqrtf(y); z = sqrtf(z); return *this; }
+ vec &mul(const vec &o) { x *= o.x; y *= o.y; z *= o.z; return *this; }
vec &mul(float f) { x *= f; y *= f; z *= f; return *this; }
vec &square() { mul(*this); return *this; }
- vec &div(const vec &o) { x /= o.x; y /= o.y; z /= o.z; return *this; }
+ vec &div(const vec &o) { x /= o.x; y /= o.y; z /= o.z; return *this; }
vec &div(float f) { x /= f; y /= f; z /= f; return *this; }
vec &recip() { x = 1/x; y = 1/y; z = 1/z; return *this; }
- vec &add(const vec &o) { x += o.x; y += o.y; z += o.z; return *this; }
+ vec &add(const vec &o) { x += o.x; y += o.y; z += o.z; return *this; }
vec &add(float f) { x += f; y += f; z += f; return *this; }
- vec &add2(float f) { x += f; y += f; return *this; }
- vec &addz(float f) { z += f; return *this; }
- vec &sub(const vec &o) { x -= o.x; y -= o.y; z -= o.z; return *this; }
+ vec &add2(float f) { x += f; y += f; return *this; }
+ vec &addz(float f) { z += f; return *this; }
+ vec &sub(const vec &o) { x -= o.x; y -= o.y; z -= o.z; return *this; }
vec &sub(float f) { x -= f; y -= f; z -= f; return *this; }
- vec &sub2(float f) { x -= f; y -= f; return *this; }
- vec &subz(float f) { z -= f; return *this; }
- vec &neg2() { x = -x; y = -y; return *this; }
- vec &neg() { x = -x; y = -y; z = -z; return *this; }
- vec &min(const vec &o) { x = ::min(x, o.x); y = ::min(y, o.y); z = ::min(z, o.z); return *this; }
- vec &max(const vec &o) { x = ::max(x, o.x); y = ::max(y, o.y); z = ::max(z, o.z); return *this; }
+ vec &sub2(float f) { x -= f; y -= f; return *this; }
+ vec &subz(float f) { z -= f; return *this; }
+ vec &neg2() { x = -x; y = -y; return *this; }
+ vec &neg() { x = -x; y = -y; z = -z; return *this; }
+ vec &min(const vec &o) { x = ::min(x, o.x); y = ::min(y, o.y); z = ::min(z, o.z); return *this; }
+ vec &max(const vec &o) { x = ::max(x, o.x); y = ::max(y, o.y); z = ::max(z, o.z); return *this; }
vec &min(float f) { x = ::min(x, f); y = ::min(y, f); z = ::min(z, f); return *this; }
vec &max(float f) { x = ::max(x, f); y = ::max(y, f); z = ::max(z, f); return *this; }
vec &clamp(float f, float h) { x = ::clamp(x, f, h); y = ::clamp(y, f, h); z = ::clamp(z, f, h); return *this; }
vec &abs() { x = fabs(x); y = fabs(y); z = fabs(z); return *this; }
float magnitude2() const { return sqrtf(dot2(*this)); }
- float magnitude() const { return sqrtf(squaredlen()); }
+ float magnitude() const { return sqrtf(squaredlen()); }
vec &normalize() { div(magnitude()); return *this; }
vec &safenormalize() { float m = magnitude(); if(m) div(m); return *this; }
bool isnormalized() const { float m = squaredlen(); return (m>0.99f && m<1.01f); }
vec &reflect(const vec &n) { float k = 2*dot(n); x -= k*n.x; y -= k*n.y; z -= k*n.z; return *this; }
vec &project(const vec &n) { float k = dot(n); x -= k*n.x; y -= k*n.y; z -= k*n.z; return *this; }
vec &projectxydir(const vec &n) { if(n.z) z = -(x*n.x/n.z + y*n.y/n.z); return *this; }
- vec &projectxy(const vec &n)
- {
+ vec &projectxy(const vec &n) {
float m = squaredlen(), k = dot(n);
projectxydir(n);
rescale(sqrtf(::max(m - k*k, 0.0f)));
return *this;
}
- vec &projectxy(const vec &n, float threshold)
- {
+ vec &projectxy(const vec &n, float threshold) {
float m = squaredlen(), k = ::min(dot(n), threshold);
projectxydir(n);
rescale(sqrtf(::max(m - k*k, 0.0f)));
vec &lerp(const vec &a, const vec &b, float t) { x = a.x + (b.x-a.x)*t; y = a.y + (b.y-a.y)*t; z = a.z + (b.z-a.z)*t; return *this; }
template<class B> vec &madd(const vec &a, const B &b) { return add(vec(a).mul(b)); }
template<class B> vec &msub(const vec &a, const B &b) { return sub(vec(a).mul(b)); }
-
- vec &rescale(float k)
- {
+ vec &rescale(float k) {
float mag = magnitude();
if(mag > 1e-6f) mul(k / mag);
return *this;
}
-
vec &rotate_around_z(float c, float s) { float rx = x, ry = y; x = c*rx-s*ry; y = c*ry+s*rx; return *this; }
vec &rotate_around_x(float c, float s) { float ry = y, rz = z; y = c*ry-s*rz; z = c*rz+s*ry; return *this; }
vec &rotate_around_y(float c, float s) { float rx = x, rz = z; x = c*rx+s*rz; z = c*rz-s*rx; return *this; }
-
vec &rotate_around_z(float angle) { return rotate_around_z(cosf(angle), sinf(angle)); }
vec &rotate_around_x(float angle) { return rotate_around_x(cosf(angle), sinf(angle)); }
vec &rotate_around_y(float angle) { return rotate_around_y(cosf(angle), sinf(angle)); }
-
vec &rotate_around_z(const vec2 &sc) { return rotate_around_z(sc.x, sc.y); }
vec &rotate_around_x(const vec2 &sc) { return rotate_around_x(sc.x, sc.y); }
vec &rotate_around_y(const vec2 &sc) { return rotate_around_y(sc.x, sc.y); }
-
- vec &rotate(float c, float s, const vec &d)
- {
+ vec &rotate(float c, float s, const vec &d) {
*this = vec(x*(d.x*d.x*(1-c)+c) + y*(d.x*d.y*(1-c)-d.z*s) + z*(d.x*d.z*(1-c)+d.y*s),
x*(d.y*d.x*(1-c)+d.z*s) + y*(d.y*d.y*(1-c)+c) + z*(d.y*d.z*(1-c)-d.x*s),
x*(d.x*d.z*(1-c)-d.y*s) + y*(d.y*d.z*(1-c)+d.x*s) + z*(d.z*d.z*(1-c)+c));
}
vec &rotate(float angle, const vec &d) { return rotate(cosf(angle), sinf(angle), d); }
vec &rotate(const vec2 &sc, const vec &d) { return rotate(sc.x, sc.y, d); }
-
- void orthogonal(const vec &d)
- {
+ void orthogonal(const vec &d) {
*this = fabs(d.x) > fabs(d.z) ? vec(-d.y, d.x, 0) : vec(0, -d.z, d.y);
}
-
- void orthonormalize(vec &s, vec &t) const
- {
+ void orthonormalize(vec &s, vec &t) const {
s.sub(vec(*this).mul(dot(s)));
t.sub(vec(*this).mul(dot(t)))
.sub(vec(s).mul(s.dot(t)));
}
-
template<class T>
- bool insidebb(const T &bbmin, const T &bbmax) const
- {
+ bool insidebb(const T &bbmin, const T &bbmax) const {
return x >= bbmin.x && x <= bbmax.x && y >= bbmin.y && y <= bbmax.y && z >= bbmin.z && z <= bbmax.z;
}
-
template<class T, class U>
- bool insidebb(const T &o, U size) const
- {
+ bool insidebb(const T &o, U size) const {
return x >= o.x && x <= o.x + size && y >= o.y && y <= o.y + size && z >= o.z && z <= o.z + size;
}
-
- template<class T> float dist_to_bb(const T &min, const T &max) const
- {
+ template<class T> float dist_to_bb(const T &min, const T &max) const {
float sqrdist = 0;
- loopi(3)
- {
+ loopi(3) {
if (v[i] < min[i]) { float delta = v[i]-min[i]; sqrdist += delta*delta; }
else if(v[i] > max[i]) { float delta = max[i]-v[i]; sqrdist += delta*delta; }
}
return sqrtf(sqrdist);
}
-
- template<class T, class S> float dist_to_bb(const T &o, S size) const
- {
+ template<class T, class S> float dist_to_bb(const T &o, S size) const {
return dist_to_bb(o, T(o).add(size));
}
-
- static vec hexcolor(int color)
- {
+ static vec hexcolor(int color) {
return vec(((color>>16)&0xFF)*(1.0f/255.0f), ((color>>8)&0xFF)*(1.0f/255.0f), (color&0xFF)*(1.0f/255.0f));
}
int tohexcolor() const { return (int(::clamp(r, 0.0f, 1.0f)*255)<<16)|(int(::clamp(g, 0.0f, 1.0f)*255)<<8)|int(::clamp(b, 0.0f, 1.0f)*255); }
inline vec2::vec2(const vec &v) : x(v.x), y(v.y) {}
-static inline bool htcmp(const vec &x, const vec &y)
-{
+static inline bool htcmp(const vec &x, const vec &y) {
return x == y;
}
-static inline uint hthash(const vec &k)
-{
+static inline uint hthash(const vec &k) {
union { uint i; float f; } x, y, z;
x.f = k.x; y.f = k.y; z.f = k.z;
uint v = x.i^y.i^z.i;
return v + (v>>12);
}
-struct vec4
-{
- union
- {
+struct vec4 {
+ union {
struct { float x, y, z, w; };
struct { float r, g, b, a; };
float v[4];
};
-
vec4() {}
explicit vec4(const vec &p, float w = 0) : x(p.x), y(p.y), z(p.z), w(w) {}
vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
explicit vec4(const float *v) : x(v[0]), y(v[1]), z(v[2]), w(v[3]) {}
-
- float &operator[](int i) { return v[i]; }
+ float &operator[](int i) { return v[i]; }
float operator[](int i) const { return v[i]; }
-
template<class T> float dot3(const T &o) const { return x*o.x + y*o.y + z*o.z; }
float dot(const vec4 &o) const { return dot3(o) + w*o.w; }
- float dot(const vec &o) const { return x*o.x + y*o.y + z*o.z + w; }
+ float dot(const vec &o) const { return x*o.x + y*o.y + z*o.z + w; }
float squaredlen() const { return dot(*this); }
- float magnitude() const { return sqrtf(squaredlen()); }
+ float magnitude() const { return sqrtf(squaredlen()); }
float magnitude3() const { return sqrtf(dot3(*this)); }
vec4 &normalize() { mul(1/magnitude()); return *this; }
vec4 &safenormalize() { float m = magnitude(); if(m) mul(1/m); return *this; }
-
- vec4 &lerp(const vec4 &b, float t)
- {
+ vec4 &lerp(const vec4 &b, float t) {
x += (b.x-x)*t;
y += (b.y-y)*t;
z += (b.z-z)*t;
w += (b.w-w)*t;
return *this;
}
- vec4 &lerp(const vec4 &a, const vec4 &b, float t)
- {
+ vec4 &lerp(const vec4 &a, const vec4 &b, float t) {
x = a.x+(b.x-a.x)*t;
y = a.y+(b.y-a.y)*t;
z = a.z+(b.z-a.z)*t;
w = a.w+(b.w-a.w)*t;
return *this;
}
-
- vec4 &mul3(float f) { x *= f; y *= f; z *= f; return *this; }
- vec4 &mul(float f) { mul3(f); w *= f; return *this; }
+ vec4 &mul3(float f) { x *= f; y *= f; z *= f; return *this; }
+ vec4 &mul(float f) { mul3(f); w *= f; return *this; }
vec4 &mul(const vec4 &o) { x *= o.x; y *= o.y; z *= o.z; w *= o.w; return *this; }
- vec4 &square() { mul(*this); return *this; }
- vec4 &div3(float f) { x /= f; y /= f; z /= f; return *this; }
- vec4 &div(float f) { div3(f); w /= f; return *this; }
+ vec4 &square() { mul(*this); return *this; }
+ vec4 &div3(float f) { x /= f; y /= f; z /= f; return *this; }
+ vec4 &div(float f) { div3(f); w /= f; return *this; }
vec4 &div(const vec4 &o) { x /= o.x; y /= o.y; z /= o.z; w /= o.w; return *this; }
vec4 &recip() { x = 1/x; y = 1/y; z = 1/z; w = 1/w; return *this; }
vec4 &add(const vec4 &o) { x += o.x; y += o.y; z += o.z; w += o.w; return *this; }
- vec4 &addw(float f) { w += f; return *this; }
+ vec4 &addw(float f) { w += f; return *this; }
vec4 &sub(const vec4 &o) { x -= o.x; y -= o.y; z -= o.z; w -= o.w; return *this; }
- vec4 &subw(float f) { w -= f; return *this; }
+ vec4 &subw(float f) { w -= f; return *this; }
vec4 &neg3() { x = -x; y = -y; z = -z; return *this; }
- vec4 &neg() { neg3(); w = -w; return *this; }
+ vec4 &neg() { neg3(); w = -w; return *this; }
template<class B> vec4 &madd(const vec4 &a, const B &b) { return add(vec4(a).mul(b)); }
template<class B> vec4 &msub(const vec4 &a, const B &b) { return sub(vec4(a).mul(b)); }
-
void setxyz(const vec &v) { x = v.x; y = v.y; z = v.z; }
-
vec4 &rotate_around_z(float c, float s) { float rx = x, ry = y; x = c*rx-s*ry; y = c*ry+s*rx; return *this; }
vec4 &rotate_around_x(float c, float s) { float ry = y, rz = z; y = c*ry-s*rz; z = c*rz+s*ry; return *this; }
vec4 &rotate_around_y(float c, float s) { float rx = x, rz = z; x = c*rx+s*rz; z = c*rz-s*rx; return *this; }
-
vec4 &rotate_around_z(float angle) { return rotate_around_z(cosf(angle), sinf(angle)); }
vec4 &rotate_around_x(float angle) { return rotate_around_x(cosf(angle), sinf(angle)); }
vec4 &rotate_around_y(float angle) { return rotate_around_y(cosf(angle), sinf(angle)); }
struct matrix4x3;
struct matrix4;
-struct quat : vec4
-{
+struct quat : vec4 {
quat() {}
quat(float x, float y, float z, float w) : vec4(x, y, z, w) {}
- quat(const vec &axis, float angle)
- {
+ quat(const vec &axis, float angle) {
w = cosf(angle/2);
float s = sinf(angle/2);
x = s*axis.x;
y = s*axis.y;
z = s*axis.z;
}
- explicit quat(const vec &v)
- {
+ explicit quat(const vec &v) {
x = v.x;
y = v.y;
z = v.z;
explicit quat(const matrix3 &m) { convertmatrix(m); }
explicit quat(const matrix4x3 &m) { convertmatrix(m); }
explicit quat(const matrix4 &m) { convertmatrix(m); }
-
void restorew() { w = 1.0f-x*x-y*y-z*z; w = w<0 ? 0 : -sqrtf(w); }
-
quat &add(const vec4 &o) { vec4::add(o); return *this; }
quat &sub(const vec4 &o) { vec4::sub(o); return *this; }
quat &mul(float k) { vec4::mul(k); return *this; }
-
- quat &mul(const quat &p, const quat &o)
- {
+ quat &mul(const quat &p, const quat &o) {
x = p.w*o.x + p.x*o.w + p.y*o.z - p.z*o.y;
y = p.w*o.y - p.x*o.z + p.y*o.w + p.z*o.x;
z = p.w*o.z + p.x*o.y - p.y*o.x + p.z*o.w;
return *this;
}
quat &mul(const quat &o) { return mul(quat(*this), o); }
-
quat &invert() { neg3(); return *this; }
-
- void calcangleaxis(float &angle, vec &axis)
- {
+ void calcangleaxis(float &angle, vec &axis) {
float rr = dot3(*this);
- if(rr>0)
- {
+ if(rr>0) {
angle = 2*acosf(w);
axis = vec(x, y, z).mul(1/rr);
}
else { angle = 0; axis = vec(0, 0, 1); }
}
-
- vec rotate(const vec &v) const
- {
+ vec rotate(const vec &v) const {
return vec().cross(*this, vec().cross(*this, v).add(vec(v).mul(w))).mul(2).add(v);
}
-
- vec invertedrotate(const vec &v) const
- {
+ vec invertedrotate(const vec &v) const {
return vec().cross(*this, vec().cross(*this, v).sub(vec(v).mul(w))).mul(2).add(v);
}
-
template<class M>
- void convertmatrix(const M &m)
- {
+ void convertmatrix(const M &m) {
float trace = m.a.x + m.b.y + m.c.z;
- if(trace>0)
- {
+ if(trace>0) {
float r = sqrtf(1 + trace), inv = 0.5f/r;
w = 0.5f*r;
x = (m.b.z - m.c.y)*inv;
y = (m.c.x - m.a.z)*inv;
z = (m.a.y - m.b.x)*inv;
}
- else if(m.a.x > m.b.y && m.a.x > m.c.z)
- {
+ else if(m.a.x > m.b.y && m.a.x > m.c.z) {
float r = sqrtf(1 + m.a.x - m.b.y - m.c.z), inv = 0.5f/r;
x = 0.5f*r;
y = (m.a.y + m.b.x)*inv;
z = (m.c.x + m.a.z)*inv;
w = (m.b.z - m.c.y)*inv;
}
- else if(m.b.y > m.c.z)
- {
+ else if(m.b.y > m.c.z) {
float r = sqrtf(1 + m.b.y - m.a.x - m.c.z), inv = 0.5f/r;
x = (m.a.y + m.b.x)*inv;
y = 0.5f*r;
z = (m.b.z + m.c.y)*inv;
w = (m.c.x - m.a.z)*inv;
}
- else
- {
+ else {
float r = sqrtf(1 + m.c.z - m.a.x - m.b.y), inv = 0.5f/r;
x = (m.c.x + m.a.z)*inv;
y = (m.b.z + m.c.y)*inv;
}
};
-struct dualquat
-{
+struct dualquat {
quat real, dual;
-
dualquat() {}
dualquat(const quat &q, const vec &p)
: real(q),
dual(0.5f*( p.x*q.w + p.y*q.z - p.z*q.y),
0.5f*(-p.x*q.z + p.y*q.w + p.z*q.x),
0.5f*( p.x*q.y - p.y*q.x + p.z*q.w),
- -0.5f*( p.x*q.x + p.y*q.y + p.z*q.z))
- {
+ -0.5f*( p.x*q.x + p.y*q.y + p.z*q.z)) {
}
explicit dualquat(const quat &q) : real(q), dual(0, 0, 0, 0) {}
explicit dualquat(const matrix4x3 &m);
-
dualquat &mul(float k) { real.mul(k); dual.mul(k); return *this; }
dualquat &add(const dualquat &d) { real.add(d.real); dual.add(d.dual); return *this; }
-
- dualquat &lerp(const dualquat &to, float t)
- {
+ dualquat &lerp(const dualquat &to, float t) {
float k = real.dot(to.real) < 0 ? -t : t;
real.mul(1-t).add(vec4(to.real).mul(k));
dual.mul(1-t).add(vec4(to.dual).mul(k));
return *this;
}
- dualquat &lerp(const dualquat &from, const dualquat &to, float t)
- {
+ dualquat &lerp(const dualquat &from, const dualquat &to, float t) {
float k = from.real.dot(to.real) < 0 ? -t : t;
(real = from.real).mul(1-t).add(vec4(to.real).mul(k));
(dual = from.dual).mul(1-t).add(vec4(to.dual).mul(k));
return *this;
}
-
- dualquat &invert()
- {
+ dualquat &invert() {
real.invert();
dual.invert();
dual.sub(quat(real).mul(2*real.dot(dual)));
return *this;
}
-
- void mul(const dualquat &p, const dualquat &o)
- {
+ void mul(const dualquat &p, const dualquat &o) {
real.mul(p.real, o.real);
dual.mul(p.real, o.dual).add(quat().mul(p.dual, o.real));
}
void mul(const dualquat &o) { mul(dualquat(*this), o); }
-
- void mulorient(const quat &q)
- {
+ void mulorient(const quat &q) {
real.mul(q, quat(real));
dual.mul(quat(q).invert(), quat(dual));
}
-
- void mulorient(const quat &q, const dualquat &base)
- {
+ void mulorient(const quat &q, const dualquat &base) {
quat trans;
trans.mul(base.dual, quat(base.real).invert());
dual.mul(quat(q).invert(), quat(real).mul(trans).add(dual));
-
real.mul(q, quat(real));
dual.add(quat().mul(real, trans.invert())).sub(quat(real).mul(2*base.real.dot(base.dual)));
}
-
- void normalize()
- {
+ void normalize() {
float invlen = 1/real.magnitude();
real.mul(invlen);
dual.mul(invlen);
}
-
- void translate(const vec &p)
- {
+ void translate(const vec &p) {
dual.x += 0.5f*( p.x*real.w + p.y*real.z - p.z*real.y);
dual.y += 0.5f*(-p.x*real.z + p.y*real.w + p.z*real.x);
dual.z += 0.5f*( p.x*real.y - p.y*real.x + p.z*real.w);
dual.w += -0.5f*( p.x*real.x + p.y*real.y + p.z*real.z);
}
-
- void scale(float k)
- {
+ void scale(float k) {
dual.mul(k);
}
-
- void fixantipodal(const dualquat &d)
- {
- if(real.dot(d.real) < 0)
- {
+ void fixantipodal(const dualquat &d) {
+ if(real.dot(d.real) < 0) {
real.neg();
dual.neg();
}
}
-
- void accumulate(const dualquat &d, float k)
- {
+ void accumulate(const dualquat &d, float k) {
if(real.dot(d.real) < 0) k = -k;
real.add(vec4(d.real).mul(k));
dual.add(vec4(d.dual).mul(k));
}
-
- vec transform(const vec &v) const
- {
+ vec transform(const vec &v) const {
return vec().cross(real, vec().cross(real, v).add(vec(v).mul(real.w)).add(vec(dual))).add(vec(dual).mul(real.w)).sub(vec(real).mul(dual.w)).mul(2).add(v);
}
-
- quat transform(const quat &q) const
- {
+ quat transform(const quat &q) const {
return quat().mul(real, q);
}
-
- vec transposedtransform(const vec &v) const
- {
+ vec transposedtransform(const vec &v) const {
return dualquat(*this).invert().transform(v);
}
-
- vec transformnormal(const vec &v) const
- {
+ vec transformnormal(const vec &v) const {
return real.rotate(v);
}
-
- vec transposedtransformnormal(const vec &v) const
- {
+ vec transposedtransformnormal(const vec &v) const {
return real.invertedrotate(v);
}
-
- vec gettranslation() const
- {
+ vec gettranslation() const {
return vec().cross(real, dual).add(vec(dual).mul(real.w)).sub(vec(real).mul(dual.w)).mul(2);
}
};
-struct matrix3
-{
+struct matrix3 {
vec a, b, c;
-
matrix3() {}
matrix3(const vec &a, const vec &b, const vec &c) : a(a), b(b), c(c) {}
explicit matrix3(float angle, const vec &axis) { rotate(angle, axis); }
- explicit matrix3(const quat &q)
- {
+ explicit matrix3(const quat &q) {
float x = q.x, y = q.y, z = q.z, w = q.w,
tx = 2*x, ty = 2*y, tz = 2*z,
txx = tx*x, tyy = ty*y, tzz = tz*z,
}
explicit matrix3(const matrix4x3 &m);
explicit matrix3(const matrix4 &m);
-
- void mul(const matrix3 &m, const matrix3 &n)
- {
+ void mul(const matrix3 &m, const matrix3 &n) {
a = vec(m.a).mul(n.a.x).madd(m.b, n.a.y).madd(m.c, n.a.z);
b = vec(m.a).mul(n.b.x).madd(m.b, n.b.y).madd(m.c, n.b.z);
c = vec(m.a).mul(n.c.x).madd(m.b, n.c.y).madd(m.c, n.c.z);
}
void mul(const matrix3 &n) { mul(matrix3(*this), n); }
-
- void multranspose(const matrix3 &m, const matrix3 &n)
- {
+ void multranspose(const matrix3 &m, const matrix3 &n) {
a = vec(m.a).mul(n.a.x).madd(m.b, n.b.x).madd(m.c, n.c.x);
b = vec(m.a).mul(n.a.y).madd(m.b, n.b.y).madd(m.c, n.c.y);
c = vec(m.a).mul(n.a.z).madd(m.b, n.b.z).madd(m.c, n.c.z);
}
void multranspose(const matrix3 &n) { multranspose(matrix3(*this), n); }
-
- void transposemul(const matrix3 &m, const matrix3 &n)
- {
+ void transposemul(const matrix3 &m, const matrix3 &n) {
a = vec(m.a.dot(n.a), m.b.dot(n.a), m.c.dot(n.a));
b = vec(m.a.dot(n.b), m.b.dot(n.b), m.c.dot(n.b));
c = vec(m.a.dot(n.c), m.b.dot(n.c), m.c.dot(n.c));
}
void transposemul(const matrix3 &n) { transposemul(matrix3(*this), n); }
-
- void transpose()
- {
+ void transpose() {
swap(a.y, b.x); swap(a.z, c.x);
swap(b.z, c.y);
}
-
template<class M>
- void transpose(const M &m)
- {
+ void transpose(const M &m) {
a = vec(m.a.x, m.b.x, m.c.x);
b = vec(m.a.y, m.b.y, m.c.y);
c = vec(m.a.z, m.b.z, m.c.z);
}
-
- void invert(const matrix3 &o)
- {
+ void invert(const matrix3 &o) {
vec unscale(1/o.a.squaredlen(), 1/o.b.squaredlen(), 1/o.c.squaredlen());
transpose(o);
a.mul(unscale);
c.mul(unscale);
}
void invert() { invert(matrix3(*this)); }
-
- void normalize()
- {
+ void normalize() {
a.normalize();
b.normalize();
c.normalize();
}
-
- void scale(float k)
- {
+ void scale(float k) {
a.mul(k);
b.mul(k);
c.mul(k);
}
-
- void rotate(float angle, const vec &axis)
- {
+ void rotate(float angle, const vec &axis) {
rotate(cosf(angle), sinf(angle), axis);
}
-
- void rotate(float ck, float sk, const vec &axis)
- {
+ void rotate(float ck, float sk, const vec &axis) {
a = vec(axis.x*axis.x*(1-ck)+ck, axis.x*axis.y*(1-ck)+axis.z*sk, axis.x*axis.z*(1-ck)-axis.y*sk);
b = vec(axis.x*axis.y*(1-ck)-axis.z*sk, axis.y*axis.y*(1-ck)+ck, axis.y*axis.z*(1-ck)+axis.x*sk);
c = vec(axis.x*axis.z*(1-ck)+axis.y*sk, axis.y*axis.z*(1-ck)-axis.x*sk, axis.z*axis.z*(1-ck)+ck);
}
-
- void setyaw(float ck, float sk)
- {
+ void setyaw(float ck, float sk) {
a = vec(ck, sk, 0);
b = vec(-sk, ck, 0);
c = vec(0, 0, 1);
}
-
- void setyaw(float angle)
- {
+ void setyaw(float angle) {
setyaw(cosf(angle), sinf(angle));
}
-
float trace() const { return a.x + b.y + c.z; }
-
- bool calcangleaxis(float tr, float &angle, vec &axis, float threshold = 1e-16f) const
- {
- if(tr <= -1)
- {
- if(a.x >= b.y && a.x >= c.z)
- {
+ bool calcangleaxis(float tr, float &angle, vec &axis, float threshold = 1e-16f) const {
+ if(tr <= -1) {
+ if(a.x >= b.y && a.x >= c.z) {
float r = 1 + a.x - b.y - c.z;
if(r <= threshold) return false;
r = sqrtf(r);
axis.y = b.x/r;
axis.z = c.x/r;
}
- else if(b.y >= c.z)
- {
+ else if(b.y >= c.z) {
float r = 1 + b.y - a.x - c.z;
if(r <= threshold) return false;
r = sqrtf(r);
axis.x = b.x/r;
axis.z = c.y/r;
}
- else
- {
+ else {
float r = 1 + b.y - a.x - c.z;
if(r <= threshold) return false;
r = sqrtf(r);
}
angle = M_PI;
}
- else if(tr >= 3)
- {
+ else if(tr >= 3) {
axis = vec(0, 0, 1);
angle = 0;
}
- else
- {
+ else {
axis = vec(b.z - c.y, c.x - a.z, a.y - b.x);
float r = axis.squaredlen();
if(r <= threshold) return false;
}
return true;
}
-
bool calcangleaxis(float &angle, vec &axis, float threshold = 1e-16f) const { return calcangleaxis(trace(), angle, axis, threshold); }
-
- vec transform(const vec &o) const
- {
+ vec transform(const vec &o) const {
return vec(a).mul(o.x).madd(b, o.y).madd(c, o.z);
}
vec transposedtransform(const vec &o) const { return vec(a.dot(o), b.dot(o), c.dot(o)); }
- vec abstransform(const vec &o) const
- {
+ vec abstransform(const vec &o) const {
return vec(a).mul(o.x).abs().add(vec(b).mul(o.y).abs()).add(vec(c).mul(o.z).abs());
}
- vec abstransposedtransform(const vec &o) const
- {
+ vec abstransposedtransform(const vec &o) const {
return vec(a.absdot(o), b.absdot(o), c.absdot(o));
}
-
- void identity()
- {
+ void identity() {
a = vec(1, 0, 0);
b = vec(0, 1, 0);
c = vec(0, 0, 1);
}
-
- void rotate_around_x(float ck, float sk)
- {
+ void rotate_around_x(float ck, float sk) {
vec rb = vec(b).mul(ck).madd(c, sk),
rc = vec(c).mul(ck).msub(b, sk);
b = rb;
}
void rotate_around_x(float angle) { rotate_around_x(cosf(angle), sinf(angle)); }
void rotate_around_x(const vec2 &sc) { rotate_around_x(sc.x, sc.y); }
-
- void rotate_around_y(float ck, float sk)
- {
+ void rotate_around_y(float ck, float sk) {
vec rc = vec(c).mul(ck).madd(a, sk),
ra = vec(a).mul(ck).msub(c, sk);
c = rc;
}
void rotate_around_y(float angle) { rotate_around_y(cosf(angle), sinf(angle)); }
void rotate_around_y(const vec2 &sc) { rotate_around_y(sc.x, sc.y); }
-
- void rotate_around_z(float ck, float sk)
- {
+ void rotate_around_z(float ck, float sk) {
vec ra = vec(a).mul(ck).madd(b, sk),
rb = vec(b).mul(ck).msub(a, sk);
a = ra;
}
void rotate_around_z(float angle) { rotate_around_z(cosf(angle), sinf(angle)); }
void rotate_around_z(const vec2 &sc) { rotate_around_z(sc.x, sc.y); }
-
vec transform(const vec2 &o) { return vec(a).mul(o.x).madd(b, o.y); }
vec transposedtransform(const vec2 &o) const { return vec(a.dot2(o), b.dot2(o), c.dot2(o)); }
-
vec rowx() const { return vec(a.x, b.x, c.x); }
vec rowy() const { return vec(a.y, b.y, c.y); }
vec rowz() const { return vec(a.z, b.z, c.z); }
};
-struct matrix4x3
-{
+struct matrix4x3 {
vec a, b, c, d;
-
matrix4x3() {}
matrix4x3(const vec &a, const vec &b, const vec &c, const vec &d) : a(a), b(b), c(c), d(d) {}
matrix4x3(const matrix3 &rot, const vec &trans) : a(rot.a), b(rot.b), c(rot.c), d(trans) {}
- matrix4x3(const dualquat &dq)
- {
+ matrix4x3(const dualquat &dq) {
vec4 r = vec4(dq.real).mul(1/dq.real.squaredlen()), rr = vec4(r).mul(dq.real);
r.mul(2);
float xy = r.x*dq.real.y, xz = r.x*dq.real.z, yz = r.y*dq.real.z,
d = vec(-(dq.dual.w*r.x - dq.dual.x*r.w + dq.dual.y*r.z - dq.dual.z*r.y),
-(dq.dual.w*r.y - dq.dual.x*r.z - dq.dual.y*r.w + dq.dual.z*r.x),
-(dq.dual.w*r.z + dq.dual.x*r.y - dq.dual.y*r.x - dq.dual.z*r.w));
-
}
explicit matrix4x3(const matrix4 &m);
-
- void mul(float k)
- {
+ void mul(float k) {
a.mul(k);
b.mul(k);
c.mul(k);
d.mul(k);
}
-
void setscale(float x, float y, float z) { a.x = x; b.y = y; c.z = z; }
void setscale(const vec &v) { setscale(v.x, v.y, v.z); }
void setscale(float n) { setscale(n, n, n); }
-
- void scale(float x, float y, float z)
- {
+ void scale(float x, float y, float z) {
a.mul(x);
b.mul(y);
c.mul(z);
}
void scale(const vec &v) { scale(v.x, v.y, v.z); }
void scale(float n) { scale(n, n, n); }
-
void settranslation(const vec &p) { d = p; }
void settranslation(float x, float y, float z) { d = vec(x, y, z); }
-
void translate(const vec &p) { d.madd(a, p.x).madd(b, p.y).madd(c, p.z); }
void translate(float x, float y, float z) { translate(vec(x, y, z)); }
void translate(const vec &p, float scale) { translate(vec(p).mul(scale)); }
-
void posttranslate(const vec &p) { d.add(p); }
void posttranslate(float x, float y, float z) { posttranslate(vec(x, y, z)); }
void posttranslate(const vec &p, float scale) { d.madd(p, scale); }
-
- void accumulate(const matrix4x3 &m, float k)
- {
+ void accumulate(const matrix4x3 &m, float k) {
a.madd(m.a, k);
b.madd(m.b, k);
c.madd(m.c, k);
d.madd(m.d, k);
}
-
- void normalize()
- {
+ void normalize() {
a.normalize();
b.normalize();
c.normalize();
}
-
- void lerp(const matrix4x3 &to, float t)
- {
+ void lerp(const matrix4x3 &to, float t) {
a.lerp(to.a, t);
b.lerp(to.b, t);
c.lerp(to.c, t);
d.lerp(to.d, t);
}
- void lerp(const matrix4x3 &from, const matrix4x3 &to, float t)
- {
+ void lerp(const matrix4x3 &from, const matrix4x3 &to, float t) {
a.lerp(from.a, to.a, t);
b.lerp(from.b, to.b, t);
c.lerp(from.c, to.c, t);
d.lerp(from.d, to.d, t);
}
-
- void identity()
- {
+ void identity() {
a = vec(1, 0, 0);
b = vec(0, 1, 0);
c = vec(0, 0, 1);
d = vec(0, 0, 0);
}
-
- void mul(const matrix4x3 &m, const matrix4x3 &n)
- {
+ void mul(const matrix4x3 &m, const matrix4x3 &n) {
a = vec(m.a).mul(n.a.x).madd(m.b, n.a.y).madd(m.c, n.a.z);
b = vec(m.a).mul(n.b.x).madd(m.b, n.b.y).madd(m.c, n.b.z);
c = vec(m.a).mul(n.c.x).madd(m.b, n.c.y).madd(m.c, n.c.z);
d = vec(m.d).madd(m.a, n.d.x).madd(m.b, n.d.y).madd(m.c, n.d.z);
}
void mul(const matrix4x3 &n) { mul(matrix4x3(*this), n); }
-
- void mul(const matrix3 &m, const matrix4x3 &n)
- {
+ void mul(const matrix3 &m, const matrix4x3 &n) {
a = vec(m.a).mul(n.a.x).madd(m.b, n.a.y).madd(m.c, n.a.z);
b = vec(m.a).mul(n.b.x).madd(m.b, n.b.y).madd(m.c, n.b.z);
c = vec(m.a).mul(n.c.x).madd(m.b, n.c.y).madd(m.c, n.c.z);
d = vec(m.a).mul(n.d.x).madd(m.b, n.d.y).madd(m.c, n.d.z);
}
-
- void mul(const matrix3 &rot, const vec &trans, const matrix4x3 &n)
- {
+ void mul(const matrix3 &rot, const vec &trans, const matrix4x3 &n) {
mul(rot, n);
d.add(trans);
}
-
- void transpose()
- {
+ void transpose() {
d = vec(a.dot(d), b.dot(d), c.dot(d)).neg();
swap(a.y, b.x); swap(a.z, c.x);
swap(b.z, c.y);
}
-
- void transpose(const matrix4x3 &o)
- {
+ void transpose(const matrix4x3 &o) {
a = vec(o.a.x, o.b.x, o.c.x);
b = vec(o.a.y, o.b.y, o.c.y);
c = vec(o.a.z, o.b.z, o.c.z);
d = vec(o.a.dot(o.d), o.b.dot(o.d), o.c.dot(o.d)).neg();
}
-
- void transposemul(const matrix4x3 &m, const matrix4x3 &n)
- {
+ void transposemul(const matrix4x3 &m, const matrix4x3 &n) {
vec t(m.a.dot(m.d), m.b.dot(m.d), m.c.dot(m.d));
a = vec(m.a.dot(n.a), m.b.dot(n.a), m.c.dot(n.a));
b = vec(m.a.dot(n.b), m.b.dot(n.b), m.c.dot(n.b));
c = vec(m.a.dot(n.c), m.b.dot(n.c), m.c.dot(n.c));
d = vec(m.a.dot(n.d), m.b.dot(n.d), m.c.dot(n.d)).sub(t);
}
-
- void multranspose(const matrix4x3 &m, const matrix4x3 &n)
- {
+ void multranspose(const matrix4x3 &m, const matrix4x3 &n) {
vec t(n.a.dot(n.d), n.b.dot(n.d), n.c.dot(n.d));
a = vec(m.a).mul(n.a.x).madd(m.b, n.b.x).madd(m.c, n.c.x);
b = vec(m.a).mul(n.a.y).madd(m.b, n.b.y).madd(m.c, n.c.y);
c = vec(m.a).mul(n.a.z).madd(m.b, n.b.z).madd(m.c, n.c.z);
d = vec(m.d).msub(m.a, t.x).msub(m.b, t.y).msub(m.c, t.z);
}
-
- void invert(const matrix4x3 &o)
- {
+ void invert(const matrix4x3 &o) {
vec unscale(1/o.a.squaredlen(), 1/o.b.squaredlen(), 1/o.c.squaredlen());
transpose(o);
a.mul(unscale);
d.mul(unscale);
}
void invert() { invert(matrix4x3(*this)); }
-
- void rotate(float angle, const vec &d)
- {
+ void rotate(float angle, const vec &d) {
rotate(cosf(angle), sinf(angle), d);
}
-
- void rotate(float ck, float sk, const vec &axis)
- {
+ void rotate(float ck, float sk, const vec &axis) {
matrix3 m;
m.rotate(ck, sk, axis);
*this = matrix4x3(m, vec(0, 0, 0));
}
-
- void rotate_around_x(float ck, float sk)
- {
+ void rotate_around_x(float ck, float sk) {
vec rb = vec(b).mul(ck).madd(c, sk),
rc = vec(c).mul(ck).msub(b, sk);
b = rb;
}
void rotate_around_x(float angle) { rotate_around_x(cosf(angle), sinf(angle)); }
void rotate_around_x(const vec2 &sc) { rotate_around_x(sc.x, sc.y); }
-
- void rotate_around_y(float ck, float sk)
- {
+ void rotate_around_y(float ck, float sk) {
vec rc = vec(c).mul(ck).madd(a, sk),
ra = vec(a).mul(ck).msub(c, sk);
c = rc;
}
void rotate_around_y(float angle) { rotate_around_y(cosf(angle), sinf(angle)); }
void rotate_around_y(const vec2 &sc) { rotate_around_y(sc.x, sc.y); }
-
- void rotate_around_z(float ck, float sk)
- {
+ void rotate_around_z(float ck, float sk) {
vec ra = vec(a).mul(ck).madd(b, sk),
rb = vec(b).mul(ck).msub(a, sk);
a = ra;
}
void rotate_around_z(float angle) { rotate_around_z(cosf(angle), sinf(angle)); }
void rotate_around_z(const vec2 &sc) { rotate_around_z(sc.x, sc.y); }
-
vec transform(const vec &o) const { return vec(d).madd(a, o.x).madd(b, o.y).madd(c, o.z); }
vec transposedtransform(const vec &o) const { vec p = vec(o).sub(d); return vec(a.dot(p), b.dot(p), c.dot(p)); }
vec transformnormal(const vec &o) const { return vec(a).mul(o.x).madd(b, o.y).madd(c, o.z); }
vec transposedtransformnormal(const vec &o) const { return vec(a.dot(o), b.dot(o), c.dot(o)); }
vec transform(const vec2 &o) const { return vec(d).madd(a, o.x).madd(b, o.y); }
-
vec4 rowx() const { return vec4(a.x, b.x, c.x, d.x); }
vec4 rowy() const { return vec4(a.y, b.y, c.y, d.y); }
vec4 rowz() const { return vec4(a.z, b.z, c.z, d.z); }
};
-inline dualquat::dualquat(const matrix4x3 &m) : real(m)
-{
+inline dualquat::dualquat(const matrix4x3 &m) : real(m) {
dual.x = 0.5f*( m.d.x*real.w + m.d.y*real.z - m.d.z*real.y);
dual.y = 0.5f*(-m.d.x*real.z + m.d.y*real.w + m.d.z*real.x);
dual.z = 0.5f*( m.d.x*real.y - m.d.y*real.x + m.d.z*real.w);
inline matrix3::matrix3(const matrix4x3 &m) : a(m.a), b(m.b), c(m.c) {}
-struct plane : vec
-{
+struct plane : vec {
float offset;
-
float dist(const vec &p) const { return dot(p)+offset; }
float dist(const vec4 &p) const { return p.dot3(*this) + p.w*offset; }
bool operator==(const plane &p) const { return x==p.x && y==p.y && z==p.z && offset==p.offset; }
bool operator!=(const plane &p) const { return x!=p.x || y!=p.y || z!=p.z || offset!=p.offset; }
-
plane() {}
plane(const vec &c, float off) : vec(c), offset(off) {}
plane(const vec4 &p) : vec(p), offset(p.w) {}
- plane(int d, float off)
- {
+ plane(int d, float off) {
x = y = z = 0.0f;
v[d] = 1.0f;
offset = -off;
}
plane(float a, float b, float c, float d) : vec(a, b, c), offset(d) {}
-
- void toplane(const vec &n, const vec &p)
- {
+ void toplane(const vec &n, const vec &p) {
x = n.x; y = n.y; z = n.z;
offset = -dot(p);
}
-
- bool toplane(const vec &a, const vec &b, const vec &c)
- {
+ bool toplane(const vec &a, const vec &b, const vec &c) {
cross(vec(b).sub(a), vec(c).sub(a));
float mag = magnitude();
if(!mag) return false;
offset = -dot(a);
return true;
}
-
- bool rayintersect(const vec &o, const vec &ray, float &dist)
- {
+ bool rayintersect(const vec &o, const vec &ray, float &dist) {
float cosalpha = dot(ray);
if(cosalpha==0) return false;
float deltac = offset+dot(o);
dist -= deltac/cosalpha;
return true;
}
-
- plane &reflectz(float rz)
- {
+ plane &reflectz(float rz) {
offset += 2*rz*z;
z = -z;
return *this;
}
-
- plane &invert()
- {
+ plane &invert() {
neg();
offset = -offset;
return *this;
}
-
- plane &scale(float k)
- {
+ plane &scale(float k) {
mul(k);
return *this;
}
-
- plane &translate(const vec &p)
- {
+ plane &translate(const vec &p) {
offset += dot(p);
return *this;
}
-
- plane &normalize()
- {
+ plane &normalize() {
float mag = magnitude();
div(mag);
offset /= mag;
return *this;
}
-
float zintersect(const vec &p) const { return -(x*p.x+y*p.y+offset)/z; }
float zdelta(const vec &p) const { return -(x*p.x+y*p.y)/z; }
float zdist(const vec &p) const { return p.z-zintersect(p); }
};
-struct triangle
-{
+struct triangle {
vec a, b, c;
-
triangle(const vec &a, const vec &b, const vec &c) : a(a), b(b), c(c) {}
triangle() {}
-
triangle &add(const vec &o) { a.add(o); b.add(o); c.add(o); return *this; }
triangle &sub(const vec &o) { a.sub(o); b.sub(o); c.sub(o); return *this; }
-
bool operator==(const triangle &t) const { return a == t.a && b == t.b && c == t.c; }
};
struct usvec;
struct svec;
-struct ivec
-{
- union
- {
+struct ivec {
+ union {
struct { int x, y, z; };
struct { int r, g, b; };
int v[3];
};
-
ivec() {}
explicit ivec(const vec &v) : x(int(v.x)), y(int(v.y)), z(int(v.z)) {}
ivec(int a, int b, int c) : x(a), y(b), z(c) {}
- ivec(int d, int row, int col, int depth)
- {
+ ivec(int d, int row, int col, int depth) {
v[R[d]] = row;
v[C[d]] = col;
v[D[d]] = depth;
explicit ivec(const ivec2 &v, int z = 0);
explicit ivec(const usvec &v);
explicit ivec(const svec &v);
-
- int &operator[](int i) { return v[i]; }
+ int &operator[](int i) { return v[i]; }
int operator[](int i) const { return v[i]; }
-
//int idx(int i) { return v[i]; }
bool operator==(const ivec &v) const { return x==v.x && y==v.y && z==v.z; }
bool operator!=(const ivec &v) const { return x!=v.x || y!=v.y || z!=v.z; }
ivec &cross(const ivec &a, const ivec &b) { x = a.y*b.z-a.z*b.y; y = a.z*b.x-a.x*b.z; z = a.x*b.y-a.y*b.x; return *this; }
int dot(const ivec &o) const { return x*o.x + y*o.y + z*o.z; }
float dist(const plane &p) const { return x*p.x + y*p.y + z*p.z + p.offset; }
-
static inline ivec floor(const vec &o) { return ivec(int(::floor(o.x)), int(::floor(o.y)), int(::floor(o.z))); }
static inline ivec ceil(const vec &o) { return ivec(int(::ceil(o.x)), int(::ceil(o.y)), int(::ceil(o.z))); }
};
inline vec::vec(const ivec &v) : x(v.x), y(v.y), z(v.z) {}
-static inline bool htcmp(const ivec &x, const ivec &y)
-{
+static inline bool htcmp(const ivec &x, const ivec &y) {
return x == y;
}
-static inline uint hthash(const ivec &k)
-{
+static inline uint hthash(const ivec &k) {
return k.x^k.y^k.z;
}
-struct ivec2
-{
- union
- {
+struct ivec2 {
+ union {
struct { int x, y; };
int v[2];
};
-
ivec2() {}
ivec2(int x, int y) : x(x), y(y) {}
explicit ivec2(const vec2 &v) : x(int(v.x)), y(int(v.y)) {}
explicit ivec2(const ivec &v) : x(v.x), y(v.y) {}
-
- int &operator[](int i) { return v[i]; }
+ int &operator[](int i) { return v[i]; }
int operator[](int i) const { return v[i]; }
-
bool operator==(const ivec2 &o) const { return x == o.x && y == o.y; }
bool operator!=(const ivec2 &o) const { return x != o.x || y != o.y; }
-
bool iszero() const { return x==0 && y==0; }
ivec2 &shl(int n) { x<<= n; y<<= n; return *this; }
ivec2 &shr(int n) { x>>= n; y>>= n; return *this; }
inline ivec::ivec(const ivec2 &v, int z) : x(v.x), y(v.y), z(z) {}
-static inline bool htcmp(const ivec2 &x, const ivec2 &y)
-{
+static inline bool htcmp(const ivec2 &x, const ivec2 &y) {
return x == y;
}
-static inline uint hthash(const ivec2 &k)
-{
+static inline uint hthash(const ivec2 &k) {
return k.x^k.y;
}
-struct ivec4
-{
- union
- {
+struct ivec4 {
+ union {
struct { int x, y, z, w; };
struct { int r, g, b, a; };
int v[4];
};
-
ivec4() {}
explicit ivec4(const ivec &p, int w = 0) : x(p.x), y(p.y), z(p.z), w(w) {}
ivec4(int x, int y, int z, int w) : x(x), y(y), z(z), w(w) {}
explicit ivec4(const vec4 &v) : x(int(v.x)), y(int(v.y)), z(int(v.z)), w(int(v.w)) {}
-
bool operator==(const ivec4 &o) const { return x == o.x && y == o.y && z == o.z && w == o.w; }
bool operator!=(const ivec4 &o) const { return x != o.x || y != o.y || z != o.z || w != o.w; }
};
inline ivec::ivec(const ivec4 &v) : x(v.x), y(v.y), z(v.z) {}
-static inline bool htcmp(const ivec4 &x, const ivec4 &y)
-{
+static inline bool htcmp(const ivec4 &x, const ivec4 &y) {
return x == y;
}
-static inline uint hthash(const ivec4 &k)
-{
+static inline uint hthash(const ivec4 &k) {
return k.x^k.y^k.z^k.w;
}
struct bvec4;
-struct bvec
-{
- union
- {
+struct bvec {
+ union {
struct { uchar x, y, z; };
struct { uchar r, g, b; };
uchar v[3];
};
-
bvec() {}
bvec(uchar x, uchar y, uchar z) : x(x), y(y), z(z) {}
explicit bvec(const vec &v) : x(uchar((v.x+1)*(255.0f/2.0f))), y(uchar((v.y+1)*(255.0f/2.0f))), z(uchar((v.z+1)*(255.0f/2.0f))) {}
explicit bvec(const bvec4 &v);
-
- uchar &operator[](int i) { return v[i]; }
+ uchar &operator[](int i) { return v[i]; }
uchar operator[](int i) const { return v[i]; }
-
bool operator==(const bvec &v) const { return x==v.x && y==v.y && z==v.z; }
bool operator!=(const bvec &v) const { return x!=v.x || y!=v.y || z!=v.z; }
-
bool iszero() const { return x==0 && y==0 && z==0; }
-
vec tonormal() const { return vec(x*(2.0f/255.0f)-1.0f, y*(2.0f/255.0f)-1.0f, z*(2.0f/255.0f)-1.0f); }
-
- bvec &normalize()
- {
+ bvec &normalize() {
vec n(x-127.5f, y-127.5f, z-127.5f);
float mag = 127.5f/n.magnitude();
x = uchar(n.x*mag+127.5f);
z = uchar(n.z*mag+127.5f);
return *this;
}
-
void lerp(const bvec &a, const bvec &b, float t) { x = uchar(a.x + (b.x-a.x)*t); y = uchar(a.y + (b.y-a.y)*t); z = uchar(a.z + (b.z-a.z)*t); }
-
- void lerp(const bvec &a, const bvec &b, int ka, int kb, int d)
- {
+ void lerp(const bvec &a, const bvec &b, int ka, int kb, int d) {
x = uchar((a.x*ka + b.x*kb)/d);
y = uchar((a.y*ka + b.y*kb)/d);
z = uchar((a.z*ka + b.z*kb)/d);
}
-
void flip() { x ^= 0x80; y ^= 0x80; z ^= 0x80; }
-
void scale(int k, int d) { x = uchar((x*k)/d); y = uchar((y*k)/d); z = uchar((z*k)/d); }
-
bvec &shl(int n) { x<<= n; y<<= n; z<<= n; return *this; }
bvec &shr(int n) { x>>= n; y>>= n; z>>= n; return *this; }
-
static bvec fromcolor(const vec &v) { return bvec(uchar(v.x*255.0f), uchar(v.y*255.0f), uchar(v.z*255.0f)); }
vec tocolor() const { return vec(x*(1.0f/255.0f), y*(1.0f/255.0f), z*(1.0f/255.0f)); }
-
static bvec from565(ushort c) { return bvec((((c>>11)&0x1F)*527 + 15) >> 6, (((c>>5)&0x3F)*259 + 35) >> 6, ((c&0x1F)*527 + 15) >> 6); }
-
- static bvec hexcolor(int color)
- {
+ static bvec hexcolor(int color) {
return bvec((color>>16)&0xFF, (color>>8)&0xFF, color&0xFF);
}
int tohexcolor() const { return (int(r)<<16)|(int(g)<<8)|int(b); }
};
-struct bvec4
-{
- union
- {
+struct bvec4 {
+ union {
struct { uchar x, y, z, w; };
struct { uchar r, g, b, a; };
uchar v[4];
uint mask;
};
-
bvec4() {}
bvec4(uchar x, uchar y, uchar z, uchar w = 0) : x(x), y(y), z(z), w(w) {}
bvec4(const bvec &v, uchar w = 0) : x(v.x), y(v.y), z(v.z), w(w) {}
-
- uchar &operator[](int i) { return v[i]; }
+ uchar &operator[](int i) { return v[i]; }
uchar operator[](int i) const { return v[i]; }
-
bool operator==(const bvec4 &v) const { return mask==v.mask; }
bool operator!=(const bvec4 &v) const { return mask!=v.mask; }
-
bool iszero() const { return mask==0; }
-
vec tonormal() const { return vec(x*(2.0f/255.0f)-1.0f, y*(2.0f/255.0f)-1.0f, z*(2.0f/255.0f)-1.0f); }
-
- void lerp(const bvec4 &a, const bvec4 &b, float t)
- {
+ void lerp(const bvec4 &a, const bvec4 &b, float t) {
x = uchar(a.x + (b.x-a.x)*t);
y = uchar(a.y + (b.y-a.y)*t);
z = uchar(a.z + (b.z-a.z)*t);
w = a.w;
}
-
- void lerp(const bvec4 &a, const bvec4 &b, int ka, int kb, int d)
- {
+ void lerp(const bvec4 &a, const bvec4 &b, int ka, int kb, int d) {
x = uchar((a.x*ka + b.x*kb)/d);
y = uchar((a.y*ka + b.y*kb)/d);
z = uchar((a.z*ka + b.z*kb)/d);
w = a.w;
}
-
void flip() { mask ^= 0x80808080; }
};
inline bvec::bvec(const bvec4 &v) : x(v.x), y(v.y), z(v.z) {}
-struct usvec
-{
- union
- {
+struct usvec {
+ union {
struct { ushort x, y, z; };
ushort v[3];
};
-
ushort &operator[](int i) { return v[i]; }
ushort operator[](int i) const { return v[i]; }
};
inline ivec::ivec(const usvec &v) : x(v.x), y(v.y), z(v.z) {}
-struct svec
-{
- union
- {
+struct svec {
+ union {
struct { short x, y, z; };
short v[3];
};
-
svec() {}
svec(short x, short y, short z) : x(x), y(y), z(z) {}
explicit svec(const ivec &v) : x(v.x), y(v.y), z(v.z) {}
-
short &operator[](int i) { return v[i]; }
short operator[](int i) const { return v[i]; }
};
inline ivec::ivec(const svec &v) : x(v.x), y(v.y), z(v.z) {}
-struct svec2
-{
- union
- {
+struct svec2 {
+ union {
struct { short x, y; };
short v[2];
};
-
svec2() {}
svec2(short x, short y) : x(x), y(y) {}
-
short &operator[](int i) { return v[i]; }
short operator[](int i) const { return v[i]; }
-
bool operator==(const svec2 &o) const { return x == o.x && y == o.y; }
bool operator!=(const svec2 &o) const { return x != o.x || y != o.y; }
-
bool iszero() const { return x==0 && y==0; }
};
-struct dvec4
-{
+struct dvec4 {
double x, y, z, w;
-
dvec4() {}
dvec4(double x, double y, double z, double w) : x(x), y(y), z(z), w(w) {}
dvec4(const vec4 &v) : x(v.x), y(v.y), z(v.z), w(v.w) {}
-
template<class B> dvec4 &madd(const dvec4 &a, const B &b) { return add(dvec4(a).mul(b)); }
- dvec4 &mul(double f) { x *= f; y *= f; z *= f; w *= f; return *this; }
+ dvec4 &mul(double f) { x *= f; y *= f; z *= f; w *= f; return *this; }
dvec4 &mul(const dvec4 &o) { x *= o.x; y *= o.y; z *= o.z; w *= o.w; return *this; }
- dvec4 &add(double f) { x += f; y += f; z += f; w += f; return *this; }
+ dvec4 &add(double f) { x += f; y += f; z += f; w += f; return *this; }
dvec4 &add(const dvec4 &o) { x += o.x; y += o.y; z += o.z; w += o.w; return *this; }
-
operator vec4() const { return vec4(x, y, z, w); }
};
-struct matrix4
-{
+struct matrix4 {
vec4 a, b, c, d;
-
matrix4() {}
matrix4(const float *m) : a(m), b(m+4), c(m+8), d(m+12) {}
matrix4(const vec &a, const vec &b, const vec &c = vec(0, 0, 1))
- : a(a.x, b.x, c.x, 0), b(a.y, b.y, c.y, 0), c(a.z, b.z, c.z, 0), d(0, 0, 0, 1)
- {}
+ : a(a.x, b.x, c.x, 0), b(a.y, b.y, c.y, 0), c(a.z, b.z, c.z, 0), d(0, 0, 0, 1) {
+ }
matrix4(const vec4 &a, const vec4 &b, const vec4 &c, const vec4 &d = vec4(0, 0, 0, 1))
- : a(a), b(b), c(c), d(d)
- {}
+ : a(a), b(b), c(c), d(d) {
+ }
matrix4(const matrix4x3 &m)
- : a(m.a, 0), b(m.b, 0), c(m.c, 0), d(m.d, 1)
- {}
+ : a(m.a, 0), b(m.b, 0), c(m.c, 0), d(m.d, 1) {
+ }
matrix4(const matrix3 &rot, const vec &trans)
- : a(rot.a, 0), b(rot.b, 0), c(rot.c, 0), d(trans, 1)
- {}
-
- void mul(const matrix4 &x, const matrix3 &y)
- {
+ : a(rot.a, 0), b(rot.b, 0), c(rot.c, 0), d(trans, 1) {
+ }
+ void mul(const matrix4 &x, const matrix3 &y) {
a = vec4(x.a).mul(y.a.x).madd(x.b, y.a.y).madd(x.c, y.a.z);
b = vec4(x.a).mul(y.b.x).madd(x.b, y.b.y).madd(x.c, y.b.z);
c = vec4(x.a).mul(y.c.x).madd(x.b, y.c.y).madd(x.c, y.c.z);
d = x.d;
}
void mul(const matrix3 &y) { mul(matrix4(*this), y); }
-
- template<class T> void mult(const matrix4 &x, const matrix4 &y)
- {
+ template<class T> void mult(const matrix4 &x, const matrix4 &y) {
a = T(x.a).mul(y.a.x).madd(x.b, y.a.y).madd(x.c, y.a.z).madd(x.d, y.a.w);
b = T(x.a).mul(y.b.x).madd(x.b, y.b.y).madd(x.c, y.b.z).madd(x.d, y.b.w);
c = T(x.a).mul(y.c.x).madd(x.b, y.c.y).madd(x.c, y.c.z).madd(x.d, y.c.w);
d = T(x.a).mul(y.d.x).madd(x.b, y.d.y).madd(x.c, y.d.z).madd(x.d, y.d.w);
}
-
void mul(const matrix4 &x, const matrix4 &y) { mult<vec4>(x, y); }
void mul(const matrix4 &y) { mult<vec4>(matrix4(*this), y); }
-
void muld(const matrix4 &x, const matrix4 &y) { mult<dvec4>(x, y); }
void muld(const matrix4 &y) { mult<dvec4>(matrix4(*this), y); }
-
- void rotate_around_x(float ck, float sk)
- {
+ void rotate_around_x(float ck, float sk) {
vec4 rb = vec4(b).mul(ck).madd(c, sk),
rc = vec4(c).mul(ck).msub(b, sk);
b = rb;
}
void rotate_around_x(float angle) { rotate_around_x(cosf(angle), sinf(angle)); }
void rotate_around_x(const vec2 &sc) { rotate_around_x(sc.x, sc.y); }
-
- void rotate_around_y(float ck, float sk)
- {
+ void rotate_around_y(float ck, float sk) {
vec4 rc = vec4(c).mul(ck).madd(a, sk),
ra = vec4(a).mul(ck).msub(c, sk);
c = rc;
}
void rotate_around_y(float angle) { rotate_around_y(cosf(angle), sinf(angle)); }
void rotate_around_y(const vec2 &sc) { rotate_around_y(sc.x, sc.y); }
-
- void rotate_around_z(float ck, float sk)
- {
+ void rotate_around_z(float ck, float sk) {
vec4 ra = vec4(a).mul(ck).madd(b, sk),
rb = vec4(b).mul(ck).msub(a, sk);
a = ra;
}
void rotate_around_z(float angle) { rotate_around_z(cosf(angle), sinf(angle)); }
void rotate_around_z(const vec2 &sc) { rotate_around_z(sc.x, sc.y); }
-
- void rotate(float ck, float sk, const vec &axis)
- {
+ void rotate(float ck, float sk, const vec &axis) {
matrix3 m;
m.rotate(ck, sk, axis);
mul(m);
}
void rotate(float angle, const vec &dir) { rotate(cosf(angle), sinf(angle), dir); }
void rotate(const vec2 &sc, const vec &dir) { rotate(sc.x, sc.y, dir); }
-
- void identity()
- {
+ void identity() {
a = vec4(1, 0, 0, 0);
b = vec4(0, 1, 0, 0);
c = vec4(0, 0, 1, 0);
d = vec4(0, 0, 0, 1);
}
-
void settranslation(const vec &v) { d.setxyz(v); }
void settranslation(float x, float y, float z) { d.x = x; d.y = y; d.z = z; }
-
void translate(const vec &p) { d.madd(a, p.x).madd(b, p.y).madd(c, p.z); }
void translate(float x, float y, float z) { translate(vec(x, y, z)); }
void translate(const vec &p, float scale) { translate(vec(p).mul(scale)); }
-
void setscale(float x, float y, float z) { a.x = x; b.y = y; c.z = z; }
void setscale(const vec &v) { setscale(v.x, v.y, v.z); }
void setscale(float n) { setscale(n, n, n); }
-
- void scale(float x, float y, float z)
- {
+ void scale(float x, float y, float z) {
a.mul(x);
b.mul(y);
c.mul(z);
}
void scale(const vec &v) { scale(v.x, v.y, v.z); }
void scale(float n) { scale(n, n, n); }
-
- void scalexy(float x, float y)
- {
+ void scalexy(float x, float y) {
a.x *= x; a.y *= y;
b.x *= x; b.y *= y;
c.x *= x; c.y *= y;
d.x *= x; d.y *= y;
}
-
- void scalez(float k)
- {
+ void scalez(float k) {
a.z *= k;
b.z *= k;
c.z *= k;
d.z *= k;
}
-
- void reflectz(float z)
- {
+ void reflectz(float z) {
d.add(vec4(c).mul(2*z));
c.neg();
}
-
- void projective(float zscale = 0.5f, float zoffset = 0.5f)
- {
+ void projective(float zscale = 0.5f, float zoffset = 0.5f) {
a.x = 0.5f*(a.x + a.w);
a.y = 0.5f*(a.y + a.w);
b.x = 0.5f*(b.x + b.w);
c.z = zscale*c.z + zoffset*c.w;
d.z = zscale*d.z + zoffset*d.w;
}
-
- void jitter(float x, float y)
- {
+ void jitter(float x, float y) {
a.x += x * a.w;
a.y += y * a.w;
b.x += x * b.w;
d.x += x * d.w;
d.y += y * d.w;
}
-
- void transpose()
- {
+ void transpose() {
swap(a.y, b.x); swap(a.z, c.x); swap(a.w, d.x);
swap(b.z, c.y); swap(b.w, d.y);
swap(c.w, d.z);
}
-
- void transpose(const matrix4 &m)
- {
+ void transpose(const matrix4 &m) {
a = vec4(m.a.x, m.b.x, m.c.x, m.d.x);
b = vec4(m.a.y, m.b.y, m.c.y, m.d.y);
c = vec4(m.a.z, m.b.z, m.c.z, m.d.z);
d = vec4(m.a.w, m.b.w, m.c.w, m.d.w);
}
-
- void frustum(float left, float right, float bottom, float top, float znear, float zfar)
- {
+ void frustum(float left, float right, float bottom, float top, float znear, float zfar) {
float width = right - left, height = top - bottom, zrange = znear - zfar;
a = vec4(2*znear/width, 0, 0, 0);
b = vec4(0, 2*znear/height, 0, 0);
c = vec4((right + left)/width, (top + bottom)/height, (zfar + znear)/zrange, -1);
d = vec4(0, 0, 2*znear*zfar/zrange, 0);
}
-
- void perspective(float fovy, float aspect, float znear, float zfar)
- {
+ void perspective(float fovy, float aspect, float znear, float zfar) {
float ydist = znear * tan(fovy/2*RAD), xdist = ydist * aspect;
frustum(-xdist, xdist, -ydist, ydist, znear, zfar);
}
-
- void ortho(float left, float right, float bottom, float top, float znear, float zfar)
- {
+ void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
float width = right - left, height = top - bottom, zrange = znear - zfar;
a = vec4(2/width, 0, 0, 0);
b = vec4(0, 2/height, 0, 0);
c = vec4(0, 0, 2/zrange, 0);
d = vec4(-(right+left)/width, -(top+bottom)/height, (zfar+znear)/zrange, 1);
}
-
- void clip(const plane &p, const matrix4 &m)
- {
+ void clip(const plane &p, const matrix4 &m) {
float x = ((p.x<0 ? -1 : (p.x>0 ? 1 : 0)) + m.c.x) / m.a.x,
y = ((p.y<0 ? -1 : (p.y>0 ? 1 : 0)) + m.c.y) / m.b.y,
w = (1 + m.c.z) / m.d.z,
c = vec4(m.c.x, m.c.y, p.z*scale + 1.0f, m.c.w);
d = vec4(m.d.x, m.d.y, p.offset*scale, m.d.w);
}
-
- void transform(const vec &in, vec &out) const
- {
+ void transform(const vec &in, vec &out) const {
out = vec(a).mul(in.x).add(vec(b).mul(in.y)).add(vec(c).mul(in.z)).add(vec(d));
}
-
- void transform(const vec4 &in, vec &out) const
- {
+ void transform(const vec4 &in, vec &out) const {
out = vec(a).mul(in.x).add(vec(b).mul(in.y)).add(vec(c).mul(in.z)).add(vec(d).mul(in.w));
}
-
- void transform(const vec &in, vec4 &out) const
- {
+ void transform(const vec &in, vec4 &out) const {
out = vec4(a).mul(in.x).madd(b, in.y).madd(c, in.z).add(d);
}
-
- void transform(const vec4 &in, vec4 &out) const
- {
+ void transform(const vec4 &in, vec4 &out) const {
out = vec4(a).mul(in.x).madd(b, in.y).madd(c, in.z).madd(d, in.w);
}
-
- template<class T, class U> T transform(const U &in) const
- {
+ template<class T, class U> T transform(const U &in) const {
T v;
transform(in, v);
return v;
}
-
- template<class T> vec perspectivetransform(const T &in) const
- {
+ template<class T> vec perspectivetransform(const T &in) const {
vec4 v;
transform(in, v);
return vec(v).div(v.w);
}
-
- void transformnormal(const vec &in, vec &out) const
- {
+ void transformnormal(const vec &in, vec &out) const {
out = vec(a).mul(in.x).add(vec(b).mul(in.y)).add(vec(c).mul(in.z));
}
-
- void transformnormal(const vec &in, vec4 &out) const
- {
+ void transformnormal(const vec &in, vec4 &out) const {
out = vec4(a).mul(in.x).madd(b, in.y).madd(c, in.z);
}
-
- template<class T, class U> T transformnormal(const U &in) const
- {
+ template<class T, class U> T transformnormal(const U &in) const {
T v;
transformnormal(in, v);
return v;
}
-
- void transposedtransform(const vec &in, vec &out) const
- {
+ void transposedtransform(const vec &in, vec &out) const {
vec p = vec(in).sub(vec(d));
out.x = a.dot3(p);
out.y = b.dot3(p);
out.z = c.dot3(p);
}
-
- void transposedtransformnormal(const vec &in, vec &out) const
- {
+ void transposedtransformnormal(const vec &in, vec &out) const {
out.x = a.dot3(in);
out.y = b.dot3(in);
out.z = c.dot3(in);
}
-
- void transposedtransform(const plane &in, plane &out) const
- {
+ void transposedtransform(const plane &in, plane &out) const {
out.x = in.dist(a);
out.y = in.dist(b);
out.z = in.dist(c);
out.offset = in.dist(d);
}
-
- float getscale() const
- {
+ float getscale() const {
return sqrtf(a.x*a.y + b.x*b.x + c.x*c.x);
}
-
- vec gettranslation() const
- {
+ vec gettranslation() const {
return vec(d);
}
-
vec4 rowx() const { return vec4(a.x, b.x, c.x, d.x); }
vec4 rowy() const { return vec4(a.y, b.y, c.y, d.y); }
vec4 rowz() const { return vec4(a.z, b.z, c.z, d.z); }
vec4 roww() const { return vec4(a.w, b.w, c.w, d.w); }
-
bool invert(const matrix4 &m, double mindet = 1.0e-12);
};
inline matrix3::matrix3(const matrix4 &m)
- : a(m.a), b(m.b), c(m.c)
-{}
+ : a(m.a), b(m.b), c(m.c) {
+}
inline matrix4x3::matrix4x3(const matrix4 &m)
- : a(m.a), b(m.b), c(m.c), d(m.d)
-{}
+ : a(m.a), b(m.b), c(m.c), d(m.d) {
+}
-struct matrix2
-{
+struct matrix2 {
vec2 a, b;
-
matrix2() {}
matrix2(const vec2 &a, const vec2 &b) : a(a), b(b) {}
explicit matrix2(const matrix4 &m) : a(m.a), b(m.b) {}
explicit matrix2(const matrix3 &m) : a(m.a), b(m.b) {}
};
-struct squat
-{
+struct squat {
short x, y, z, w;
-
squat() {}
squat(const vec4 &q) { convert(q); }
-
- void convert(const vec4 &q)
- {
+ void convert(const vec4 &q) {
x = short(q.x*32767.5f-0.5f);
y = short(q.y*32767.5f-0.5f);
z = short(q.z*32767.5f-0.5f);
w = short(q.w*32767.5f-0.5f);
}
-
- void lerp(const vec4 &a, const vec4 &b, float t)
- {
+ void lerp(const vec4 &a, const vec4 &b, float t) {
vec4 q;
q.lerp(a, b, t);
convert(q);
extern bool linecylinderintersect(const vec &from, const vec &to, const vec &start, const vec &end, float radius, float &dist);
extern const vec2 sincos360[];
-static inline int mod360(int angle)
-{
+static inline int mod360(int angle) {
if(angle < 0) angle = 360 + (angle <= -360 ? angle%360 : angle);
else if(angle >= 360) angle %= 360;
return angle;
extern int glversion;
extern int intel_mapbufferrange_bug;
-namespace gle
-{
- struct attribinfo
- {
+namespace gle {
+ struct attribinfo {
int type, size, formatsize, offset;
GLenum format;
-
attribinfo() : type(0), size(0), formatsize(0), offset(0), format(GL_FALSE) {}
-
- bool operator==(const attribinfo &a) const
- {
+ bool operator==(const attribinfo &a) const {
return type == a.type && size == a.size && format == a.format && offset == a.offset;
}
- bool operator!=(const attribinfo &a) const
- {
+ bool operator!=(const attribinfo &a) const {
return type != a.type || size != a.size || format != a.format || offset != a.offset;
}
};
-
extern const char * const attribnames[MAXATTRIBS] = { "vvertex", "vcolor", "vtexcoord0", "vtexcoord1", "vnormal", "vtangent", "vboneweight", "vboneindex" };
ucharbuf attribbuf;
static uchar *attribdata;
static bool changedattribs = false;
static vector<GLint> multidrawstart;
static vector<GLsizei> multidrawcount;
-
#define MAXQUADS (0x10000/4)
static GLuint quadindexes = 0;
static bool quadsenabled = false;
-
#define MAXVBOSIZE (4*1024*1024)
static GLuint vbo = 0;
static int vbooffset = MAXVBOSIZE;
-
static GLuint defaultvao = 0;
-
- void enablequads()
- {
+ void enablequads() {
quadsenabled = true;
-
if(glversion < 300) return;
-
- if(quadindexes)
- {
+ if(quadindexes) {
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, quadindexes);
return;
}
-
glGenBuffers_(1, &quadindexes);
ushort *data = new ushort[MAXQUADS*6], *dst = data;
- for(int idx = 0; idx < MAXQUADS*4; idx += 4, dst += 6)
- {
+ for(int idx = 0; idx < MAXQUADS*4; idx += 4, dst += 6) {
dst[0] = idx;
dst[1] = idx + 1;
dst[2] = idx + 2;
glBufferData_(GL_ELEMENT_ARRAY_BUFFER, MAXQUADS*6*sizeof(ushort), data, GL_STATIC_DRAW);
delete[] data;
}
-
- void disablequads()
- {
+ void disablequads() {
quadsenabled = false;
-
if(glversion < 300) return;
-
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
}
-
- void drawquads(int offset, int count)
- {
+ void drawquads(int offset, int count) {
if(count <= 0) return;
- if(glversion < 300)
- {
+ if(glversion < 300) {
glDrawArrays(GL_QUADS, offset*4, count*4);
return;
}
- if(offset + count > MAXQUADS)
- {
+ if(offset + count > MAXQUADS) {
if(offset >= MAXQUADS) return;
count = MAXQUADS - offset;
}
glDrawRangeElements_(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, (ushort *)0 + offset*6);
}
-
- void defattrib(int type, int size, int format)
- {
- if(type == ATTRIB_VERTEX)
- {
+ void defattrib(int type, int size, int format) {
+ if(type == ATTRIB_VERTEX) {
numattribs = attribmask = 0;
vertexsize = 0;
}
a.type = type;
a.size = size;
a.format = format;
- switch(format)
- {
+ switch(format) {
case 'B': case GL_UNSIGNED_BYTE: a.formatsize = 1; a.format = GL_UNSIGNED_BYTE; break;
case 'b': case GL_BYTE: a.formatsize = 1; a.format = GL_BYTE; break;
case 'S': case GL_UNSIGNED_SHORT: a.formatsize = 2; a.format = GL_UNSIGNED_SHORT; break;
a.offset = vertexsize;
vertexsize += a.formatsize;
}
-
- void defattribs(const char *fmt)
- {
- for(;; fmt += 3)
- {
+ void defattribs(const char *fmt) {
+ for(;; fmt += 3) {
GLenum format;
- switch(fmt[0])
- {
+ switch(fmt[0]) {
case 'v': format = ATTRIB_VERTEX; break;
case 'c': format = ATTRIB_COLOR; break;
case 't': format = ATTRIB_TEXCOORD0; break;
defattrib(format, fmt[1]-'0', fmt[2]);
}
}
-
- static inline void setattrib(const attribinfo &a, uchar *buf)
- {
- switch(a.type)
- {
+ static inline void setattrib(const attribinfo &a, uchar *buf) {
+ switch(a.type) {
case ATTRIB_VERTEX:
case ATTRIB_TEXCOORD0:
case ATTRIB_TEXCOORD1:
glVertexAttribPointer_(a.type, a.size, a.format, GL_TRUE, vertexsize, buf);
break;
}
- if(!(enabled&(1<<a.type)))
- {
+ if(!(enabled&(1<<a.type))) {
glEnableVertexAttribArray_(a.type);
enabled |= 1<<a.type;
}
}
-
- static inline void unsetattrib(const attribinfo &a)
- {
+ static inline void unsetattrib(const attribinfo &a) {
glDisableVertexAttribArray_(a.type);
enabled &= ~(1<<a.type);
}
-
- static inline void setattribs(uchar *buf)
- {
+ static inline void setattribs(uchar *buf) {
bool forceattribs = numattribs != numlastattribs || vertexsize != lastvertexsize || buf != lastbuf;
- if(forceattribs || changedattribs)
- {
+ if(forceattribs || changedattribs) {
int diffmask = enabled & lastattribmask & ~attribmask;
- if(diffmask) loopi(numlastattribs)
- {
+ if(diffmask) loopi(numlastattribs) {
const attribinfo &a = lastattribs[i];
if(diffmask & (1<<a.type)) unsetattrib(a);
}
uchar *src = buf;
- loopi(numattribs)
- {
+ loopi(numattribs) {
const attribinfo &a = attribdefs[i];
- if(forceattribs || a != lastattribs[i])
- {
+ if(forceattribs || a != lastattribs[i]) {
setattrib(a, src);
lastattribs[i] = a;
}
changedattribs = false;
}
}
-
- void begin(GLenum mode)
- {
+ void begin(GLenum mode) {
primtype = mode;
}
-
- void begin(GLenum mode, int numverts)
- {
+ void begin(GLenum mode, int numverts) {
primtype = mode;
- if(glversion >= 300 && !intel_mapbufferrange_bug)
- {
+ if(glversion >= 300 && !intel_mapbufferrange_bug) {
int len = numverts * vertexsize;
- if(vbooffset + len >= MAXVBOSIZE)
- {
+ if(vbooffset + len >= MAXVBOSIZE) {
len = min(len, MAXVBOSIZE);
if(!vbo) glGenBuffers_(1, &vbo);
glBindBuffer_(GL_ARRAY_BUFFER, vbo);
if(buf) attribbuf.reset((uchar *)buf, len);
}
}
-
- void multidraw()
- {
+ void multidraw() {
int start = multidrawstart.length() ? multidrawstart.last() + multidrawcount.last() : 0,
count = attribbuf.length()/vertexsize - start;
- if(count > 0)
- {
+ if(count > 0) {
multidrawstart.add(start);
multidrawcount.add(count);
}
}
-
- int end()
- {
+ int end() {
uchar *buf = attribbuf.getbuf();
- if(attribbuf.empty())
- {
- if(buf != attribdata)
- {
+ if(attribbuf.empty()) {
+ if(buf != attribdata) {
glUnmapBuffer_(GL_ARRAY_BUFFER);
attribbuf.reset(attribdata, MAXVBOSIZE);
}
return 0;
}
int start = 0;
- if(glversion >= 300)
- {
- if(buf == attribdata)
- {
- if(vbooffset + attribbuf.length() >= MAXVBOSIZE)
- {
+ if(glversion >= 300) {
+ if(buf == attribdata) {
+ if(vbooffset + attribbuf.length() >= MAXVBOSIZE) {
if(!vbo) glGenBuffers_(1, &vbo);
glBindBuffer_(GL_ARRAY_BUFFER, vbo);
glBufferData_(GL_ARRAY_BUFFER, MAXVBOSIZE, NULL, GL_STREAM_DRAW);
else if(!lastvertexsize) glBindBuffer_(GL_ARRAY_BUFFER, vbo);
void *dst = intel_mapbufferrange_bug ? NULL :
glMapBufferRange_(GL_ARRAY_BUFFER, vbooffset, attribbuf.length(), GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT);
- if(dst)
- {
+ if(dst) {
memcpy(dst, attribbuf.getbuf(), attribbuf.length());
glUnmapBuffer_(GL_ARRAY_BUFFER);
}
}
else glUnmapBuffer_(GL_ARRAY_BUFFER);
buf = (uchar *)0 + vbooffset;
- if(vertexsize == lastvertexsize && buf >= lastbuf)
- {
+ if(vertexsize == lastvertexsize && buf >= lastbuf) {
start = int(buf - lastbuf)/vertexsize;
if(primtype == GL_QUADS && (start%4 || start + attribbuf.length()/vertexsize >= 4*MAXQUADS))
start = 0;
}
setattribs(buf);
int numvertexes = attribbuf.length()/vertexsize;
- if(primtype == GL_QUADS)
- {
+ if(primtype == GL_QUADS) {
if(!quadsenabled) enablequads();
- for(int quads = numvertexes/4;;)
- {
+ for(int quads = numvertexes/4;;) {
int count = min(quads, MAXQUADS);
drawquads(start/4, count);
quads -= count;
start = 0;
}
}
- else
- {
- if(multidrawstart.length())
- {
+ else {
+ if(multidrawstart.length()) {
multidraw();
if(start) loopv(multidrawstart) multidrawstart[i] += start;
glMultiDrawArrays_(primtype, multidrawstart.getbuf(), multidrawcount.getbuf(), multidrawstart.length());
attribbuf.reset(attribdata, MAXVBOSIZE);
return numvertexes;
}
-
- void forcedisable()
- {
+ void forcedisable() {
for(int i = 0; enabled; i++) if(enabled&(1<<i)) { glDisableVertexAttribArray_(i); enabled &= ~(1<<i); }
numlastattribs = lastattribmask = lastvertexsize = 0;
lastbuf = NULL;
if(quadsenabled) disablequads();
if(glversion >= 300) glBindBuffer_(GL_ARRAY_BUFFER, 0);
}
-
- void setup()
- {
- if(glversion >= 300)
- {
+ void setup() {
+ if(glversion >= 300) {
if(!defaultvao) glGenVertexArrays_(1, &defaultvao);
glBindVertexArray_(defaultvao);
}
attribdata = new uchar[MAXVBOSIZE];
attribbuf.reset(attribdata, MAXVBOSIZE);
}
-
- void cleanup()
- {
+ void cleanup() {
disable();
-
if(quadindexes) { glDeleteBuffers_(1, &quadindexes); quadindexes = 0; }
-
if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; }
vbooffset = MAXVBOSIZE;
-
if(defaultvao) { glDeleteVertexArrays_(1, &defaultvao); defaultvao = 0; }
}
}
-namespace gle
-{
- enum
- {
+namespace gle {
+ enum {
ATTRIB_VERTEX = 0,
ATTRIB_COLOR = 1,
ATTRIB_TEXCOORD0 = 2,
ATTRIB_BONEINDEX = 7,
MAXATTRIBS = 8
};
-
extern const char * const attribnames[MAXATTRIBS];
extern ucharbuf attribbuf;
-
extern int enabled;
extern void forcedisable();
static inline void disable() { if(enabled) forcedisable(); }
-
extern void begin(GLenum mode);
extern void begin(GLenum mode, int numverts);
extern void defattribs(const char *fmt);
extern void defattrib(int type, int size, int format);
-
#define GLE_DEFATTRIB(name, type, defaultsize, defaultformat) \
static inline void def##name(int size = defaultsize, int format = defaultformat) { defattrib(type, size, format); }
-
GLE_DEFATTRIB(vertex, ATTRIB_VERTEX, 3, GL_FLOAT)
GLE_DEFATTRIB(color, ATTRIB_COLOR, 3, GL_FLOAT)
GLE_DEFATTRIB(texcoord0, ATTRIB_TEXCOORD0, 2, GL_FLOAT)
GLE_DEFATTRIB(tangent, ATTRIB_TANGENT, 4, GL_FLOAT)
GLE_DEFATTRIB(boneweight, ATTRIB_BONEWEIGHT, 4, GL_UNSIGNED_BYTE)
GLE_DEFATTRIB(boneindex, ATTRIB_BONEINDEX, 4, GL_UNSIGNED_BYTE)
-
#define GLE_INITATTRIB(name, index, suffix, type) \
static inline void name##suffix(type x) { glVertexAttrib1##suffix##_(index, x); } \
static inline void name##suffix(type x, type y) { glVertexAttrib2##suffix##_(index, x, y); } \
static inline void name(const vec4 &v) { glVertexAttrib4fv_(index, v.v); }
#define GLE_INITATTRIBN(name, index, suffix, type, defaultw) \
static inline void name##suffix(type x, type y, type z, type w = defaultw) { glVertexAttrib4N##suffix##_(index, x, y, z, w); }
-
GLE_INITATTRIBF(vertex, ATTRIB_VERTEX)
GLE_INITATTRIBF(color, ATTRIB_COLOR)
static inline void color(const bvec4 &v) { glVertexAttrib4Nubv_(ATTRIB_COLOR, v.v); }
static inline void tangent(float x, float y, float z, float w = 1.0f) { glVertexAttrib4f_(ATTRIB_TANGENT, x, y, z, w); }
static inline void tangent(const vec &v, float w = 1.0f) { glVertexAttrib4f_(ATTRIB_TANGENT, v.x, v.y, v.z, w); }
static inline void tangent(const vec4 &v) { glVertexAttrib4fv_(ATTRIB_TANGENT, v.v); }
-
#define GLE_ATTRIBPOINTER(name, index, defaultnormalized, defaultsize, defaulttype, prepare) \
static inline void enable##name() { prepare; glEnableVertexAttribArray_(index); } \
static inline void disable##name() { glDisableVertexAttribArray_(index); } \
prepare; \
glVertexAttribPointer_(index, size, type, normalized, stride, data); \
}
-
static inline void enableattrib(int index) { disable(); glEnableVertexAttribArray_(index); }
static inline void disableattrib(int index) { glDisableVertexAttribArray_(index); }
GLE_ATTRIBPOINTER(vertex, ATTRIB_VERTEX, GL_FALSE, 3, GL_FLOAT, disable())
GLE_ATTRIBPOINTER(tangent, ATTRIB_TANGENT, GL_TRUE, 4, GL_FLOAT, )
GLE_ATTRIBPOINTER(boneweight, ATTRIB_BONEWEIGHT, GL_TRUE, 4, GL_UNSIGNED_BYTE, )
GLE_ATTRIBPOINTER(boneindex, ATTRIB_BONEINDEX, GL_FALSE, 4, GL_UNSIGNED_BYTE, )
-
static inline void bindebo(GLuint ebo) { disable(); glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, ebo); }
static inline void clearebo() { glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0); }
static inline void bindvbo(GLuint vbo) { disable(); glBindBuffer_(GL_ARRAY_BUFFER, vbo); }
static inline void clearvbo() { glBindBuffer_(GL_ARRAY_BUFFER, 0); }
-
template<class T>
- static inline void attrib(T x)
- {
- if(attribbuf.check(sizeof(T)))
- {
+ static inline void attrib(T x) {
+ if(attribbuf.check(sizeof(T))) {
T *buf = (T *)attribbuf.pad(sizeof(T));
buf[0] = x;
}
}
-
template<class T>
- static inline void attrib(T x, T y)
- {
- if(attribbuf.check(2*sizeof(T)))
- {
+ static inline void attrib(T x, T y) {
+ if(attribbuf.check(2*sizeof(T))) {
T *buf = (T *)attribbuf.pad(2*sizeof(T));
buf[0] = x;
buf[1] = y;
}
}
-
template<class T>
- static inline void attrib(T x, T y, T z)
- {
- if(attribbuf.check(3*sizeof(T)))
- {
+ static inline void attrib(T x, T y, T z) {
+ if(attribbuf.check(3*sizeof(T))) {
T *buf = (T *)attribbuf.pad(3*sizeof(T));
buf[0] = x;
buf[1] = y;
buf[2] = z;
}
}
-
template<class T>
- static inline void attrib(T x, T y, T z, T w)
- {
- if(attribbuf.check(4*sizeof(T)))
- {
+ static inline void attrib(T x, T y, T z, T w) {
+ if(attribbuf.check(4*sizeof(T))) {
T *buf = (T *)attribbuf.pad(4*sizeof(T));
buf[0] = x;
buf[1] = y;
buf[3] = w;
}
}
-
template<size_t N, class T>
- static inline void attribv(const T *v)
- {
+ static inline void attribv(const T *v) {
attribbuf.put((const uchar *)v, N*sizeof(T));
}
-
#define GLE_ATTRIB(suffix, type) \
static inline void attrib##suffix(type x) { attrib<type>(x); } \
static inline void attrib##suffix(type x, type y) { attrib<type>(x, y); } \
static inline void attrib##suffix(type x, type y, type z) { attrib<type>(x, y, z); } \
static inline void attrib##suffix(type x, type y, type z, type w) { attrib<type>(x, y, z, w); }
-
GLE_ATTRIB(f, float)
GLE_ATTRIB(d, double)
GLE_ATTRIB(b, char)
GLE_ATTRIB(us, ushort)
GLE_ATTRIB(i, int)
GLE_ATTRIB(ui, uint)
-
static inline void attrib(const vec &v) { attribf(v.x, v.y, v.z); }
static inline void attrib(const vec &v, float w) { attribf(v.x, v.y, v.z, w); }
static inline void attrib(const vec2 &v) { attribf(v.x, v.y); }
static inline void attrib(const bvec &b) { attribub(b.x, b.y, b.z); }
static inline void attrib(const bvec &b, uchar w) { attribub(b.x, b.y, b.z, w); }
static inline void attrib(const bvec4 &b) { attribub(b.x, b.y, b.z, b.w); }
-
extern void multidraw();
extern int end();
-
extern void enablequads();
extern void disablequads();
extern void drawquads(int offset, int count);
-
extern void setup();
extern void cleanup();
}
extern uint totalsecs;
extern int gamespeed, paused;
-enum
-{
+enum {
MATF_INDEX_SHIFT = 0,
MATF_CLIP_SHIFT = 5,
MATF_FLAG_SHIFT = 8,
-
MATF_INDEX = 3 << MATF_INDEX_SHIFT,
MATF_CLIP = 7 << MATF_CLIP_SHIFT,
MATF_FLAGS = 0xFF << MATF_FLAG_SHIFT
};
-enum // cube empty-space materials
-{
+enum { // cube empty-space materials {
MAT_AIR = 0, // the default, fill the empty space with air
-
MAT_NOCLIP = 1 << MATF_CLIP_SHIFT, // collisions always treat cube as empty
MAT_CLIP = 2 << MATF_CLIP_SHIFT, // collisions always treat cube as solid
MAT_GAMECLIP = 3 << MATF_CLIP_SHIFT, // game specific clip material
-
MAT_DEATH = 1 << MATF_FLAG_SHIFT, // force player suicide
MAT_ALPHA = 4 << MATF_FLAG_SHIFT // alpha blended
};
enum { EDIT_FACE = 0, EDIT_TEX, EDIT_MAT, EDIT_FLIP, EDIT_COPY, EDIT_PASTE, EDIT_ROTATE, EDIT_REPLACE, EDIT_DELCUBE, EDIT_REMIP, EDIT_VSLOT, EDIT_UNDO, EDIT_REDO };
-struct selinfo
-{
+struct selinfo {
int corner;
int cx, cxs, cy, cys;
ivec o, s;
int size() const { return s.x*s.y*s.z; }
int us(int d) const { return s[d]*grid; }
bool operator==(const selinfo &sel) const { return o==sel.o && s==sel.s && grid==sel.grid && orient==sel.orient; }
- bool validate()
- {
+ bool validate() {
extern int worldsize;
if(grid <= 0 || grid >= worldsize) return false;
if(o.x >= worldsize || o.y >= worldsize || o.z >= worldsize) return false;
// console
-enum
-{
+enum {
CON_INFO = 1<<0,
CON_WARN = 1<<1,
CON_ERROR = 1<<2,
CON_DEBUG = 1<<3,
CON_INIT = 1<<4,
CON_ECHO = 1<<5,
-
CON_FLAGS = 0xFFFF,
CON_TAG_SHIFT = 16,
CON_TAG_MASK = (0x7FFF << CON_TAG_SHIFT)
// octa
extern int lookupmaterial(const vec &o);
-static inline bool insideworld(const vec &o)
-{
+static inline bool insideworld(const vec &o) {
extern int worldsize;
return o.x>=0 && o.x<worldsize && o.y>=0 && o.y<worldsize && o.z>=0 && o.z<worldsize;
}
-static inline bool insideworld(const ivec &o)
-{
+static inline bool insideworld(const ivec &o) {
extern int worldsize;
return uint(o.x)<uint(worldsize) && uint(o.y)<uint(worldsize) && uint(o.z)<uint(worldsize);
}
extern int text_visible(const char *str, float hitx, float hity, int maxwidth);
extern void text_posf(const char *str, int cursor, float &cx, float &cy, int maxwidth);
-static inline int text_width(const char *str)
-{
+static inline int text_width(const char *str) {
return int(ceil(text_widthf(str)));
}
-static inline void text_bounds(const char *str, int &width, int &height, int maxwidth = -1)
-{
+static inline void text_bounds(const char *str, int &width, int &height, int maxwidth = -1) {
float widthf, heightf;
text_boundsf(str, widthf, heightf, maxwidth);
width = int(ceil(widthf));
height = int(ceil(heightf));
}
-static inline void text_pos(const char *str, int cursor, int &cx, int &cy, int maxwidth)
-{
+static inline void text_pos(const char *str, int cursor, int &cx, int &cy, int maxwidth) {
float cxf, cyf;
text_posf(str, cursor, cxf, cyf, maxwidth);
cx = int(cxf);
}
// renderva
-enum
-{
+enum {
DL_SHRINK = 1<<0,
DL_EXPAND = 1<<1,
DL_FLASH = 1<<2
extern void pushhudtranslate(float tx, float ty, float sx = 0, float sy = 0);
// renderparticles
-enum
-{
+enum {
PART_BLOOD = 0,
PART_WATER,
PART_SMOKE,
PART_STEAM,
PART_FLAME,
- PART_FIREBALL1, PART_FIREBALL2, PART_FIREBALL3,
- PART_STREAK, PART_LIGHTNING,
- PART_EXPLOSION, PART_EXPLOSION_BLUE,
+ PART_STREAK,
PART_SPARK, PART_EDIT,
PART_SNOW,
PART_MUZZLE_FLASH1, PART_MUZZLE_FLASH2, PART_MUZZLE_FLASH3,
extern void particle_icon(const vec &s, int ix, int iy, int type, int fade = 2000, int color = 0xFFFFFF, float size = 2.0f, int gravity = 0);
extern void particle_meter(const vec &s, float val, int type, int fade = 1, int color = 0xFFFFFF, int color2 = 0xFFFFF, float size = 2.0f);
extern void particle_flare(const vec &p, const vec &dest, int fade, int type, int color = 0xFFFFFF, float size = 0.28f, physent *owner = NULL);
-extern void particle_fireball(const vec &dest, float max, int type, int fade = -1, int color = 0xFFFFFF, float size = 4.0f);
extern void removetrackedparticles(physent *owner = NULL);
// decal
-enum
-{
+enum {
DECAL_SCORCH = 0,
DECAL_BLOOD,
DECAL_BULLET
extern void findplayerspawn(dynent *d, int forceent = -1, int tag = 0);
// sound
-enum
-{
+enum {
SND_MAP = 1<<0,
SND_NO_ALT = 1<<1,
SND_USE_ALT = 1<<2
enum { MDL_CULL_VFC = 1<<0, MDL_CULL_DIST = 1<<1, MDL_CULL_OCCLUDED = 1<<2, MDL_CULL_QUERY = 1<<3, MDL_SHADOW = 1<<4, MDL_DYNSHADOW = 1<<5, MDL_LIGHT = 1<<6, MDL_DYNLIGHT = 1<<7, MDL_FULLBRIGHT = 1<<8, MDL_NORENDER = 1<<9, MDL_LIGHT_FAST = 1<<10, MDL_HUD = 1<<11, MDL_GHOST = 1<<12 };
struct model;
-struct modelattach
-{
+struct modelattach {
const char *tag, *name;
int anim, basetime;
vec *pos;
model *m;
-
modelattach() : tag(NULL), name(NULL), anim(-1), basetime(0), pos(NULL), m(NULL) {}
modelattach(const char *tag, const char *name, int anim = -1, int basetime = 0) : tag(tag), name(name), anim(anim), basetime(basetime), pos(NULL), m(NULL) {}
modelattach(const char *tag, vec *pos) : tag(tag), name(NULL), anim(-1), basetime(0), pos(pos), m(NULL) {}
enum { EDITORFOCUSED = 1, EDITORUSED, EDITORFOREVER };
-struct g3d_gui
-{
+struct g3d_gui {
virtual ~g3d_gui() {}
-
virtual void start(int starttime, float basescale, int *tab = NULL, bool allowinput = true) = 0;
virtual void end() = 0;
-
virtual int text(const char *text, int color, const char *icon = NULL) = 0;
- int textf(const char *fmt, int color, const char *icon = NULL, ...) PRINTFARGS(2, 5)
- {
+ int textf(const char *fmt, int color, const char *icon = NULL, ...) PRINTFARGS(2, 5) {
defvformatstring(str, icon, fmt);
return text(str, color, icon);
}
virtual int button(const char *text, int color, const char *icon = NULL) = 0;
- int buttonf(const char *fmt, int color, const char *icon = NULL, ...) PRINTFARGS(2, 5)
- {
+ int buttonf(const char *fmt, int color, const char *icon = NULL, ...) PRINTFARGS(2, 5) {
defvformatstring(str, icon, fmt);
return button(str, color, icon);
}
virtual int title(const char *text, int color, const char *icon = NULL) = 0;
- int titlef(const char *fmt, int color, const char *icon = NULL, ...) PRINTFARGS(2, 5)
- {
+ int titlef(const char *fmt, int color, const char *icon = NULL, ...) PRINTFARGS(2, 5) {
defvformatstring(str, icon, fmt);
return title(str, color, icon);
}
virtual void background(int color, int parentw = 0, int parenth = 0) = 0;
-
virtual void pushlist() {}
virtual void poplist() {}
-
virtual bool allowautotab(bool on) = 0;
virtual bool shouldtab() = 0;
virtual void tab(const char *name = NULL, int color = 0) = 0;
virtual bool mergehits(bool on) = 0;
};
-struct g3d_callback
-{
+struct g3d_callback {
virtual ~g3d_callback() {}
-
int starttime() { return totalmillis; }
-
virtual void gui(g3d_gui &g, bool firstpass) = 0;
};
-enum
-{
+enum {
GUI_2D = 1<<0,
GUI_FOLLOW = 1<<1,
GUI_FORCE_2D = 1<<2,
// the interface the engine uses to run the gameplay module
-namespace entities
-{
+namespace entities {
extern void editent(int i, bool local);
extern const char *entnameinfo(entity &e);
extern const char *entname(int i);
extern const char *entmodel(const entity &e);
}
-namespace game
-{
+namespace game {
extern void parseoptions(vector<const char *> &args);
-
extern void gamedisconnect(bool cleanup);
extern void parsepacketclient(int chan, packetbuf &p);
extern void connectattempt(const char *name, const char *password, const ENetAddress &address);
extern bool ispaused();
extern int scaletime(int t);
extern bool allowmouselook();
-
extern const char *gameident();
extern const char *savedconfig();
extern const char *restoreconfig();
extern const char *autoexec();
extern const char *savedservers();
extern void loadconfigs();
-
extern void updateworld();
extern void initclient();
extern void physicstrigger(physent *d, bool local, int floorlevel, int material = 0);
extern bool serverinfoentry(g3d_gui *g, int i, const char *name, int port, const char *desc, const char *map, int ping, const vector<int> &attr, int np);
}
-namespace server
-{
+namespace server {
extern void *newclientinfo();
extern void deleteclientinfo(void *ci);
extern void serverinit();
extern int serverport(int infoport = -1);
extern const char *defaultmaster();
extern int masterport();
- extern void processmasterinput(const char *cmd, int cmdlen, const char *args);
+ extern void processmasterinput(const char *cmd, int cmdlen);
extern void masterconnected();
extern void masterdisconnected();
extern bool ispaused();
///////////////////////////// console ////////////////////////
-void conoutf(const char *fmt, ...)
-{
+void conoutf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
conoutfv(CON_INFO, fmt, args);
va_end(args);
}
-void conoutf(int type, const char *fmt, ...)
-{
+void conoutf(int type, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
conoutfv(type, fmt, args);
va_end(args);
}
-void conoutf(int type, int tag, const char *fmt, ...)
-{
+void conoutf(int type, int tag, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
conoutfv(type | ((tag << CON_TAG_SHIFT) & CON_TAG_MASK), fmt, args);
U, U, U, U, u, u, u, u, u, u, u, u, u, u, u, u, \
u, u, u, u, u, u, u, u, u, u, u, u, u, u, U, u
-extern const uchar cubectype[256] =
-{
+extern const uchar cubectype[256] = {
CUBECTYPE(CT_SPACE,
CT_PRINT,
CT_PRINT|CT_DIGIT,
CT_PRINT|CT_UNICODE|CT_ALPHA|CT_LOWER,
CT_PRINT|CT_UNICODE|CT_ALPHA|CT_UPPER)
};
-extern const int cube2unichars[256] =
-{
+extern const int cube2unichars[256] = {
0, 192, 193, 194, 195, 196, 197, 198, 199, 9, 10, 11, 12, 13, 200, 201,
202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
0x42C, 0x42D, 0x42E, 0x42F, 0x431, 0x432, 0x433, 0x434, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D,
0x43F, 0x442, 0x444, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x454, 0x490, 0x491
};
-extern const int uni2cubeoffsets[8] =
-{
+extern const int uni2cubeoffsets[8] = {
0, 256, 658, 658, 512, 658, 658, 658
};
-extern const uchar uni2cubechars[878] =
-{
+extern const uchar uni2cubechars[878] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-extern const uchar cubelowerchars[256] =
-{
+extern const uchar cubelowerchars[256] = {
0, 130, 131, 132, 133, 134, 135, 136, 137, 9, 10, 11, 12, 13, 138, 139,
140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
};
-extern const uchar cubeupperchars[256] =
-{
+extern const uchar cubeupperchars[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
};
-size_t decodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry)
-{
+size_t decodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry) {
uchar *dst = dstbuf, *dstend = &dstbuf[dstlen];
const uchar *src = srcbuf, *srcend = &srcbuf[srclen];
- if(dstbuf == srcbuf)
- {
+ if(dstbuf == srcbuf) {
int len = min(dstlen, srclen);
for(const uchar *end4 = &srcbuf[len&~3]; src < end4; src += 4) if(*(const int *)src & 0x80808080) goto decode;
for(const uchar *end = &srcbuf[len]; src < end; src++) if(*src & 0x80) goto decode;
decode:
dst += src - srcbuf;
- while(src < srcend && dst < dstend)
- {
+ while(src < srcend && dst < dstend) {
int c = *src++;
if(c < 0x80) *dst++ = c;
- else if(c >= 0xC0)
- {
+ else if(c >= 0xC0) {
int uni;
- if(c >= 0xE0)
- {
- if(c >= 0xF0)
- {
- if(c >= 0xF8)
- {
- if(c >= 0xFC)
- {
+ if(c >= 0xE0) {
+ if(c >= 0xF0) {
+ if(c >= 0xF8) {
+ if(c >= 0xFC) {
if(c >= 0xFE) continue;
uni = c&1; if(srcend - src < 5) break;
c = *src; if((c&0xC0) != 0x80) continue; src++; uni = (uni<<6) | (c&0x3F);
return dst - dstbuf;
}
-size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry)
-{
+size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry) {
uchar *dst = dstbuf, *dstend = &dstbuf[dstlen];
const uchar *src = srcbuf, *srcend = &srcbuf[srclen];
- if(src < srcend && dst < dstend) do
- {
+ if(src < srcend && dst < dstend) do {
int uni = cube2uni(*src);
- if(uni <= 0x7F)
- {
+ if(uni <= 0x7F) {
if(dst >= dstend) goto done;
const uchar *end = min(srcend, &src[dstend-dst]);
- do
- {
- if(uni == '\f')
- {
+ do {
+ if(uni == '\f') {
if(++src >= srcend) goto done;
goto uni1;
}
#include <dirent.h>
string homedir = "";
-struct packagedir
-{
+struct packagedir {
char *dir, *filter;
size_t dirlen, filterlen;
};
vector<packagedir> packagedirs;
-char *makerelpath(const char *dir, const char *file, const char *prefix, const char *cmd)
-{
+char *makerelpath(const char *dir, const char *file, const char *prefix, const char *cmd) {
static string tmp;
if(prefix) copystring(tmp, prefix);
else tmp[0] = '\0';
- if(file[0]=='<')
- {
+ if(file[0]=='<') {
const char *end = strrchr(file, '>');
- if(end)
- {
+ if(end) {
size_t len = strlen(tmp);
copystring(&tmp[len], file, min(sizeof(tmp)-len, size_t(end+2-file)));
file = end+1;
}
}
if(cmd) concatstring(tmp, cmd);
- if(dir)
- {
+ if(dir) {
defformatstring(pname, "%s/%s", dir, file);
concatstring(tmp, pname);
}
}
-char *path(char *s)
-{
- for(char *curpart = s;;)
- {
+char *path(char *s) {
+ for(char *curpart = s;;) {
char *endpart = strchr(curpart, '&');
if(endpart) *endpart = '\0';
- if(curpart[0]=='<')
- {
+ if(curpart[0]=='<') {
char *file = strrchr(curpart, '>');
if(!file) return s;
curpart = file+1;
}
for(char *t = curpart; (t = strpbrk(t, "/\\")); *t++ = PATHDIV);
- for(char *prevdir = NULL, *curdir = curpart;;)
- {
+ for(char *prevdir = NULL, *curdir = curpart;;) {
prevdir = curdir[0]==PATHDIV ? curdir+1 : curdir;
curdir = strchr(prevdir, PATHDIV);
if(!curdir) break;
- if(prevdir+1==curdir && prevdir[0]=='.')
- {
+ if(prevdir+1==curdir && prevdir[0]=='.') {
memmove(prevdir, curdir+1, strlen(curdir+1)+1);
curdir = prevdir;
}
- else if(curdir[1]=='.' && curdir[2]=='.' && curdir[3]==PATHDIV)
- {
+ else if(curdir[1]=='.' && curdir[2]=='.' && curdir[3]==PATHDIV) {
if(prevdir+2==curdir && prevdir[0]=='.' && prevdir[1]=='.') continue;
memmove(prevdir, curdir+4, strlen(curdir+4)+1);
- if(prevdir-2 >= curpart && prevdir[-1]==PATHDIV)
- {
+ if(prevdir-2 >= curpart && prevdir[-1]==PATHDIV) {
prevdir -= 2;
while(prevdir-1 >= curpart && prevdir[-1] != PATHDIV) --prevdir;
}
curdir = prevdir;
}
}
- if(endpart)
- {
+ if(endpart) {
*endpart = '&';
curpart = endpart+1;
}
return s;
}
-char *path(const char *s, bool copy)
-{
+char *path(const char *s, bool copy) {
static string tmp;
copystring(tmp, s);
path(tmp);
return tmp;
}
-const char *parentdir(const char *directory)
-{
+const char *parentdir(const char *directory) {
const char *p = directory + strlen(directory);
while(p > directory && *p != '/' && *p != '\\') p--;
static string parent;
return parent;
}
-bool fileexists(const char *path, const char *mode)
-{
+bool fileexists(const char *path, const char *mode) {
bool exists = true;
if(mode[0]=='w' || mode[0]=='a') path = parentdir(path);
if(access(path[0] ? path : ".", mode[0]=='w' || mode[0]=='a' ? W_OK : (mode[0]=='d' ? X_OK : R_OK)) == -1) exists = false;
return exists;
}
-bool createdir(const char *path)
-{
+bool createdir(const char *path) {
size_t len = strlen(path);
- if(path[len-1]==PATHDIV)
- {
+ if(path[len-1]==PATHDIV) {
static string strip;
path = copystring(strip, path, len);
}
return mkdir(path, 0777)==0;
}
-size_t fixpackagedir(char *dir)
-{
+size_t fixpackagedir(char *dir) {
path(dir);
size_t len = strlen(dir);
- if(len > 0 && dir[len-1] != PATHDIV)
- {
+ if(len > 0 && dir[len-1] != PATHDIV) {
dir[len] = PATHDIV;
dir[len+1] = '\0';
}
return len;
}
-bool subhomedir(char *dst, int len, const char *src)
-{
+bool subhomedir(char *dst, int len, const char *src) {
const char *sub = strstr(src, "$HOME");
if(!sub) sub = strchr(src, '~');
- if(sub && sub-src < len)
- {
+ if(sub && sub-src < len) {
const char *home = getenv("HOME");
if(!home || !home[0]) return false;
dst[sub-src] = '\0';
return true;
}
-const char *sethomedir(const char *dir)
-{
+const char *sethomedir(const char *dir) {
string pdir;
copystring(pdir, dir);
if(!subhomedir(pdir, sizeof(pdir), dir) || !fixpackagedir(pdir)) return NULL;
return homedir;
}
-const char *addpackagedir(const char *dir)
-{
+const char *addpackagedir(const char *dir) {
string pdir;
copystring(pdir, dir);
if(!subhomedir(pdir, sizeof(pdir), dir) || !fixpackagedir(pdir)) return NULL;
char *filter = pdir;
- for(;;)
- {
+ for(;;) {
static int len = strlen("packages");
filter = strstr(filter, "packages");
if(!filter) break;
return pf.dir;
}
-const char *findfile(const char *filename, const char *mode)
-{
+const char *findfile(const char *filename, const char *mode) {
static string s;
- if(homedir[0])
- {
+ if(homedir[0]) {
formatstring(s, "%s%s", homedir, filename);
if(fileexists(s, mode)) return s;
- if(mode[0]=='w' || mode[0]=='a')
- {
+ if(mode[0]=='w' || mode[0]=='a') {
string dirs;
copystring(dirs, s);
char *dir = strchr(dirs[0]==PATHDIV ? dirs+1 : dirs, PATHDIV);
- while(dir)
- {
+ while(dir) {
*dir = '\0';
if(!fileexists(dirs, "d") && !createdir(dirs)) return s;
*dir = PATHDIV;
}
}
if(mode[0]=='w' || mode[0]=='a') return filename;
- loopv(packagedirs)
- {
+ loopv(packagedirs) {
packagedir &pf = packagedirs[i];
if(pf.filter && strncmp(filename, pf.filter, pf.filterlen)) continue;
formatstring(s, "%s%s", pf.dir, filename);
return filename;
}
-bool listdir(const char *dirname, bool rel, const char *ext, vector<char *> &files)
-{
+bool listdir(const char *dirname, bool rel, const char *ext, vector<char *> &files) {
size_t extsize = ext ? strlen(ext)+1 : 0;
defformatstring(pathname, rel ? "./%s" : "%s", dirname);
DIR *d = opendir(pathname);
- if(d)
- {
+ if(d) {
struct dirent *de;
- while((de = readdir(d)) != NULL)
- {
+ while((de = readdir(d)) != NULL) {
if(!ext) files.add(newstring(de->d_name));
- else
- {
+ else {
size_t namelen = strlen(de->d_name);
- if(namelen > extsize)
- {
+ if(namelen > extsize) {
namelen -= extsize;
if(de->d_name[namelen] == '.' && strncmp(de->d_name+namelen+1, ext, extsize-1)==0)
files.add(newstring(de->d_name, namelen));
else return false;
}
-int listfiles(const char *dir, const char *ext, vector<char *> &files)
-{
+int listfiles(const char *dir, const char *ext, vector<char *> &files) {
string dirname;
copystring(dirname, dir);
path(dirname);
int dirs = 0;
if(listdir(dirname, true, ext, files)) dirs++;
string s;
- if(homedir[0])
- {
+ if(homedir[0]) {
formatstring(s, "%s%s", homedir, dirname);
if(listdir(s, false, ext, files)) dirs++;
}
- loopv(packagedirs)
- {
+ loopv(packagedirs) {
packagedir &pf = packagedirs[i];
if(pf.filter && strncmp(dirname, pf.filter, dirlen == pf.filterlen-1 ? dirlen : pf.filterlen))
continue;
}
#ifndef STANDALONE
-static Sint64 rwopsseek(SDL_RWops *rw, Sint64 pos, int whence)
-{
+static Sint64 rwopsseek(SDL_RWops *rw, Sint64 pos, int whence) {
stream *f = (stream *)rw->hidden.unknown.data1;
if((!pos && whence==SEEK_CUR) || f->seek(pos, whence)) return (int)f->tell();
return -1;
}
-static size_t rwopsread(SDL_RWops *rw, void *buf, size_t size, size_t nmemb)
-{
+static size_t rwopsread(SDL_RWops *rw, void *buf, size_t size, size_t nmemb) {
stream *f = (stream *)rw->hidden.unknown.data1;
return f->read(buf, size*nmemb)/size;
}
-static size_t rwopswrite(SDL_RWops *rw, const void *buf, size_t size, size_t nmemb)
-{
+static size_t rwopswrite(SDL_RWops *rw, const void *buf, size_t size, size_t nmemb) {
stream *f = (stream *)rw->hidden.unknown.data1;
return f->write(buf, size*nmemb)/size;
}
-static int rwopsclose(SDL_RWops *rw)
-{
+static int rwopsclose(SDL_RWops *rw) {
return 0;
}
-SDL_RWops *stream::rwops()
-{
+SDL_RWops *stream::rwops() {
SDL_RWops *rw = SDL_AllocRW();
if(!rw) return NULL;
rw->hidden.unknown.data1 = this;
}
#endif
-stream::offset stream::size()
-{
+stream::offset stream::size() {
offset pos = tell(), endpos;
if(pos < 0 || !seek(0, SEEK_END)) return -1;
endpos = tell();
return pos == endpos || seek(pos, SEEK_SET) ? endpos : -1;
}
-bool stream::getline(char *str, size_t len)
-{
- loopi(len-1)
- {
+bool stream::getline(char *str, size_t len) {
+ loopi(len-1) {
if(read(&str[i], 1) != 1) { str[i] = '\0'; return i > 0; }
else if(str[i] == '\n') { str[i+1] = '\0'; return true; }
}
return true;
}
-size_t stream::printf(const char *fmt, ...)
-{
+size_t stream::printf(const char *fmt, ...) {
char buf[512];
char *str = buf;
va_list args;
int len = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if(len <= 0) return 0;
- if(len >= (int)sizeof(buf))
- {
+ if(len >= (int)sizeof(buf)) {
str = new char[len+1];
va_start(args, fmt);
vsnprintf(str, len+1, fmt, args);
return n;
}
-struct filestream : stream
-{
+struct filestream : stream {
FILE *file;
-
filestream() : file(NULL) {}
~filestream() { close(); }
-
- bool open(const char *name, const char *mode)
- {
+ bool open(const char *name, const char *mode) {
if(file) return false;
file = fopen(name, mode);
return file!=NULL;
}
-
- bool opentemp(const char *name, const char *mode)
- {
+ bool opentemp(const char *name, const char *mode) {
if(file) return false;
file = tmpfile();
return file!=NULL;
}
-
- void close()
- {
+ void close() {
if(file) { fclose(file); file = NULL; }
}
-
bool end() { return feof(file)!=0; }
- offset tell()
- {
+ offset tell() {
offset off = ftello(file);
return off + 1 >= 0 ? off : -1;
}
- bool seek(offset pos, int whence = SEEK_SET)
- {
+ bool seek(offset pos, int whence = SEEK_SET) {
return fseeko(file, pos, whence) >= 0;
}
-
size_t read(void *buf, size_t len) { return fread(buf, 1, len, file); }
size_t write(const void *buf, size_t len) { return fwrite(buf, 1, len, file); }
bool flush() { return !fflush(file); }
bool putchar(int c) { return fputc(c, file)!=EOF; }
bool getline(char *str, size_t len) { return fgets(str, len, file)!=NULL; }
bool putstring(const char *str) { return fputs(str, file)!=EOF; }
-
- size_t printf(const char *fmt, ...)
- {
+ size_t printf(const char *fmt, ...) {
va_list v;
va_start(v, fmt);
int result = vfprintf(file, fmt, v);
}
};
-struct gzstream : stream
-{
- enum
- {
+struct gzstream : stream {
+ enum {
MAGIC1 = 0x1F,
MAGIC2 = 0x8B,
BUFSIZE = 16384,
OS_UNIX = 0x03
};
-
- enum
- {
+ enum {
F_ASCII = 0x01,
F_CRC = 0x02,
F_EXTRA = 0x04,
F_COMMENT = 0x10,
F_RESERVED = 0xE0
};
-
stream *file;
z_stream zfile;
uchar *buf;
bool reading, writing, autoclose;
uint crc;
size_t headersize;
-
- gzstream() : file(NULL), buf(NULL), reading(false), writing(false), autoclose(false), crc(0), headersize(0)
- {
+ gzstream() : file(NULL), buf(NULL), reading(false), writing(false), autoclose(false), crc(0), headersize(0) {
zfile.zalloc = NULL;
zfile.zfree = NULL;
zfile.opaque = NULL;
zfile.next_in = zfile.next_out = NULL;
zfile.avail_in = zfile.avail_out = 0;
}
-
- ~gzstream()
- {
+ ~gzstream() {
close();
}
-
- void writeheader()
- {
+ void writeheader() {
uchar header[] = { MAGIC1, MAGIC2, Z_DEFLATED, 0, 0, 0, 0, 0, 0, OS_UNIX };
file->write(header, sizeof(header));
}
-
- void readbuf(size_t size = BUFSIZE)
- {
+ void readbuf(size_t size = BUFSIZE) {
if(!zfile.avail_in) zfile.next_in = (Bytef *)buf;
size = min(size, size_t(&buf[BUFSIZE] - &zfile.next_in[zfile.avail_in]));
size_t n = file->read(zfile.next_in + zfile.avail_in, size);
if(n > 0) zfile.avail_in += n;
}
-
- uchar readbyte(size_t size = BUFSIZE)
- {
+ uchar readbyte(size_t size = BUFSIZE) {
if(!zfile.avail_in) readbuf(size);
if(!zfile.avail_in) return 0;
zfile.avail_in--;
return *(uchar *)zfile.next_in++;
}
-
- void skipbytes(size_t n)
- {
- while(n > 0 && zfile.avail_in > 0)
- {
+ void skipbytes(size_t n) {
+ while(n > 0 && zfile.avail_in > 0) {
size_t skipped = min(n, size_t(zfile.avail_in));
zfile.avail_in -= skipped;
zfile.next_in += skipped;
if(n <= 0) return;
file->seek(n, SEEK_CUR);
}
-
- bool checkheader()
- {
+ bool checkheader() {
readbuf(10);
if(readbyte() != MAGIC1 || readbyte() != MAGIC2 || readbyte() != Z_DEFLATED) return false;
uchar flags = readbyte();
if(flags & F_RESERVED) return false;
skipbytes(6);
- if(flags & F_EXTRA)
- {
+ if(flags & F_EXTRA) {
size_t len = readbyte(512);
len |= size_t(readbyte(512))<<8;
skipbytes(len);
headersize = size_t(file->tell() - zfile.avail_in);
return zfile.avail_in > 0 || !file->end();
}
-
- bool open(stream *f, const char *mode, bool needclose, int level)
- {
+ bool open(stream *f, const char *mode, bool needclose, int level) {
if(file) return false;
- for(; *mode; mode++)
- {
+ for(; *mode; mode++) {
if(*mode=='r') { reading = true; break; }
else if(*mode=='w') { writing = true; break; }
}
- if(reading)
- {
+ if(reading) {
if(inflateInit2(&zfile, -MAX_WBITS) != Z_OK) reading = false;
}
else if(writing && deflateInit2(&zfile, level, Z_DEFLATED, -MAX_WBITS, min(MAX_MEM_LEVEL, 8), Z_DEFAULT_STRATEGY) != Z_OK) writing = false;
if(!reading && !writing) return false;
-
file = f;
crc = crc32(0, NULL, 0);
buf = new uchar[BUFSIZE];
-
- if(reading)
- {
+ if(reading) {
if(!checkheader()) { stopreading(); return false; }
}
else if(writing) writeheader();
-
autoclose = needclose;
return true;
}
-
uint getcrc() { return crc; }
-
- void finishreading()
- {
+ void finishreading() {
if(!reading) return;
}
-
- void stopreading()
- {
+ void stopreading() {
if(!reading) return;
inflateEnd(&zfile);
reading = false;
}
-
- void finishwriting()
- {
+ void finishwriting() {
if(!writing) return;
- for(;;)
- {
+ for(;;) {
int err = zfile.avail_out > 0 ? deflate(&zfile, Z_FINISH) : Z_OK;
if(err != Z_OK && err != Z_STREAM_END) break;
flushbuf();
if(err == Z_STREAM_END) break;
}
- uchar trailer[8] =
- {
+ uchar trailer[8] = {
uchar(crc&0xFF), uchar((crc>>8)&0xFF), uchar((crc>>16)&0xFF), uchar((crc>>24)&0xFF),
uchar(zfile.total_in&0xFF), uchar((zfile.total_in>>8)&0xFF), uchar((zfile.total_in>>16)&0xFF), uchar((zfile.total_in>>24)&0xFF)
};
file->write(trailer, sizeof(trailer));
}
-
- void stopwriting()
- {
+ void stopwriting() {
if(!writing) return;
deflateEnd(&zfile);
writing = false;
}
-
- void close()
- {
+ void close() {
if(reading) finishreading();
stopreading();
if(writing) finishwriting();
DELETEA(buf);
if(autoclose) DELETEP(file);
}
-
bool end() { return !reading && !writing; }
offset tell() { return reading ? zfile.total_out : (writing ? zfile.total_in : offset(-1)); }
offset rawtell() { return file ? file->tell() : offset(-1); }
-
- offset size()
- {
+ offset size() {
if(!file) return -1;
offset pos = tell();
if(!file->seek(-4, SEEK_END)) return -1;
uint isize = file->getlil<uint>();
return file->seek(pos, SEEK_SET) ? isize : offset(-1);
}
-
offset rawsize() { return file ? file->size() : offset(-1); }
-
- bool seek(offset pos, int whence)
- {
+ bool seek(offset pos, int whence) {
if(writing || !reading) return false;
-
- if(whence == SEEK_END)
- {
+ if(whence == SEEK_END) {
uchar skip[512];
while(read(skip, sizeof(skip)) == sizeof(skip));
return !pos;
}
else if(whence == SEEK_CUR) pos += zfile.total_out;
-
if(pos >= (offset)zfile.total_out) pos -= zfile.total_out;
else if(pos < 0 || !file->seek(headersize, SEEK_SET)) return false;
- else
- {
- if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf))
- {
+ else {
+ if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf)) {
zfile.avail_in += zfile.total_in;
zfile.next_in -= zfile.total_in;
}
- else
- {
+ else {
zfile.avail_in = 0;
zfile.next_in = NULL;
}
inflateReset(&zfile);
crc = crc32(0, NULL, 0);
}
-
uchar skip[512];
- while(pos > 0)
- {
+ while(pos > 0) {
size_t skipped = (size_t)min(pos, (offset)sizeof(skip));
if(read(skip, skipped) != skipped) { stopreading(); return false; }
pos -= skipped;
}
-
return true;
}
-
- size_t read(void *buf, size_t len)
- {
+ size_t read(void *buf, size_t len) {
if(!reading || !buf || !len) return 0;
zfile.next_out = (Bytef *)buf;
zfile.avail_out = len;
- while(zfile.avail_out > 0)
- {
- if(!zfile.avail_in)
- {
+ while(zfile.avail_out > 0) {
+ if(!zfile.avail_in) {
readbuf(BUFSIZE);
if(!zfile.avail_in) { stopreading(); break; }
}
crc = crc32(crc, (Bytef *)buf, len - zfile.avail_out);
return len - zfile.avail_out;
}
-
- bool flushbuf(bool full = false)
- {
+ bool flushbuf(bool full = false) {
if(full) deflate(&zfile, Z_SYNC_FLUSH);
- if(zfile.next_out && zfile.avail_out < BUFSIZE)
- {
+ if(zfile.next_out && zfile.avail_out < BUFSIZE) {
if(file->write(buf, BUFSIZE - zfile.avail_out) != BUFSIZE - zfile.avail_out || (full && !file->flush()))
return false;
}
zfile.avail_out = BUFSIZE;
return true;
}
-
bool flush() { return flushbuf(true); }
-
- size_t write(const void *buf, size_t len)
- {
+ size_t write(const void *buf, size_t len) {
if(!writing || !buf || !len) return 0;
zfile.next_in = (Bytef *)buf;
zfile.avail_in = len;
- while(zfile.avail_in > 0)
- {
+ while(zfile.avail_in > 0) {
if(!zfile.avail_out && !flushbuf()) { stopwriting(); break; }
int err = deflate(&zfile, Z_NO_FLUSH);
if(err != Z_OK) { stopwriting(); break; }
}
};
-struct utf8stream : stream
-{
- enum
- {
+struct utf8stream : stream {
+ enum {
BUFSIZE = 4096
};
stream *file;
size_t bufread, bufcarry, buflen;
bool reading, writing, autoclose;
uchar buf[BUFSIZE];
-
- utf8stream() : file(NULL), pos(0), bufread(0), bufcarry(0), buflen(0), reading(false), writing(false), autoclose(false)
- {
+ utf8stream() : file(NULL), pos(0), bufread(0), bufcarry(0), buflen(0), reading(false), writing(false), autoclose(false) {
}
-
- ~utf8stream()
- {
+ ~utf8stream() {
close();
}
-
- bool readbuf(size_t size = BUFSIZE)
- {
+ bool readbuf(size_t size = BUFSIZE) {
if(bufread >= bufcarry) { if(bufcarry > 0 && bufcarry < buflen) memmove(buf, &buf[bufcarry], buflen - bufcarry); buflen -= bufcarry; bufread = bufcarry = 0; }
size_t n = file->read(&buf[buflen], min(size, BUFSIZE - buflen));
if(n <= 0) return false;
if(carry > bufcarry && carry < buflen) { memmove(&buf[bufcarry], &buf[carry], buflen - carry); buflen -= carry - bufcarry; }
return true;
}
-
- bool checkheader()
- {
+ bool checkheader() {
size_t n = file->read(buf, 3);
if(n == 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) return true;
buflen = n;
return false;
}
-
- bool open(stream *f, const char *mode, bool needclose)
- {
+ bool open(stream *f, const char *mode, bool needclose) {
if(file) return false;
- for(; *mode; mode++)
- {
+ for(; *mode; mode++) {
if(*mode=='r') { reading = true; break; }
else if(*mode=='w') { writing = true; break; }
}
if(!reading && !writing) return false;
-
file = f;
-
if(reading) checkheader();
-
autoclose = needclose;
return true;
}
-
- void finishreading()
- {
+ void finishreading() {
if(!reading) return;
}
-
- void stopreading()
- {
+ void stopreading() {
if(!reading) return;
reading = false;
}
-
- void stopwriting()
- {
+ void stopwriting() {
if(!writing) return;
writing = false;
}
-
- void close()
- {
+ void close() {
stopreading();
stopwriting();
if(autoclose) DELETEP(file);
}
-
bool end() { return !reading && !writing; }
offset tell() { return reading || writing ? pos : offset(-1); }
-
- bool seek(offset off, int whence)
- {
+ bool seek(offset off, int whence) {
if(writing || !reading) return false;
-
- if(whence == SEEK_END)
- {
+ if(whence == SEEK_END) {
uchar skip[512];
while(read(skip, sizeof(skip)) == sizeof(skip));
return !off;
}
else if(whence == SEEK_CUR) off += pos;
-
if(off >= pos) off -= pos;
else if(off < 0 || !file->seek(0, SEEK_SET)) return false;
- else
- {
+ else {
bufread = bufcarry = buflen = 0;
pos = 0;
checkheader();
}
-
uchar skip[512];
- while(off > 0)
- {
+ while(off > 0) {
size_t skipped = (size_t)min(off, (offset)sizeof(skip));
if(read(skip, skipped) != skipped) { stopreading(); return false; }
off -= skipped;
}
-
return true;
}
-
- size_t read(void *dst, size_t len)
- {
+ size_t read(void *dst, size_t len) {
if(!reading || !dst || !len) return 0;
size_t next = 0;
- while(next < len)
- {
+ while(next < len) {
if(bufread >= bufcarry) { if(readbuf(BUFSIZE)) continue; stopreading(); break; }
size_t n = min(len - next, bufcarry - bufread);
memcpy(&((uchar *)dst)[next], &buf[bufread], n);
pos += next;
return next;
}
-
- bool getline(char *dst, size_t len)
- {
+ bool getline(char *dst, size_t len) {
if(!reading || !dst || !len) return false;
--len;
size_t next = 0;
- while(next < len)
- {
+ while(next < len) {
if(bufread >= bufcarry) { if(readbuf(BUFSIZE)) continue; stopreading(); if(!next) return false; break; }
size_t n = min(len - next, bufcarry - bufread);
uchar *endline = (uchar *)memchr(&buf[bufread], '\n', n);
pos += next;
return true;
}
-
- size_t write(const void *src, size_t len)
- {
+ size_t write(const void *src, size_t len) {
if(!writing || !src || !len) return 0;
uchar dst[512];
size_t next = 0;
- while(next < len)
- {
+ while(next < len) {
size_t carry = 0, n = encodeutf8(dst, sizeof(dst), &((uchar *)src)[next], len - next, &carry);
if(n > 0 && file->write(dst, n) != n) { stopwriting(); break; }
next += carry;
pos += next;
return next;
}
-
bool flush() { return file->flush(); }
};
-stream *openrawfile(const char *filename, const char *mode)
-{
+stream *openrawfile(const char *filename, const char *mode) {
const char *found = findfile(filename, mode);
if(!found) return NULL;
filestream *file = new filestream;
return file;
}
-stream *openfile(const char *filename, const char *mode)
-{
+stream *openfile(const char *filename, const char *mode) {
#ifndef STANDALONE
stream *s = openzipfile(filename, mode);
if(s) return s;
return openrawfile(filename, mode);
}
-stream *opentempfile(const char *name, const char *mode)
-{
+stream *opentempfile(const char *name, const char *mode) {
const char *found = findfile(name, mode);
filestream *file = new filestream;
if(!file->opentemp(found ? found : name, mode)) { delete file; return NULL; }
return file;
}
-stream *opengzfile(const char *filename, const char *mode, stream *file, int level)
-{
+stream *opengzfile(const char *filename, const char *mode, stream *file, int level) {
stream *source = file ? file : openfile(filename, mode);
if(!source) return NULL;
gzstream *gz = new gzstream;
return gz;
}
-stream *openutf8file(const char *filename, const char *mode, stream *file)
-{
+stream *openutf8file(const char *filename, const char *mode, stream *file) {
stream *source = file ? file : openfile(filename, mode);
if(!source) return NULL;
utf8stream *utf8 = new utf8stream;
return utf8;
}
-char *loadfile(const char *fn, size_t *size, bool utf8)
-{
+char *loadfile(const char *fn, size_t *size, bool utf8) {
stream *f = openfile(fn, "rb");
if(!f) return NULL;
stream::offset fsize = f->size();
char *buf = new (false) char[len+1];
if(!buf) { delete f; return NULL; }
size_t offset = 0;
- if(utf8 && len >= 3)
- {
+ if(utf8 && len >= 3) {
if(f->read(buf, 3) != 3) { delete f; delete[] buf; return NULL; }
if(((uchar *)buf)[0] == 0xEF && ((uchar *)buf)[1] == 0xBB && ((uchar *)buf)[2] == 0xBF) len -= 3;
else offset += 3;
#include "cube.h"
-void *operator new(size_t size)
-{
+void *operator new(size_t size) {
void *p = malloc(size);
if(!p) abort();
return p;
}
-void *operator new[](size_t size)
-{
+void *operator new[](size_t size) {
void *p = malloc(size);
if(!p) abort();
return p;
void operator delete(void *p, size_t n) { (void) n; if(p) free(p); }
void operator delete[](void *p, size_t n) { (void) n; if(p) free(p); }
-void *operator new(size_t size, bool err)
-{
+void *operator new(size_t size, bool err) {
void *p = malloc(size);
if(!p && err) abort();
return p;
}
-void *operator new[](size_t size, bool err)
-{
+void *operator new[](size_t size, bool err) {
void *p = malloc(size);
if(!p && err) abort();
return p;
static uint state[N];
static int next = N;
-void seedMT(uint seed)
-{
+void seedMT(uint seed) {
state[0] = seed;
for(uint i = 1; i < N; i++)
state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i;
next = 0;
}
-uint randomMT()
-{
+uint randomMT() {
int cur = next;
- if(++next >= N)
- {
+ if(++next >= N) {
if(next > N) { seedMT(5489U + time(NULL)); cur = next++; }
else next = 0;
}
// all network traffic is in 32bit ints, which are then compressed using the following simple scheme (assumes that most values are small).
template<class T>
-static inline void putint_(T &p, int n)
-{
+static inline void putint_(T &p, int n) {
if(n<128 && n>-127) p.put(n);
else if(n<0x8000 && n>=-0x8000) { p.put(0x80); p.put(n); p.put(n>>8); }
else { p.put(0x81); p.put(n); p.put(n>>8); p.put(n>>16); p.put(n>>24); }
void putint(packetbuf &p, int n) { putint_(p, n); }
void putint(vector<uchar> &p, int n) { putint_(p, n); }
-int getint(ucharbuf &p)
-{
+int getint(ucharbuf &p) {
int c = (schar)p.get();
if(c==-128) { int n = p.get(); n |= ((schar)p.get())<<8; return n; }
else if(c==-127) { int n = p.get(); n |= p.get()<<8; n |= p.get()<<16; return n|(p.get()<<24); }
// much smaller encoding for unsigned integers up to 28 bits, but can handle signed
template<class T>
-static inline void putuint_(T &p, int n)
-{
- if(n < 0 || n >= (1<<21))
- {
+static inline void putuint_(T &p, int n) {
+ if(n < 0 || n >= (1<<21)) {
p.put(0x80 | (n & 0x7F));
p.put(0x80 | ((n >> 7) & 0x7F));
p.put(0x80 | ((n >> 14) & 0x7F));
p.put(n >> 21);
}
else if(n < (1<<7)) p.put(n);
- else if(n < (1<<14))
- {
+ else if(n < (1<<14)) {
p.put(0x80 | (n & 0x7F));
p.put(n >> 7);
}
- else
- {
+ else {
p.put(0x80 | (n & 0x7F));
p.put(0x80 | ((n >> 7) & 0x7F));
p.put(n >> 14);
void putuint(packetbuf &p, int n) { putuint_(p, n); }
void putuint(vector<uchar> &p, int n) { putuint_(p, n); }
-int getuint(ucharbuf &p)
-{
+int getuint(ucharbuf &p) {
int n = p.get();
- if(n & 0x80)
- {
+ if(n & 0x80) {
n += (p.get() << 7) - 0x80;
if(n & (1<<14)) n += (p.get() << 14) - (1<<14);
if(n & (1<<21)) n += (p.get() << 21) - (1<<21);
}
template<class T>
-static inline void putfloat_(T &p, float f)
-{
+static inline void putfloat_(T &p, float f) {
lilswap(&f, 1);
p.put((uchar *)&f, sizeof(float));
}
void putfloat(packetbuf &p, float f) { putfloat_(p, f); }
void putfloat(vector<uchar> &p, float f) { putfloat_(p, f); }
-float getfloat(ucharbuf &p)
-{
+float getfloat(ucharbuf &p) {
float f;
p.get((uchar *)&f, sizeof(float));
return lilswap(f);
}
template<class T>
-static inline void sendstring_(const char *t, T &p)
-{
+static inline void sendstring_(const char *t, T &p) {
while(*t) putint(p, *t++);
putint(p, 0);
}
void sendstring(const char *t, packetbuf &p) { sendstring_(t, p); }
void sendstring(const char *t, vector<uchar> &p) { sendstring_(t, p); }
-void getstring(char *text, ucharbuf &p, size_t len)
-{
+void getstring(char *text, ucharbuf &p, size_t len) {
char *t = text;
- do
- {
+ do {
if(t>=&text[len]) { text[len-1] = 0; return; }
if(!p.remaining()) { *t = 0; return; }
*t = getint(p);
while(*t++);
}
-void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len)
-{
- for(int c = uchar(*src); c; c = uchar(*++src))
- {
- if(c == '\f')
- {
+void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len) {
+ for(int c = uchar(*src); c; c = uchar(*++src)) {
+ if(c == '\f') {
if(!*++src) break;
continue;
}
- if(!iscubeprint(c))
- {
+ if(!iscubeprint(c)) {
if(!iscubespace(c) || !whitespace) continue;
if(forcespace) c = ' ';
}
*dst = '\0';
}
-void ipmask::parse(const char *name)
-{
+void ipmask::parse(const char *name) {
union { uchar b[sizeof(enet_uint32)]; enet_uint32 i; } ipconv, maskconv;
ipconv.i = 0;
maskconv.i = 0;
- loopi(4)
- {
+ loopi(4) {
char *end = NULL;
int n = strtol(name, &end, 10);
if(!end) break;
if(end > name) { ipconv.b[i] = n; maskconv.b[i] = 0xFF; }
name = end;
- while(int c = *name)
- {
+ while(int c = *name) {
++name;
if(c == '.') break;
- if(c == '/')
- {
+ if(c == '/') {
int range = clamp(int(strtol(name, NULL, 10)), 0, 32);
mask = range ? ENET_HOST_TO_NET_32(0xFFffFFff << (32 - range)) : maskconv.i;
ip = ipconv.i & mask;
mask = maskconv.i;
}
-int ipmask::print(char *buf) const
-{
+int ipmask::print(char *buf) const {
char *start = buf;
union { uchar b[sizeof(enet_uint32)]; enet_uint32 i; } ipconv, maskconv;
ipconv.i = ip;
maskconv.i = mask;
int lastdigit = -1;
- loopi(4) if(maskconv.b[i])
- {
+ loopi(4) if(maskconv.b[i]) {
if(lastdigit >= 0) *buf++ = '.';
loopj(i - lastdigit - 1) { *buf++ = '*'; *buf++ = '.'; }
buf += sprintf(buf, "%d", ipconv.b[i]);
#undef swap
#endif
template<class T>
-static inline void swap(T &a, T &b)
-{
+static inline void swap(T &a, T &b) {
T t = a;
a = b;
b = t;
#undef min
#endif
template<class T>
-static inline T max(T a, T b)
-{
+static inline T max(T a, T b) {
return a > b ? a : b;
}
template<class T>
-static inline T min(T a, T b)
-{
+static inline T min(T a, T b) {
return a < b ? a : b;
}
template<class T, class U>
-static inline T clamp(T a, U b, U c)
-{
+static inline T clamp(T a, U b, U c) {
return max(T(b), min(a, T(c)));
}
inline void vformatstring(char *d, const char *fmt, va_list v, int len) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; }
template<size_t N> inline void vformatstring(char (&d)[N], const char *fmt, va_list v) { vformatstring(d, fmt, v, N); }
-inline char *copystring(char *d, const char *s, size_t len)
-{
+inline char *copystring(char *d, const char *s, size_t len) {
size_t slen = min(strlen(s), len-1);
memcpy(d, s, slen);
d[slen] = 0;
inline char *concatstring(char *d, const char *s, size_t len) { size_t used = strlen(d); return used < len ? copystring(d+used, s, len-used) : d; }
template<size_t N> inline char *concatstring(char (&d)[N], const char *s) { return concatstring(d, s, N); }
-inline char *prependstring(char *d, const char *s, size_t len)
-{
+inline char *prependstring(char *d, const char *s, size_t len) {
size_t slen = min(strlen(s), len);
memmove(&d[slen], d, min(len - slen, strlen(d) + 1));
memcpy(d, s, slen);
template<size_t N> inline char *prependstring(char (&d)[N], const char *s) { return prependstring(d, s, N); }
inline void nformatstring(char *d, int len, const char *fmt, ...) PRINTFARGS(3, 4);
-inline void nformatstring(char *d, int len, const char *fmt, ...)
-{
+inline void nformatstring(char *d, int len, const char *fmt, ...) {
va_list v;
va_start(v, fmt);
vformatstring(d, fmt, v, len);
}
template<size_t N> inline void formatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
-template<size_t N> inline void formatstring(char (&d)[N], const char *fmt, ...)
-{
+template<size_t N> inline void formatstring(char (&d)[N], const char *fmt, ...) {
va_list v;
va_start(v, fmt);
vformatstring(d, fmt, v, int(N));
}
template<size_t N> inline void concformatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
-template<size_t N> inline void concformatstring(char (&d)[N], const char *fmt, ...)
-{
+template<size_t N> inline void concformatstring(char (&d)[N], const char *fmt, ...) {
va_list v;
va_start(v, fmt);
int len = strlen(d);
#define defformatstring(d,...) string d; formatstring(d, __VA_ARGS__)
#define defvformatstring(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); }
-template<size_t N> inline bool matchstring(const char *s, size_t len, const char (&d)[N])
-{
+template<size_t N> inline bool matchstring(const char *s, size_t len, const char (&d)[N]) {
return len == N-1 && !memcmp(s, d, N-1);
}
inline char *newstring(size_t l) { return new char[l+1]; }
inline char *newstring(const char *s, size_t l) { return copystring(newstring(l), s, l+1); }
-inline char *newstring(const char *s) { size_t l = strlen(s); char *d = newstring(l); memcpy(d, s, l+1); return d; }
+inline char *newstring(const char *s) { size_t l = strlen(s); char *d = newstring(l); memcpy(d, s, l+1); return d; }
#define loopv(v) for(int i = 0; i<(v).length(); i++)
#define loopvj(v) for(int j = 0; j<(v).length(); j++)
template<class T, size_t N> inline void memclear(T (&p)[N]) { memset((void *)p, 0, N * sizeof(T)); }
template <class T>
-struct databuf
-{
- enum
- {
+struct databuf {
+ enum {
OVERREAD = 1<<0,
OVERWROTE = 1<<1
};
-
T *buf;
int len, maxlen;
uchar flags;
-
databuf() : buf(NULL), len(0), maxlen(0), flags(0) {}
-
template<class U>
databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {}
-
- void reset()
- {
+ void reset() {
len = 0;
flags = 0;
}
-
- void reset(T *buf_, int maxlen_)
- {
+ void reset(T *buf_, int maxlen_) {
reset();
buf = buf_;
maxlen = maxlen_;
}
-
- const T &get()
- {
+ const T &get() {
static T overreadval = 0;
if(len<maxlen) return buf[len++];
flags |= OVERREAD;
return overreadval;
}
-
- databuf subbuf(int sz)
- {
+ databuf subbuf(int sz) {
sz = clamp(sz, 0, maxlen-len);
len += sz;
return databuf(&buf[len-sz], sz);
}
-
- T *pad(int numvals)
- {
+ T *pad(int numvals) {
T *vals = &buf[len];
len += min(numvals, maxlen-len);
return vals;
}
-
- void put(const T &val)
- {
+ void put(const T &val) {
if(len<maxlen) buf[len++] = val;
else flags |= OVERWROTE;
}
-
- void put(const T *vals, int numvals)
- {
+ void put(const T *vals, int numvals) {
if(maxlen-len<numvals) flags |= OVERWROTE;
memcpy(&buf[len], (const void *)vals, min(maxlen-len, numvals)*sizeof(T));
len += min(maxlen-len, numvals);
}
-
- int get(T *vals, int numvals)
- {
+ int get(T *vals, int numvals) {
int read = min(maxlen-len, numvals);
if(read<numvals) flags |= OVERREAD;
memcpy(vals, (void *)&buf[len], read*sizeof(T));
len += read;
return read;
}
-
- void offset(int n)
- {
+ void offset(int n) {
n = min(n, maxlen);
buf += n;
maxlen -= n;
len = max(len-n, 0);
}
-
T *getbuf() const { return buf; }
bool empty() const { return len==0; }
int length() const { return len; }
int remaining() const { return maxlen-len; }
bool overread() const { return (flags&OVERREAD)!=0; }
bool overwrote() const { return (flags&OVERWROTE)!=0; }
-
bool check(int n) { return remaining() >= n; }
-
- void forceoverread()
- {
+ void forceoverread() {
len = maxlen;
flags |= OVERREAD;
}
typedef databuf<char> charbuf;
typedef databuf<uchar> ucharbuf;
-struct packetbuf : ucharbuf
-{
+struct packetbuf : ucharbuf {
ENetPacket *packet;
int growth;
-
packetbuf(ENetPacket *packet) : ucharbuf(packet->data, packet->dataLength), packet(packet), growth(0) {}
- packetbuf(int growth, int pflags = 0) : growth(growth)
- {
+ packetbuf(int growth, int pflags = 0) : growth(growth) {
packet = enet_packet_create(NULL, growth, pflags);
buf = (uchar *)packet->data;
maxlen = packet->dataLength;
}
~packetbuf() { cleanup(); }
-
void reliable() { packet->flags |= ENET_PACKET_FLAG_RELIABLE; }
-
- void resize(int n)
- {
+ void resize(int n) {
enet_packet_resize(packet, n);
buf = (uchar *)packet->data;
maxlen = packet->dataLength;
}
-
- void checkspace(int n)
- {
+ void checkspace(int n) {
if(len + n > maxlen && packet && growth > 0) resize(max(len + n, maxlen + growth));
}
-
- ucharbuf subbuf(int sz)
- {
+ ucharbuf subbuf(int sz) {
checkspace(sz);
return ucharbuf::subbuf(sz);
}
-
- void put(const uchar &val)
- {
+ void put(const uchar &val) {
checkspace(1);
ucharbuf::put(val);
}
-
- void put(const uchar *vals, int numvals)
- {
+ void put(const uchar *vals, int numvals) {
checkspace(numvals);
ucharbuf::put(vals, numvals);
}
-
- ENetPacket *finalize()
- {
+ ENetPacket *finalize() {
resize(len);
return packet;
}
-
- void cleanup()
- {
+ void cleanup() {
if(growth > 0 && packet && !packet->referenceCount) { enet_packet_destroy(packet); packet = NULL; buf = NULL; len = maxlen = 0; }
}
};
template<class T>
static inline float heapscore(const T &n) { return n; }
-struct sortless
-{
+struct sortless {
template<class T> bool operator()(const T &x, const T &y) const { return x < y; }
bool operator()(char *x, char *y) const { return strcmp(x, y) < 0; }
bool operator()(const char *x, const char *y) const { return strcmp(x, y) < 0; }
};
-struct sortnameless
-{
+struct sortnameless {
template<class T> bool operator()(const T &x, const T &y) const { return sortless()(x.name, y.name); }
template<class T> bool operator()(T *x, T *y) const { return sortless()(x->name, y->name); }
template<class T> bool operator()(const T *x, const T *y) const { return sortless()(x->name, y->name); }
};
template<class T, class F>
-static inline void insertionsort(T *start, T *end, F fun)
-{
- for(T *i = start+1; i < end; i++)
- {
- if(fun(*i, i[-1]))
- {
+static inline void insertionsort(T *start, T *end, F fun) {
+ for(T *i = start+1; i < end; i++) {
+ if(fun(*i, i[-1])) {
T tmp = *i;
*i = i[-1];
T *j = i-1;
}
template<class T, class F>
-static inline void insertionsort(T *buf, int n, F fun)
-{
+static inline void insertionsort(T *buf, int n, F fun) {
insertionsort(buf, buf+n, fun);
}
template<class T>
-static inline void insertionsort(T *buf, int n)
-{
+static inline void insertionsort(T *buf, int n) {
insertionsort(buf, buf+n, sortless());
}
template<class T, class F>
-static inline void quicksort(T *start, T *end, F fun)
-{
- while(end-start > 10)
- {
+static inline void quicksort(T *start, T *end, F fun) {
+ while(end-start > 10) {
T *mid = &start[(end-start)/2], *i = start+1, *j = end-2, pivot;
- if(fun(*start, *mid)) /* start < mid */
- {
+ if(fun(*start, *mid)) /* start < mid */ {
if(fun(end[-1], *start)) { pivot = *start; *start = end[-1]; end[-1] = *mid; } /* end < start < mid */
else if(fun(end[-1], *mid)) { pivot = end[-1]; end[-1] = *mid; } /* start <= end < mid */
else { pivot = *mid; } /* start < mid <= end */
else if(fun(*mid, end[-1])) { pivot = end[-1]; end[-1] = *start; *start = *mid; } /* mid < end <= start */
else { pivot = *mid; swap(*start, end[-1]); } /* end <= mid <= start */
*mid = end[-2];
- do
- {
+ do {
while(fun(*i, pivot)) if(++i >= j) goto partitioned;
while(fun(pivot, *--j)) if(i >= j) goto partitioned;
swap(*i, *j);
partitioned:
end[-2] = *i;
*i = pivot;
-
- if(i-start < end-(i+1))
- {
+ if(i-start < end-(i+1)) {
quicksort(start, i, fun);
start = i+1;
}
- else
- {
+ else {
quicksort(i+1, end, fun);
end = i;
}
}
-
insertionsort(start, end, fun);
}
template<class T, class F>
-static inline void quicksort(T *buf, int n, F fun)
-{
+static inline void quicksort(T *buf, int n, F fun) {
quicksort(buf, buf+n, fun);
}
template<class T>
-static inline void quicksort(T *buf, int n)
-{
+static inline void quicksort(T *buf, int n) {
quicksort(buf, buf+n, sortless());
}
-template<class T> struct isclass
-{
+template<class T> struct isclass {
template<class C> static char test(void (C::*)(void));
template<class C> static int test(...);
enum { yes = sizeof(test<T>(0)) == 1 ? 1 : 0, no = yes^1 };
};
-static inline uint hthash(const char *key)
-{
+static inline uint hthash(const char *key) {
uint h = 5381;
for(int i = 0, k; (k = key[i]); i++) h = ((h<<5)+h)^k; // bernstein k=33 xor
return h;
}
-static inline bool htcmp(const char *x, const char *y)
-{
+static inline bool htcmp(const char *x, const char *y) {
return !strcmp(x, y);
}
-struct stringslice
-{
+struct stringslice {
const char *str;
int len;
stringslice() {}
stringslice(const char *str, int len) : str(str), len(len) {}
stringslice(const char *str, const char *end) : str(str), len(int(end-str)) {}
-
const char *end() const { return &str[len]; }
};
inline int stringlen(const char *s) { return int(strlen(s)); }
inline int stringlen(const stringslice &s) { return s.len; }
-inline char *copystring(char *d, const stringslice &s, size_t len)
-{
+inline char *copystring(char *d, const stringslice &s, size_t len) {
size_t slen = min(size_t(s.len), len-1);
memcpy(d, s.str, slen);
d[slen] = 0;
}
template<size_t N> inline char *copystring(char (&d)[N], const stringslice &s) { return copystring(d, s, N); }
-static inline uint memhash(const void *ptr, int len)
-{
+static inline uint memhash(const void *ptr, int len) {
const uchar *data = (const uchar *)ptr;
uint h = 5381;
loopi(len) h = ((h<<5)+h)^data[i];
static inline uint hthash(const stringslice &s) { return memhash(s.str, s.len); }
-static inline bool htcmp(const stringslice &x, const char *y)
-{
+static inline bool htcmp(const stringslice &x, const char *y) {
return x.len == (int)strlen(y) && !memcmp(x.str, y, x.len);
}
-static inline uint hthash(int key)
-{
+static inline uint hthash(int key) {
return key;
}
-static inline bool htcmp(int x, int y)
-{
+static inline bool htcmp(int x, int y) {
return x==y;
}
#ifndef STANDALONE
-static inline uint hthash(GLuint key)
-{
+static inline uint hthash(GLuint key) {
return key;
}
-static inline bool htcmp(GLuint x, GLuint y)
-{
+static inline bool htcmp(GLuint x, GLuint y) {
return x==y;
}
#endif
-template <class T> struct vector
-{
+template <class T> struct vector {
static const int MINSIZE = 8;
-
T *buf;
int alen, ulen;
-
- vector() : buf(NULL), alen(0), ulen(0)
- {
+ vector() : buf(NULL), alen(0), ulen(0) {
}
-
- vector(const vector &v) : buf(NULL), alen(0), ulen(0)
- {
+ vector(const vector &v) : buf(NULL), alen(0), ulen(0) {
*this = v;
}
-
~vector() { shrink(0); if(buf) delete[] (uchar *)buf; }
-
- vector<T> &operator=(const vector<T> &v)
- {
+ vector<T> &operator=(const vector<T> &v) {
shrink(0);
if(v.length() > alen) growbuf(v.length());
loopv(v) add(v[i]);
return *this;
}
-
- T &add(const T &x)
- {
+ T &add(const T &x) {
if(ulen==alen) growbuf(ulen+1);
new (&buf[ulen]) T(x);
return buf[ulen++];
}
-
- T &add()
- {
+ T &add() {
if(ulen==alen) growbuf(ulen+1);
new (&buf[ulen]) T;
return buf[ulen++];
}
-
- T &dup()
- {
+ T &dup() {
if(ulen==alen) growbuf(ulen+1);
new (&buf[ulen]) T(buf[ulen-1]);
return buf[ulen++];
}
-
- void move(vector<T> &v)
- {
- if(!ulen)
- {
+ void move(vector<T> &v) {
+ if(!ulen) {
swap(buf, v.buf);
swap(ulen, v.ulen);
swap(alen, v.alen);
}
- else
- {
+ else {
growbuf(ulen+v.ulen);
if(v.ulen) memcpy(&buf[ulen], (void *)v.buf, v.ulen*sizeof(T));
ulen += v.ulen;
v.ulen = 0;
}
}
-
bool inrange(size_t i) const { return i<size_t(ulen); }
bool inrange(int i) const { return i>=0 && i<ulen; }
-
T &pop() { return buf[--ulen]; }
T &last() { return buf[ulen-1]; }
void drop() { ulen--; buf[ulen].~T(); }
bool empty() const { return ulen==0; }
-
int capacity() const { return alen; }
int length() const { return ulen; }
T &operator[](int i) { ASSERT(i>=0 && i<ulen); return buf[i]; }
const T &operator[](int i) const { ASSERT(i >= 0 && i<ulen); return buf[i]; }
-
void disown() { buf = NULL; alen = ulen = 0; }
-
void shrink(int i) { ASSERT(i<=ulen); if(isclass<T>::no) ulen = i; else while(ulen>i) drop(); }
void setsize(int i) { ASSERT(i<=ulen); ulen = i; }
-
void deletecontents() { while(!empty()) delete pop(); }
void deletearrays() { while(!empty()) delete[] pop(); }
-
T *getbuf() { return buf; }
const T *getbuf() const { return buf; }
bool inbuf(const T *e) const { return e >= buf && e < &buf[ulen]; }
-
template<class F>
- void sort(F fun, int i = 0, int n = -1)
- {
+ void sort(F fun, int i = 0, int n = -1) {
quicksort(&buf[i], n < 0 ? ulen-i : n, fun);
}
-
void sort() { sort(sortless()); }
void sortname() { sort(sortnameless()); }
-
- void growbuf(int sz)
- {
+ void growbuf(int sz) {
int olen = alen;
if(alen <= 0) alen = max(MINSIZE, sz);
else while(alen < sz) alen += alen/2;
if(alen <= olen) return;
uchar *newbuf = new uchar[alen*sizeof(T)];
- if(olen > 0)
- {
+ if(olen > 0) {
if(ulen > 0) memcpy(newbuf, (void *)buf, ulen*sizeof(T));
delete[] (uchar *)buf;
}
buf = (T *)newbuf;
}
-
- databuf<T> reserve(int sz)
- {
+ databuf<T> reserve(int sz) {
if(alen-ulen < sz) growbuf(ulen+sz);
return databuf<T>(&buf[ulen], sz);
}
-
- void advance(int sz)
- {
+ void advance(int sz) {
ulen += sz;
}
-
- void addbuf(const databuf<T> &p)
- {
+ void addbuf(const databuf<T> &p) {
advance(p.length());
}
-
- T *pad(int n)
- {
+ T *pad(int n) {
T *buf = reserve(n).buf;
advance(n);
return buf;
}
-
void put(const T &v) { add(v); }
-
- void put(const T *v, int n)
- {
+ void put(const T *v, int n) {
databuf<T> buf = reserve(n);
buf.put(v, n);
addbuf(buf);
}
-
- void remove(int i, int n)
- {
+ void remove(int i, int n) {
for(int p = i+n; p<ulen; p++) buf[p-n] = buf[p];
ulen -= n;
}
-
- T remove(int i)
- {
+ T remove(int i) {
T e = buf[i];
for(int p = i+1; p<ulen; p++) buf[p-1] = buf[p];
ulen--;
return e;
}
-
- T removeunordered(int i)
- {
+ T removeunordered(int i) {
T e = buf[i];
ulen--;
if(ulen>0) buf[i] = buf[ulen];
return e;
}
-
template<class U>
- int find(const U &o)
- {
+ int find(const U &o) {
loopi(ulen) if(buf[i]==o) return i;
return -1;
}
-
- void addunique(const T &o)
- {
+ void addunique(const T &o) {
if(find(o) < 0) add(o);
}
-
- void removeobj(const T &o)
- {
- loopi(ulen) if(buf[i] == o)
- {
+ void removeobj(const T &o) {
+ loopi(ulen) if(buf[i] == o) {
int dst = i;
for(int j = i+1; j < ulen; j++) if(!(buf[j] == o)) buf[dst++] = buf[j];
setsize(dst);
break;
}
}
-
- void replacewithlast(const T &o)
- {
+ void replacewithlast(const T &o) {
if(!ulen) return;
- loopi(ulen-1) if(buf[i]==o)
- {
+ loopi(ulen-1) if(buf[i]==o) {
buf[i] = buf[ulen-1];
break;
}
ulen--;
}
-
- T &insert(int i, const T &e)
- {
+ T &insert(int i, const T &e) {
add(T());
for(int p = ulen-1; p>i; p--) buf[p] = buf[p-1];
buf[i] = e;
return buf[i];
}
-
- T *insert(int i, const T *e, int n)
- {
+ T *insert(int i, const T *e, int n) {
if(alen-ulen < n) growbuf(ulen+n);
loopj(n) add(T());
for(int p = ulen-1; p>=i+n; p--) buf[p] = buf[p-n];
loopj(n) buf[i+j] = e[j];
return &buf[i];
}
-
- void reverse()
- {
+ void reverse() {
loopi(ulen/2) swap(buf[i], buf[ulen-1-i]);
}
-
static int heapparent(int i) { return (i - 1) >> 1; }
static int heapchild(int i) { return (i << 1) + 1; }
-
- void buildheap()
- {
+ void buildheap() {
for(int i = ulen/2; i >= 0; i--) downheap(i);
}
-
- int upheap(int i)
- {
+ int upheap(int i) {
float score = heapscore(buf[i]);
- while(i > 0)
- {
+ while(i > 0) {
int pi = heapparent(i);
if(score >= heapscore(buf[pi])) break;
swap(buf[i], buf[pi]);
}
return i;
}
-
- T &addheap(const T &x)
- {
+ T &addheap(const T &x) {
add(x);
return buf[upheap(ulen-1)];
}
-
- int downheap(int i)
- {
+ int downheap(int i) {
float score = heapscore(buf[i]);
- for(;;)
- {
+ for(;;) {
int ci = heapchild(i);
if(ci >= ulen) break;
float cscore = heapscore(buf[ci]);
- if(score > cscore)
- {
+ if(score > cscore) {
if(ci+1 < ulen && heapscore(buf[ci+1]) < cscore) { swap(buf[ci+1], buf[i]); i = ci+1; }
else { swap(buf[ci], buf[i]); i = ci; }
}
}
return i;
}
-
- T removeheap()
- {
+ T removeheap() {
T e = removeunordered(0);
if(ulen) downheap(0);
return e;
}
-
template<class K>
- int htfind(const K &key)
- {
+ int htfind(const K &key) {
loopi(ulen) if(htcmp(key, buf[i])) return i;
return -1;
}
};
-template<class H, class E, class K, class T> struct hashbase
-{
+template<class H, class E, class K, class T> struct hashbase {
typedef E elemtype;
typedef K keytype;
typedef T datatype;
-
enum { CHUNKSIZE = 64 };
-
struct chain { E elem; chain *next; };
struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; };
-
int size;
int numelems;
chain **chains;
-
chainchunk *chunks;
chain *unused;
-
enum { DEFAULTSIZE = 1<<10 };
-
hashbase(int size = DEFAULTSIZE)
- : size(size)
- {
+ : size(size) {
numelems = 0;
chunks = NULL;
unused = NULL;
chains = new chain *[size];
memset(chains, 0, size*sizeof(chain *));
}
-
- ~hashbase()
- {
+ ~hashbase() {
DELETEA(chains);
deletechunks();
}
-
- chain *insert(uint h)
- {
- if(!unused)
- {
+ chain *insert(uint h) {
+ if(!unused) {
chainchunk *chunk = new chainchunk;
chunk->next = chunks;
chunks = chunk;
numelems++;
return c;
}
-
template<class U>
- T &insert(uint h, const U &key)
- {
+ T &insert(uint h, const U &key) {
chain *c = insert(h);
H::setkey(c->elem, key);
return H::getdata(c->elem);
}
-
#define HTFIND(success, fail) \
uint h = hthash(key)&(this->size-1); \
- for(chain *c = this->chains[h]; c; c = c->next) \
- { \
+ for(chain *c = this->chains[h]; c; c = c->next) { \
+ \
if(htcmp(key, H::getkey(c->elem))) return success H::getdata(c->elem); \
} \
return (fail);
-
template<class U>
- T *access(const U &key)
- {
+ T *access(const U &key) {
HTFIND(&, NULL);
}
-
template<class U, class V>
- T &access(const U &key, const V &elem)
- {
+ T &access(const U &key, const V &elem) {
HTFIND( , insert(h, key) = elem);
}
-
template<class U>
- T &operator[](const U &key)
- {
+ T &operator[](const U &key) {
HTFIND( , insert(h, key));
}
-
template<class U>
- T &find(const U &key, T ¬found)
- {
+ T &find(const U &key, T ¬found) {
HTFIND( , notfound);
}
-
template<class U>
- const T &find(const U &key, const T ¬found)
- {
+ const T &find(const U &key, const T ¬found) {
HTFIND( , notfound);
}
-
template<class U>
- bool remove(const U &key)
- {
+ bool remove(const U &key) {
uint h = hthash(key)&(size-1);
- for(chain **p = &chains[h], *c = chains[h]; c; p = &c->next, c = c->next)
- {
- if(htcmp(key, H::getkey(c->elem)))
- {
+ for(chain **p = &chains[h], *c = chains[h]; c; p = &c->next, c = c->next) {
+ if(htcmp(key, H::getkey(c->elem))) {
*p = c->next;
c->elem.~E();
new (&c->elem) E;
}
return false;
}
-
- void deletechunks()
- {
- for(chainchunk *nextchunk; chunks; chunks = nextchunk)
- {
+ void deletechunks() {
+ for(chainchunk *nextchunk; chunks; chunks = nextchunk) {
nextchunk = chunks->next;
delete chunks;
}
}
-
- void clear()
- {
+ void clear() {
if(!numelems) return;
memset(chains, 0, size*sizeof(chain *));
numelems = 0;
unused = NULL;
deletechunks();
}
-
static inline chain *enumnext(void *i) { return ((chain *)i)->next; }
static inline K &enumkey(void *i) { return H::getkey(((chain *)i)->elem); }
static inline T &enumdata(void *i) { return H::getdata(((chain *)i)->elem); }
};
-template<class T> struct hashset : hashbase<hashset<T>, T, T, T>
-{
+template<class T> struct hashset : hashbase<hashset<T>, T, T, T> {
typedef hashbase<hashset<T>, T, T, T> basetype;
-
hashset(int size = basetype::DEFAULTSIZE) : basetype(size) {}
-
static inline const T &getkey(const T &elem) { return elem; }
static inline T &getdata(T &elem) { return elem; }
- template<class K> static inline void setkey(T &elem, const K &key) {}
-
+ template<class K> static inline void setkey(T &, const K &) {}
template<class V>
- T &add(const V &elem)
- {
+ T &add(const V &elem) {
return basetype::access(elem, elem);
}
};
-template<class T> struct hashnameset : hashbase<hashnameset<T>, T, const char *, T>
-{
+template<class T> struct hashnameset : hashbase<hashnameset<T>, T, const char *, T> {
typedef hashbase<hashnameset<T>, T, const char *, T> basetype;
-
hashnameset(int size = basetype::DEFAULTSIZE) : basetype(size) {}
-
template<class U> static inline const char *getkey(const U &elem) { return elem.name; }
template<class U> static inline const char *getkey(U *elem) { return elem->name; }
static inline T &getdata(T &elem) { return elem; }
template<class K> static inline void setkey(T &elem, const K &key) {}
-
template<class V>
- T &add(const V &elem)
- {
+ T &add(const V &elem) {
return basetype::access(getkey(elem), elem);
}
};
-template<class K, class T> struct hashtableentry
-{
+template<class K, class T> struct hashtableentry {
K key;
T data;
};
-template<class K, class T> struct hashtable : hashbase<hashtable<K, T>, hashtableentry<K, T>, K, T>
-{
+template<class K, class T> struct hashtable : hashbase<hashtable<K, T>, hashtableentry<K, T>, K, T> {
typedef hashbase<hashtable<K, T>, hashtableentry<K, T>, K, T> basetype;
typedef typename basetype::elemtype elemtype;
-
hashtable(int size = basetype::DEFAULTSIZE) : basetype(size) {}
-
static inline K &getkey(elemtype &elem) { return elem.key; }
static inline T &getdata(elemtype &elem) { return elem.data; }
template<class U> static inline void setkey(elemtype &elem, const U &key) { elem.key = key; }
#define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { k &e = (ht).enumkey(ec); t &f = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; }
#define enumerate(ht,t,e,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { t &e = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; }
-struct unionfind
-{
- struct ufval
- {
+struct unionfind {
+ struct ufval {
int rank, next;
-
ufval() : rank(0), next(-1) {}
};
-
vector<ufval> ufvals;
-
- int find(int k)
- {
+ int find(int k) {
if(k>=ufvals.length()) return k;
while(ufvals[k].next>=0) k = ufvals[k].next;
return k;
}
-
- int compressfind(int k)
- {
+ int compressfind(int k) {
if(ufvals[k].next<0) return k;
return ufvals[k].next = compressfind(ufvals[k].next);
}
-
- void unite (int x, int y)
- {
+ void unite (int x, int y) {
while(ufvals.length() <= max(x, y)) ufvals.add();
x = compressfind(x);
y = compressfind(y);
if(x==y) return;
ufval &xval = ufvals[x], &yval = ufvals[y];
if(xval.rank < yval.rank) xval.next = y;
- else
- {
+ else {
yval.next = x;
if(xval.rank==yval.rank) yval.rank++;
}
}
};
-template <class T, int SIZE> struct queue
-{
+template <class T, int SIZE> struct queue {
int head, tail, len;
T data[SIZE];
-
queue() { clear(); }
-
void clear() { head = tail = len = 0; }
-
int capacity() const { return SIZE; }
int length() const { return len; }
bool empty() const { return !len; }
bool full() const { return len == SIZE; }
-
bool inrange(size_t i) const { return i<size_t(len); }
bool inrange(int i) const { return i>=0 && i<len; }
-
T &added() { return data[tail > 0 ? tail-1 : SIZE-1]; }
T &added(int offset) { return data[tail-offset > 0 ? tail-offset-1 : tail-offset-1 + SIZE]; }
T &adding() { return data[tail]; }
T &adding(int offset) { return data[tail+offset >= SIZE ? tail+offset - SIZE : tail+offset]; }
- T &add()
- {
+ T &add() {
T &t = data[tail];
tail++;
if(tail >= SIZE) tail -= SIZE;
return t;
}
T &add(const T &e) { return add() = e; }
-
- databuf<T> reserve(int sz)
- {
+ databuf<T> reserve(int sz) {
if(!len) head = tail = 0;
return databuf<T>(&data[tail], min(sz, SIZE-tail));
}
-
- void advance(int sz)
- {
+ void advance(int sz) {
if(len + sz > SIZE) sz = SIZE - len;
tail += sz;
if(tail >= SIZE) tail -= SIZE;
len += sz;
}
-
- void addbuf(const databuf<T> &p)
- {
+ void addbuf(const databuf<T> &p) {
advance(p.length());
}
-
- T &pop()
- {
+ T &pop() {
tail--;
if(tail < 0) tail += SIZE;
len--;
return data[tail];
}
-
T &removing() { return data[head]; }
T &removing(int offset) { return data[head+offset >= SIZE ? head+offset - SIZE : head+offset]; }
- T &remove()
- {
+ T &remove() {
T &t = data[head];
head++;
if(head >= SIZE) head -= SIZE;
len--;
return t;
}
-
- T remove(int offset)
- {
+ T remove(int offset) {
T val = removing(offset);
if(head+offset >= SIZE) for(int i = head+offset - SIZE + 1; i < tail; i++) data[i-1] = data[i];
else if(head < tail) for(int i = head+offset + 1; i < tail; i++) data[i-1] = data[i];
- else
- {
+ else {
for(int i = head+offset + 1; i < SIZE; i++) data[i-1] = data[i];
data[SIZE-1] = data[0];
for(int i = 1; i < tail; i++) data[i-1] = data[i];
len--;
return val;
}
-
T &operator[](int offset) { return removing(offset); }
const T &operator[](int offset) const { return removing(offset); }
};
-template <class T, int SIZE> struct reversequeue : queue<T, SIZE>
-{
+template <class T, int SIZE> struct reversequeue : queue<T, SIZE> {
T &operator[](int offset) { return queue<T, SIZE>::added(offset); }
const T &operator[](int offset) const { return queue<T, SIZE>::added(offset); }
};
template<> inline double endianswap<double>(double n) { union { double t; uint i; } conv; conv.t = n; conv.i = endianswap64(conv.i); return conv.t; }
template<class T> inline void endianswap(T *buf, size_t len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); }
template<class T> inline T endiansame(T n) { return n; }
-template<class T> inline void endiansame(T *buf, size_t len) {}
+//~template<class T> inline void endiansame(T *buf, size_t len) {}
+template<class T> inline void endiansame(T *, size_t) {}
#ifdef SDL_BYTEORDER
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define lilswap endiansame
template<class T> inline void bigswap(T *buf, size_t len) { if(*(const uchar *)&islittleendian) endianswap(buf, len); }
#endif
-struct stream
-{
+struct stream {
typedef off_t offset;
-
virtual ~stream() {}
virtual void close() = 0;
virtual bool end() = 0;
virtual offset tell() { return -1; }
virtual offset rawtell() { return tell(); }
- virtual bool seek(offset pos, int whence = SEEK_SET) { return false; }
+ virtual bool seek(offset pos, int whence = SEEK_SET) { (void) pos; (void) whence; return false; }
virtual offset size();
virtual offset rawsize() { return size(); }
- virtual size_t read(void *buf, size_t len) { return 0; }
- virtual size_t write(const void *buf, size_t len) { return 0; }
+ virtual size_t read(void *buf, size_t len) { (void) buf; (void) len; return 0; }
+ virtual size_t write(const void *buf, size_t len) { (void) buf; (void) len; return 0; }
virtual bool flush() { return true; }
virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; }
virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; }
virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); }
virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3);
virtual uint getcrc() { return 0; }
-
template<class T> size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); }
template<class T> bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
template<class T> bool putlil(T n) { return put<T>(lilswap(n)); }
template<class T> bool putbig(T n) { return put<T>(bigswap(n)); }
-
template<class T> size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); }
template<class T> T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
template<class T> T getlil() { return lilswap(get<T>()); }
};
template<class T>
-struct streambuf
-{
+struct streambuf {
stream *s;
-
streambuf(stream *s) : s(s) {}
-
T get() { return s->get<T>(); }
size_t get(T *vals, size_t numvals) { return s->get(vals, numvals); }
void put(const T &val) { s->put(&val, 1); }
size_t length() { return s->size(); }
};
-enum
-{
+enum {
CT_PRINT = 1<<0,
CT_SPACE = 1<<1,
CT_DIGIT = 1<<2,
static inline int iscubelower(uchar c) { return cubectype[c]&CT_LOWER; }
static inline int iscubeupper(uchar c) { return cubectype[c]&CT_UPPER; }
static inline int iscubepunct(uchar c) { return cubectype[c] == CT_PRINT; }
-static inline int cube2uni(uchar c)
-{
+static inline int cube2uni(uchar c) {
extern const int cube2unichars[256];
return cube2unichars[c];
}
-static inline uchar uni2cube(int c)
-{
+static inline uchar uni2cube(int c) {
extern const int uni2cubeoffsets[8];
extern const uchar uni2cubechars[];
return uint(c) <= 0x7FF ? uni2cubechars[uni2cubeoffsets[c>>8] + (c&0xFF)] : 0;
}
-static inline uchar cubelower(uchar c)
-{
+static inline uchar cubelower(uchar c) {
extern const uchar cubelowerchars[256];
return cubelowerchars[c];
}
-static inline uchar cubeupper(uchar c)
-{
+static inline uchar cubeupper(uchar c) {
extern const uchar cubeupperchars[256];
return cubeupperchars[c];
}
extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len);
template<size_t N> static inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); }
-struct ipmask
-{
+struct ipmask {
enet_uint32 ip, mask;
-
void parse(const char *name);
int print(char *buf) const;
bool check(enet_uint32 host) const { return (host & mask) == ip; }
#include "cube.h"
-enum
-{
+enum {
ZIP_LOCAL_FILE_SIGNATURE = 0x04034B50,
ZIP_LOCAL_FILE_SIZE = 30,
ZIP_FILE_SIGNATURE = 0x02014B50,
ZIP_DIRECTORY_SIZE = 22
};
-struct ziplocalfileheader
-{
+struct ziplocalfileheader {
uint signature;
ushort version, flags, compression, modtime, moddate;
uint crc32, compressedsize, uncompressedsize;
ushort namelength, extralength;
};
-struct zipfileheader
-{
+struct zipfileheader {
uint signature;
ushort version, needversion, flags, compression, modtime, moddate;
uint crc32, compressedsize, uncompressedsize;
uint externalattribs, offset;
};
-struct zipdirectoryheader
-{
+struct zipdirectoryheader {
uint signature;
ushort disknumber, directorydisk, diskentries, entries;
uint size, offset;
ushort commentlength;
};
-struct zipfile
-{
+struct zipfile {
char *name;
uint header, offset, size, compressedsize;
-
- zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0)
- {
+ zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0) {
}
- ~zipfile()
- {
+ ~zipfile() {
DELETEA(name);
}
};
struct zipstream;
-struct ziparchive
-{
+struct ziparchive {
char *name;
FILE *data;
hashnameset<zipfile> files;
int openfiles;
zipstream *owner;
-
- ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL)
- {
+ ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL) {
}
- ~ziparchive()
- {
+ ~ziparchive() {
DELETEA(name);
if(data) { fclose(data); data = NULL; }
}
};
-static bool findzipdirectory(FILE *f, zipdirectoryheader &hdr)
-{
+static bool findzipdirectory(FILE *f, zipdirectoryheader &hdr) {
if(fseek(f, 0, SEEK_END) < 0) return false;
-
long offset = ftell(f);
if(offset < 0) return false;
-
uchar buf[1024], *src = NULL;
long end = max(offset - 0xFFFFL - ZIP_DIRECTORY_SIZE, 0L);
size_t len = 0;
const uint signature = lilswap<uint>(ZIP_DIRECTORY_SIGNATURE);
-
- while(offset > end)
- {
+ while(offset > end) {
size_t carry = min(len, size_t(ZIP_DIRECTORY_SIZE-1)), next = min(sizeof(buf) - carry, size_t(offset - end));
offset -= next;
memmove(&buf[next], buf, carry);
for(; search >= buf; search--) if(*(uint *)search == signature) break;
if(search >= buf) { src = search; break; }
}
-
if(!src || &buf[len] - src < ZIP_DIRECTORY_SIZE) return false;
-
hdr.signature = lilswap(*(uint *)src); src += 4;
hdr.disknumber = lilswap(*(ushort *)src); src += 2;
hdr.directorydisk = lilswap(*(ushort *)src); src += 2;
hdr.size = lilswap(*(uint *)src); src += 4;
hdr.offset = lilswap(*(uint *)src); src += 4;
hdr.commentlength = lilswap(*(ushort *)src); src += 2;
-
if(hdr.signature != ZIP_DIRECTORY_SIGNATURE || hdr.disknumber != hdr.directorydisk || hdr.diskentries != hdr.entries) return false;
-
return true;
}
-static bool readzipdirectory(const char *archname, FILE *f, int entries, int offset, uint size, vector<zipfile> &files)
-{
+static bool readzipdirectory(const char *archname, FILE *f, int entries, int offset, uint size, vector<zipfile> &files) {
uchar *buf = new (false) uchar[size], *src = buf;
if(!buf || fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, size, f) != size) { delete[] buf; return false; }
- loopi(entries)
- {
+ loopi(entries) {
if(src + ZIP_FILE_SIZE > &buf[size]) break;
-
zipfileheader hdr;
hdr.signature = lilswap(*(uint *)src); src += 4;
hdr.version = lilswap(*(ushort *)src); src += 2;
hdr.externalattribs = lilswap(*(uint *)src); src += 4;
hdr.offset = lilswap(*(uint *)src); src += 4;
if(hdr.signature != ZIP_FILE_SIGNATURE) break;
- if(!hdr.namelength || !hdr.uncompressedsize || (hdr.compression && (hdr.compression != Z_DEFLATED || !hdr.compressedsize)))
- {
+ if(!hdr.namelength || !hdr.uncompressedsize || (hdr.compression && (hdr.compression != Z_DEFLATED || !hdr.compressedsize))) {
src += hdr.namelength + hdr.extralength + hdr.commentlength;
continue;
}
if(src + hdr.namelength > &buf[size]) break;
-
string pname;
int namelen = min((int)hdr.namelength, (int)sizeof(pname)-1);
memcpy(pname, src, namelen);
pname[namelen] = '\0';
path(pname);
char *name = newstring(pname);
-
zipfile &f = files.add();
f.name = name;
f.header = hdr.offset;
f.size = hdr.uncompressedsize;
f.compressedsize = hdr.compression ? hdr.compressedsize : 0;
-
src += hdr.namelength + hdr.extralength + hdr.commentlength;
}
delete[] buf;
-
return files.length() > 0;
}
-static bool readlocalfileheader(FILE *f, ziplocalfileheader &h, uint offset)
-{
+static bool readlocalfileheader(FILE *f, ziplocalfileheader &h, uint offset) {
uchar buf[ZIP_LOCAL_FILE_SIZE];
if(fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, ZIP_LOCAL_FILE_SIZE, f) != ZIP_LOCAL_FILE_SIZE)
return false;
static vector<ziparchive *> archives;
-ziparchive *findzip(const char *name)
-{
+ziparchive *findzip(const char *name) {
loopv(archives) if(!strcmp(name, archives[i]->name)) return archives[i];
return NULL;
}
-static bool checkprefix(vector<zipfile> &files, const char *prefix, int prefixlen)
-{
- loopv(files)
- {
+static bool checkprefix(vector<zipfile> &files, const char *prefix, int prefixlen) {
+ loopv(files) {
if(!strncmp(files[i].name, prefix, prefixlen)) return false;
}
return true;
}
-static void mountzip(ziparchive &arch, vector<zipfile> &files, const char *mountdir, const char *stripdir)
-{
+static void mountzip(ziparchive &arch, vector<zipfile> &files, const char *mountdir, const char *stripdir) {
string packagesdir = "packages/";
path(packagesdir);
size_t striplen = stripdir ? strlen(stripdir) : 0;
- if(!mountdir && !stripdir) loopv(files)
- {
+ if(!mountdir && !stripdir) loopv(files) {
zipfile &f = files[i];
const char *foundpackages = strstr(f.name, packagesdir);
- if(foundpackages)
- {
- if(foundpackages > f.name)
- {
+ if(foundpackages) {
+ if(foundpackages > f.name) {
stripdir = f.name;
striplen = foundpackages - f.name;
}
break;
}
const char *foundogz = strstr(f.name, ".ogz");
- if(foundogz)
- {
+ if(foundogz) {
const char *ogzdir = foundogz;
while(--ogzdir >= f.name && *ogzdir != PATHDIV);
- if(ogzdir < f.name || checkprefix(files, f.name, ogzdir + 1 - f.name))
- {
- if(ogzdir >= f.name)
- {
+ if(ogzdir < f.name || checkprefix(files, f.name, ogzdir + 1 - f.name)) {
+ if(ogzdir >= f.name) {
stripdir = f.name;
striplen = ogzdir + 1 - f.name;
}
}
}
string mdir = "", fname;
- if(mountdir)
- {
+ if(mountdir) {
copystring(mdir, mountdir);
if(fixpackagedir(mdir) <= 1) mdir[0] = '\0';
}
- loopv(files)
- {
+ loopv(files) {
zipfile &f = files[i];
formatstring(fname, "%s%s", mdir, striplen && !strncmp(f.name, stripdir, striplen) ? &f.name[striplen] : f.name);
if(arch.files.access(fname)) continue;
}
}
-bool addzip(const char *name, const char *mount = NULL, const char *strip = NULL)
-{
+bool addzip(const char *name, const char *mount = NULL, const char *strip = NULL) {
string pname;
copystring(pname, name);
path(pname);
size_t plen = strlen(pname);
if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
-
ziparchive *exists = findzip(pname);
- if(exists)
- {
+ if(exists) {
conoutf(CON_ERROR, "already added zip %s", pname);
return true;
}
-
FILE *f = fopen(findfile(pname, "rb"), "rb");
- if(!f)
- {
+ if(!f) {
conoutf(CON_ERROR, "could not open file %s", pname);
return false;
}
zipdirectoryheader h;
vector<zipfile> files;
- if(!findzipdirectory(f, h) || !readzipdirectory(pname, f, h.entries, h.offset, h.size, files))
- {
+ if(!findzipdirectory(f, h) || !readzipdirectory(pname, f, h.entries, h.offset, h.size, files)) {
conoutf(CON_ERROR, "could not read directory in zip %s", pname);
fclose(f);
return false;
}
-
ziparchive *arch = new ziparchive;
arch->name = newstring(pname);
arch->data = f;
mountzip(*arch, files, mount, strip);
archives.add(arch);
-
conoutf("added zip %s", pname);
return true;
}
-bool removezip(const char *name)
-{
+bool removezip(const char *name) {
string pname;
copystring(pname, name);
path(pname);
int plen = (int)strlen(pname);
if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
ziparchive *exists = findzip(pname);
- if(!exists)
- {
+ if(!exists) {
conoutf(CON_ERROR, "zip %s is not loaded", pname);
return false;
}
- if(exists->openfiles)
- {
+ if(exists->openfiles) {
conoutf(CON_ERROR, "zip %s has open files", pname);
return false;
}
return true;
}
-struct zipstream : stream
-{
- enum
- {
+struct zipstream : stream {
+ enum {
BUFSIZE = 16384
};
-
ziparchive *arch;
zipfile *info;
z_stream zfile;
uchar *buf;
uint reading;
bool ended;
-
- zipstream() : arch(NULL), info(NULL), buf(NULL), reading(~0U), ended(false)
- {
+ zipstream() : arch(NULL), info(NULL), buf(NULL), reading(~0U), ended(false) {
zfile.zalloc = NULL;
zfile.zfree = NULL;
zfile.opaque = NULL;
zfile.next_in = zfile.next_out = NULL;
zfile.avail_in = zfile.avail_out = 0;
}
-
- ~zipstream()
- {
+ ~zipstream() {
close();
}
-
- void readbuf(uint size = BUFSIZE)
- {
+ void readbuf(uint size = BUFSIZE) {
if(!zfile.avail_in) zfile.next_in = (Bytef *)buf;
size = min(size, uint(&buf[BUFSIZE] - &zfile.next_in[zfile.avail_in]));
- if(arch->owner != this)
- {
+ if(arch->owner != this) {
arch->owner = NULL;
if(fseek(arch->data, reading, SEEK_SET) >= 0) arch->owner = this;
else return;
zfile.avail_in += n;
reading += n;
}
-
- bool open(ziparchive *a, zipfile *f)
- {
- if(f->offset == ~0U)
- {
+ bool open(ziparchive *a, zipfile *f) {
+ if(f->offset == ~0U) {
ziplocalfileheader h;
a->owner = NULL;
if(!readlocalfileheader(a->data, h, f->header)) return false;
f->offset = f->header + ZIP_LOCAL_FILE_SIZE + h.namelength + h.extralength;
}
-
if(f->compressedsize && inflateInit2(&zfile, -MAX_WBITS) != Z_OK) return false;
-
a->openfiles++;
arch = a;
info = f;
if(f->compressedsize) buf = new uchar[BUFSIZE];
return true;
}
-
- void stopreading()
- {
+ void stopreading() {
if(reading == ~0U) return;
if(info->compressedsize) inflateEnd(&zfile);
reading = ~0U;
}
-
- void close()
- {
+ void close() {
stopreading();
DELETEA(buf);
if(arch) { arch->owner = NULL; arch->openfiles--; arch = NULL; }
}
-
offset size() { return info->size; }
bool end() { return reading == ~0U || ended; }
offset tell() { return reading != ~0U ? (info->compressedsize ? zfile.total_out : reading - info->offset) : offset(-1); }
-
- bool seek(offset pos, int whence)
- {
+ bool seek(offset pos, int whence) {
if(reading == ~0U) return false;
- if(!info->compressedsize)
- {
- switch(whence)
- {
+ if(!info->compressedsize) {
+ switch(whence) {
case SEEK_END: pos += info->offset + info->size; break;
case SEEK_CUR: pos += reading; break;
case SEEK_SET: pos += info->offset; break;
ended = false;
return true;
}
-
- switch(whence)
- {
+ switch(whence) {
case SEEK_END: pos += info->size; break;
case SEEK_CUR: pos += zfile.total_out; break;
case SEEK_SET: break;
default: return false;
}
-
- if(pos >= (offset)info->size)
- {
+ if(pos >= (offset)info->size) {
reading = info->offset + info->compressedsize;
zfile.next_in += zfile.avail_in;
zfile.avail_in = 0;
ended = false;
return true;
}
-
if(pos < 0) return false;
if(pos >= (offset)zfile.total_out) pos -= zfile.total_out;
- else
- {
- if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf))
- {
+ else {
+ if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf)) {
zfile.avail_in += zfile.total_in;
zfile.next_in -= zfile.total_in;
}
- else
- {
+ else {
arch->owner = NULL;
zfile.avail_in = 0;
zfile.next_in = NULL;
}
inflateReset(&zfile);
}
-
uchar skip[512];
- while(pos > 0)
- {
+ while(pos > 0) {
size_t skipped = (size_t)min(pos, (offset)sizeof(skip));
if(read(skip, skipped) != skipped) return false;
pos -= skipped;
}
-
ended = false;
return true;
}
-
- size_t read(void *buf, size_t len)
- {
+ size_t read(void *buf, size_t len) {
if(reading == ~0U || !buf || !len) return 0;
- if(!info->compressedsize)
- {
- if(arch->owner != this)
- {
+ if(!info->compressedsize) {
+ if(arch->owner != this) {
arch->owner = NULL;
if(fseek(arch->data, reading, SEEK_SET) < 0) { stopreading(); return 0; }
arch->owner = this;
}
-
size_t n = fread(buf, 1, min(len, size_t(info->size + info->offset - reading)), arch->data);
reading += n;
if(n < len) ended = true;
return n;
}
-
zfile.next_out = (Bytef *)buf;
zfile.avail_out = len;
- while(zfile.avail_out > 0)
- {
+ while(zfile.avail_out > 0) {
if(!zfile.avail_in) readbuf(BUFSIZE);
int err = inflate(&zfile, Z_NO_FLUSH);
- if(err != Z_OK)
- {
+ if(err != Z_OK) {
if(err == Z_STREAM_END) ended = true;
else stopreading();
break;
}
};
-stream *openzipfile(const char *name, const char *mode)
-{
+stream *openzipfile(const char *name, const char *mode) {
for(; *mode; mode++) if(*mode=='w' || *mode=='a') return NULL;
- loopvrev(archives)
- {
+ loopvrev(archives) {
ziparchive *arch = archives[i];
zipfile *f = arch->files.access(name);
if(!f) continue;
return NULL;
}
-bool findzipfile(const char *name)
-{
- loopvrev(archives)
- {
+bool findzipfile(const char *name) {
+ loopvrev(archives) {
ziparchive *arch = archives[i];
if(arch->files.access(name)) return true;
}
return false;
}
-int listzipfiles(const char *dir, const char *ext, vector<char *> &files)
-{
+int listzipfiles(const char *dir, const char *ext, vector<char *> &files) {
size_t extsize = ext ? strlen(ext)+1 : 0, dirsize = strlen(dir);
int dirs = 0;
- loopvrev(archives)
- {
+ loopvrev(archives) {
ziparchive *arch = archives[i];
int oldsize = files.length();
- enumerate(arch->files, zipfile, f,
- {
+ enumerate(arch->files, zipfile, f, {
if(strncmp(f.name, dir, dirsize)) continue;
const char *name = f.name + dirsize;
if(name[0] == PATHDIV) name++;
if(strchr(name, PATHDIV)) continue;
if(!ext) files.add(newstring(name));
- else
- {
+ else {
size_t namelen = strlen(name);
- if(namelen > extsize)
- {
+ if(namelen > extsize) {
namelen -= extsize;
if(name[namelen] == '.' && strncmp(name+namelen+1, ext, extsize-1)==0)
files.add(newstring(name, namelen));