Beispiel #1
0
/**
 * @brief Slides a door
 * @note The new door state must already be set
 * @param[in,out] door The entity of the inline model. The aabb of this bmodel will get updated
 * in this function to reflect the new door position in the world
 * @sa LET_SlideDoor
 */
static void Door_SlidingUse (edict_t *door)
{
	const bool open = door->doorState == STATE_OPENED;
	vec3_t moveAngles, moveDir, distanceVec;
	int distance;

	/* get the movement angle vector - a negative speed value will close the door*/
	GET_SLIDING_DOOR_SHIFT_VECTOR(door->dir, open ? 1 : -1, moveAngles);

	/* get the direction vector from the movement angles that were set on the entity */
	AngleVectors(moveAngles, moveDir, NULL, NULL);
	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. This is the
	 * distance the door has to slide to fully open or close */
	distance = DotProduct(moveDir, door->size);

	/* the door is moved in one step on the server side - lerping is not needed here - so we
	 * perform the scalar multiplication with the distance the door must move in order to
	 * fully close/open */
	VectorMul(distance, moveAngles, distanceVec);

	/* set the updated position. The bounding boxes that are used for tracing must be
	 * shifted when the door state changes. As the mins and maxs of the aabb are absolute
	 * world coordinates in the map we have to translate the position by the above
	 * calculated movement vector */
	VectorAdd(door->origin, distanceVec, door->origin);						/* calc new model position */
//	gi.SetInlineModelOrientation(door->model, door->origin, door->angles);	/* move the model out of the way */
}
Beispiel #2
0
/**
 * @brief Grahm-Schmidt orthogonalization
 * @param[out] out Orthogonalized vector
 * @param[in] in Reference vector
 */
void Orthogonalize (vec3_t out, const vec3_t in)
{
	vec3_t tmp;
	VectorMul(DotProduct(out, in), in, tmp);
	VectorSubtract(out, tmp, out);
	VectorNormalizeFast(out);
}
Beispiel #3
0
int main(int argc, char **argv) {
  
  if (argc < 2) {
    fprintf(stderr, "usage: %s objfilename[s]\n", argv[0]);
    return -1;
  }

  XYZ minP, maxP;

  int i;
  for (i = 1; i < argc; i++) {
    OBJ_STRUCT *obj; // = loadObj(argv[argc -i], "null", 1, 1, 1, 1);
    char *ext = argv[argc-i] + strlen(argv[argc-i]) - 3;
    if (!strncmp(ext, "obj", 3)) {
      obj = loadObj(argv[argc-i], "null", 1,1,1,1);
    } else if (!strncmp(ext, "stl", 3)) {
      obj = loadObjFromSTL(argv[argc-i], "null", 1,1,1,1);
    } else {
      fprintf(stderr, "Cannot load file '%s'.\n", argv[argc-i]);
      exit(-1);
    }
    if (i == 1) {
      minP = obj->minP;
      maxP = obj->maxP;
    } else {
      if (obj->minP.x < minP.x) {
	minP.x = obj->minP.x;
      }
      if (obj->minP.y < minP.y) {
	minP.y = obj->minP.y;
      }
      if (obj->minP.z < minP.z) {
	minP.z = obj->minP.z;
      }

      if (obj->maxP.x > maxP.x) {
	maxP.x = obj->maxP.x;
      }
      if (obj->maxP.y > maxP.y) {
	maxP.y = obj->maxP.y;
      }
      if (obj->maxP.z > maxP.z) {
	maxP.z = obj->maxP.z;
      }
      
    }
  }

  // offset all model parts
  XYZ mid = VectorAdd(minP, maxP);
  mid = VectorMul(mid, 0.5);
  fprintf(stderr, "OBJ vertex range: (%f,%f,%f) -> (%f,%f,%f)\n", minP.x, minP.y, minP.z,
	  maxP.x, maxP.y, maxP.z);
  fprintf(stderr, "OBJ vertex midpoint: (%f,%f,%f)\n", mid.x, mid.y, mid.z);

  return 0;
}
Beispiel #4
0
/**
 * @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;
}
Beispiel #5
0
void update() {
	// Redraw screen now, please, and call again in 15ms.
	glutPostRedisplay();
	glutTimerFunc(15, updateI, 0);

	
	// Input is win32 only
	HWND window = GetActiveWindow();
	if(window == GetForegroundWindow()) {
		POINT p;
		GetCursorPos(&p);
		ScreenToClient(window, &p);
		glutWarpPointer(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2);

		float angleX = (p.x - (WINDOW_WIDTH / 2)) * CAM_ROTSPEED;
		Quaternion rotX = RotationQuaternion(-angleX, MakeVector(0, 1, 0));
		camera.front = TransformVector(RotationMatrixFromQuaternion(rotX), camera.front);

		camera.elevation += (p.y - (WINDOW_HEIGHT / 2)) * CAM_ROTSPEED;
		camera.elevation = max(-0.9f, min(camera.elevation, 0.9f));

		if(GetAsyncKeyState('W') != 0) {
			camera.pos = VectorAdd(camera.pos, VectorMul(camera.front, CAM_MOVESPEED));
		}

		if(GetAsyncKeyState('S') != 0) {
			camera.pos = VectorAdd(camera.pos, VectorMul(camera.front, -CAM_MOVESPEED));
		}

		if(GetAsyncKeyState('E') != 0) {
			camera.pos = VectorAdd(camera.pos, VectorMul(camera.up, CAM_MOVESPEED));
		}

		if(GetAsyncKeyState('Q') != 0) {
			camera.pos = VectorAdd(camera.pos, VectorMul(camera.up, -CAM_MOVESPEED));
		}

		if(GetAsyncKeyState('D') != 0) {
			camera.pos = VectorAdd(camera.pos, VectorMul(VectorCross(camera.front, camera.up), CAM_MOVESPEED));
		}

		if(GetAsyncKeyState('A') != 0) {
			camera.pos = VectorAdd(camera.pos, VectorMul(VectorCross(camera.front, camera.up), -CAM_MOVESPEED));
		}
	}
}
Beispiel #6
0
/**
 * @brief Calculates normals and tangents for all frames and does vertex merging based on smoothness
 * @param mesh The mesh to calculate normals for
 * @param nFrames How many frames the mesh has
 * @param smoothness How aggressively should normals be smoothed; value is compared with dotproduct of vectors to decide if they should be merged
 * @sa R_ModCalcNormalsAndTangents
 */
