Exemple #1
0
/*
 * Draws the plant.
 */
void drawPlant(int i,float scale,float radscale,int string)
{  
  char *ptr = lsystem[string];
  char ch[] = { '\0','\0' };
  GLfloat c1[] = { 0.6549f,0.4901f,0.2392f }; /* light brown */
  GLfloat c2[] = { 0.3607f,0.2510f,0.2000f }; /* dark brown */
  GLfloat c3[] = { 0.1373f,0.5568f,0.1373f }; /* forest green */

  if(i==0)
    return;
  
  PushMatrix();
  while(*ptr != '\0')
    {
      switch(*ptr)
	{
	case 'F':
	  Rotate(tilt/10000,0.0,0.0,1.0); /* tilt very very slightly */
	  LoadMatrix();
	  if(do_growth && floor(growth)==i)
	    {
	      draw_branch(LENGTH*scale*(growth-1),RADIUS*radscale,BASE_TRI,c1,c2);
	      Translate(0.0,LENGTH*scale*(growth-1),0.0);
	    }
	  else
	    {
	      draw_branch(LENGTH*scale,RADIUS*radscale,BASE_TRI,c1,c2);
	      Translate(0.0,LENGTH*scale,0.0);
	    }
	  break;
	case '[':
	  PushMatrix();
	  break;
	case ']':
	  PopMatrix();
	  break;
	case 'L':
	  if(do_growth && floor(growth)==i)
	      draw_leaf(4*(growth-1)*scale,1*(growth-1)*scale,25,c3);
	  else
	    draw_leaf(4*scale,1*scale,25,c3);
	  break;
	case 'R':
	  Rotate(yrotate,0.0,1.0,0.0);
	  break;
	case 'T':
	  Rotate(tilt,0.0,0.0,1.0);
	  break;
	default:
	  if(isdigit(*ptr))
	    {
	      ch[0] = *ptr;
	      drawPlant(i-1,scale*SCALE,radscale*RADSCALE,atoi(ch));
	    }
	  break;
	}
      ptr++;
    }
  PopMatrix();
}
void Device_OpenGL::Draw2DTextureFullViewport(Texture* texture)
{
    DisableDepthTest();
    PushMatrix();
    SetIdentityMatrix();
    UnbindVBO(VBO::VBO_TARGET_ARRAY_BUFFER);
    //-------------------------------------------
    float x = Screen::GetInstance()->GetRatio();
    float y = 1.0f;
    float z = -1.0f;
    float vertices[30] = { -x, y, z, 0.0f, 1.0f,
                           -x, -y, z, 0.0f, 0.0f,
                           x, -y, z, 1.0f, 0.0f,
                           -x, y, z, 0.0f, 1.0f,
                           x, -y, z, 1.0f, 0.0f,
                           x, y, z, 1.0f, 1.0f
                         };
    SetAttributePointer(ATTRIBUTE_FLOAT3_POSITION, vertices, sizeof(float) * 5);
    SetAttributePointer(ATTRIBUTE_FLOAT2_TEXCOORD_DIFFUSE, vertices + 3, sizeof(float) * 5);
    Device_Base::GetInstance()->UpdateVertexAttribPointer();
    Device_Base::GetInstance()->SetUniformTexture(UNIFORM_TEXTURE_DIFFUSE, texture);
    Device_Base::GetInstance()->SetUniformMatrix(UNIFORM_MATRIX_MODEL, Device_Base::GetInstance()->GetMatrixWorld());
    Device_Base::GetInstance()->SetUniformMatrix(UNIFORM_MATRIX_PROJECTION, m_MatrixProjection2DLogical);

    Device_Base::GetInstance()->DrawArray(Device_Base::PRIMITIVE_TRIANGLE_LIST, 0, 6);
    //-------------------------------------------
    EnableDepthTest();
    PopMatrix();

}
/**
 * \param type bit 0: render OSD, bit 1: render EOSD
 */
