示例#1
0
uint32_t Bitmap::GetPixel(int x, int y) {
    SPAssert(x >= 0);
    SPAssert(y >= 0);
    SPAssert(x < w);
    SPAssert(y < h);
    return pixels[x + y * w];
}
示例#2
0
		void Corpse::Spring(NodeType n1,
							NodeType n2,
							float distance,
							float dt){
			SPADES_MARK_FUNCTION_DEBUG();
			SPAssert(n1 >= 0); SPAssert(n1 < NodeCount);
			SPAssert(n2 >= 0); SPAssert(n2 < NodeCount);
			Node& a = nodes[n1];
			Node& b = nodes[n2];
			Vector3 diff = b.pos - a.pos;
			float dist = diff.GetLength();
			Vector3 force = diff.Normalize() * (distance - dist);
			force *= dt * 50.f;
			
			b.vel += force;
			a.vel -= force;
			
			b.pos += force / (dt * 50.f) * 0.5f;
			a.pos -= force / (dt * 50.f) * 0.5f;
			
			Vector3 velMid = (a.vel + b.vel) * .5f;
			float dump = 1.f - powf(.1f, dt);
			a.vel += (velMid - a.vel) * dump;
			b.vel += (velMid - b.vel) * dump;
			
		}
示例#3
0
void Bitmap::SetPixel(int x, int y, uint32_t p) {
    SPAssert(x >= 0);
    SPAssert(y >= 0);
    SPAssert(x < w);
    SPAssert(y < h);
    pixels[x + y * w] = p;
}
示例#4
0
		void GLVoxelModel::BuildVertices(spades::VoxelModel *model) {
			SPADES_MARK_FUNCTION();

			SPAssert(vertices.empty());
			SPAssert(indices.empty());

			int w = model->GetWidth();
			int h = model->GetHeight();
			int d = model->GetDepth();
			for (int x = 0; x < w; x++) {
				for (int y = 0; y < h; y++) {
					for (int z = 0; z < d; z++) {
						if (!model->IsSolid(x, y, z))
							continue;

						uint32_t color = model->GetColor(x, y, z);
						color |= 0xff000000UL;

						if (!model->IsSolid(x - 1, y, z))
							EmitFace(model, x, y, z, -1, 0, 0, color);
						if (!model->IsSolid(x + 1, y, z))
							EmitFace(model, x, y, z, 1, 0, 0, color);
						if (!model->IsSolid(x, y - 1, z))
							EmitFace(model, x, y, z, 0, -1, 0, color);
						if (!model->IsSolid(x, y + 1, z))
							EmitFace(model, x, y, z, 0, 1, 0, color);
						if (!model->IsSolid(x, y, z - 1))
							EmitFace(model, x, y, z, 0, 0, -1, color);
						if (!model->IsSolid(x, y, z + 1))
							EmitFace(model, x, y, z, 0, 0, 1, color);
					}
				}
			}
		}
示例#5
0
	void DeflateStream::CompressBuffer() {
		SPADES_MARK_FUNCTION();
		SPAssert(mode == CompressModeCompress);
		char outputBuffer[chunkSize];
		
		if(!valid){
			SPRaise("State is invalid");
		}
		
		zstream.avail_in = (unsigned int) buffer.size();
		zstream.next_in = (Bytef*)buffer.data();
		
		do{
			zstream.avail_out = chunkSize;
			zstream.next_out = (Bytef*)outputBuffer;
			int ret = deflate(&zstream, Z_NO_FLUSH);
			if(ret == Z_STREAM_ERROR) {
				valid = false;
				deflateEnd(&zstream);
				SPRaise("Error while deflating: %s",
						zError(ret));
			}
			
			int got = chunkSize - zstream.avail_out;
			baseStream->Write(outputBuffer, got);
		}while(zstream.avail_out == 0);
		
		SPAssert(zstream.avail_in == 0);
		std::vector<char>().swap(buffer);
	}
示例#6
0
	std::string TrimSpaces(const std::string& str){
		size_t pos = str.find_first_not_of(" \t\n\r");
		if(pos == std::string::npos)
			return std::string();
		size_t po2 = str.find_last_not_of(" \t\n\r");
		SPAssert(po2 != std::string::npos);
		SPAssert(po2 >= pos);
		return str.substr(pos, po2 - pos + 1);
	}
