light: implement _shadowworldonly, fix _shadowself which was broken
This commit is contained in:
parent
62db977309
commit
6f07303504
|
|
@ -158,8 +158,10 @@ CreateGeometryFromWindings(RTCScene scene, const std::vector<winding_t *> &windi
|
||||||
|
|
||||||
RTCDevice device;
|
RTCDevice device;
|
||||||
RTCScene scene;
|
RTCScene scene;
|
||||||
/* global shadow casters */
|
|
||||||
sceneinfo skygeom, solidgeom, fencegeom, selfshadowgeom, switchableshadowgeom;
|
sceneinfo skygeom; // sky. always occludes.
|
||||||
|
sceneinfo solidgeom; // solids. always occludes.
|
||||||
|
sceneinfo filtergeom; // conditional occluders.. needs to run ray intersection filter
|
||||||
|
|
||||||
static const bsp2_t *bsp_static;
|
static const bsp2_t *bsp_static;
|
||||||
|
|
||||||
|
|
@ -175,12 +177,8 @@ Embree_SceneinfoForGeomID(unsigned int geomID)
|
||||||
return skygeom;
|
return skygeom;
|
||||||
} else if (geomID == solidgeom.geomID) {
|
} else if (geomID == solidgeom.geomID) {
|
||||||
return solidgeom;
|
return solidgeom;
|
||||||
} else if (geomID == fencegeom.geomID) {
|
} else if (geomID == filtergeom.geomID) {
|
||||||
return fencegeom;
|
return filtergeom;
|
||||||
} else if (geomID == selfshadowgeom.geomID) {
|
|
||||||
return selfshadowgeom;
|
|
||||||
} else if (geomID == switchableshadowgeom.geomID) {
|
|
||||||
return switchableshadowgeom;
|
|
||||||
} else {
|
} else {
|
||||||
Error("unexpected geomID");
|
Error("unexpected geomID");
|
||||||
}
|
}
|
||||||
|
|
@ -227,6 +225,15 @@ void AddGlassToRay(const RTCIntersectContext* context, unsigned rayIndex, float
|
||||||
|
|
||||||
void AddDynamicOccluderToRay(const RTCIntersectContext* context, unsigned rayIndex, int style);
|
void AddDynamicOccluderToRay(const RTCIntersectContext* context, unsigned rayIndex, int style);
|
||||||
|
|
||||||
|
static const unsigned RAYMASK_HASMODEL_SHIFT = 0;
|
||||||
|
static const unsigned RAYMASK_HASMODEL_MASK = (1 << RAYMASK_HASMODEL_SHIFT);
|
||||||
|
|
||||||
|
static const unsigned RAYMASK_MODELINDEX_SHIFT = 1;
|
||||||
|
static const unsigned RAYMASK_MODELINDEX_MASK = (0xffff << RAYMASK_MODELINDEX_SHIFT);
|
||||||
|
|
||||||
|
static const unsigned RAYMASK_RAYINDEX_SHIFT = 17;
|
||||||
|
static const unsigned RAYMASK_RAYINDEX_MASK = (0x7fff << RAYMASK_RAYINDEX_SHIFT);
|
||||||
|
|
||||||
// called to evaluate transparency
|
// called to evaluate transparency
|
||||||
template<filtertype_t filtertype>
|
template<filtertype_t filtertype>
|
||||||
static void
|
static void
|
||||||
|
|
@ -251,40 +258,59 @@ Embree_FilterFuncN(int* valid,
|
||||||
const unsigned &primID = RTCHitN_primID(potentialHit, N, i);
|
const unsigned &primID = RTCHitN_primID(potentialHit, N, i);
|
||||||
|
|
||||||
// unpack ray index
|
// unpack ray index
|
||||||
const unsigned rayIndex = (mask >> 1);
|
const bool hasmodel = static_cast<bool>((mask & RAYMASK_HASMODEL_MASK) >> RAYMASK_HASMODEL_SHIFT);
|
||||||
|
const unsigned raySourceModelindex = (mask & RAYMASK_MODELINDEX_MASK) >> RAYMASK_MODELINDEX_SHIFT;
|
||||||
|
const unsigned rayIndex = (mask & RAYMASK_RAYINDEX_MASK) >> RAYMASK_RAYINDEX_SHIFT;
|
||||||
|
|
||||||
// bail if we hit a selfshadow face, but the ray is not coming from within that model
|
const modelinfo_t *source_modelinfo = hasmodel ? ModelInfoForModel(bsp_static, raySourceModelindex) : nullptr;
|
||||||
if (geomID == selfshadowgeom.geomID) {
|
const modelinfo_t *hit_modelinfo = Embree_LookupModelinfo(geomID, primID);
|
||||||
const bool from_selfshadow = ((mask & 1) == 1);
|
Q_assert(hit_modelinfo != nullptr);
|
||||||
if (!from_selfshadow) {
|
|
||||||
|
if (hit_modelinfo->shadowworldonly.boolValue()) {
|
||||||
|
// we hit "_shadowworldonly" "1" geometry. Ignore the hit unless we are from world.
|
||||||
|
if (!source_modelinfo || !source_modelinfo->isWorld()) {
|
||||||
// reject hit
|
// reject hit
|
||||||
valid[i] = INVALID;
|
valid[i] = INVALID;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (geomID == switchableshadowgeom.geomID) {
|
}
|
||||||
|
|
||||||
|
if (hit_modelinfo->shadowself.boolValue()) {
|
||||||
|
// only casts shadows on itself
|
||||||
|
if (source_modelinfo != hit_modelinfo) {
|
||||||
|
// reject hit
|
||||||
|
valid[i] = INVALID;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit_modelinfo->switchableshadow.boolValue()) {
|
||||||
// we hit a dynamic shadow caster. reject the hit, but store the
|
// we hit a dynamic shadow caster. reject the hit, but store the
|
||||||
// info about what we hit.
|
// info about what we hit.
|
||||||
const modelinfo_t *modelinfo = Embree_LookupModelinfo(geomID, primID);
|
|
||||||
int style = modelinfo->switchshadstyle.intValue();
|
int style = hit_modelinfo->switchshadstyle.intValue();
|
||||||
|
|
||||||
AddDynamicOccluderToRay(context, rayIndex, style);
|
AddDynamicOccluderToRay(context, rayIndex, style);
|
||||||
|
|
||||||
// reject hit
|
// reject hit
|
||||||
valid[i] = INVALID;
|
valid[i] = INVALID;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
// test fence textures and glass
|
// test fence textures and glass
|
||||||
const bsp2_dface_t *face = Embree_LookupFace(geomID, primID);
|
const bsp2_dface_t *face = Embree_LookupFace(geomID, primID);
|
||||||
const modelinfo_t *modelinfo = Embree_LookupModelinfo(geomID, primID);
|
const char *name = Face_TextureName(bsp_static, face);
|
||||||
|
|
||||||
|
const float alpha = hit_modelinfo->alpha.floatValue();
|
||||||
|
const bool isFence = (name[0] == '{');
|
||||||
|
const bool isGlass = (alpha < 1.0f);
|
||||||
|
|
||||||
|
if (isFence || isGlass) {
|
||||||
vec3_t hitpoint;
|
vec3_t hitpoint;
|
||||||
Embree_RayEndpoint(ray, potentialHit, N, i, hitpoint);
|
Embree_RayEndpoint(ray, potentialHit, N, i, hitpoint);
|
||||||
const int sample = SampleTexture(face, bsp_static, hitpoint);
|
const int sample = SampleTexture(face, bsp_static, hitpoint);
|
||||||
|
|
||||||
float alpha = 1.0f;
|
if (isGlass) {
|
||||||
if (modelinfo != nullptr) {
|
|
||||||
alpha = modelinfo->alpha.floatValue();
|
|
||||||
if (alpha < 1.0f) {
|
|
||||||
// hit glass...
|
// hit glass...
|
||||||
|
|
||||||
vec3_t rayDir = {
|
vec3_t rayDir = {
|
||||||
|
|
@ -317,10 +343,9 @@ Embree_FilterFuncN(int* valid,
|
||||||
valid[i] = INVALID;
|
valid[i] = INVALID;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const char *name = Face_TextureName(bsp_static, face);
|
|
||||||
if (name[0] == '{') {
|
if (isFence) {
|
||||||
if (sample == 255) {
|
if (sample == 255) {
|
||||||
// reject hit
|
// reject hit
|
||||||
valid[i] = INVALID;
|
valid[i] = INVALID;
|
||||||
|
|
@ -526,56 +551,75 @@ Embree_TraceInit(const bsp2_t *bsp)
|
||||||
bsp_static = bsp;
|
bsp_static = bsp;
|
||||||
Q_assert(device == nullptr);
|
Q_assert(device == nullptr);
|
||||||
|
|
||||||
std::vector<const bsp2_dface_t *> skyfaces, solidfaces, fencefaces, selfshadowfaces, switchableshadowfaces;
|
std::vector<const bsp2_dface_t *> skyfaces, solidfaces, filterfaces;
|
||||||
|
|
||||||
/* Check against the list of global shadow casters */
|
// check all modelinfos
|
||||||
for (const modelinfo_t *model : tracelist) {
|
for (int mi = 0; mi<bsp->nummodels; mi++) {
|
||||||
// TODO: factor out
|
const modelinfo_t *model = ModelInfoForModel(bsp, mi);
|
||||||
const bool isWorld = (model->model == &bsp->dmodels[0]);
|
|
||||||
|
const bool isWorld = model->isWorld();
|
||||||
|
const bool shadow = model->shadow.boolValue();
|
||||||
|
const bool shadowself = model->shadowself.boolValue();
|
||||||
|
const bool shadowworldonly = model->shadowworldonly.boolValue();
|
||||||
|
const bool switchableshadow = model->switchableshadow.boolValue();
|
||||||
|
|
||||||
|
if (!(isWorld || shadow || shadowself || shadowworldonly || switchableshadow))
|
||||||
|
continue;
|
||||||
|
|
||||||
for (int i=0; i<model->model->numfaces; i++) {
|
for (int i=0; i<model->model->numfaces; i++) {
|
||||||
const bsp2_dface_t *face = BSP_GetFace(bsp, model->model->firstface + i);
|
const bsp2_dface_t *face = BSP_GetFace(bsp, model->model->firstface + i);
|
||||||
|
const char *texname = Face_TextureName(bsp, face);
|
||||||
|
|
||||||
// check for TEX_NOSHADOW
|
// check for TEX_NOSHADOW
|
||||||
const uint64_t extended_flags = extended_texinfo_flags[face->texinfo];
|
const uint64_t extended_flags = extended_texinfo_flags[face->texinfo];
|
||||||
if (extended_flags & TEX_NOSHADOW)
|
if (extended_flags & TEX_NOSHADOW)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const char *texname = Face_TextureName(bsp, face);
|
// handle switchableshadow
|
||||||
|
if (switchableshadow) {
|
||||||
|
filterfaces.push_back(face);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle glass
|
||||||
if (model->alpha.floatValue() < 1.0f) {
|
if (model->alpha.floatValue() < 1.0f) {
|
||||||
fencefaces.push_back(face);
|
filterfaces.push_back(face);
|
||||||
} else if (!Q_strncasecmp("sky", texname, 3)) {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fence
|
||||||
|
if (texname[0] == '{') {
|
||||||
|
filterfaces.push_back(face);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle sky
|
||||||
|
if (!Q_strncasecmp("sky", texname, 3)) {
|
||||||
skyfaces.push_back(face);
|
skyfaces.push_back(face);
|
||||||
} else if (texname[0] == '{') {
|
continue;
|
||||||
fencefaces.push_back(face);
|
}
|
||||||
} else if (texname[0] == '*') {
|
|
||||||
|
// liquids
|
||||||
|
if (texname[0] == '*') {
|
||||||
if (!isWorld) {
|
if (!isWorld) {
|
||||||
// world liquids never cast shadows; shadow casting bmodel liquids do
|
// world liquids never cast shadows; shadow casting bmodel liquids do
|
||||||
solidfaces.push_back(face);
|
solidfaces.push_back(face);
|
||||||
}
|
}
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// solid faces
|
||||||
|
|
||||||
|
if (isWorld || shadow){
|
||||||
solidfaces.push_back(face);
|
solidfaces.push_back(face);
|
||||||
|
} else {
|
||||||
|
// shadowself or shadowworldonly
|
||||||
|
Q_assert(shadowself || shadowworldonly);
|
||||||
|
filterfaces.push_back(face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Self-shadow models */
|
|
||||||
for (const modelinfo_t *model : selfshadowlist) {
|
|
||||||
for (int i=0; i<model->model->numfaces; i++) {
|
|
||||||
const bsp2_dface_t *face = BSP_GetFace(bsp, model->model->firstface + i);
|
|
||||||
selfshadowfaces.push_back(face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dynamic-shadow models */
|
|
||||||
for (const modelinfo_t *model : switchableshadowlist) {
|
|
||||||
for (int i=0; i<model->model->numfaces; i++) {
|
|
||||||
const bsp2_dface_t *face = BSP_GetFace(bsp, model->model->firstface + i);
|
|
||||||
switchableshadowfaces.push_back(face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Special handling of skip-textured bmodels */
|
/* Special handling of skip-textured bmodels */
|
||||||
std::vector<winding_t *> skipwindings;
|
std::vector<winding_t *> skipwindings;
|
||||||
for (const modelinfo_t *model : tracelist) {
|
for (const modelinfo_t *model : tracelist) {
|
||||||
|
|
@ -605,29 +649,19 @@ Embree_TraceInit(const bsp2_t *bsp)
|
||||||
scene = rtcDeviceNewScene(device, RTC_SCENE_STATIC | RTC_SCENE_COHERENT, RTC_INTERSECT1 | RTC_INTERSECT_STREAM);
|
scene = rtcDeviceNewScene(device, RTC_SCENE_STATIC | RTC_SCENE_COHERENT, RTC_INTERSECT1 | RTC_INTERSECT_STREAM);
|
||||||
skygeom = CreateGeometry(bsp, scene, skyfaces);
|
skygeom = CreateGeometry(bsp, scene, skyfaces);
|
||||||
solidgeom = CreateGeometry(bsp, scene, solidfaces);
|
solidgeom = CreateGeometry(bsp, scene, solidfaces);
|
||||||
fencegeom = CreateGeometry(bsp, scene, fencefaces);
|
filtergeom = CreateGeometry(bsp, scene, filterfaces);
|
||||||
selfshadowgeom = CreateGeometry(bsp, scene, selfshadowfaces);
|
|
||||||
switchableshadowgeom = CreateGeometry(bsp, scene, switchableshadowfaces);
|
|
||||||
CreateGeometryFromWindings(scene, skipwindings);
|
CreateGeometryFromWindings(scene, skipwindings);
|
||||||
|
|
||||||
rtcSetIntersectionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
rtcSetIntersectionFilterFunctionN(scene, filtergeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
||||||
rtcSetOcclusionFilterFunctionN(scene, fencegeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
|
rtcSetOcclusionFilterFunctionN(scene, filtergeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
|
||||||
|
|
||||||
rtcSetIntersectionFilterFunctionN(scene, selfshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
|
||||||
rtcSetOcclusionFilterFunctionN(scene, selfshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
|
|
||||||
|
|
||||||
rtcSetIntersectionFilterFunctionN(scene, switchableshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::INTERSECTION>);
|
|
||||||
rtcSetOcclusionFilterFunctionN(scene, switchableshadowgeom.geomID, Embree_FilterFuncN<filtertype_t::OCCLUSION>);
|
|
||||||
|
|
||||||
rtcCommit (scene);
|
rtcCommit (scene);
|
||||||
|
|
||||||
logprint("Embree_TraceInit: %d skyfaces %d solidfaces %d fencefaces %d selfshadowfaces %d switchableshadowfaces %d skipwindings\n",
|
logprint("Embree_TraceInit:\n");
|
||||||
(int)skyfaces.size(),
|
logprint("\t%d sky faces\n", (int)skyfaces.size());
|
||||||
(int)solidfaces.size(),
|
logprint("\t%d solid faces\n", (int)solidfaces.size());
|
||||||
(int)fencefaces.size(),
|
logprint("\t%d filtered faces\n", (int)filterfaces.size());
|
||||||
(int)selfshadowfaces.size(),
|
logprint("\t%d shadow-casting skip faces\n", (int)skipwindings.size());
|
||||||
(int)switchableshadowfaces.size(),
|
|
||||||
(int)skipwindings.size());
|
|
||||||
|
|
||||||
FreeWindings(skipwindings);
|
FreeWindings(skipwindings);
|
||||||
}
|
}
|
||||||
|
|
@ -646,12 +680,21 @@ static RTCRay SetupRay(unsigned rayindex, const vec3_t start, const vec3_t dir,
|
||||||
// NOTE: we are not using the ray masking feature of embree, but just using
|
// NOTE: we are not using the ray masking feature of embree, but just using
|
||||||
// this field to store whether the ray is coming from self-shadow geometry
|
// this field to store whether the ray is coming from self-shadow geometry
|
||||||
ray.mask = 0;
|
ray.mask = 0;
|
||||||
if (modelinfo && modelinfo->shadowself.boolValue()) {
|
|
||||||
ray.mask |= 1;
|
if (modelinfo) {
|
||||||
|
ray.mask |= RAYMASK_HASMODEL_MASK;
|
||||||
|
|
||||||
|
// Hacky..
|
||||||
|
const int modelindex = (modelinfo->model - bsp_static->dmodels);
|
||||||
|
Q_assert(modelindex >= 0 && modelindex < bsp_static->nummodels);
|
||||||
|
Q_assert(modelindex <= 65535);
|
||||||
|
|
||||||
|
ray.mask |= (static_cast<unsigned>(modelindex) << RAYMASK_MODELINDEX_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack the ray index into the rest of the mask
|
// pack the ray index into the rest of the mask
|
||||||
ray.mask |= (rayindex << 1);
|
Q_assert(rayindex <= 32767);
|
||||||
|
ray.mask |= (rayindex << RAYMASK_RAYINDEX_SHIFT);
|
||||||
|
|
||||||
ray.time = 0.f;
|
ray.time = 0.f;
|
||||||
return ray;
|
return ray;
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
// entity 1
|
// entity 1
|
||||||
{
|
{
|
||||||
"classname" "light"
|
"classname" "light"
|
||||||
"origin" "-40 8 104"
|
"origin" "-40 8 152"
|
||||||
"angle" "-0"
|
"angle" "-0"
|
||||||
"delay" "2"
|
"delay" "2"
|
||||||
"light" "500"
|
"light" "500"
|
||||||
|
|
@ -80,45 +80,53 @@
|
||||||
"_shadowself" "1"
|
"_shadowself" "1"
|
||||||
// brush 0
|
// brush 0
|
||||||
{
|
{
|
||||||
( -72 -136 96 ) ( 24 -136 112 ) ( 24 -136 96 ) narrow -8 80 -0 1 1
|
( -64 -176 72 ) ( -64 -112 72 ) ( -80 -192 72 ) narrow -0 -0 -0 1 1
|
||||||
( -40 -152 96 ) ( -40 -88 112 ) ( -40 -152 112 ) narrow -8 80 -0 1 1
|
( -80 -96 88 ) ( -80 -192 88 ) ( -80 -96 72 ) narrow -0 56 -0 1 1
|
||||||
( -72 -152 48 ) ( 24 -88 48 ) ( -72 -88 48 ) narrow -8 8 -0 1 1
|
( -80 -192 88 ) ( -64 -176 88 ) ( -80 -192 72 ) narrow 0 0 0 1 1
|
||||||
( -72 -152 112 ) ( 24 -88 112 ) ( 24 -152 112 ) narrow -8 8 -0 1 1
|
( -80 -96 88 ) ( -64 -112 88 ) ( -80 -192 88 ) narrow -0 -0 -0 1 1
|
||||||
( -72 -120 96 ) ( 24 -120 112 ) ( -72 -120 112 ) narrow -8 80 -0 1 1
|
( -64 -176 88 ) ( -64 -112 88 ) ( -64 -176 72 ) narrow 16 56 -0 1 1
|
||||||
( 48 -152 96 ) ( 48 -88 112 ) ( 48 -88 96 ) narrow -8 80 -0 1 1
|
( -64 -112 72 ) ( -64 -112 88 ) ( -80 -96 72 ) narrow 0 0 0 1 1
|
||||||
|
}
|
||||||
|
// brush 1
|
||||||
|
{
|
||||||
|
( -80 -192 72 ) ( 80 -192 72 ) ( -64 -176 72 ) narrow -0 -0 -0 1 1
|
||||||
|
( -64 -176 88 ) ( -80 -192 88 ) ( -64 -176 72 ) narrow 0 0 0 1 1
|
||||||
|
( 64 -176 72 ) ( 64 -176 88 ) ( -64 -176 72 ) narrow -16 56 -0 1 1
|
||||||
|
( -80 -192 88 ) ( 80 -192 88 ) ( -80 -192 72 ) narrow -0 56 -0 1 1
|
||||||
|
( 80 -192 72 ) ( 80 -192 88 ) ( 64 -176 72 ) narrow 0 0 0 1 1
|
||||||
|
( 64 -176 88 ) ( 80 -192 88 ) ( -64 -176 88 ) narrow -0 -0 -0 1 1
|
||||||
|
}
|
||||||
|
// brush 2
|
||||||
|
{
|
||||||
|
( -80 -96 72 ) ( -80 -96 88 ) ( -64 -112 72 ) narrow 0 0 0 1 1
|
||||||
|
( -64 -112 88 ) ( 64 -112 88 ) ( -64 -112 72 ) narrow -16 56 -0 1 1
|
||||||
|
( 64 -112 72 ) ( 80 -96 72 ) ( -64 -112 72 ) narrow -0 -0 -0 1 1
|
||||||
|
( -80 -96 88 ) ( 80 -96 88 ) ( -64 -112 88 ) narrow -0 -0 -0 1 1
|
||||||
|
( 64 -112 88 ) ( 80 -96 88 ) ( 64 -112 72 ) narrow 0 0 0 1 1
|
||||||
|
( 80 -96 72 ) ( 80 -96 88 ) ( -80 -96 72 ) narrow -0 56 -0 1 1
|
||||||
|
}
|
||||||
|
// brush 3
|
||||||
|
{
|
||||||
|
( 80 -192 72 ) ( 80 -96 72 ) ( 64 -176 72 ) narrow -0 -0 -0 1 1
|
||||||
|
( 64 -112 88 ) ( 64 -176 88 ) ( 64 -112 72 ) narrow 16 56 -0 1 1
|
||||||
|
( 64 -176 88 ) ( 80 -192 88 ) ( 64 -176 72 ) narrow 0 0 0 1 1
|
||||||
|
( 64 -112 88 ) ( 80 -96 88 ) ( 64 -176 88 ) narrow -0 -0 -0 1 1
|
||||||
|
( 80 -192 88 ) ( 80 -96 88 ) ( 80 -192 72 ) narrow -0 56 -0 1 1
|
||||||
|
( 80 -96 72 ) ( 80 -96 88 ) ( 64 -112 72 ) narrow 0 0 0 1 1
|
||||||
|
}
|
||||||
|
// brush 4
|
||||||
|
{
|
||||||
|
( -64 -176 64 ) ( 64 -176 80 ) ( 64 -176 64 ) narrow 0 0 0 1 1
|
||||||
|
( -64 -176 64 ) ( -64 -112 80 ) ( -64 -176 80 ) narrow 0 0 0 1 1
|
||||||
|
( -64 -176 64 ) ( 64 -112 64 ) ( -64 -112 64 ) narrow 0 0 0 1 1
|
||||||
|
( -64 -176 80 ) ( 64 -112 80 ) ( 64 -176 80 ) narrow 0 0 0 1 1
|
||||||
|
( -64 -112 64 ) ( 64 -112 80 ) ( -64 -112 80 ) narrow 0 0 0 1 1
|
||||||
|
( 64 -176 64 ) ( 64 -112 80 ) ( 64 -112 64 ) narrow 0 0 0 1 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// entity 4
|
// entity 4
|
||||||
{
|
{
|
||||||
"classname" "func_wall"
|
"classname" "func_wall"
|
||||||
"_shadowself" "1"
|
|
||||||
// brush 0
|
|
||||||
{
|
|
||||||
( -80 -144 88 ) ( 16 -144 104 ) ( 16 -144 88 ) narrow -0 72 -0 1 1
|
|
||||||
( -64 -160 88 ) ( -64 -96 104 ) ( -64 -160 104 ) narrow -0 72 -0 1 1
|
|
||||||
( -80 -160 56 ) ( 16 -96 56 ) ( -80 -96 56 ) narrow -0 -0 -0 1 1
|
|
||||||
( -80 -160 104 ) ( 16 -96 104 ) ( 16 -160 104 ) narrow -0 -0 -0 1 1
|
|
||||||
( -80 -112 88 ) ( 16 -112 104 ) ( -80 -112 104 ) narrow -0 72 -0 1 1
|
|
||||||
( 64 -160 88 ) ( 64 -96 104 ) ( 64 -96 88 ) narrow -0 72 -0 1 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// entity 5
|
|
||||||
{
|
|
||||||
"classname" "func_wall"
|
|
||||||
"_shadowself" "1"
|
|
||||||
// brush 0
|
|
||||||
{
|
|
||||||
( -80 -160 72 ) ( 16 -160 88 ) ( 16 -160 72 ) narrow -0 56 -0 1 1
|
|
||||||
( -80 -160 72 ) ( -80 -96 88 ) ( -80 -160 88 ) narrow -0 56 -0 1 1
|
|
||||||
( -80 -160 72 ) ( 16 -96 72 ) ( -80 -96 72 ) narrow -0 -0 -0 1 1
|
|
||||||
( -80 -160 88 ) ( 16 -96 88 ) ( 16 -160 88 ) narrow -0 -0 -0 1 1
|
|
||||||
( -80 -96 72 ) ( 16 -96 88 ) ( -80 -96 88 ) narrow -0 56 -0 1 1
|
|
||||||
( 80 -160 72 ) ( 80 -96 88 ) ( 80 -96 72 ) narrow -0 56 -0 1 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// entity 6
|
|
||||||
{
|
|
||||||
"classname" "func_wall"
|
|
||||||
"_shadow" "1"
|
"_shadow" "1"
|
||||||
// brush 0
|
// brush 0
|
||||||
{
|
{
|
||||||
|
|
@ -130,7 +138,7 @@
|
||||||
( -32 -80 16 ) ( -32 -64 32 ) ( -32 -64 16 ) narrow -112 -0 -0 1 1
|
( -32 -80 16 ) ( -32 -64 32 ) ( -32 -64 16 ) narrow -112 -0 -0 1 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// entity 7
|
// entity 5
|
||||||
{
|
{
|
||||||
"classname" "func_illusionary"
|
"classname" "func_illusionary"
|
||||||
// brush 0
|
// brush 0
|
||||||
|
|
@ -143,7 +151,7 @@
|
||||||
( 144 -320 16 ) ( 144 -256 80 ) ( 144 -256 16 ) narrow -0 16 -0 1 1
|
( 144 -320 16 ) ( 144 -256 80 ) ( 144 -256 16 ) narrow -0 16 -0 1 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// entity 8
|
// entity 6
|
||||||
{
|
{
|
||||||
"classname" "func_wall"
|
"classname" "func_wall"
|
||||||
"_shadowworldonly" "1"
|
"_shadowworldonly" "1"
|
||||||
|
|
@ -157,3 +165,53 @@
|
||||||
( -0 -80 16 ) ( -0 -64 32 ) ( -0 -64 16 ) narrow -112 -0 -0 1 1
|
( -0 -80 16 ) ( -0 -64 32 ) ( -0 -64 16 ) narrow -112 -0 -0 1 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// entity 7
|
||||||
|
{
|
||||||
|
"classname" "func_wall"
|
||||||
|
"_shadowself" "1"
|
||||||
|
// brush 0
|
||||||
|
{
|
||||||
|
( -32 -152 144 ) ( -96 -152 144 ) ( -16 -152 160 ) narrow 80 80 270 1 -1
|
||||||
|
( -112 -136 160 ) ( -16 -136 160 ) ( -112 -152 160 ) narrow -80 -40 180 1 -1
|
||||||
|
( -16 -136 160 ) ( -32 -136 144 ) ( -16 -152 160 ) narrow 96 -96 270 1 1
|
||||||
|
( -112 -136 160 ) ( -96 -136 144 ) ( -16 -136 160 ) narrow 80 80 270 1 -1
|
||||||
|
( -32 -136 144 ) ( -96 -136 144 ) ( -32 -152 144 ) narrow -64 -40 180 1 -1
|
||||||
|
( -96 -152 144 ) ( -96 -136 144 ) ( -112 -152 160 ) narrow -0 -96 90 1 -1
|
||||||
|
}
|
||||||
|
// brush 1
|
||||||
|
{
|
||||||
|
( -16 -152 160 ) ( -16 -152 -0 ) ( -32 -152 144 ) narrow 80 80 270 1 -1
|
||||||
|
( -32 -136 144 ) ( -16 -136 160 ) ( -32 -152 144 ) narrow 96 -96 270 1 1
|
||||||
|
( -32 -152 16 ) ( -32 -136 16 ) ( -32 -152 144 ) narrow 64 -40 270 1 1
|
||||||
|
( -16 -136 160 ) ( -16 -136 -0 ) ( -16 -152 160 ) narrow 80 -40 270 1 1
|
||||||
|
( -16 -152 -0 ) ( -16 -136 -0 ) ( -32 -152 16 ) narrow -64 -96 90 1 -1
|
||||||
|
( -32 -136 16 ) ( -16 -136 -0 ) ( -32 -136 144 ) narrow 80 80 270 1 -1
|
||||||
|
}
|
||||||
|
// brush 2
|
||||||
|
{
|
||||||
|
( -112 -152 160 ) ( -112 -136 160 ) ( -96 -152 144 ) narrow -0 -96 90 1 -1
|
||||||
|
( -96 -136 144 ) ( -96 -136 16 ) ( -96 -152 144 ) narrow 64 -40 270 1 1
|
||||||
|
( -96 -152 16 ) ( -112 -152 -0 ) ( -96 -152 144 ) narrow 80 80 270 1 -1
|
||||||
|
( -112 -136 160 ) ( -112 -136 -0 ) ( -96 -136 144 ) narrow 80 80 270 1 -1
|
||||||
|
( -96 -136 16 ) ( -112 -136 -0 ) ( -96 -152 16 ) narrow 32 -96 270 1 1
|
||||||
|
( -112 -152 -0 ) ( -112 -136 -0 ) ( -112 -152 160 ) narrow 80 -40 270 1 1
|
||||||
|
}
|
||||||
|
// brush 3
|
||||||
|
{
|
||||||
|
( -16 -152 -0 ) ( -112 -152 -0 ) ( -32 -152 16 ) narrow 80 80 270 1 -1
|
||||||
|
( -96 -136 16 ) ( -32 -136 16 ) ( -96 -152 16 ) narrow -64 -40 180 1 -1
|
||||||
|
( -32 -136 16 ) ( -16 -136 -0 ) ( -32 -152 16 ) narrow -64 -96 90 1 -1
|
||||||
|
( -96 -136 16 ) ( -112 -136 -0 ) ( -32 -136 16 ) narrow 80 80 270 1 -1
|
||||||
|
( -16 -136 -0 ) ( -112 -136 -0 ) ( -16 -152 -0 ) narrow -80 -40 180 1 -1
|
||||||
|
( -112 -152 -0 ) ( -112 -136 -0 ) ( -96 -152 16 ) narrow 32 -96 270 1 1
|
||||||
|
}
|
||||||
|
// brush 4
|
||||||
|
{
|
||||||
|
( -32 -160 144 ) ( -32 -144 16 ) ( -32 -160 16 ) narrow 80 -96 270 1 1
|
||||||
|
( -32 -160 144 ) ( -96 -144 144 ) ( -32 -144 144 ) narrow -80 -96 180 1 -1
|
||||||
|
( -32 -160 144 ) ( -96 -160 16 ) ( -96 -160 144 ) narrow 80 80 270 1 -1
|
||||||
|
( -32 -144 144 ) ( -96 -144 16 ) ( -32 -144 16 ) narrow 80 80 270 1 -1
|
||||||
|
( -96 -160 144 ) ( -96 -144 16 ) ( -96 -144 144 ) narrow 80 -96 270 1 1
|
||||||
|
( -32 -160 16 ) ( -96 -144 16 ) ( -96 -160 16 ) narrow -80 -96 180 1 -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue