Esempio n. 1
0
void			SceneRenderer::render(
				bool _lastFrame,
				bool _sameFrame,
				bool fullWindow)
{
  static const GLfloat blindnessColor[4] = { 1.0f, 1.0f, 0.0f, 1.0f };
  static const GLfloat dimnessColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  static const float dimDensity = 0.75f;
  bool               lighting   = BZDB.isTrue("lighting");

  lastFrame = _lastFrame;
  sameFrame = _sameFrame;

  // avoid OpenGL calls as long as possible -- there's a good
  // chance we're waiting on the vertical retrace.

  // set the view frustum
  if (sceneIterator) sceneIterator->resetFrustum(&frustum);

  // get the important lights in the scene
  int i;
  int numLights = 0;
  if (!sameFrame) {
    clearLights();
    if (sceneIterator && !blank && lighting) {
      // add lights
      sceneIterator->reset();
      SceneNode* node;
      while ((node = sceneIterator->getNext()) != NULL)
	node->addLight(*this);
      numLights = lights.size();

      // pick maxLights most important light sources
      // should go by full lighting function but we'll just go by distance
      if (numLights > maxLights) {
	const GLfloat* eye = frustum.getEye();
	for (i = 0; i < maxLights; i++) {
	  GLfloat maxImportance = lights[i]->getImportance(eye);
	  for (int j = i + 1; j < numLights; j++) {
	    GLfloat importance = lights[j]->getImportance(eye);
	    if (importance > maxImportance) {
	      OpenGLLight* temp = lights[i];
	      lights[j] = lights[i];
	      lights[i] = temp;
	      maxImportance = importance;
	    }
	  }
	}
	numLights = maxLights;
      }
    }
  }

  // get the nodes to draw
  if (!blank) {
    // empty the render node lists in preparation for the next frame
    OpenGLGState::clearLists();
    orderedList.clear();
    shadowList.clear();
    flareLightList.clear();

    // make the lists of render nodes sorted in optimal rendering order
    if (sceneIterator) {
      sceneIterator->reset();
      SceneNode* node;
      while ((node = sceneIterator->getNext()) != NULL)
	node->getRenderNodes(*this);
    }

    // sort ordered list in reverse depth order
    if (!inOrder)
      orderedList.sort(frustum.getEye());
  }

  // prepare transforms
  // note -- lights should not be positioned before view is set
  frustum.executeDeepProjection();
  glPushMatrix();
  frustum.executeView();

  // turn sunlight on -- the ground needs it
  if (lighting && sunOrMoonUp) {
    theSun.execute(SunLight);
    theSun.enableLight(SunLight);
  }

  // turn on fog for teleporter blindness if close to a teleporter
  float teleporterProximity = 0.0f;
  if (!blank && LocalPlayer::getMyTank() && (LocalPlayer::getMyTank()->getTeam() != ObserverTeam))
    teleporterProximity = LocalPlayer::getMyTank()->getTeleporterProximity();

  float worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  bool reallyUseFogHack = useFogHack && (useQualityValue >= 2);
  if (reallyUseFogHack) {
    if (useDimming) {
      const float density = dimDensity;
      glFogi(GL_FOG_MODE, GL_LINEAR);
      glFogf(GL_FOG_START, -density * 1000.0f * worldSize);
      glFogf(GL_FOG_END, (1.0f - density) * 1000.0f * worldSize);
      glFogfv(GL_FOG_COLOR, dimnessColor);
      glEnable(GL_FOG);
    }
    else if (teleporterProximity > 0.0f && useFogHack) {
      const float density = (teleporterProximity > 0.75f) ?
				1.0f : teleporterProximity / 0.75f;
      glFogi(GL_FOG_MODE, GL_LINEAR);
      glFogf(GL_FOG_START, -density * 1000.0f * worldSize);
      glFogf(GL_FOG_END, (1.0f - density) * 1000.0f * worldSize);
      glFogfv(GL_FOG_COLOR, blindnessColor);
      glEnable(GL_FOG);
    }
  }

  // set scissor

  glScissor(window.getOriginX(), window.getOriginY() + window.getHeight() - window.getViewHeight(),
      window.getWidth(), window.getViewHeight());

  if (useDepthComplexityOn) {
  //  glEnable(GL_STENCIL_TEST);
   // glClear(GL_STENCIL_BUFFER_BIT);
  //  glStencilFunc(GL_ALWAYS, 0, 0xf);
	//	glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
  }
  if (useHiddenLineOn) {
    //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   // glClear(GL_COLOR_BUFFER_BIT);
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  }
  else if (useWireframeOn) {
    //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
   // glClear(GL_COLOR_BUFFER_BIT);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  }

  // prepare z buffer
	/*
  if (BZDB.isTrue("zbuffer"))
	{
    if (sameFrame && ++depthRange == numDepthRanges)
			depthRange = 0;
    if (exposed || useHiddenLineOn || --depthRange < 0)
		{
      depthRange = numDepthRanges - 1;
      glClear(GL_DEPTH_BUFFER_BIT);
      exposed = false;
    }
    if (!sameFrame && numDepthRanges != 1)
		{
      if (useHiddenLineOn) {
	glDepthRange(0.0, 1.0);
      }
      else {
	GLclampd x_near = (GLclampd)depthRange * depthRangeSize;
	glDepthRange(x_near, x_near + depthRangeSize);
      }
    }
  }
	*/
  // draw start of background (no depth testing)
  OpenGLGState::resetState();
  if (background)
	{
    background->setBlank(blank);
    background->setInvert(invert);
    background->renderSkyAndGround(*this, fullWindow);
  }

  // prepare the other lights but don't turn them on yet --
  // we may need to turn them on when drawing the background.
  if (lighting) {
    for (i = 0; i < numLights; i++)
      lights[i]->execute(i + reservedLights);
  }

  // draw rest of background
  if (background)
    background->render(*this);

  if (!blank) {
    if (lighting) {
      // now turn on the remaining lights
      for (i = 0; i < numLights; i++)
	OpenGLLight::enableLight(i + reservedLights);
    }

    frustum.executeProjection();
    if (BZDB.isTrue("zbuffer")) glEnable(GL_DEPTH_TEST);

    if (useHiddenLineOn) {
#if defined(GL_VERSION_1_1)
      glEnable(GL_POLYGON_OFFSET_FILL);
#elif defined(GL_EXT_polygon_offset)
      glEnable(GL_POLYGON_OFFSET_EXT);
#endif
    }
		// render the normal stuff
   doRender();

    if (useHiddenLineOn) {
#if defined(GL_VERSION_1_1)
      glDisable(GL_POLYGON_OFFSET_FILL);
#elif defined(GL_EXT_polygon_offset)
      glDisable(GL_POLYGON_OFFSET_EXT);
#endif
      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      doRender();
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }

    OpenGLGState::resetState();

    // shut off lights
    if (lighting) {
      theSun.enableLight(SunLight, false);
      for (i = 0; i < numLights; i++)
	OpenGLLight::enableLight(i + reservedLights, false);
    }

    if (BZDB.isTrue("zbuffer")) glDisable(GL_DEPTH_TEST);

    // FIXME -- must do post-rendering: flare lights, etc.
    // flare lights are in world coordinates.  trace ray to that world
    // position and calculate opacity.  if opaque then don't render
    // flare, otherwise modulate input color by opacity and draw a
    // billboard texture (constant size in screen space).
  }

  // back to original state
  if (!useHiddenLineOn && useWireframeOn)
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  glPopMatrix();

  if ((reallyUseFogHack && (teleporterProximity > 0.0f || useDimming)))
    glDisable(GL_FOG);

  if (!reallyUseFogHack) {
    float density = 0.0f;
    const GLfloat* color = NULL;
    if (useDimming) {
      density = dimDensity;
      color = dimnessColor;
    }
    else if (teleporterProximity > 0.0f) {
      density = (teleporterProximity > 0.75f) ?
			1.0f : teleporterProximity / 0.75f;
      color = blindnessColor;
    }
    if (density > 0.0f && color != NULL) {
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glMatrixMode(GL_MODELVIEW);
      glColor4f(color[0], color[1], color[2], density);
			glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
    }
  }

  if (useDepthComplexityOn) {
    static const GLfloat depthColors[][3] = {
				{ 0.0f, 0.0f, 0.0f },	// black -- 0 times
				{ 0.5f, 0.0f, 1.0f },	// purple -- 1 time
				{ 0.0f, 0.0f, 1.0f },	// blue -- 2 times
				{ 0.0f, 1.0f, 1.0f },	// cyan -- 3 times
				{ 0.0f, 1.0f, 0.0f },	// green -- 4 times
				{ 1.0f, 1.0f, 0.0f },	// yellow -- 5 times
				{ 1.0f, 0.5f, 0.0f },	// orange -- 6 times
				{ 1.0f, 0.0f, 0.0f }	// red -- 7 or more
			};
    static const int numColors = countof(depthColors);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    for (i = 0; i < numColors; i++) {
      glStencilFunc(i == numColors - 1 ? GL_LEQUAL : GL_EQUAL, i, 0xf);
      glColor3fv(depthColors[i]);
      glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
    }
    glDisable(GL_STENCIL_TEST);
  }
}