示例#7
0
		void Corpse::SetNode(NodeType n, spades::Vector3 v){
			SPAssert(n >= 0); SPAssert(n < NodeCount);
			nodes[n].pos = v;
			nodes[n].vel = MakeVector3(VelNoise(),
									   VelNoise(),
									   0.f);
			nodes[n].lastPos = v;
			nodes[n].lastForce = MakeVector3(0, 0,0);
			
		}
示例#8
0
		void World::SetPlayer(int i,
							  spades::client::Player *p){
			SPADES_MARK_FUNCTION();
			SPAssert(i >= 0);
			SPAssert( i < (int)players.size());
			if(players[i] == p)
				return;
			if(players[i])
				delete players[i];
			players[i] = p;
		}
示例#9
0
		static float MyACos(float v){
			SPAssert(!isnan(v));
			if(v >= 1.f) return 0.f;
			if(v <= -1.f) return static_cast<float>(M_PI);
			float vv = acosf(v);
			if(isnan(vv)){
				vv = acosf(v * .9999f);
			}
			SPAssert(!isnan(vv));
			return vv;
		}
示例#10
0
	size_t DeflateStream::Read(void *data, size_t bytes) {
		SPADES_MARK_FUNCTION();
		size_t readBytes = 0;
		while(bytes > 0){
			if(bufferPos >= buffer.size()){
				FillBuffer();
				if(reachedEOF && bufferPos >= buffer.size())
					break;
			}
			
			size_t copySize = bytes;
			if(copySize > (buffer.size() - bufferPos))
				copySize = buffer.size() - bufferPos;
			
			memcpy(data, buffer.data() + bufferPos,
				   copySize);
			
			reinterpret_cast<char *&>(data) += copySize;
			SPAssert(bytes >= copySize);
			bytes -= copySize;
			readBytes += copySize;
			bufferPos += copySize;
			position += copySize;
		}
		return readBytes;
	}
示例#11
0
		GLFramebufferManager::BufferHandle::BufferHandle(GLFramebufferManager*m,
														 size_t index):
		manager(m), bufferIndex(index), valid(true){
			SPAssert(bufferIndex < manager->buffers.size());
			Buffer&b = manager->buffers[bufferIndex];
			b.refCount++;
		}
示例#12
0
		void GLFramebufferManager::MakeSureAllBuffersReleased(){
			SPADES_MARK_FUNCTION();
			
			for(size_t i = 0; i < buffers.size(); i++){
				SPAssert(buffers[i].refCount == 0);
			}
		}
示例#13
0
		void GLSpriteRenderer::Flush() {
			SPADES_MARK_FUNCTION_DEBUG();
			
			if(vertices.empty())
				return;
			
			device->VertexAttribPointer(positionAttribute(),
										4, IGLDevice::FloatType,
										false, sizeof(Vertex),
										&(vertices[0].x));
			device->VertexAttribPointer(spritePosAttribute(),
										4, IGLDevice::FloatType,
										false, sizeof(Vertex),
										&(vertices[0].sx));
			device->VertexAttribPointer(colorAttribute(),
										4, IGLDevice::FloatType,
										false, sizeof(Vertex),
										&(vertices[0].r));
			
			SPAssert(lastImage);
			lastImage->Bind(IGLDevice::Texture2D);
			
			device->DrawElements(IGLDevice::Triangles,
								 indices.size(),
								 IGLDevice::UnsignedInt,
								 indices.data());
			
			vertices.clear();
			indices.clear();
		}
示例#14
0
		void Corpse::AngleSpring(NodeType n1id,
								 NodeType n2id,
								 Vector3 dir,
								 float minDot,
								 float maxDot,
								 float dt){
			Node& n1 = nodes[n1id];
			Node& n2 = nodes[n2id];
			Vector3 diff = n2.pos - n1.pos;
			float ln1 = diff.GetLength();
			float dot = Vector3::Dot(diff, dir) / (ln1 + 0.000000001f);
			
			if(dot >= minDot && dot <= maxDot)
				return;
			
			float strength = 0.f;
			
			Vector3 a1 = Vector3::Cross(dir, diff);
			a1 = Vector3::Cross(diff, a1).Normalize();
			
			Vector3 a2 = -a1;
			//a1=-a1; a2=-a2;
			//a1 = -a1;
			
			if(dot > maxDot){
				strength = MyACos(dot) - MyACos(maxDot);
			}else if(dot < minDot){
				strength = MyACos(dot) - MyACos(minDot);
			}
			
			SPAssert(!isnan(strength));
			
			strength *= 100.f;
			strength *= dt;
			
			a1 *= strength;
			a2 *= strength;
			
			n2.vel += a1;
			n1.vel += a2;
			//nBase.vel -= a1 + a2;
			
			/*
			 d1 += a1 * 0.01;
			 d2 += a2 * 0.01;
			 float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength());
			 
			 if(dot > maxDot){
			 if(nd < dot)
			 printf("GOOD %f -> %f\n", dot, nd);
			 else
			 printf("BAD %f -> %f\n", dot, nd);
			 }else{
			 if(nd > dot)
			 printf("GOOD %f -> %f\n", dot, nd);
			 else
			 printf("BAD %f -> %f\n", dot, nd);
			 }*/
		}