void R_ModCalcUniqueNormalsAndTangents (mAliasMesh_t *mesh, int nFrames, float smoothness)
{
	int i, j;
	vec3_t triangleNormals[MAX_ALIAS_TRIS];
	vec3_t triangleTangents[MAX_ALIAS_TRIS];
	vec3_t triangleBitangents[MAX_ALIAS_TRIS];
	const mAliasVertex_t *vertexes = mesh->vertexes;
	mAliasCoord_t *stcoords = mesh->stcoords;
	mAliasVertex_t *newVertexes;
	mAliasComplexVertex_t tmpVertexes[MAX_ALIAS_VERTS];
	vec3_t tmpBitangents[MAX_ALIAS_VERTS];
	mAliasCoord_t *newStcoords;
	const int numIndexes = mesh->num_tris * 3;
	const int32_t *indexArray = mesh->indexes;
	int32_t *newIndexArray;
	int indRemap[MAX_ALIAS_VERTS];
	int sharedTris[MAX_ALIAS_VERTS];
	int numVerts = 0;

	newIndexArray = (int32_t *)Mem_PoolAlloc(sizeof(int32_t) * numIndexes, vid_modelPool, 0);

	/* calculate per-triangle surface normals */
	for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
		vec3_t dir1, dir2;
		vec2_t dir1uv, dir2uv;

		/* calculate two mostly perpendicular edge directions */
		VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
		VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
		Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
		Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);

		/* we have two edge directions, we can calculate a third vector from
		 * them, which is the direction of the surface normal */
		CrossProduct(dir1, dir2, triangleNormals[j]);

		/* then we use the texture coordinates to calculate a tangent space */
		if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
			const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);
		} else {
			const float frac = 1.0 / (0.00001);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);
		}

		/* normalize */
		VectorNormalizeFast(triangleNormals[j]);
		VectorNormalizeFast(triangleTangents[j]);
		VectorNormalizeFast(triangleBitangents[j]);

		Orthogonalize(triangleTangents[j], triangleBitangents[j]);
	}

	/* do smoothing */
	for (i = 0; i < numIndexes; i++) {
		const int idx = (i - i % 3) / 3;
		VectorCopy(triangleNormals[idx], tmpVertexes[i].normal);
		VectorCopy(triangleTangents[idx], tmpVertexes[i].tangent);
		VectorCopy(triangleBitangents[idx], tmpBitangents[i]);

		for (j = 0; j < numIndexes; j++) {
			const int idx2 = (j - j % 3) / 3;
			/* don't add a vertex with itself */
			if (j == i)
				continue;

			/* only average normals if vertices have the same position
			 * and the normals aren't too far apart to start with */
			if (VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)
					&& DotProduct(triangleNormals[idx], triangleNormals[idx2]) > smoothness) {
				/* average the normals */
				VectorAdd(tmpVertexes[i].normal, triangleNormals[idx2], tmpVertexes[i].normal);

				/* if the tangents match as well, average them too.
				 * Note that having matching normals without matching tangents happens
				 * when the order of vertices in two triangles sharing the vertex
				 * in question is different.  This happens quite frequently if the
				 * modeler does not go out of their way to avoid it. */

				if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])
						&& DotProduct(triangleTangents[idx], triangleTangents[idx2]) > smoothness
						&& DotProduct(triangleBitangents[idx], triangleBitangents[idx2]) > smoothness) {
					/* average the tangents */
					VectorAdd(tmpVertexes[i].tangent, triangleTangents[idx2], tmpVertexes[i].tangent);
					VectorAdd(tmpBitangents[i], triangleBitangents[idx2], tmpBitangents[i]);
				}
			}
		}

		VectorNormalizeFast(tmpVertexes[i].normal);
		VectorNormalizeFast(tmpVertexes[i].tangent);
		VectorNormalizeFast(tmpBitangents[i]);
	}

	/* assume all vertices are unique until proven otherwise */
	for (i = 0; i < numIndexes; i++)
		indRemap[i] = -1;

	/* merge vertices that have become identical */
	for (i = 0; i < numIndexes; i++) {
		vec3_t n, b, t, v;
		if (indRemap[i] != -1)
			continue;

		for (j = i + 1; j < numIndexes; j++) {
			if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])
					&& VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)
					&& (DotProduct(tmpVertexes[i].normal, tmpVertexes[j].normal) > smoothness)
					&& (DotProduct(tmpVertexes[i].tangent, tmpVertexes[j].tangent) > smoothness)) {
				indRemap[j] = i;
				newIndexArray[j] = numVerts;
			}
		}

		VectorCopy(tmpVertexes[i].normal, n);
		VectorCopy(tmpVertexes[i].tangent, t);
		VectorCopy(tmpBitangents[i], b);

		/* normalization here does shared-vertex smoothing */
		VectorNormalizeFast(n);
		VectorNormalizeFast(t);
		VectorNormalizeFast(b);

		/* Grahm-Schmidt orthogonalization */
		VectorMul(DotProduct(t, n), n, v);
		VectorSubtract(t, v, t);
		VectorNormalizeFast(t);

		/* calculate handedness */
		CrossProduct(n, t, v);
		tmpVertexes[i].tangent[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;
		VectorCopy(n, tmpVertexes[i].normal);
		VectorCopy(t, tmpVertexes[i].tangent);

		newIndexArray[i] = numVerts++;
		indRemap[i] = i;
	}

	for (i = 0; i < numVerts; i++)
		sharedTris[i] = 0;

	for (i = 0; i < numIndexes; i++)
		sharedTris[newIndexArray[i]]++;

	/* set up reverse-index that maps Vertex objects to a list of triangle verts */
	mesh->revIndexes = (mIndexList_t *)Mem_PoolAlloc(sizeof(mIndexList_t) * numVerts, vid_modelPool, 0);
	for (i = 0; i < numVerts; i++) {
		mesh->revIndexes[i].length = 0;
		mesh->revIndexes[i].list = (int32_t *)Mem_PoolAlloc(sizeof(int32_t) * sharedTris[i], vid_modelPool, 0);
	}

	/* merge identical vertexes, storing only unique ones */
	newVertexes = (mAliasVertex_t *)Mem_PoolAlloc(sizeof(mAliasVertex_t) * numVerts * nFrames, vid_modelPool, 0);
	newStcoords = (mAliasCoord_t *)Mem_PoolAlloc(sizeof(mAliasCoord_t) * numVerts, vid_modelPool, 0);
	for (i = 0; i < numIndexes; i++) {
		const int idx = indexArray[indRemap[i]];
		const int idx2 = newIndexArray[i];

		/* add vertex to new vertex array */
		VectorCopy(vertexes[idx].point, newVertexes[idx2].point);
		Vector2Copy(stcoords[idx], newStcoords[idx2]);
		mesh->revIndexes[idx2].list[mesh->revIndexes[idx2].length++] = i;
	}

	/* copy over the points from successive frames */
	for (i = 1; i < nFrames; i++) {
		for (j = 0; j < numIndexes; j++) {
			const int idx = indexArray[indRemap[j]] + (mesh->num_verts * i);
			const int idx2 = newIndexArray[j] + (numVerts * i);

			VectorCopy(vertexes[idx].point, newVertexes[idx2].point);
		}
	}

	/* copy new arrays back into original mesh */
	Mem_Free(mesh->stcoords);
	Mem_Free(mesh->indexes);
	Mem_Free(mesh->vertexes);

	mesh->num_verts = numVerts;
	mesh->vertexes = newVertexes;
	mesh->stcoords = newStcoords;
	mesh->indexes = newIndexArray;
}
Beispiel #7
0
/**
 * @brief Calculates a per-vertex tangentspace basis and stores it in GL arrays attached to the mesh
 * @param mesh The mesh to calculate normals for
 * @param framenum The animation frame to calculate normals for
 * @param translate The frame translation for the given animation frame
 * @param backlerp Whether to store the results in the GL arrays for the previous keyframe or the next keyframe
 * @sa R_ModCalcUniqueNormalsAndTangents
 */
