/** * @brief Slides a door * * @note Though doors, sliding doors need a very different handling: * because it's movement is animated (unlike the rotating door), * the final position that is used to calculate the routing data * is set once the animation finished (because this recalculation * might be very expensive). * * @param[in,out] le The local entity of the inline model * @param[in] speed The speed to slide with - a negative value to close the door * @sa Door_SlidingUse */ void LET_SlideDoor (le_t* le, int speed) { vec3_t moveAngles, moveDir; /* get the movement angle vector */ GET_SLIDING_DOOR_SHIFT_VECTOR(le->dir, speed, moveAngles); /* this origin is only an offset to the absolute mins/maxs for rendering */ VectorAdd(le->origin, moveAngles, le->origin); /* get the direction vector from the movement angles that were set on the entity */ AngleVectors(moveAngles, moveDir, nullptr, nullptr); moveDir[0] = fabsf(moveDir[0]); moveDir[1] = fabsf(moveDir[1]); moveDir[2] = fabsf(moveDir[2]); /* calculate the distance from the movement angles and the entity size */ const int distance = DotProduct(moveDir, le->size); bool endPos = false; if (speed > 0) { /* check whether the distance the door may slide is slided already * - if so, stop the movement of the door */ if (fabs(le->origin[le->dir & 3]) >= distance) endPos = true; } else { /* the sliding door has not origin set - except when it is opened. This door type is no * origin brush based bmodel entity. So whenever the origin vector is not the zero vector, * the door is opened. */ if (VectorEmpty(le->origin)) endPos = true; } if (endPos) { vec3_t distanceVec; /* the door finished its move - either close or open, so make sure to recalc the routing * data and set the mins/maxs for the inline brush model */ cBspModel_t* model = CM_InlineModel(cl.mapTiles, le->inlineModelName); assert(model); /* we need the angles vector normalized */ GET_SLIDING_DOOR_SHIFT_VECTOR(le->dir, (speed < 0) ? -1 : 1, moveAngles); /* the bounding box of the door is updated in one step - here is no lerping needed */ VectorMul(distance, moveAngles, distanceVec); model->cbmBox.shift(distanceVec); CL_RecalcRouting(le); /* reset the think function as the movement finished */ LE_SetThink(le, nullptr); } else le->thinkDelay = 1000; }
/** * @brief Rotates AABB around given origin point; note that it will expand the box unless all angles are multiples of 90 degrees * @note Not fully verified so far */ void AABB::rotateAround (const vec3_t origin, const vec3_t angles) { /* reject non-rotations */ if (VectorEmpty(angles)) return; /* construct box-centered coordinates (center and corners) */ vec3_t center, halfDiagonal; VectorInterpolation(mins, maxs, 0.5f, center); VectorSubtract(maxs, center, halfDiagonal); /* offset coordinate frame to rotation origin */ VectorSubtract(center, origin, center); /* rotate center by given angles */ vec3_t m[3]; VectorCreateRotationMatrix(angles, m); vec3_t newCenter; VectorRotate(m, center, newCenter); /* short-circuit calculation of the rotated box half-extents */ /* shortcut is: instead of calculating all 8 AABB corners, use the symmetry by rotating box around it's center. */ VectorAbs(m[0]); VectorAbs(m[1]); VectorAbs(m[2]); vec3_t newHalfDiagonal; VectorRotate(m, halfDiagonal, newHalfDiagonal); /* de-offset coordinate frame from rotation origin */ VectorAdd(newCenter, origin, newCenter); /* finally, combine results into new AABB */ VectorAdd(newCenter, newHalfDiagonal, maxs); VectorSubtract(newCenter, newHalfDiagonal, mins); }
void SymbolsAdd(char* identifier, AstDeclaration* declaration, int line) { int current = 0; int last = 0; Symbol* new_symbol = NULL; if (!symbols) init(); /* Verifies if this declaration shadows a symbol in the current block */ if (!VectorEmpty(blocks)) last = (int)(intptr_t)VectorPeek(blocks); for (current = VectorSize(symbols) - 1; current >= last; current--) { Symbol* symbol = (Symbol*)VectorGet(symbols, current); if (symbol->identifier == identifier) ErrorL(line, "symbol '%s' is already declared", identifier); } /* Inserts the the symbol */ new_symbol = NEW(Symbol); new_symbol->identifier = identifier; new_symbol->declaration = declaration; VectorPush(symbols, new_symbol); }
void GL_DrawBspModel( mmodel_t *model ) { mface_t *face; int count, mask = 0; vec3_t bounds[2]; vec_t dot; vec3_t transformed, temp; entity_t *ent = glr.ent; glCullResult_t cull; if( glr.entrotated ) { cull = GL_CullSphere( ent->origin, model->radius ); if( cull == CULL_OUT ) { c.spheresCulled++; return; } if( cull == CULL_CLIP ) { VectorCopy( model->mins, bounds[0] ); VectorCopy( model->maxs, bounds[1] ); cull = GL_CullLocalBox( ent->origin, bounds ); if( cull == CULL_OUT ) { c.rotatedBoxesCulled++; return; } } VectorSubtract( glr.fd.vieworg, ent->origin, temp ); transformed[0] = DotProduct( temp, glr.entaxis[0] ); transformed[1] = DotProduct( temp, glr.entaxis[1] ); transformed[2] = DotProduct( temp, glr.entaxis[2] ); } else { VectorAdd( model->mins, ent->origin, bounds[0] ); VectorAdd( model->maxs, ent->origin, bounds[1] ); cull = GL_CullBox( bounds ); if( cull == CULL_OUT ) { c.boxesCulled++; return; } VectorSubtract( glr.fd.vieworg, ent->origin, transformed ); if( VectorEmpty( ent->origin ) && model->drawframe != glr.drawframe ) { mask = SURF_TRANS33|SURF_TRANS66; } } // protect against infinite loop if the same inline model // with alpha faces is referenced by multiple entities model->drawframe = glr.drawframe; #if USE_DLIGHTS glr.dlightframe++; if( gl_dynamic->integer == 1 ) { GL_TransformLights( model ); } #endif if( gl_dynamic->integer ) { GL_BeginLights(); } qglPushMatrix(); qglTranslatef( ent->origin[0], ent->origin[1], ent->origin[2] ); if( glr.entrotated ) { qglRotatef( ent->angles[YAW], 0, 0, 1 ); qglRotatef( ent->angles[PITCH], 0, 1, 0 ); qglRotatef( ent->angles[ROLL], 1, 0, 0 ); } // draw visible faces // FIXME: go by headnode instead? face = model->firstface; count = model->numfaces; while( count-- ) { dot = PlaneDiffFast( transformed, face->plane ); if( BSP_CullFace( face, dot ) ) { c.facesCulled++; } else if( face->drawflags & mask ) { // FIXME: alpha faces are not supported // on rotated or translated inline models GL_AddAlphaFace( face ); } else { GL_AddSolidFace( face ); } face++; } if( gl_dynamic->integer ) { GL_EndLights(); } GL_DrawSolidFaces(); qglPopMatrix(); }
/** * @brief * @sa FinalLightFace */ void BuildFacelights (unsigned int facenum) { dBspSurface_t* face; dBspPlane_t* plane; dBspTexinfo_t* tex; float* center; float* sdir, *tdir; vec3_t normal, binormal; vec4_t tangent; lightinfo_t li; float scale; int i, j, numsamples; facelight_t* fl; int* headhints; const int grid_type = config.soft ? 1 : 0; if (facenum >= MAX_MAP_FACES) { Com_Printf("MAX_MAP_FACES hit\n"); return; } face = &curTile->faces[facenum]; plane = &curTile->planes[face->planenum]; tex = &curTile->texinfo[face->texinfo]; if (tex->surfaceFlags & SURF_WARP) return; /* non-lit texture */ sdir = tex->vecs[0]; tdir = tex->vecs[1]; /* lighting -extra antialiasing */ if (config.extrasamples) numsamples = config.soft ? SOFT_SAMPLES : MAX_SAMPLES; else numsamples = 1; OBJZERO(li); scale = 1.0 / numsamples; /* each sample contributes this much */ li.face = face; li.facedist = plane->dist; VectorCopy(plane->normal, li.facenormal); /* negate the normal and dist */ if (face->side) { VectorNegate(li.facenormal, li.facenormal); li.facedist = -li.facedist; } /* get the origin offset for rotating bmodels */ VectorCopy(face_offset[facenum], li.modelorg); /* calculate lightmap texture mins and maxs */ CalcLightinfoExtents(&li); /* and the lightmap texture vectors */ CalcLightinfoVectors(&li); /* now generate all of the sample points */ CalcPoints(&li, 0, 0); fl = &facelight[config.compile_for_day][facenum]; fl->numsamples = li.numsurfpt; fl->samples = Mem_AllocTypeN(vec3_t, fl->numsamples); fl->directions = Mem_AllocTypeN(vec3_t, fl->numsamples); center = face_extents[facenum].center; /* center of the face */ /* Also setup the hints. Each hint is specific to each light source, including sunlight. */ headhints = Mem_AllocTypeN(int, (numlights[config.compile_for_day] + 1)); /* calculate light for each sample */ for (i = 0; i < fl->numsamples; i++) { float* const sample = fl->samples[i]; /* accumulate lighting here */ float* const direction = fl->directions[i]; /* accumulate direction here */ if (tex->surfaceFlags & SURF_PHONG) /* interpolated normal */ SampleNormal(&li, li.surfpt[i], normal); else /* or just plane normal */ VectorCopy(li.facenormal, normal); for (j = 0; j < numsamples; j++) { /* with antialiasing */ vec3_t pos; /* add offset for supersampling */ VectorMA(li.surfpt[i], sampleofs[grid_type][j][0] * li.step, li.textoworld[0], pos); VectorMA(pos, sampleofs[grid_type][j][1] * li.step, li.textoworld[1], pos); NudgeSamplePosition(pos, normal, center, pos); GatherSampleLight(pos, normal, sample, direction, scale, headhints); } if (VectorNotEmpty(direction)) { vec3_t dir; /* normalize it */ VectorNormalize(direction); /* finalize the lighting direction for the sample */ TangentVectors(normal, sdir, tdir, tangent, binormal); dir[0] = DotProduct(direction, tangent); dir[1] = DotProduct(direction, binormal); dir[2] = DotProduct(direction, normal); VectorCopy(dir, direction); } } /* Free the hints. */ Mem_Free(headhints); for (i = 0; i < fl->numsamples; i++) { /* pad them */ float* const direction = fl->directions[i]; if (VectorEmpty(direction)) VectorSet(direction, 0.0, 0.0, 1.0); } /* free the sample positions for the face */ Mem_Free(li.surfpt); }
/** * @brief Create lights out of patches and entity lights * @sa LightWorld * @sa BuildPatch */ void BuildLights (void) { int i; light_t* l; /* surfaces */ for (i = 0; i < MAX_MAP_FACES; i++) { /* iterate subdivided patches */ for(const patch_t* p = face_patches[i]; p; p = p->next) { if (VectorEmpty(p->light)) continue; numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); VectorCopy(p->origin, l->origin); l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; l->type = emit_surface; l->intensity = ColorNormalize(p->light, l->color); l->intensity *= p->area * config.surface_scale; } } /* entities (skip the world) */ for (i = 1; i < num_entities; i++) { float intensity; const char* color; const char* target; const entity_t* e = &entities[i]; const char* name = ValueForKey(e, "classname"); if (!Q_strstart(name, "light")) continue; /* remove those lights that are only for the night version */ if (config.compile_for_day) { const int spawnflags = atoi(ValueForKey(e, "spawnflags")); if (!(spawnflags & 1)) /* day */ continue; } numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); GetVectorForKey(e, "origin", l->origin); /* link in */ l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; intensity = FloatForKey(e, "light"); if (!intensity) intensity = 300.0; color = ValueForKey(e, "_color"); if (color && color[0] != '\0'){ if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3) Sys_Error("Invalid _color entity property given: %s", color); ColorNormalize(l->color, l->color); } else VectorSet(l->color, 1.0, 1.0, 1.0); l->intensity = intensity * config.entity_scale; l->type = emit_point; target = ValueForKey(e, "target"); if (target[0] != '\0' || Q_streq(name, "light_spot")) { l->type = emit_spotlight; l->stopdot = FloatForKey(e, "_cone"); if (!l->stopdot) l->stopdot = 10; l->stopdot = cos(l->stopdot * torad); if (target[0] != '\0') { /* point towards target */ entity_t* e2 = FindTargetEntity(target); if (!e2) Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n", (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target); else { vec3_t dest; GetVectorForKey(e2, "origin", dest); VectorSubtract(dest, l->origin, l->normal); VectorNormalize(l->normal); } } else { /* point down angle */ const float angle = FloatForKey(e, "angle"); if (angle == ANGLE_UP) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = 1.0; } else if (angle == ANGLE_DOWN) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = -1.0; } else { l->normal[2] = 0; l->normal[0] = cos(angle * torad); l->normal[1] = sin(angle * torad); } } } } /* handle worldspawn light settings */ { const entity_t* e = &entities[0]; const char* ambient, *light, *angles, *color; float f; int i; if (config.compile_for_day) { ambient = ValueForKey(e, "ambient_day"); light = ValueForKey(e, "light_day"); angles = ValueForKey(e, "angles_day"); color = ValueForKey(e, "color_day"); } else { ambient = ValueForKey(e, "ambient_night"); light = ValueForKey(e, "light_night"); angles = ValueForKey(e, "angles_night"); color = ValueForKey(e, "color_night"); } if (light[0] != '\0') sun_intensity = atoi(light); if (angles[0] != '\0') { VectorClear(sun_angles); if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2) Sys_Error("wrong angles values given: '%s'", angles); AngleVectors(sun_angles, sun_normal, nullptr, nullptr); } if (color[0] != '\0') { GetVectorFromString(color, sun_color); ColorNormalize(sun_color, sun_color); } if (ambient[0] != '\0') GetVectorFromString(ambient, sun_ambient_color); /* optionally pull brightness from worldspawn */ f = FloatForKey(e, "brightness"); if (f > 0.0) config.brightness = f; /* saturation as well */ f = FloatForKey(e, "saturation"); if (f > 0.0) config.saturation = f; else Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f); f = FloatForKey(e, "contrast"); if (f > 0.0) config.contrast = f; else Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f); /* lightmap resolution downscale (e.g. 4 = 1 << 4) */ i = atoi(ValueForKey(e, "quant")); if (i >= 1 && i <= 6) config.lightquant = i; else Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i); } Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n", sun_intensity, sun_angles[0], sun_angles[1], sun_color[0], sun_color[1], sun_color[2], sun_ambient_color[0], sun_ambient_color[1], sun_ambient_color[2]); Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night")); }