static void do_render_osd(int type) {
  if (((type & 1) && osdtexCnt > 0) || ((type & 2) && eosdDispList)) {
    // set special rendering parameters
    if (!scaled_osd) {
      MatrixMode(GL_PROJECTION);
      PushMatrix();
      LoadIdentity();
      Ortho(0, vo_dwidth, vo_dheight, 0, -1, 1);
    }
    Enable(GL_BLEND);
    if ((type & 2) && eosdDispList) {
      BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      CallList(eosdDispList);
    }
    if ((type & 1) && osdtexCnt > 0) {
      Color4ub((osd_color >> 16) & 0xff, (osd_color >> 8) & 0xff, osd_color & 0xff, 0xff - (osd_color >> 24));
      // draw OSD
#ifndef FAST_OSD
      BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
      CallLists(osdtexCnt, GL_UNSIGNED_INT, osdaDispList);
#endif
      BlendFunc(GL_SRC_ALPHA, GL_ONE);
      CallLists(osdtexCnt, GL_UNSIGNED_INT, osdDispList);
    }
    // set rendering parameters back to defaults
    Disable(GL_BLEND);
    if (!scaled_osd)
      PopMatrix();
    BindTexture(gl_target, 0);
  }
void GL2HudRenderer::render() {
	if (client->getStateId() != Client::StateId::PLAYING)
		return;

	const Character &character = client->getLocalCharacter();
	if (!character.isValid())
		return;

	GL(Enable(GL_TEXTURE_2D));
	vec2f texs[4];
	GL2TextureManager::Entry tex_entry = renderer->getTextureManager()->get(client->getLocalCharacter().getBlock());
	GL2TextureManager::getTextureCoords(tex_entry.index, tex_entry.type, texs);
	GL(BindTexture(GL_TEXTURE_2D, tex_entry.tex));

	GL(Color4f(1.0f, 1.0f, 1.0f, 1.0f));

	GL(PushMatrix());
	float d = (client->getGraphics()->getWidth() < client->getGraphics()->getHeight() ? client->getGraphics()->getWidth() : client->getGraphics()->getHeight()) * 0.05f;
	GL(Translatef(-client->getGraphics()->getDrawWidth() * 0.48f, -client->getGraphics()->getDrawHeight() * 0.48f, 0));
	glBegin(GL_QUADS);
		glTexCoord2f(texs[0][0], texs[0][1]); glVertex2f(0, 0);
		glTexCoord2f(texs[1][0], texs[1][1]); glVertex2f(d, 0);
		glTexCoord2f(texs[2][0], texs[2][1]); glVertex2f(d, d);
		glTexCoord2f(texs[3][0], texs[3][1]); glVertex2f(0, d);
	glEnd();
	LOG_OPENGL_ERROR;

	GL(PopMatrix());
}
Exemple #5
0
void VideoEngine::PushState()
{
    // Push current modelview transformation
    glMatrixMode(GL_MODELVIEW);
    PushMatrix();

    _context_stack.push(_current_context);
}
void dSceneRender::DrawArrow (int segments, dFloat radius, dFloat heigh, const dVector& stemColor, const dVector& tipColor)
{
	dMatrix matrix (dGetIdentityMatrix());
	matrix.m_posit.m_x = heigh / 2.0f;
	PushMatrix(matrix);
	SetColor(stemColor);
	DrawCylinder(segments, radius, heigh);

	dFloat tipLength = heigh / 3.0f;
	matrix.m_posit.m_x = (heigh + tipLength) / 2.0f;
	PushMatrix(matrix);
	SetColor(tipColor);
	DrawCone(segments, radius * 2.0f, tipLength);

	PopMatrix();
	PopMatrix();
}
//-- Cube ---------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void Renderer::Cube( float nx, float ny, float nz, float x, float y, float z )
{
	//    4-------5
	//   /|      /|
	//  0-------1 |
	//  | 7-----|-6
	//  |/      |/
	//  3-------2

	PushMatrix();

	Translate(  ( nx + x ) * 0.5f,
				( ny + y ) * 0.5f,
				( nz + z ) * 0.5f );

	DiffuseUVCubeVertexShader* pShader = NULL;
	if ( g_envMapSet )
	{
		pShader = &DiffuseUVEnvCubeVertexShader::StaticType;
	}
	else
	{
		pShader = &DiffuseUVCubeVertexShader::StaticType;
	}

	CommitTransforms( pShader );
	CommitTextureState();

	PopMatrix();

	D3DXVECTOR4 vScale( ( x - nx ) * 0.5f, ( y - ny ) * 0.5f, ( z - nz ) * 0.5f, 1.0f );

	pShader->SetScale( &vScale );
	pShader->SetColour( &g_fColour );

	m_pD3DDevice->SetVertexShader( pShader->GetVertexShader() );
	m_pD3DDevice->SetVertexDeclaration( g_pPosNormalColUVDeclaration );

	m_pD3DDevice->SetStreamSource( 0,
								   g_pCubeVbuffer,
								   0,
								   sizeof( PosColNormalUVVertex ) );

	m_pD3DDevice->SetIndices( g_pCubeIbuffer );

	m_pD3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12 );

	m_pD3DDevice->SetStreamSource( 0,
								   NULL,
								   0,
								   sizeof( PosColNormalUVVertex ) );

	m_pD3DDevice->SetIndices( NULL );

} // Cube
void GL2ChunkRenderer::renderChunk(vec3i64 chunkCoords) {
	auto it = renderInfos.find(chunkCoords);
	if (it == renderInfos.end() || it->second.dl == 0)
		return;

	Character &character = client->getLocalCharacter();
	vec3i64 cd = chunkCoords - character.getChunkPos();

	GL(PushMatrix());
	GL(Translatef(cd[0] * (float) Chunk::WIDTH, cd[1] * (float) Chunk::WIDTH, cd[2] * (float) Chunk::WIDTH))
	GL(CallList(it->second.dl));
	GL(PopMatrix());
}
Exemple #9
0
int draw(Display *display,int num, int mouseX, int mouseY) {
	double angle1, angle2;
	double dx,dy;
	double tx,ty;
	double cosa, sina;
	double x,y,x2,y2;
	
	x = pupils[num];
    y = pupils[num+1];
    x2 = eyes[num];
    y2 = eyes[num+1];
    
    DrawEllipse(display, (int)eyes[num], (int)eyes[num+1], EYE_W, EYE_H);
    	  
    PushStyle(display);
    Fill1i(display, 0);
    
	dx = (double)mouseX - x;
	dy = (double)mouseY - y;
	angle1 = atan2(dy,dx);

	cosa = cos(angle1);
	sina = sin(angle1);
	tx = mouseX - cosa * EYE_RAD;
	ty = mouseY - sina * EYE_RAD;

	dx = tx - x2;
	dy = ty - y2;
	angle2 = atan2(dy,dx);

	cosa = cos(angle2);
	sina = sin(angle2);
	x 	= x2 + cosa * EYE_RAD;
	y 	= y2 + sina * EYE_RAD;

	PushMatrix(display);
	Translate2f(display,x, y);
	Rotate(display, angle1);
	DrawEllipse(display, EYE_RAD, 0, PUPIL_W, PUPIL_W);
	PopMatrix(display);
	
	pupils[num] = x;
	pupils[num+1] = y;
    
    PopStyle(display);
    return 0;
}
Exemple #10
0
static int render(struct Cube* This, HTEXTURE* ptex)
{
    int imap[6][4] = 
    {
        {2, 3, 1, 0},
        {3, 7, 0, 4},
        {2, 6, 3, 7},
        {0, 4, 1, 5},
        {1, 5, 2, 6},
        {7, 6, 4, 5},
    };
    int f, it;
    FPOINT3D pt[4];
    for (f = 0; f < 6; ++f)
    {
        if (This->face[f].visable)
        {
            int bObjSet = 0;
            for (it = 0; it < 4; ++it)
            {
                memcpy(&pt[it], &This->pos[imap[f][it]], sizeof(VECTOR3D));
                pt[it].color = 0xFFFFFFFF;
            }
            PushMatrix();
            if (This->rotate_x != 0.0f)
            {
                ObjectRotate(This->rotate_x, 1.0f, 0.0f, 0.0f);
                bObjSet = 1;
            }
            if (This->rotate_y != 0.0f)
            {
                ObjectRotate(This->rotate_y, 0.0f, -1.0f, 0.0f);
                bObjSet = 1;
            }
            if (This->rotate_z != 0.0f)
            {
                ObjectRotate(This->rotate_z, 0.0f, 0.0f, -1.0f);
                bObjSet = 1;
            }
            This->face[f].render(&This->face[f], ptex, pt);
            PopMatrix();
        }
    }
    return 0 ;
}
  void TextEngineRenderer::DrawRectangle(glm::vec2 center, glm::vec2 dimensions) {
    PushMatrix();
    matrix_stack.back() *= glm::scale(glm::translate(glm::mat4(1), glm::vec3(center, 0.0f)),
                                      glm::vec3(dimensions, 1));

    face_program.Use();
    face_program.Uniforms({
      {u8"projection", &projection},
      {u8"model_view", &matrix_stack.back()}
    });
    face_program.Uniforms({
      {u8"color", fill}
    });
    rectangle_array.Bind();
    glDrawArrays(unit_square.element_type, 0, unit_square.element_count);
    CHECK_STATE(!glGetError());

    PopMatrix();
  }
