Example #1
0
void EERIEDrawBitmapUVs(Rectf rect, float z, TextureContainer * tex,
                        Color color, Vec2f uv0, Vec2f uv1, Vec2f uv2, Vec2f uv3) {
	
	rect.move(-.5f, -.5f);
	
	ColorRGBA col = color.toRGBA();
	TexturedVertex v[4];
	v[0] = TexturedVertex(Vec3f(rect.topLeft(),     z), 1.f, col, uv0);
	v[1] = TexturedVertex(Vec3f(rect.topRight(),    z), 1.f, col, uv1);
	v[2] = TexturedVertex(Vec3f(rect.bottomLeft(),  z), 1.f, col, uv2);
	v[3] = TexturedVertex(Vec3f(rect.bottomRight(), z), 1.f, col, uv3);
	SetTextureDrawPrim(tex, v, Renderer::TriangleStrip);
}
Example #2
0
void EERIEDrawBitmap_uv(Rectf rect, float z, TextureContainer * tex,
                        Color color, float u0, float v0, float u1, float v1) {
	
	rect.move(-.5f, -.5f);
	
	Vec2f uv = (tex) ? tex->uv : Vec2f_ONE;
	u0 *= uv.x, u1 *= uv.x, v0 *= uv.y, v1 *= uv.y;

	ColorRGBA col = color.toRGBA();
	TexturedVertex v[4];
	v[0] = TexturedVertex(Vec3f(rect.topLeft(),     z), 1.f, col, Vec2f(u0, v0));
	v[1] = TexturedVertex(Vec3f(rect.topRight(),    z), 1.f, col, Vec2f(u1, v0));
	v[2] = TexturedVertex(Vec3f(rect.bottomRight(), z), 1.f, col, Vec2f(u1, v1));
	v[3] = TexturedVertex(Vec3f(rect.bottomLeft(),  z), 1.f, col, Vec2f(u0, v1));
	SetTextureDrawPrim(tex, v, Renderer::TriangleFan);
}
Example #3
0
void CreateBitmap(TexturedQuad& s, Rectf rect, float z, TextureContainer * tex, Color color, bool isRhw) {
	
	rect.move(-.5f, -.5f);
	
	Vec2f uv = (tex) ? tex->uv : Vec2f_ZERO;
	ColorRGBA col = color.toRGBA();
	float val = 1.f;

	if(isRhw) {
		val -= z;
	}
	
	s.v[0] = TexturedVertex(Vec3f(rect.topLeft(), z), val, col, Vec2f(0.f, 0.f));
	s.v[1] = TexturedVertex(Vec3f(rect.topRight(), z), val, col, Vec2f(uv.x, 0.f));
	s.v[2] = TexturedVertex(Vec3f(rect.bottomRight(), z), val, col, Vec2f(uv.x, uv.y));
	s.v[3] = TexturedVertex(Vec3f(rect.bottomLeft(), z), val, col, Vec2f(0.f, uv.y));
}
Example #4
0
void EERIEDrawBitmap2DecalY(Rectf rect, float z, TextureContainer * tex, Color color, float _fDeltaY) {
	
	rect.move(-.5f, -.5f);
	
	rect.top = rect.top + _fDeltaY * rect.height();
	
	Vec2f uv = (tex) ? tex->uv : Vec2f_ZERO;
	float sv = uv.y * _fDeltaY;	
	ColorRGBA col = color.toRGBA();
	
	Vec2f uv1(0.f, sv);
	Vec2f uv2(uv.x, sv);
	Vec2f uv3(uv.x, uv.y);
	Vec2f uv4(0.f, uv.y);
	
	TexturedVertex v[4];
	v[0] = TexturedVertex(Vec3f(rect.topLeft(),     z), 1.f, col, uv1);
	v[1] = TexturedVertex(Vec3f(rect.topRight(),    z), 1.f, col, uv2);
	v[2] = TexturedVertex(Vec3f(rect.bottomRight(), z), 1.f, col, uv3);
	v[3] = TexturedVertex(Vec3f(rect.bottomLeft(),  z), 1.f, col, uv4);
	SetTextureDrawPrim(tex, v, Renderer::TriangleFan);
}
void ARXDRAW_DrawInterShadows() {
	
	ARX_PROFILE_FUNC();
	
	g_shadowBatch.clear();
	
	GRenderer->SetFogColor(Color::none);
	GRenderer->SetDepthBias(1);
	
	for(long i=0; i<TREATZONE_CUR; i++) {
		if(treatio[i].show != 1 || !treatio[i].io)
			continue;
		
		Entity *io = treatio[i].io;
		
		if(   !io->obj
		   || (io->ioflags & IO_JUST_COLLIDE)
		   || (io->ioflags & IO_NOSHADOW)
		   || (io->ioflags & IO_GOLD)
		   || !(io->show == SHOW_FLAG_IN_SCENE)
		) {
			continue;
		}
		
		
		EERIE_BKG_INFO * bkgData = getFastBackgroundData(io->pos.x, io->pos.z);
		if(bkgData && !bkgData->treat) { //TODO is that correct ?
			continue;
		}
		
		TexturedVertex ltv[4];
		ltv[0] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, ColorRGBA(0), Vec2f(0.3f, 0.3f));
		ltv[1] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, ColorRGBA(0), Vec2f(0.7f, 0.3f));
		ltv[2] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, ColorRGBA(0), Vec2f(0.7f, 0.7f));
		ltv[3] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, ColorRGBA(0), Vec2f(0.3f, 0.7f));
		
		if(io->obj->grouplist.size() <= 1) {
			for(size_t k = 0; k < io->obj->vertexlist.size(); k += 9) {
				EERIEPOLY *ep = CheckInPoly(io->obj->vertexlist3[k].v);
				
				if(!ep)
					continue;
				
				Vec3f in;
				in.y = ep->min.y - 3.f;
				float r = 0.5f - ((float)glm::abs(io->obj->vertexlist3[k].v.y - in.y)) * (1.f/500);
				r -= io->invisibility;
				r *= io->scale;
				
				if(r <= 0.f)
					continue;
				
				float s1 = 16.f * io->scale;
				float s2 = s1 * (1.f/2);
				in.x = io->obj->vertexlist3[k].v.x - s2;
				in.z = io->obj->vertexlist3[k].v.z - s2;
				
				r *= 255.f;
				long lv = r;
				ltv[0].color = ltv[1].color = ltv[2].color = ltv[3].color = Color(lv, lv, lv, 255).toRGBA();
				
				ltv[0].p = EE_RT(in);
				in.x += s1;
				ltv[1].p = EE_RT(in);
				in.z += s1;
				ltv[2].p = EE_RT(in);
				in.x -= s1;
				ltv[3].p = EE_RT(in);
				
				if(ltv[0].p.z > 0.f && ltv[1].p.z > 0.f && ltv[2].p.z > 0.f) {
					AddToShadowBatch(&ltv[0], &ltv[1], &ltv[2]);
					AddToShadowBatch(&ltv[0], &ltv[2], &ltv[3]);
				}
			}
		} else {
			for(size_t k = 0; k < io->obj->grouplist.size(); k++) {
				long origin = io->obj->grouplist[k].origin;
				EERIEPOLY *ep = CheckInPoly(io->obj->vertexlist3[origin].v);
				
				if(!ep)
					continue;
				
				Vec3f in;
				in.y = ep->min.y - 3.f;
				float r = 0.8f - ((float)glm::abs(io->obj->vertexlist3[origin].v.y - in.y)) * (1.f/500);
				r *= io->obj->grouplist[k].siz;
				r -= io->invisibility;
				
				if(r <= 0.f)
					continue;
				
				float s1 = io->obj->grouplist[k].siz * 44.f;
				float s2 = s1 * (1.f/2);
				in.x = io->obj->vertexlist3[origin].v.x - s2;
				in.z = io->obj->vertexlist3[origin].v.z - s2;
				
				r *= 255.f;
				long lv = r;
				ltv[0].color = ltv[1].color = ltv[2].color = ltv[3].color = Color(lv, lv, lv, 255).toRGBA();
				
				ltv[0].p = EE_RT(in);
				in.x += s1;
				ltv[1].p = EE_RT(in);
				in.z += s1;
				ltv[2].p = EE_RT(in);
				in.x -= s1;
				ltv[3].p = EE_RT(in);
				
				AddToShadowBatch(&ltv[0], &ltv[1], &ltv[2]);
				AddToShadowBatch(&ltv[0], &ltv[2], &ltv[3]);
			}
		}
	}
	
	if(g_shadowBatch.size() > 0)
	{
		GRenderer->SetRenderState(Renderer::DepthWrite, false);
		GRenderer->SetBlendFunc(Renderer::BlendZero, Renderer::BlendInvSrcColor);
		GRenderer->SetRenderState(Renderer::AlphaBlending, true);
		GRenderer->SetTexture(0, Boom);
		
		EERIEDRAWPRIM(Renderer::TriangleList, &g_shadowBatch[0], g_shadowBatch.size());
		
		GRenderer->SetRenderState(Renderer::AlphaBlending, false);
		GRenderer->SetRenderState(Renderer::DepthWrite, true);
		GRenderer->SetDepthBias(0);
		GRenderer->SetFogColor(ulBKGColor);
	}
}
void TexturedSphere::build(int stacks, int slices, std::vector<TexturedVertex> *vertices,
                           std::vector<unsigned int> *indices) {
  // Vertical step
  float phi_step = M_PI / stacks;

  // do not count the poles as rings
  int num_rings = stacks-1;

  // Compute vertices for each stack ring.
  for(unsigned int i = 1; i <= num_rings; ++i) {
    // Current vertical angle
    float phi = i*phi_step;

    // Vertices of ring
    float theta_step = 2.0f*M_PI / slices;
    for(unsigned int j = 0; j <= slices; ++j) {
      // Current horizontal angle
      float theta = j*theta_step;

      TexturedVertex v;

      // Convert from spherical to cartesian coords
      v.position[0] = glm::sin(phi) * glm::cos(theta);
      v.position[1] = glm::cos(phi);
      v.position[2] = glm::sin(phi) * glm::sin(theta);
      
      // Normal is equal to position for unit sphere
      v.normal = v.position;

      // Compute texture coords
      v.texcoord[0] = 1.0f - theta / (2.0f * M_PI);
      v.texcoord[1] = phi / M_PI;

      vertices->push_back(v);
    }
  }

  // Poles
  vertices->push_back(TexturedVertex(0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f));
  vertices->push_back(TexturedVertex(0.0f,  1.0f, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f, 0.0f));

  // Pole indices
  unsigned int north_pole_index = vertices->size()-1;
  unsigned int south_pole_index = vertices->size()-2;

  unsigned int num_ring_vertices = slices+1;

  // Compute indices for inner stacks (not connected to poles).
  for(unsigned int i = 0; i < stacks-2; ++i) {
    for(unsigned int j = 0; j < slices; ++j) {
      indices->push_back( i    * num_ring_vertices + j);
      indices->push_back( i    * num_ring_vertices + j+1);
      indices->push_back((i+1) * num_ring_vertices + j);

      indices->push_back((i+1) * num_ring_vertices + j);
      indices->push_back(  i   * num_ring_vertices + j+1);
      indices->push_back((i+1) * num_ring_vertices + j+1);
    }
  }

  // Compute indices for top stack
  for(unsigned int i = 0; i < slices; ++i) {
    indices->push_back(north_pole_index);
    indices->push_back(i+1);
    indices->push_back(i);
  }

  // Compute indices for bottom stack
  unsigned int base_index = (num_rings-1)*num_ring_vertices;
  for(unsigned int i = 0; i < slices; ++i) {
    indices->push_back(south_pole_index);
    indices->push_back(base_index+i);
    indices->push_back(base_index+i+1);
  }
  
  // Set the sizes
  m_vertex_count_ = vertices->size();
  m_index_count_ = indices->size();
}
void StelQGLRenderer::drawRectInternal
	(const bool textured, const float x, const float y, const float width, 
	 const float height, const float angle)
{
	statistics[RECT_DRAWS] += 1.0;
	// Could be improved by keeping the vertex buffer as a data member,
	// or even caching all rectangle draws to the same buffer and drawing them 
	// at once at the end of the frame.
	
	Vec2f ne, nw, se, sw;

	// Faster path for angles that are zero or extremely small.
	if(abs(angle) < 0.1)
	{
		ne = Vec2f(x, y);
		nw = Vec2f(x + width, y);
		se = Vec2f(x, y + height);
		sw = Vec2f(x + width, y + height);
	}
	// Need to rotate the rectangle (around its center).
	else
	{
		const float cosr       = std::cos(angle / 180 * M_PI);
		const float sinr       = std::sin(angle / 180 * M_PI);
		const float halfWidth  = width  * 0.5;
		const float halfHeight = height * 0.5;
		const Vec2f center(x + halfWidth, y + halfHeight);

		const float widthCos  = halfWidth  * cosr;
		const float heightCos = halfHeight * cosr;
		const float widthSin  = halfWidth  * sinr;
		const float heightSin = halfHeight * sinr;

		ne = center + Vec2f(-widthCos + heightSin, -widthSin - heightCos);
		nw = center + Vec2f(widthCos  + heightSin, widthSin  - heightCos);
		se = center + Vec2f(-widthCos - heightSin, -widthSin + heightCos);
		sw = center + Vec2f(widthCos  - heightSin, widthSin  + heightCos);
	}
	
	// Prepare a vertex buffer for the rectangle and draw it.
	if(textured)
	{
		if(NULL == texturedRectBuffer)
		{
			texturedRectBuffer = 
				createVertexBuffer<TexturedVertex>(PrimitiveType_TriangleStrip);
		}
		else
		{
			texturedRectBuffer->unlock();
			texturedRectBuffer->clear();
		}

		texturedRectBuffer->addVertex(TexturedVertex(ne, Vec2f(0.0f , 0.0f)));
		texturedRectBuffer->addVertex(TexturedVertex(nw, Vec2f(1.0f , 0.0f)));
		texturedRectBuffer->addVertex(TexturedVertex(se, Vec2f(0.0f , 1.0f)));
		texturedRectBuffer->addVertex(TexturedVertex(sw, Vec2f(1.0f , 1.0f)));

		texturedRectBuffer->lock();
		drawVertexBuffer(texturedRectBuffer);
	}
	else
	{
		if(NULL == plainRectBuffer)
		{
			plainRectBuffer = 
				createVertexBuffer<VertexP2>(PrimitiveType_TriangleStrip);
		}
		else
		{
			plainRectBuffer->unlock();
			plainRectBuffer->clear();
		}

		plainRectBuffer->addVertex(VertexP2(ne));
		plainRectBuffer->addVertex(VertexP2(nw));
		plainRectBuffer->addVertex(VertexP2(se));
		plainRectBuffer->addVertex(VertexP2(sw));

		plainRectBuffer->lock();
		drawVertexBuffer(plainRectBuffer);
	}
}
void StelQGLRenderer::drawText(const TextParams& params)
{
	statistics[TEXT_DRAWS] += 1.0;
	StelQGLTextureBackend* currentTexture = currentlyBoundTextures[0];

	if(params.string_.length() == 0)
	{
		return;
	}

	viewport.enablePainting();
	if(currentFontSet)
	{
		viewport.setFont(currentFont);
	}
	QPainter* painter = viewport.getPainter();
	Q_ASSERT_X(NULL != painter, Q_FUNC_INFO, 
	           "Trying to draw text but painting is disabled");

	QFontMetrics fontMetrics = painter->fontMetrics();

	StelProjectorP projector = NULL == params.projector_
	                         ? StelApp::getInstance().getCore()->getProjection2d() 
	                         : params.projector_;
	Vec3f win;
	if(params.doNotProject_) 
	{
		win = params.position_;
	}
	else if(!projector->project(params.position_, win))
	{
		viewport.disablePainting();
		return;
	}

	const int x = win[0];
	const int y = win[1];

	// Avoid drawing if outside viewport.
	// We do a worst-case approximation as getting exact text dimensions is expensive.
	// We also account for rotation by assuming the worst case in bot X and Y 
	// (culling with a rotating rectangle would be expensive)
	const int cullDistance = 
		std::max(fontMetrics.height(), params.string_.size() * fontMetrics.maxWidth());
	const Vec4i viewXywh = projector->getViewportXywh();
	const int viewMinX = viewXywh[0];
	const int viewMinY = viewXywh[1];
	const int viewMaxX = viewMinX + viewXywh[2];
	const int viewMaxY = viewMinY + viewXywh[3];

	if(y + cullDistance < viewMinY || y - cullDistance > viewMaxY ||
	   x + cullDistance < viewMinX || x - cullDistance > viewMaxX)
	{
		viewport.disablePainting();
		return;
	}

	if(projector->useGravityLabels() && !params.noGravity_)
	{
		drawTextGravityHelper(params, *painter, x, y, projector);
		return;
	}
	
	const int pixelSize   = painter->font().pixelSize();
	// Strings drawn by drawText() can differ by text, font size, or the font itself.
	const QByteArray hash = params.string_.toUtf8() + QByteArray::number(pixelSize) + 
	                        painter->font().family().toUtf8();
	StelQGLTextureBackend* textTexture = textTextureCache.object(hash);

	// No texture in cache for this string, need to draw it.
	if (NULL == textTexture) 
	{
		const QRect extents = fontMetrics.boundingRect(params.string_);

		// Width and height of the text. 
		// Texture width/height is required to be at least equal to this.
		//
		// Both X and Y need to be at least 1 so we don't create an empty image 
		// (doesn't work with textures)
		const int requiredWidth  = std::max(1, extents.width() + 1 + static_cast<int>(0.02f * extents.width()));
		const int requiredHeight = std::max(1, extents.height());
		// Create temporary image and render text into it

		// QImage is used solely to reuse existing QGLTextureBackend constructor 
		// function. QPixmap could be used as well (not sure which is faster, 
		// needs profiling)
		QImage image = areNonPowerOfTwoTexturesSupported() 
		             ? QImage(requiredWidth, requiredHeight, QImage::Format_ARGB32_Premultiplied) 
		             : QImage(StelUtils::smallestPowerOfTwoGreaterOrEqualTo(requiredWidth), 
		                      StelUtils::smallestPowerOfTwoGreaterOrEqualTo(requiredHeight),
		                      QImage::Format_ARGB32);
		image.fill(Qt::transparent);

		QPainter fontPainter(&image);
		fontPainter.setFont(painter->font());
		fontPainter.setRenderHints(QPainter::TextAntialiasing, true);
		fontPainter.setPen(Qt::white);

		// The second argument ensures the text is positioned correctly even if 
		// the image is enlarged to power-of-two.
		fontPainter.drawText(-extents.x(), 
		                     image.height() - requiredHeight - extents.y(), 
		                     params.string_);

		textTexture = StelQGLTextureBackend::constructFromImage
			(this, QString(), TextureParams().filtering(TextureFiltering_Linear), image);
		const QSize size = textTexture->getDimensions();
		if(!textTexture->getStatus() == TextureStatus_Loaded)
		{
			qWarning() << "Texture error: " << textTexture->getErrorMessage();
			Q_ASSERT_X(false, Q_FUNC_INFO, "Failed to construct a text texture");
		}
		textTextureCache.insert(hash, textTexture, 4 * size.width() * size.height());
	}

	// Even if NPOT textures are not supported, we always draw the full rectangle 
	// of the texture. The extra space is fully transparent, so it's not an issue.

	// Shortcut variables to calculate the rectangle.
	const QSize size   = textTexture->getDimensions();
	const float w      = size.width();
	const float h      = size.height();
	const float xShift = params.xShift_;
	const float yShift = params.yShift_;

	const float angleDegrees = 
		params.angleDegrees_ + 
		(params.noGravity_ ? 0.0f : projector->getDefaultAngleForGravityText());
	// Zero out very small angles.
	// 
	// (this could also be used to optimize the case with zero angled
	//  to avoid sin/cos if needed)
	const bool  angled = std::fabs(angleDegrees) >= 1.0f * M_PI / 180.f;
	const float cosr   = angled  ? std::cos(angleDegrees * M_PI / 180.0) : 1.0f;
	const float sinr   = angled  ? std::sin(angleDegrees * M_PI / 180.0) : 0.0f;

	// Corners of the (possibly rotated) texture rectangle.
	const Vec2f ne(round(x + cosr * xShift       - sinr * yShift),
	               round(y + sinr * xShift       + cosr * yShift));
	const Vec2f nw(round(x + cosr * (w + xShift) - sinr * yShift),
	               round(y + sinr * (w + xShift) + cosr * yShift));
	const Vec2f se(round(x + cosr * xShift       - sinr * (h + yShift)),
	               round(y + sinr * xShift       + cosr * (h + yShift)));
	const Vec2f sw(round(x + cosr * (w + xShift) - sinr * (h + yShift)),
	               round(y + sinr * (w + xShift) + cosr * (h + yShift)));

	// Construct the text vertex buffer if it doesn't exist yet, otherwise clear it.
	if(NULL == textBuffer)
	{
		textBuffer = createVertexBuffer<TexturedVertex>(PrimitiveType_TriangleStrip);
	}
	else
	{
		textBuffer->unlock();
		textBuffer->clear();
	}

	textBuffer->addVertex(TexturedVertex(ne, Vec2f(0.0f, 0.0f)));
	textBuffer->addVertex(TexturedVertex(nw, Vec2f(1.0f, 0.0f)));
	textBuffer->addVertex(TexturedVertex(se, Vec2f(0.0f, 1.0f)));
	textBuffer->addVertex(TexturedVertex(sw, Vec2f(1.0f, 1.0f)));
	textBuffer->lock();

	// Draw.
	const BlendMode oldBlendMode = blendMode;
	setBlendMode(BlendMode_Alpha);
	textTexture->bind(0);
	drawVertexBuffer(textBuffer);
	setBlendMode(oldBlendMode);

	// Reset user-bound texture.
	if(NULL != currentTexture)
	{
		currentTexture->bind(0);
	}
	viewport.disablePainting();
}
Example #9
0
bool EERIECreateSprite(TexturedQuad& sprite, const Vec3f & in, float siz, Color color, float Zpos, float rot = 0) {

	TexturedVertex out;
	EE_RTP(in, &out);
	out.rhw *= 3000.f;

	if(   out.p.z > 0.f
	   && out.p.z < 1000.f
	   && out.p.x > -1000.f
	   && out.p.x < 2500.f
	   && out.p.y > -500.f
	   && out.p.y < 1800.f
	) {
		float use_focal=BASICFOCAL*g_sizeRatio.x;
		float t;

		if(siz < 0) {
			t = -siz;
		} else {
			t = siz * ((out.rhw-1.f)*use_focal*0.001f);

			if(t <= 0.f)
				t = 0.00000001f;
		}
		
		if(Zpos <= 1.f) {
			out.p.z = Zpos;
			out.rhw = 1.f - out.p.z;
		} else {
			out.rhw *= (1.f/3000.f);
		}		
		
		ColorRGBA col = color.toRGBA();
		
		sprite.v[0] = TexturedVertex(Vec3f(), out.rhw, col, Vec2f_ZERO);
		sprite.v[1] = TexturedVertex(Vec3f(), out.rhw, col, Vec2f_X_AXIS);
		sprite.v[2] = TexturedVertex(Vec3f(), out.rhw, col, Vec2f(1.f, 1.f));
		sprite.v[3] = TexturedVertex(Vec3f(), out.rhw, col, Vec2f_Y_AXIS);
		
		if(rot == 0) {
			Vec3f maxs = out.p + t;
			Vec3f mins = out.p - t;

			sprite.v[0].p = Vec3f(mins.x, mins.y, out.p.z);
			sprite.v[1].p = Vec3f(maxs.x, mins.y, out.p.z);
			sprite.v[2].p = Vec3f(maxs.x, maxs.y, out.p.z);
			sprite.v[3].p = Vec3f(mins.x, maxs.y, out.p.z);
		} else {
			for(long i=0;i<4;i++) {
				float tt = glm::radians(MAKEANGLE(rot+90.f*i+45+90));
				sprite.v[i].p.x = std::sin(tt) * t + out.p.x;
				sprite.v[i].p.y = std::cos(tt) * t + out.p.y;
				sprite.v[i].p.z = out.p.z;
			}
		}

		return true;
	}

	return false;
}
Example #10
0
void ARXDRAW_DrawInterShadows()
{	
	GRenderer->SetFogColor(Color::none);
	SetZBias(1);

	long first=1;
	
	for(long i=0; i<TREATZONE_CUR; i++) {
		if(treatio[i].show != 1 || !treatio[i].io)
			continue;

		Entity *io = treatio[i].io;

		if(!io->obj || (io->ioflags & IO_JUST_COLLIDE))
			continue;


		FAST_BKG_DATA * bkgData = getFastBackgroundData(io->pos.x, io->pos.z);
		if(bkgData && !bkgData->treat) { //TODO is that correct ?
			continue;
		}

		if(!(io->ioflags & IO_NOSHADOW) && io->show==SHOW_FLAG_IN_SCENE && !(io->ioflags & IO_GOLD)) {
			TexturedVertex in;

			TexturedVertex ltv[4];
			ltv[0] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, 0, 1, Vec2f(0.3f, 0.3f));
			ltv[1] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, 0, 1, Vec2f(0.7f, 0.3f));
			ltv[2] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, 0, 1, Vec2f(0.7f, 0.7f));
			ltv[3] = TexturedVertex(Vec3f(0, 0, 0.001f), 1.f, 0, 1, Vec2f(0.3f, 0.7f));

			if(io->obj->nbgroups <= 1) {
				for(size_t k=0; k < io->obj->vertexlist.size(); k += 9) {
					EERIEPOLY *ep = EECheckInPoly(&io->obj->vertexlist3[k].v);

					if(ep) {
						in.p.y=ep->min.y-3.f;
						float r=0.5f-((float)EEfabs(io->obj->vertexlist3[k].v.y-in.p.y))*( 1.0f / 500 );
						r-=io->invisibility;
						r*=io->scale;

						if(r<=0.f)
							continue;

						float s1=16.f*io->scale;
						float s2=s1*( 1.0f / 2 );
						in.p.x=io->obj->vertexlist3[k].v.x-s2;
						in.p.z=io->obj->vertexlist3[k].v.z-s2;

						r*=255.f;
						long lv = r;
						ltv[0].color=ltv[1].color=ltv[2].color=ltv[3].color=0xFF000000 | lv<<16 | lv<<8 | lv;

						if(first) {
							first=0;
							GRenderer->SetRenderState(Renderer::DepthWrite, false);
							GRenderer->SetBlendFunc(Renderer::BlendZero, Renderer::BlendInvSrcColor);
							GRenderer->SetRenderState(Renderer::AlphaBlending, true);
							GRenderer->SetTexture(0, Boom);
						}

						EE_RT2(&in,&ltv[0]);
						in.p.x+=s1;
						EE_RT2(&in,&ltv[1]);
						in.p.z+=s1;
						EE_RT2(&in,&ltv[2]);
						in.p.x-=s1;
						EE_RT2(&in,&ltv[3]);

						if(ltv[0].p.z > 0.f && ltv[1].p.z > 0.f && ltv[2].p.z > 0.f) {
							ARX_DrawPrimitive(&ltv[0], &ltv[1], &ltv[2], 50.0f);
							ARX_DrawPrimitive(&ltv[0], &ltv[2], &ltv[3], 50.0f);
						}
					}
				}
			} else {
				for(long k = 0; k < io->obj->nbgroups; k++) {
					long origin=io->obj->grouplist[k].origin;
					EERIEPOLY *ep = EECheckInPoly(&io->obj->vertexlist3[origin].v);

					if(ep) {
						in.p.y=ep->min.y-3.f;
						float r=0.8f-((float)EEfabs(io->obj->vertexlist3[origin].v.y-in.p.y))*( 1.0f / 500 );
						r*=io->obj->grouplist[k].siz;
						r-=io->invisibility;

						if(r<=0.f)
							continue;

						float s1=io->obj->grouplist[k].siz*44.f;
						float s2=s1*( 1.0f / 2 );
						in.p.x=io->obj->vertexlist3[origin].v.x-s2;
						in.p.z=io->obj->vertexlist3[origin].v.z-s2;

						r*=255.f;
						long lv = r;
						ltv[0].color=ltv[1].color=ltv[2].color=ltv[3].color=0xFF000000 | lv<<16 | lv<<8 | lv;

						if(first) {
							first=0;
							GRenderer->SetRenderState(Renderer::DepthWrite, false);
							GRenderer->SetBlendFunc(Renderer::BlendZero, Renderer::BlendInvSrcColor);
							GRenderer->SetRenderState(Renderer::AlphaBlending, true);
							GRenderer->SetTexture(0, Boom);
						}

						EE_RT2(&in,&ltv[0]);
						in.p.x+=s1;
						EE_RT2(&in,&ltv[1]);
						in.p.z+=s1;
						EE_RT2(&in,&ltv[2]);
						in.p.x-=s1;
						EE_RT2(&in,&ltv[3]);

						ARX_DrawPrimitive(&ltv[0], &ltv[1], &ltv[2]);
						ARX_DrawPrimitive(&ltv[0], &ltv[2], &ltv[3]);
					}
				}
			}
		}

	}

	GRenderer->SetRenderState(Renderer::AlphaBlending, false);
	GRenderer->SetRenderState(Renderer::DepthWrite, true);
	SetZBias(0);
	GRenderer->SetFogColor(ulBKGColor);
}