示例#15
0
	Vector3 Matrix4::GetAxis(int axis) const {
		switch (axis) {
			case 0: return MakeVector3(m[0], m[1], m[2]);
			case 1: return MakeVector3(m[4], m[5], m[6]);
			default: SPAssert(false);
			case 2: return MakeVector3(m[8], m[9], m[10]);
		}
	}
示例#16
0
		void GLFramebufferManager::BufferHandle::Release(){
			if(valid){
				Buffer&b = manager->buffers[bufferIndex];
				SPAssert(b.refCount > 0);
				b.refCount--;
				valid = false;
			}
		}
示例#17
0
			virtual int GetDamage(HitType type, float distance) {
				switch (type) {
					case HitTypeTorso: return 27;
					case HitTypeHead: return 37;
					case HitTypeArms: return 16;
					case HitTypeLegs: return 16;
					case HitTypeBlock: return 34;
					default: SPAssert(false); return 0;
				}
			}
示例#18
0
Bitmap::Bitmap(uint32_t *pixels, int w, int h):
    pixels(pixels), w(w), h(h), autoDelete(false) {
    SPADES_MARK_FUNCTION();

    if(w < 1 || h < 1 || w > 8192 || h > 8192) {
        SPRaise("Invalid dimension: %dx%d", w, h);
    }

    SPAssert(pixels != NULL);
}
		bool SmokeSpriteEntity::Update(float dt) {
			frame += dt * fps;
			frame = fmodf(frame, 180.f);
			
			int fId = (int)floorf(frame);
			SPAssert(fId >= 0 && fId < 180);
			SetImage(GetSequence(fId, GetRenderer()));
			
			return ParticleSpriteEntity::Update(dt);
		}
示例#20
0
Bitmap::Bitmap(int ww, int hh):
    w(ww), h(hh), autoDelete(true), pixels(nullptr) {
    SPADES_MARK_FUNCTION();

    if(w < 1 || h < 1 || w > 8192 || h > 8192) {
        SPRaise("Invalid dimension: %dx%d", w, h);
    }

    pixels = new uint32_t[w * h];
    SPAssert(pixels != NULL);
}
示例#21
0
	int DeflateStream::ReadByte() {
		SPADES_MARK_FUNCTION();
		if(bufferPos >= buffer.size()){
			FillBuffer();
		}
		if(bufferPos >= buffer.size()){
			SPAssert(reachedEOF);
			return -1;
		}
		position++;
		return (unsigned char)buffer[bufferPos++];
	}
示例#22
0
		void Corpse::Spring(NodeType n1a,
							NodeType n1b,
							 NodeType n2,
							 float distance,
							 float dt){
			SPADES_MARK_FUNCTION_DEBUG();
			SPAssert(n1a >= 0); SPAssert(n1a < NodeCount);
			SPAssert(n1b >= 0); SPAssert(n1b < NodeCount);
			SPAssert(n2 >= 0); SPAssert(n2 < NodeCount);
			Node& x = nodes[n1a];
			Node& y = nodes[n1b];
			Node& b = nodes[n2];
			Vector3 diff = b.pos - (x.pos + y.pos) * .5f;
			float dist = diff.GetLength();
			Vector3 force = diff.Normalize() * (distance - dist);
			force *= dt * 50.f;
			
			b.vel += force;
			force *= .5f;
			x.vel -= force;
			y.vel -= force;
			
			Vector3 velMid = (x.vel + y.vel) * .25f + b.vel * .5f;
			float dump = 1.f - powf(.05f, dt);
			x.vel += (velMid - x.vel) * dump;
			y.vel += (velMid - y.vel) * dump;
			b.vel += (velMid - b.vel) * dump;
			
		}