Exemple #12
0
void nuiGLPainter::ApplyTexture(const nuiRenderState& rState, bool ForceApply)
{
//  if ((rState.mTexturing && !rState.mpTexture) || (!rState.mTexturing && rState.mpTexture))
//  {
//    printf("bleh!\n");
//    char* bleh = NULL;
//    bleh[0] = 0;
//  }

  // 2D Textures: 
  std::map<nuiTexture*, TextureInfo>::const_iterator it = mTextures.find(rState.mpTexture);
  bool uptodate = (it == mTextures.end()) ? false : ( !it->second.mReload && it->second.mTexture >= 0 );
  if (ForceApply || (mState.mpTexture != rState.mpTexture) || (mState.mpTexture && !uptodate))
  { 
    GLenum intarget = 0;
    GLenum outtarget = 0;

    if (mState.mpTexture)
    {      
      outtarget = GetTextureTarget(mState.mpTexture->IsPowerOfTwo());

      //mState.mpTexture->UnapplyGL(this); #TODO Un apply the texture
      nuiCheckForGLErrors();
      mState.mpTexture->Release();
      nuiCheckForGLErrors();
    }

    //NGL_OUT(_T("Change texture to 0x%x (%ls)\n"), rState.mpTexture, rState.mpTexture?rState.mpTexture->GetSource().GetChars() : nglString::Empty.GetChars());
    mState.mpTexture = rState.mpTexture ;

    if (mState.mpTexture)
    {
      intarget = GetTextureTarget(mState.mpTexture->IsPowerOfTwo());

      mState.mpTexture->Acquire();
  
      nuiSurface* pSurface = mState.mpTexture->GetSurface();
      if (pSurface)
      {
        std::map<nuiSurface*, FramebufferInfo>::const_iterator it = mFramebuffers.find(pSurface);
        bool create = (it == mFramebuffers.end()) ? true : false;  
        if (create || pSurface->IsDirty())
        {
          PushClipping();
          nuiRenderState s(mState);// PushState();
          PushProjectionMatrix();
          PushMatrix();

#ifdef _OPENGL_ES_
          if (mpSurfaceStack.empty())
          {
            //  mDefaultFramebuffer = 0;
            //  mDefaultRenderbuffer = 0;
            glGetIntegerv(GL_FRAMEBUFFER_BINDING_NUI, &mDefaultFramebuffer);
            glGetIntegerv(GL_RENDERBUFFER_BINDING_NUI, (GLint *) &mDefaultRenderbuffer);
          }
#endif

          PushSurface();


          SetState(nuiRenderState());
          ResetClipRect();
          mClip.Set(0, 0, pSurface->GetWidth(), pSurface->GetHeight());

          LoadMatrix(nglMatrixf());

          NGL_ASSERT(pSurface);
          SetSurface(pSurface);
          //Set2DProjectionMatrix(nuiRect(0.0f, 0.0f, pSurface->GetWidth(), pSurface->GetHeight()));
          nuiMatrix m;
          m.Translate(-1.0f, 1.0f, 0.0f);
          m.Scale(2.0f / pSurface->GetWidth(), -2.0f / pSurface->GetHeight(), 1.0f);
          LoadProjectionMatrix(nuiRect(pSurface->GetWidth(), pSurface->GetHeight()), m);

          // clear the surface with transparent black:
//          nuiRenderState s2(mState);// PushState();
//          mState.mClearColor = nuiColor(0.0f, 0.0f, 0.0f, 0.0f);
          SetState(mState);
//          ClearColor();  
//          SetState(s2);

//////////////////////////////          
          nuiDrawContext Ctx(nuiRect(pSurface->GetWidth(), pSurface->GetHeight()));
          Ctx.SetPainter(this);
          pSurface->Realize(&Ctx);
          Ctx.SetPainter(NULL);
//////////////////////////////

          PopSurface();
          PopMatrix();
          PopProjectionMatrix();
          //PopState();
          SetState(s);
          PopClipping();
        }
      }

      UploadTexture(mState.mpTexture);
      nuiCheckForGLErrors();
    }

    //NGL_OUT(_T("Change texture type from 0x%x to 0x%x\n"), outtarget, intarget);

    mTextureTarget = intarget;
    if (intarget != outtarget)
    {
      // Texture Target has changed
      if (outtarget)
      {
        glDisable(outtarget);
        nuiCheckForGLErrors();
      }
      //NGL_OUT(_T("disable outtarget\n"));
      if (intarget && mState.mTexturing && mState.mpTexture)
      {
        mState.mTexturing = rState.mTexturing;
        //NGL_OUT(_T("enable intarget\n"));
        glEnable(intarget);
        nuiCheckForGLErrors();
      }
    }
    else
    {
      // Texture Target have not changed     
      if (mState.mTexturing != rState.mTexturing) // Have texture on/off changed?
      {
        // Should enable or disable texturing
        mState.mTexturing = rState.mTexturing;
        if (mState.mTexturing)
        {
          glEnable(mTextureTarget);
          nuiCheckForGLErrors();
        }
        else
        {
          glDisable(mTextureTarget);
          nuiCheckForGLErrors();
        }
      }
    }
  }

  if (ForceApply || (mState.mTexturing != rState.mTexturing))
  {
    // Texture have not changed, but texturing may have been enabled / disabled
    mState.mTexturing = rState.mTexturing;

    if (mState.mpTexture)
    {
      if (mTextureTarget && mState.mTexturing)
      {
        //NGL_OUT(_T("Enable 0x%x\n"), mTextureTarget);
        glEnable(mTextureTarget);
        nuiCheckForGLErrors();
      }
      else
      {
        //NGL_OUT(_T("Disable 0x%x\n"), mTextureTarget);
        glDisable(mTextureTarget);
        nuiCheckForGLErrors();
      }
    }
    else
    {
      if (mTextureTarget)
      {
        //NGL_OUT(_T("Disable 0x%x\n"), mTextureTarget);
        glDisable(mTextureTarget);
      }
      nuiCheckForGLErrors();
    }
  }
}
  void TextEngineRenderer::Render() {
    GameState &current_state = updater.GetCurrentState();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    PushMatrix();
    matrix_stack.back() *= glm::scale(glm::mat4(1), glm::vec3(glm::vec2(current_state.zoom * 0.1f), 1.0f));
    matrix_stack.back() *= glm::translate(glm::mat4(1), glm::vec3(-current_state.camera_position, 0));

    const glm::vec2 position = glm::vec2(current_state.player_body->GetPosition().x,
                                         current_state.player_body->GetPosition().y);

    fill = glm::vec4(0.0f, 0.5f, 0.3f, 0.5f);
    for (const auto &area : scene.areas) {
      if (area->invisible) {
        continue;
      }
      if (Shape::kAxisAlignedBoundingBox == area->shape) {
        DrawAxisAlignedBoundingBox(area->aabb);
      } else {
        DrawCircle(area->aabb.center(), area->aabb.radius());
      }
    }
    fill = glm::vec4(1.0f, 0.0f, 0.0f, 0.5f);
    for (const auto &object : scene.objects) {
      if (object->invisible) {
        continue;
      }
      if (Shape::kAxisAlignedBoundingBox == object->shape) {
        DrawAxisAlignedBoundingBox(object->aabb);
      } else {
        DrawCircle(object->aabb.center(), object->aabb.radius());
      }	
    }

    const glm::mat4 normalized_to_reversed = glm::scale(glm::mat4(), glm::vec3(1.0f, -1.0f, 1.0f));
    const glm::mat4 reversed_to_offset = glm::translate(glm::mat4(), glm::vec3(glm::vec2(1.0f), 0.0f));
    const glm::mat4 offset_to_screen = glm::scale(glm::mat4(), glm::vec3(glm::vec2(0.5f), 1.0f));
    const glm::mat4 screen_to_window = glm::scale(glm::mat4(), glm::vec3(width, height, 1.0f));

    const glm::mat4 transform = (screen_to_window * offset_to_screen *
                                 reversed_to_offset * normalized_to_reversed *
                                 model_view * projection * matrix_stack.back());
    const glm::mat4 transform2 = (screen_to_window * offset_to_screen *
                                  reversed_to_offset *
                                  model_view * projection * matrix_stack.back());
    const auto inverse = glm::inverse(transform2);
    const glm::vec4 homogeneous = transform * glm::vec4(position, 0.0f, 1.0f);
    const glm::vec2 transformed = homogeneous.xy() / homogeneous.w;

    fill = glm::vec4(0.5f, 0.5f, 0.6f, 1.0f);
    PushMatrix();
    matrix_stack.back() *= glm::translate(glm::mat4(1), glm::vec3(position, 0));
    matrix_stack.back() *= glm::rotate(glm::mat4(1),
                                       current_state.player_body->GetAngle(),
                                       glm::vec3(0, 0, 1));
    DrawRectangle(glm::vec2(0), glm::vec2(0.25f, 0.5f));
    PopMatrix();
    PopMatrix();
    
    if (edit) {
      MaybeRebuildAttenuationShader();
      if (current_state.selected_item) {
        attenuation3_program.Use();
        attenuation3_program.Uniforms({
          {u8"model_view_inverse", &inverse}
        });
        const auto isaabb3 = Shape::kAxisAlignedBoundingBox == current_state.selected_item->shape;
        glUniform1i(attenuation3_program.GetUniformLocation(u8"selected_isaabb"), isaabb3);
        if (Shape::kAxisAlignedBoundingBox == current_state.selected_item->shape) {
          attenuation3_program.Uniforms({
            {u8"selected_minimum_or_center", current_state.selected_item->aabb.minimum},
            {u8"selected_maximum_or_radius", current_state.selected_item->aabb.maximum},
          });
          CHECK_STATE(!glGetError());
        } else {
          attenuation3_program.Uniforms({
            {u8"selected_minimum_or_center", current_state.selected_item->aabb.center()},
            {u8"selected_maximum_or_radius", glm::vec2(current_state.selected_item->aabb.radius())},
          });
          CHECK_STATE(!glGetError());
        }
        const auto attenuation3_coefficients = glm::vec3(
            current_state.selected_item->base_attenuation,
                current_state.selected_item->linear_attenuation,
                    current_state.selected_item->quadratic_attenuation);
        attenuation3_program.Uniforms({
          {u8"selected_attenuation", attenuation3_coefficients},
        });
        const auto color3 = glm::vec4(0, 0, 0, 0.125);
        attenuation3_program.Uniforms({
          {u8"color", color3}
        });
        attenuation_array.Bind();
        glDrawArrays(attenuation.element_type, 0, attenuation.element_count);
        CHECK_STATE(!glGetError());
        
        attenuation_program.Use();
        attenuation_program.Uniforms({
          {u8"model_view_inverse", &inverse}
        });
        const auto isaabb = Shape::kAxisAlignedBoundingBox == current_state.selected_item->shape;
        glUniform1i(attenuation_program.GetUniformLocation(u8"selected_isaabb"), isaabb);
        if (Shape::kAxisAlignedBoundingBox == current_state.selected_item->shape) {
          attenuation_program.Uniforms({
            {u8"selected_minimum_or_center", current_state.selected_item->aabb.minimum},
            {u8"selected_maximum_or_radius", current_state.selected_item->aabb.maximum},
          });
          CHECK_STATE(!glGetError());
        } else {
          attenuation_program.Uniforms({
            {u8"selected_minimum_or_center", current_state.selected_item->aabb.center()},
            {u8"selected_maximum_or_radius", glm::vec2(current_state.selected_item->aabb.radius())},
          });
          CHECK_STATE(!glGetError());
        }
        const auto attenuation_coefficients = glm::vec3(
            current_state.selected_item->base_attenuation,
                current_state.selected_item->linear_attenuation,
                    current_state.selected_item->quadratic_attenuation);
        attenuation_program.Uniforms({
          {u8"selected_attenuation", attenuation_coefficients},
        });
        const auto color = glm::vec4(0, 0, 0, 0.5);
        attenuation_program.Uniforms({
          {u8"color", color}
        });
        attenuation_array.Bind();
        glDrawArrays(attenuation.element_type, 0, attenuation.element_count);
        CHECK_STATE(!glGetError());
      }
    }

    const auto mouse_position = 2.0f * mouse.get_cursor_position();
    unsigned char mouse_buttons = 0;
    if (mouse.IsButtonDown(GLFW_MOUSE_BUTTON_1)) {
      mouse_buttons |= IMGUI_MBUT_LEFT;
    }
    if (mouse.IsButtonDown(GLFW_MOUSE_BUTTON_2)) {
      mouse_buttons |= IMGUI_MBUT_RIGHT;
    }
    
    if (edit) {
      imguiBeginFrame(mouse_position.x, height - mouse_position.y, mouse_buttons, 0);
      
      for (auto &area : scene.areas) {
        const glm::vec4 homogeneous = transform * glm::vec4(area->aabb.minimum.x, area->aabb.maximum.y, 0.0f, 1.0f);
        const glm::vec2 transformed = homogeneous.xy() / homogeneous.w;
        imguiDrawText(transformed.x, height - transformed.y, IMGUI_ALIGN_LEFT, area->name.c_str(), imguiRGBA(0, 0, 0));
      }
      
      for (auto &object : scene.objects) {
        const glm::vec4 homogeneous = transform * glm::vec4(object->aabb.minimum.x, object->aabb.maximum.y, 0.0f, 1.0f);
        const glm::vec2 transformed = homogeneous.xy() / homogeneous.w;
        imguiDrawText(transformed.x, height - transformed.y, IMGUI_ALIGN_LEFT, object->name.c_str(), imguiRGBA(0, 0, 0));
      }
      
      if (current_state.selected_item) {
        std::ostringstream name, constant, linear, quadratic;
        name << current_state.selected_item->name;
        imguiDrawText(10, height - 50, IMGUI_ALIGN_LEFT, name.str().c_str(), imguiRGBA(0, 0, 0));
        constant << "c: " << current_state.selected_item->base_attenuation;
        imguiDrawText(10, height - 75, IMGUI_ALIGN_LEFT, constant.str().c_str(), imguiRGBA(0, 0, 0));
        linear << "l: " << current_state.selected_item->linear_attenuation;
        imguiDrawText(10, height - 100, IMGUI_ALIGN_LEFT, linear.str().c_str(), imguiRGBA(0, 0, 0));
        quadratic << "q: " << current_state.selected_item->quadratic_attenuation << std::endl;
        imguiDrawText(10, height - 125, IMGUI_ALIGN_LEFT, quadratic.str().c_str(), imguiRGBA(0, 0, 0));
      }
      
      imguiEndFrame();
    }

    imguiRenderGLDraw(width, height);
  }