static void R_ModCalcNormalsAndTangents (mAliasMesh_t *mesh, int framenum, const vec3_t translate, qboolean backlerp)
{
	int i, j;
	mAliasVertex_t *vertexes = &mesh->vertexes[framenum * mesh->num_verts];
	mAliasCoord_t *stcoords = mesh->stcoords;
	const int numIndexes = mesh->num_tris * 3;
	const int32_t *indexArray = mesh->indexes;
	vec3_t triangleNormals[MAX_ALIAS_TRIS];
	vec3_t triangleTangents[MAX_ALIAS_TRIS];
	vec3_t triangleBitangents[MAX_ALIAS_TRIS];
	float *texcoords, *verts, *normals, *tangents;

	/* set up array pointers for either the previous keyframe or the next keyframe */
	texcoords = mesh->texcoords;
	if (backlerp) {
		verts = mesh->verts;
		normals = mesh->normals;
		tangents = mesh->tangents;
	} else {
		verts = mesh->next_verts;
		normals = mesh->next_normals;
		tangents = mesh->next_tangents;
	}

	/* calculate per-triangle surface normals and tangents*/
	for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
		vec3_t dir1, dir2;
		vec2_t dir1uv, dir2uv;

		/* calculate two mostly perpendicular edge directions */
		VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
		VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
		Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
		Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);

		/* we have two edge directions, we can calculate a third vector from
		 * them, which is the direction of the surface normal */
		CrossProduct(dir1, dir2, triangleNormals[j]);
		/* normalize */
		VectorNormalizeFast(triangleNormals[j]);

		/* then we use the texture coordinates to calculate a tangent space */
		if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
			const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);

			/* normalize */
			VectorNormalizeFast(triangleTangents[j]);
			VectorNormalizeFast(triangleBitangents[j]);
		} else {
			VectorClear(triangleTangents[j]);
			VectorClear(triangleBitangents[j]);
		}
	}

	/* for each vertex */
	for (i = 0; i < mesh->num_verts; i++) {
		vec3_t n, b, v;
		vec4_t t;
		const int len = mesh->revIndexes[i].length;
		const int32_t *list = mesh->revIndexes[i].list;

		VectorClear(n);
		VectorClear(t);
		VectorClear(b);

		/* for each vertex that got mapped to this one (ie. for each triangle this vertex is a part of) */
		for (j = 0; j < len; j++) {
			const int32_t idx = list[j] / 3;
			VectorAdd(n, triangleNormals[idx], n);
			VectorAdd(t, triangleTangents[idx], t);
			VectorAdd(b, triangleBitangents[idx], b);
		}

		/* normalization here does shared-vertex smoothing */
		VectorNormalizeFast(n);
		VectorNormalizeFast(t);
		VectorNormalizeFast(b);

		/* Grahm-Schmidt orthogonalization */
		Orthogonalize(t, n);

		/* calculate handedness */
		CrossProduct(n, t, v);
		t[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;

		/* copy this vertex's info to all the right places in the arrays */
		for (j = 0; j < len; j++) {
			const int32_t idx = list[j];
			const int meshIndex = mesh->indexes[list[j]];
			Vector2Copy(stcoords[meshIndex], (texcoords + (2 * idx)));
			VectorAdd(vertexes[meshIndex].point, translate, (verts + (3 * idx)));
			VectorCopy(n, (normals + (3 * idx)));
			Vector4Copy(t, (tangents + (4 * idx)));
		}
	}
}