示例#23
0
			virtual int GetDamage(HitType type, float distance) {
				switch (type) {
					case HitTypeTorso: return 27;
					case HitTypeHead: return 37;
					case HitTypeArms: return 16;
					case HitTypeLegs: return 16;
					case HitTypeBlock:
						// Actually, you cast a hit per pallet. This value is a guess, by the way.
						// --GM
						return 34;
					default: SPAssert(false); return 0;
				}
			}
			/** Combines `dest` and `src`. Group `src` will be
			 * no longer valid. */
			void CombineGroup(size_t dest, size_t src) {
				Group& g1 = groups[dest];
				Group& g2 = groups[src];
				FillGroupMap(g2.tile1, g2.tile2, dest);
				
				// extend the area
				g1.tile1.x = std::min(g1.tile1.x, g2.tile1.x);
				g1.tile1.y = std::min(g1.tile1.y, g2.tile1.y);
				g1.tile2.x = std::max(g1.tile2.x, g2.tile2.x);
				g1.tile2.y = std::max(g1.tile2.y, g2.tile2.y);
				
				g1.lod = std::max(g1.lod, g2.lod);
				
				// combine the instance list
				// [g1] + [g2] -> [g1, g2]
				Instance& destLast = allInstances[g1.lastInstance];
				Instance& srcFirst = allInstances[g2.firstInstance];
				SPAssert(destLast.next == NoInstance);
				SPAssert(srcFirst.prev == NoInstance);
				destLast.next = g2.firstInstance;
				srcFirst.prev = g1.lastInstance;
				g1.lastInstance = g2.lastInstance;
				
				// make sure the area is filled with the group `dest`
				IntVector3 tile1 = g1.tile1, tile2 = g1.tile2;
				for(int x = tile1.x; x < tile2.x; x++)
					for(int y = tile1.y; y < tile2.y; y++){
						size_t g = groupMap[x][y];
						SPAssert(g != src);
						if(g != NoGroup && g != dest) {
							CombineGroup(dest, g);
							SPAssert(groupMap[x][y] == dest);
						}else{
							groupMap[x][y] = dest;
						}
					}
				
				g2.valid = false;
			}
示例#25
0
	DeflateStream::~DeflateStream() {
		SPADES_MARK_FUNCTION();
		if(valid){
			if(mode == CompressModeCompress){
				deflateEnd(&zstream);
			}else if(mode == CompressModeDecompress){
				inflateEnd(&zstream);
			}else{
				SPAssert(false);
			}
		}
		if(autoClose){
			delete baseStream;
		}
	}
示例#26
0
			virtual int GetDamage(HitType type, float distance) {
				switch (type) {
					// These are the 0.75 damage values.
					// To be honest, we don't need this information, as the server decides the
					// damage.
					// EXCEPT for blocks, that is.
					// --GM
					case HitTypeTorso: return 49;
					case HitTypeHead: return 100;
					case HitTypeArms: return 33;
					case HitTypeLegs: return 33;
					case HitTypeBlock: return 50;
					default: SPAssert(false); return 0;
				}
			}
示例#27
0
		static void CheckEscape(GameMap *map,
								IntVector3 hitBlock,
								IntVector3 a, IntVector3 b,
								IntVector3 dir,
								float& bestDist,
								IntVector3& bestDir) {
			hitBlock += dir;
			IntVector3 aa = a + dir;
			IntVector3 bb = b + dir;
			if(map->IsSolidWrapped(hitBlock.x, hitBlock.y, hitBlock.z))
				return;
			if(map->IsSolidWrapped(aa.x, aa.y, aa.z))
				return;
			if(map->IsSolidWrapped(bb.x, bb.y, bb.z))
				return;
			float dist;
			if(dir.x == 1) {
				dist = 1.f - fractf(a.x);
				dist += 1.f - fractf(b.x);
			}else if(dir.x == -1) {
				dist = fractf(a.x);
				dist += fractf(b.x);
			}else if(dir.y == 1) {
				dist = 1.f - fractf(a.y);
				dist += 1.f - fractf(b.y);
			}else if(dir.y == -1) {
				dist = fractf(a.y);
				dist += fractf(b.y);
			}else if(dir.z == 1) {
				dist = 1.f - fractf(a.z);
				dist += 1.f - fractf(b.z);
			}else if(dir.z == -1) {
				dist = fractf(a.z);
				dist += fractf(b.z);
			}else{
				SPAssert(false);
				return;
			}
			
			if(dist < bestDist){
				bestDist = dist;
				bestDir = dir;
			}
		}
示例#28
0
		void GLVoxelModel::EmitFace(spades::VoxelModel *model, int x, int y, int z, int nx, int ny,
		                            int nz, uint32_t color) {
			SPADES_MARK_FUNCTION_DEBUG();
			// decide face tangent
			int ux = ny, uy = nz, uz = nx;
			int vx = nz, vy = nx, vz = ny;
			if (nx < 0 || ny < 0 || nz < 0) {
				vx = -vx;
				vy = -vy;
				vz = -vz;
			}
			// now cross(u, v) = n (somehow)
			SPAssert(ux * vx + uy * vy + uz * vz == 0);
			SPAssert(ux * nx + uy * ny + uz * nz == 0);
			SPAssert(nx * vx + ny * vy + nz * vz == 0);
			SPAssert(uy * vz - uz * vy == -nx);
			SPAssert(uz * vx - ux * vz == -ny);
			SPAssert(ux * vy - uy * vx == -nz);

			// decide face origin
			int fx = 0, fy = 0, fz = 0;
			if (ux == -1 || vx == -1) {
				fx = 1;
				SPAssert(ux + vx == -1);
			}
			if (uy == -1 || vy == -1) {
				fy = 1;
				SPAssert(uy + vy == -1);
			}
			if (uz == -1 || vz == -1) {
				fz = 1;
				SPAssert(uz + vz == -1);
			}
			SPAssert(nx * fx + ny * fy + nz * fz == 0);

			uint8_t aoID = calcAOID(model, x + nx, y + ny, z + nz, ux, uy, uz, vx, vy, vz);

			Vertex v;
			uint32_t idx = (uint32_t)vertices.size();

			v.aoID = aoID;
			v.red = (uint8_t)(color);
			v.green = (uint8_t)(color >> 8);
			v.blue = (uint8_t)(color >> 16);
			v.diffuse = 255;
			v.nx = nx;
			v.ny = ny;
			v.nz = nz;

			x += fx;
			y += fy;
			z += fz;

			if (nx > 0)
				x++;
			if (ny > 0)
				y++;
			if (nz > 0)
				z++;

			SPAssert(x >= 0);
			SPAssert(y >= 0);
			SPAssert(y >= 0);
			SPAssert(x + ux >= 0);
			SPAssert(y + uy >= 0);
			SPAssert(z + uz >= 0);
			SPAssert(x + vx >= 0);
			SPAssert(y + vy >= 0);
			SPAssert(z + vz >= 0);
			SPAssert(x + ux + vx >= 0);
			SPAssert(y + uy + vy >= 0);
			SPAssert(z + uz + vz >= 0);

			v.u = 0;
			v.v = 0;
			v.x = x;
			v.y = y;
			v.z = z;
			vertices.push_back(v);

			v.u = 1;
			v.v = 0;
			v.x = x + ux;
			v.y = y + uy;
			v.z = z + uz;
			vertices.push_back(v);

			v.u = 0;
			v.v = 1;
			v.x = x + vx;
			v.y = y + vy;
			v.z = z + vz;
			vertices.push_back(v);

			v.u = 1;
			v.v = 1;
			v.x = x + ux + vx;
			v.y = y + uy + vy;
			v.z = z + uz + vz;
			vertices.push_back(v);

			indices.push_back(idx);
			indices.push_back(idx + 1);
			indices.push_back(idx + 2);
			indices.push_back(idx + 1);
			indices.push_back(idx + 3);
			indices.push_back(idx + 2);
		}
示例#29
0
		void SWMapRenderer::BuildLine(Line& line,
									  float minPitch, float maxPitch) {
			
			// hard code for further optimization
			enum {
				w = 512, h = 512
			};
			SPAssert(map->Width() == 512);
			SPAssert(map->Height() == 512);
			
			const auto *rle = this->rle.data();
			auto& rleHeap = this->rleHeap;
			client::GameMap *map = this->map;
			
			// pitch culling
			{
				const auto& frustrum = renderer->frustrum;
				static const float pi = M_PI;
				const auto& horz = line.horizonDir;
				minPitch = -pi * 0.4999f;
				maxPitch = pi * 0.4999f;
				
				auto cull = [&minPitch, &maxPitch]() {
					minPitch = 2.f;
					maxPitch = -2.f;
				};
				auto clip = [&minPitch, &maxPitch, &horz, &cull](Vector3 plane) {
					if(plane.x == 0.f && plane.y == 0.f) {
						if(plane.z > 0.f) {
							minPitch = std::max(minPitch, 0.f);
						}else{
							maxPitch = std::min(maxPitch, 0.f);
						}
					}else if(plane.z == 0.f){
						if(Vector3::Dot(plane, horz) < 0.f) {
							cull();
						}
					}else{
						Vector3 prj = plane; prj.z = 0.f;
						prj = prj.Normalize();
						
						float zv = fabsf(plane.z);
						float cs = Vector3::Dot(prj, horz);
						
						float ang = zv * zv * (1.f - cs * cs) / (cs * cs);
						ang = -cs * fastSqrt(1.f + ang);
						ang = zv / ang;
                        if(isnan(ang) || isinf(ang) || ang == 0.f)
                            return;
						
						// convert to tan
						ang = fastSqrt(1.f - ang * ang) / ang;
						
						// convert to angle
						ang = atanf(ang);
                        
                        if(isnan(ang) || isinf(ang))
                            return;
						
						if(plane.z > 0.f) {
							minPitch = std::max(minPitch, ang - 0.01f);
						}else{
							maxPitch = std::min(maxPitch, -ang + 0.01f);
						}
					}
				};
				
				clip(frustrum[2].n);
				clip(frustrum[3].n);
				clip(frustrum[4].n);
				clip(frustrum[5].n);
				
			}
			
			float minTan = SpecialTan(minPitch);
			float maxTan = SpecialTan(maxPitch);
            
            {
                float minDiff = lineResolution / 10000.f;
                if(maxTan < minTan + minDiff) {
                    // too little difference; scale value might overflow.
                    maxTan = minTan + minDiff;
                }
            }
			
			line.pitchTanMin = minTan;
			line.pitchScale = lineResolution / (maxTan - minTan);
			line.pitchTanMinI = static_cast<int>(minTan * 65536.f);
			line.pitchScaleI = static_cast<int>(line.pitchScale * 65536.f);
			
			// TODO: pitch culling
			
			// ray direction
			float dirX = line.horizonDir.x;
			float dirY = line.horizonDir.y;
			if(fabsf(dirY) < 1.e-4f) dirY = 1.e-4f;
			if(fabsf(dirX) < 1.e-4f) dirX = 1.e-4f;
			float invDirX = 1.f / dirX;
			float invDirY = 1.f / dirY;
			std::int_fast8_t signX = dirX > 0.f ? 1 : -1;
			std::int_fast8_t signY = dirY > 0.f ? 1 : -1;
			int invDirXI = static_cast<int>(invDirX * 256.f);
			int invDirYI = static_cast<int>(invDirY * 256.f);
			int dirXI = static_cast<int>(dirX * 512.f);
			int dirYI = static_cast<int>(dirY * 512.f);
			if(invDirXI < 0) invDirXI = -invDirXI;
			if(invDirYI < 0) invDirYI = -invDirYI;
			if(dirXI < 0) dirXI = -dirXI;
			if(dirYI < 0) dirYI = -dirYI;
			
			// camera position
			float cx = sceneDef.viewOrigin.x;
			float cy = sceneDef.viewOrigin.y;
			float cz = sceneDef.viewOrigin.z;
			
			int icz = static_cast<int>(floorf(cz));
			
			// ray position
			//float rx = cx, ry = cy;
			int rx = static_cast<int>(cx * 512.f);
			int ry = static_cast<int>(cy * 512.f);
			
			// ray position in integer
			std::int_fast16_t irx = rx >> 9; //static_cast<int>(floorf(rx));
			std::int_fast16_t iry = ry >> 9; //static_cast<int>(floorf(ry));
			
			float fogDist = 128.f;
			float distance = 1.e-20f; // traveled path
			float invDist = 1.f / distance;
			
			//auto& pixels = line.pixels;
			
			line.pixels.resize(lineResolution);
			auto *pixels = line.pixels.data(); // std::vector feels slow...
			
			const float transScale = static_cast<float>(lineResolution) / (maxTan - minTan);
			const float transOffset = -minTan * transScale;
			
#if ENABLE_SSE
			if(lineResolution > 4){
				static_assert(sizeof(LinePixel) == 8, "size of LinePixel has changed; needs code modification");
				union {
					LinePixel pxs[2];
					__m128 m;
				};
				pxs[0].Clear();
				pxs[1].Clear();
				auto *ptr = pixels;
				for(auto *e = pixels + lineResolution; (reinterpret_cast<size_t>(ptr) & 0xf) &&
					(ptr < e); ptr++) {
					ptr->Clear();
				}
				for(auto *e = pixels + lineResolution - 2;
					ptr < e; ptr += 2) {
					_mm_store_ps(reinterpret_cast<float *>(ptr), m);
				}
				for(auto *e = pixels + lineResolution; ptr < e; ptr++) {
					ptr->Clear();
				}
			}else
#endif
			for(size_t i = 0; i < lineResolution; i++)
				pixels[i].Clear();

			
			// if culled out, bail out now (pixels are filled)
			if(minPitch >= maxPitch)
				return;
			
			std::array<float, 65> zval; // precompute (z - cz) * some
			for(size_t i = 0; i < zval.size(); i++)
				zval[i] = (static_cast<float>(i) - cz);
			
			float vmax = lineResolution + 0.5f;
			auto transform = [&zval, &transOffset, vmax, &transScale](float invDist, int z) {
				float p = ToSpecialTan(invDist * zval[z]) * transScale + transOffset;
				p = std::max(p, 0.f);
				p = std::min(p, vmax);
				return static_cast<std::uint_fast16_t>(p);
			};
			
			float zscale; // travel distance -> view Z value factor
			zscale = Vector3::Dot(line.horizonDir, sceneDef.viewAxis[2]);
			
			float heightScale; // Z value -> view Z value factor
			heightScale = sceneDef.viewAxis[2].z;
			
			std::array<float, 65> heightScaleVal; // precompute (heightScale * z)
			for(size_t i = 0; i < zval.size(); i++)
				heightScaleVal[i] = (static_cast<float>(i) * heightScale);
			
			float depthBias;
			depthBias = -cz * heightScale;
			
			RleData *lastRle;
			{
				auto ref = rle[(irx & w-1) + ((iry & h-1) * w)];
				lastRle = rleHeap.Dereference<RleData>(ref);
			}
			
			std::uint_fast16_t count = 1;
			std::uint_fast16_t cnt2 = static_cast<int>(fogDist * 8.f);
			
			while(distance < fogDist && (--cnt2) > 0) {
				std::int_fast16_t nextIRX, nextIRY;
				auto oirx = irx, oiry = iry;
				
				// DDE
				Face wallFace;
				
				if(signX > 0){
					nextIRX = irx + 1;
					if(signY > 0) {
						nextIRY = iry + 1;
						
						unsigned int timeToNextX = (512 - (rx & 511)) * invDirXI;
						unsigned int timeToNextY = (512 - (ry & 511)) * invDirYI;
						
						if(timeToNextX < timeToNextY) {
							// go across x plane
							irx = nextIRX;
							rx = irx << 9;
							ry += (dirYI * timeToNextX) >> 17;
							distance += static_cast<float>(timeToNextX) * (1.f / 512.f / 256.f);
							wallFace = Face::NegX;
						}else{
示例#30
0
		void Player::FireWeapon() {
			SPADES_MARK_FUNCTION();
			
			Vector3 muzzle = GetEye();
			muzzle += GetFront() * 0.01f;
			
			// for hit-test debugging
			std::map<int, HitTestDebugger::PlayerHit> playerHits;
			std::vector<Vector3> bulletVectors;
			
			//Vector3 right = GetRight();
			//Vector3 up = GetUp();
			
			int pellets = weapon->GetPelletSize();
			float spread = weapon->GetSpread();
			GameMap *map = world->GetMap();
			
			// pyspades takes destroying more than one block as a
			// speed hack (shotgun does this)
			bool blockDestroyed = false;
			
			Vector3 dir2 = GetFront();
			for(int i =0 ; i < pellets; i++){
				
				// AoS 0.75's way (dir2 shouldn't be normalized!)
				dir2.x += (GetRandom() - GetRandom()) * spread;
				dir2.y += (GetRandom() - GetRandom()) * spread;
				dir2.z += (GetRandom() - GetRandom()) * spread;
				Vector3 dir = dir2.Normalize();
				
				bulletVectors.push_back(dir);
				
				// first do map raycast
				GameMap::RayCastResult mapResult;
				mapResult = map->CastRay2(muzzle,
										  dir,
										  500);
				
				Player *hitPlayer = NULL;
				float hitPlayerDistance = 0.f;
				HitBodyPart hitPart = HitBodyPart::None;
				
				for(int i = 0; i < world->GetNumPlayerSlots(); i++){
					Player *other = world->GetPlayer(i);
					if(other == this || other == NULL)
						continue;
					if(other == this || !other->IsAlive() ||
					   other->GetTeamId() >= 2)
						continue;
					// quickly reject players unlikely to be hit
					if(!other->RayCastApprox(muzzle, dir))
						continue;
					
					HitBoxes hb = other->GetHitBoxes();
					Vector3 hitPos;
					
					if(hb.head.RayCast(muzzle, dir, &hitPos)) {
						float dist = (hitPos - muzzle).GetLength();
						if(hitPlayer == NULL ||
						   dist < hitPlayerDistance){
							hitPlayer = other;
							hitPlayerDistance = dist;
							hitPart = HitBodyPart::Head;
						}
					}
					if(hb.torso.RayCast(muzzle, dir, &hitPos)) {
						float dist = (hitPos - muzzle).GetLength();
						if(hitPlayer == NULL ||
						   dist < hitPlayerDistance){
							hitPlayer = other;
							hitPlayerDistance = dist;
							hitPart = HitBodyPart::Torso;
						}
					}
					for(int j = 0; j < 3 ;j++){
						if(hb.limbs[j].RayCast(muzzle, dir, &hitPos)) {
							float dist = (hitPos - muzzle).GetLength();
							if(hitPlayer == NULL ||
							   dist < hitPlayerDistance){
								hitPlayer = other;
								hitPlayerDistance = dist;
								switch(j) {
									case 0: hitPart = HitBodyPart::Limb1; break;
									case 1: hitPart = HitBodyPart::Limb2; break;
									case 2: hitPart = HitBodyPart::Arms;  break;
								}
							}
						}
					}
				}
				
				Vector3 finalHitPos;
				finalHitPos = muzzle + dir * 128.f;
				
				if(hitPlayer == nullptr && !mapResult.hit) {
					// might hit water surface.
					
				}
				
				if(mapResult.hit && (mapResult.hitPos - muzzle).GetLength() < 128.f &&
				   (hitPlayer == NULL || (mapResult.hitPos - muzzle).GetLength() < hitPlayerDistance)){
					IntVector3 outBlockCoord = mapResult.hitBlock;
					// TODO: set correct ray distance
					// FIXME: why ray casting twice?
					
					finalHitPos = mapResult.hitPos;
					
					if(outBlockCoord.x >= 0 && outBlockCoord.y >= 0 && outBlockCoord.z >= 0 &&
					   outBlockCoord.x < map->Width() && outBlockCoord.y < map->Height() &&
					   outBlockCoord.z < map->Depth()){
						if(outBlockCoord.z == 63) {
							if(world->GetListener())
								world->GetListener()->BulletHitBlock(mapResult.hitPos,
																	 mapResult.hitBlock,
																	 mapResult.normal);
						}else if(outBlockCoord.z == 62) {
							// blocks at this level cannot be damaged
							if(world->GetListener())
								world->GetListener()->BulletHitBlock(mapResult.hitPos,
																	 mapResult.hitBlock,
																	 mapResult.normal);
						}else{
							int x = outBlockCoord.x;
							int y = outBlockCoord.y;
							int z = outBlockCoord.z;
							SPAssert(map->IsSolid(x, y, z));
							
							Vector3 blockF = {x + .5f, y + .5f, z + .5f};
							float distance = (blockF - muzzle).GetLength();
							
							uint32_t color = map->GetColor(x, y, z);
							int health = color >> 24;
							health -= weapon->GetDamage(HitTypeBlock, distance);
							if(health <= 0 && !blockDestroyed){
								health = 0;
								blockDestroyed = true;
								//send destroy cmd
								if(world->GetListener() &&
								   world->GetLocalPlayer() == this)
									world->GetListener()->LocalPlayerBlockAction
									(outBlockCoord, BlockActionTool);
								
							}
							color = (color & 0xffffff) | ((uint32_t)health << 24);
							if(map->IsSolid(x, y, z))
								map->Set(x, y, z, true, color);
							
							if(world->GetListener())
								world->GetListener()->BulletHitBlock(mapResult.hitPos,
																	 mapResult.hitBlock,
																	 mapResult.normal);
						}
					}
			    }else if(hitPlayer != NULL){