void CButton::Draw() { float bz = GetBufferedZ(); CGUISpriteInstance *sprite, *sprite_over, *sprite_pressed, *sprite_disabled; int cell_id; // Statically initialise some strings, so we don't have to do // lots of allocation every time this function is called static CStr strSprite("sprite"); static CStr strSpriteOver("sprite_over"); static CStr strSpritePressed("sprite_pressed"); static CStr strSpriteDisabled("sprite_disabled"); static CStr strCellId("cell_id"); GUI<CGUISpriteInstance>::GetSettingPointer(this, strSprite, sprite); GUI<CGUISpriteInstance>::GetSettingPointer(this, strSpriteOver, sprite_over); GUI<CGUISpriteInstance>::GetSettingPointer(this, strSpritePressed, sprite_pressed); GUI<CGUISpriteInstance>::GetSettingPointer(this, strSpriteDisabled, sprite_disabled); GUI<int>::GetSetting(this, strCellId, cell_id); DrawButton(m_CachedActualSize, bz, *sprite, *sprite_over, *sprite_pressed, *sprite_disabled, cell_id); CColor color = ChooseColor(); IGUITextOwner::Draw(0, color, m_TextPos, bz+0.1f); }
void IGUIObject::ChooseMouseOverAndClosest(IGUIObject*& pObject) { if (!MouseOver()) return; // Check if we've got competition at all if (pObject == NULL) { pObject = this; return; } // Or if it's closer if (GetBufferedZ() >= pObject->GetBufferedZ()) { pObject = this; return; } }
void CDropDown::HandleMessage(SGUIMessage& Message) { // Important switch (Message.type) { case GUIM_SETTINGS_UPDATED: { // Update cached list rect if (Message.value == "size" || Message.value == "absolute" || Message.value == "dropdown_size" || Message.value == "dropdown_buffer" || Message.value == "scrollbar_style" || Message.value == "button_width") { SetupListRect(); } break; } case GUIM_MOUSE_MOTION: { if (!m_Open) break; CPos mouse = GetMousePos(); if (!GetListRect().PointInside(mouse)) break; bool scrollbar; CGUIList* pList; GUI<bool>::GetSetting(this, "scrollbar", scrollbar); GUI<CGUIList>::GetSettingPointer(this, "list", pList); float scroll = 0.f; if (scrollbar) scroll = GetScrollBar(0).GetPos(); CRect rect = GetListRect(); mouse.y += scroll; int set = -1; for (int i = 0; i < (int)pList->m_Items.size(); ++i) { if (mouse.y >= rect.top + m_ItemsYPositions[i] && mouse.y < rect.top + m_ItemsYPositions[i+1] && // mouse is not over scroll-bar !(mouse.x >= GetScrollBar(0).GetOuterRect().left && mouse.x <= GetScrollBar(0).GetOuterRect().right)) { set = i; } } if (set != -1) { m_ElementHighlight = set; //UpdateAutoScroll(); } break; } case GUIM_MOUSE_ENTER: { bool enabled; GUI<bool>::GetSetting(this, "enabled", enabled); if (!enabled) break; CStrW soundPath; if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_enter", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); break; } case GUIM_MOUSE_LEAVE: { GUI<int>::GetSetting(this, "selected", m_ElementHighlight); bool enabled; GUI<bool>::GetSetting(this, "enabled", enabled); if (!enabled) break; CStrW soundPath; if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_leave", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); break; } // We can't inherent this routine from CList, because we need to include // a mouse click to open the dropdown, also the coordinates are changed. case GUIM_MOUSE_PRESS_LEFT: { bool enabled; GUI<bool>::GetSetting(this, "enabled", enabled); if (!enabled) { CStrW soundPath; if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_disabled", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); break; } if (!m_Open) { CGUIList* pList; GUI<CGUIList>::GetSettingPointer(this, "list", pList); if (pList->m_Items.empty()) return; m_Open = true; GetScrollBar(0).SetZ(GetBufferedZ()); GUI<int>::GetSetting(this, "selected", m_ElementHighlight); // Start at the position of the selected item, if possible. GetScrollBar(0).SetPos(m_ItemsYPositions.empty() ? 0 : m_ItemsYPositions[m_ElementHighlight] - 60); CStrW soundPath; if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_opened", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); return; // overshadow } else { CPos mouse = GetMousePos(); // If the regular area is pressed, then abort, and close. if (m_CachedActualSize.PointInside(mouse)) { m_Open = false; GetScrollBar(0).SetZ(GetBufferedZ()); CStrW soundPath; if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_closed", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); return; // overshadow } if (!(mouse.x >= GetScrollBar(0).GetOuterRect().left && mouse.x <= GetScrollBar(0).GetOuterRect().right) && mouse.y >= GetListRect().top) { m_Open = false; GetScrollBar(0).SetZ(GetBufferedZ()); } } break; } case GUIM_MOUSE_WHEEL_DOWN: { bool enabled; GUI<bool>::GetSetting(this, "enabled", enabled); // Don't switch elements by scrolling when open, causes a confusing interaction between this and the scrollbar. if (m_Open || !enabled) break; GUI<int>::GetSetting(this, "selected", m_ElementHighlight); if (m_ElementHighlight + 1 >= (int)m_ItemsYPositions.size() - 1) break; ++m_ElementHighlight; GUI<int>::SetSetting(this, "selected", m_ElementHighlight); break; } case GUIM_MOUSE_WHEEL_UP: { bool enabled; GUI<bool>::GetSetting(this, "enabled", enabled); // Don't switch elements by scrolling when open, causes a confusing interaction between this and the scrollbar. if (m_Open || !enabled) break; GUI<int>::GetSetting(this, "selected", m_ElementHighlight); if (m_ElementHighlight - 1 < 0) break; m_ElementHighlight--; GUI<int>::SetSetting(this, "selected", m_ElementHighlight); break; } case GUIM_LOST_FOCUS: { if (m_Open) { CStrW soundPath; if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_closed", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); } m_Open = false; break; } case GUIM_LOAD: SetupListRect(); break; default: break; } // Important that this is after, so that overshadowed implementations aren't processed CList::HandleMessage(Message); // As HandleMessage functions return void, we need to manually verify // whether the child list's items were modified. if (CList::GetModified()) SetupText(); }
void CList::SetupText() { if (!GetGUI()) return; m_Modified = true; CGUIList* pList; GUI<CGUIList>::GetSettingPointer(this, "list", pList); //ENSURE(m_GeneratedTexts.size()>=1); m_ItemsYPositions.resize(pList->m_Items.size()+1); // Delete all generated texts. Some could probably be saved, // but this is easier, and this function will never be called // continuously, or even often, so it'll probably be okay. for (SGUIText* const& t : m_GeneratedTexts) delete t; m_GeneratedTexts.clear(); CStrW font; if (GUI<CStrW>::GetSetting(this, "font", font) != PSRETURN_OK || font.empty()) // Use the default if none is specified // TODO Gee: (2004-08-14) Don't define standard like this. Do it with the default style. font = L"default"; bool scrollbar; GUI<bool>::GetSetting(this, "scrollbar", scrollbar); float width = GetListRect().GetWidth(); // remove scrollbar if applicable if (scrollbar && GetScrollBar(0).GetStyle()) width -= GetScrollBar(0).GetStyle()->m_Width; float buffer_zone = 0.f; GUI<float>::GetSetting(this, "buffer_zone", buffer_zone); // Generate texts float buffered_y = 0.f; for (size_t i = 0; i < pList->m_Items.size(); ++i) { // Create a new SGUIText. Later on, input it using AddText() SGUIText* text = new SGUIText(); *text = GetGUI()->GenerateText(pList->m_Items[i], font, width, buffer_zone, this); m_ItemsYPositions[i] = buffered_y; buffered_y += text->m_Size.cy; AddText(text); } m_ItemsYPositions[pList->m_Items.size()] = buffered_y; // Setup scrollbar if (scrollbar) { GetScrollBar(0).SetScrollRange(m_ItemsYPositions.back()); GetScrollBar(0).SetScrollSpace(GetListRect().GetHeight()); CRect rect = GetListRect(); GetScrollBar(0).SetX(rect.right); GetScrollBar(0).SetY(rect.top); GetScrollBar(0).SetZ(GetBufferedZ()); GetScrollBar(0).SetLength(rect.bottom - rect.top); } }
void CList::DrawList(const int& selected, const CStr& _sprite, const CStr& _sprite_selected, const CStr& _textcolor) { float bz = GetBufferedZ(); // First call draw on ScrollBarOwner bool scrollbar; GUI<bool>::GetSetting(this, "scrollbar", scrollbar); if (scrollbar) IGUIScrollBarOwner::Draw(); if (GetGUI()) { CRect rect = GetListRect(); CGUISpriteInstance* sprite = NULL; CGUISpriteInstance* sprite_selectarea = NULL; int cell_id; GUI<CGUISpriteInstance>::GetSettingPointer(this, _sprite, sprite); GUI<CGUISpriteInstance>::GetSettingPointer(this, _sprite_selected, sprite_selectarea); GUI<int>::GetSetting(this, "cell_id", cell_id); CGUIList* pList; GUI<CGUIList>::GetSettingPointer(this, "list", pList); GetGUI()->DrawSprite(*sprite, cell_id, bz, rect); float scroll = 0.f; if (scrollbar) scroll = GetScrollBar(0).GetPos(); if (selected != -1) { ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size()); // Get rectangle of selection: CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll); if (rect_sel.top <= rect.bottom && rect_sel.bottom >= rect.top) { if (rect_sel.bottom > rect.bottom) rect_sel.bottom = rect.bottom; if (rect_sel.top < rect.top) rect_sel.top = rect.top; if (scrollbar) { // Remove any overlapping area of the scrollbar. if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && rect_sel.right <= GetScrollBar(0).GetOuterRect().right) rect_sel.right = GetScrollBar(0).GetOuterRect().left; if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && rect_sel.left < GetScrollBar(0).GetOuterRect().right) rect_sel.left = GetScrollBar(0).GetOuterRect().right; } GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect_sel); } } CColor color; GUI<CColor>::GetSetting(this, _textcolor, color); for (size_t i = 0; i < pList->m_Items.size(); ++i) { if (m_ItemsYPositions[i+1] - scroll < 0 || m_ItemsYPositions[i] - scroll > rect.GetHeight()) continue; // Clipping area (we'll have to substract the scrollbar) CRect cliparea = GetListRect(); if (scrollbar) { if (cliparea.right > GetScrollBar(0).GetOuterRect().left && cliparea.right <= GetScrollBar(0).GetOuterRect().right) cliparea.right = GetScrollBar(0).GetOuterRect().left; if (cliparea.left >= GetScrollBar(0).GetOuterRect().left && cliparea.left < GetScrollBar(0).GetOuterRect().right) cliparea.left = GetScrollBar(0).GetOuterRect().right; } DrawText(i, color, rect.TopLeft() - CPos(0.f, scroll - m_ItemsYPositions[i]), bz+0.1f, cliparea); } } }
void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if(!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if(!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) static double last_time; const double cur_time = timer_Time(); if(cur_time - last_time > 0.5) { last_time = cur_time; if(m_TerrainDirty) RebuildTerrainTexture(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); CMatrix3D matrix = GetDefaultGuiMatrix(); glLoadMatrixf(&matrix._11); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture glDepthMask(0); const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); // Draw the main textured quad g_Renderer.BindTexture(0, m_TerrainTexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); DrawTexture(texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); territoryTexture.BindTexture(0); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); losTexture.BindTexture(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor3f(0.0f, 0.0f, 0.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(losTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Set up the matrix for drawing points and lines glPushMatrix(); glTranslatef(x, y, z); // Rotate around the center of the map glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f); // Scale square maps to fit in circular minimap area float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); glScalef(unitScale, unitScale, 1.f); glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f); glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f); PROFILE_START("minimap units"); // Don't enable GL_POINT_SMOOTH because it's far too slow // (~70msec/frame on a GF4 rendering a thousand points) glPointSize(3.f); float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); std::vector<MinimapUnitVertex> vertexArray; vertexArray.reserve(ents.size()); for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { MinimapUnitVertex v; ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); entity_pos_t posX, posZ; if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; vertexArray.push_back(v); } } } if (!vertexArray.empty()) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size()); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); } PROFILE_END("minimap units"); DrawViewRect(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); // Reset everything back to normal glPointSize(1.0f); glEnable(GL_TEXTURE_2D); glDepthMask(1); }
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture // most of the time, updating the framebuffer twice a frame. // Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling // (those operations cause a gpu sync, which slows down the way gpu works) void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if(!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if(!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) // TODO: store frequency in a config file? static double last_time; const double cur_time = timer_Time(); const bool doUpdate = cur_time - last_time > 0.5; if(doUpdate) { last_time = cur_time; if(m_TerrainDirty) RebuildTerrainTexture(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); CMatrix3D matrix = GetDefaultGuiMatrix(); glLoadMatrixf(&matrix._11); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture glDepthMask(0); CShaderProgramPtr shader; CShaderTechniquePtr tech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { CShaderDefines defines; defines.Add(str_MINIMAP_BASE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); // Draw the main textured quad if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture(str_baseTex, m_TerrainTexture); else g_Renderer.BindTexture(0, m_TerrainTexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); else territoryTexture.BindTexture(0); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_LOS, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); shader->BindTexture(str_baseTex, losTexture.GetTexture()); } else { losTexture.BindTexture(0); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor3f(0.0f, 0.0f, 0.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(losTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_POINT, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } // Set up the matrix for drawing points and lines glPushMatrix(); glTranslatef(x, y, z); // Rotate around the center of the map glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f); // Scale square maps to fit in circular minimap area float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); glScalef(unitScale, unitScale, 1.f); glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f); glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f); PROFILE_START("minimap units"); const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); if (doUpdate) { VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>(); VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>(); m_EntitiesDrawn = 0; MinimapUnitVertex v; std::vector<MinimapUnitVertex> pingingVertices; pingingVertices.reserve(MAX_ENTITIES_DRAWN/2); const double time = timer_Time(); if (time > m_NextBlinkTime) { m_BlinkState = !m_BlinkState; m_NextBlinkTime = time + m_HalfBlinkDuration; } entity_pos_t posX, posZ; for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; // Check minimap pinging to indicate something if (m_BlinkState && cmpMinimap->CheckPing(time, m_PingDuration)) { v.r = 255; // ping color is white v.g = 255; v.b = 255; pingingVertices.push_back(v); } else { addVertex(v, attrColor, attrPos); ++m_EntitiesDrawn; } } } } // Add the pinged vertices at the end, so they are drawn on top for (size_t v = 0; v < pingingVertices.size(); ++v) { addVertex(pingingVertices[v], attrColor, attrPos); ++m_EntitiesDrawn; } ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); m_VertexArray.Upload(); } if (m_EntitiesDrawn > 0) { // Don't enable GL_POINT_SMOOTH because it's far too slow // (~70msec/frame on a GF4 rendering a thousand points) glPointSize(3.f); u8* indexBase = m_IndexArray.Bind(); u8* base = m_VertexArray.Bind(); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); } else { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glDisable(GL_TEXTURE_2D); glVertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); glColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); } if (!g_Renderer.m_SkipSubmit) { glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); } g_Renderer.GetStats().m_DrawCalls++; CVertexBuffer::Unbind(); } PROFILE_END("minimap units"); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_LINE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } else { glEnable(GL_TEXTURE_2D); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } DrawViewRect(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); } // Reset everything back to normal glPointSize(1.0f); glEnable(GL_TEXTURE_2D); glDepthMask(1); }
void CDropDown::Draw() { if (!GetGUI()) return; float bz = GetBufferedZ(); float dropdown_size, button_width; GUI<float>::GetSetting(this, "dropdown_size", dropdown_size); GUI<float>::GetSetting(this, "button_width", button_width); CGUISpriteInstance *sprite, *sprite2, *sprite2_second; int cell_id, selected=0; CColor color; GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite", sprite); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2", sprite2); GUI<int>::GetSetting(this, "cell_id", cell_id); GUI<int>::GetSetting(this, "selected", selected); GUI<CColor>::GetSetting(this, "textcolor", color); bool enabled; GUI<bool>::GetSetting(this, "enabled", enabled); GetGUI()->DrawSprite(*sprite, cell_id, bz, m_CachedActualSize); if (button_width > 0.f) { CRect rect(m_CachedActualSize.right-button_width, m_CachedActualSize.top, m_CachedActualSize.right, m_CachedActualSize.bottom); if (!enabled) { GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_disabled", sprite2_second); GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect); } else if (m_Open) { GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_pressed", sprite2_second); GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect); } else if (m_MouseHovering) { GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_over", sprite2_second); GetGUI()->DrawSprite(GUI<>::FallBackSprite(*sprite2_second, *sprite2), cell_id, bz+0.05f, rect); } else GetGUI()->DrawSprite(*sprite2, cell_id, bz+0.05f, rect); } if (selected != -1) // TODO: Maybe check validity completely? { // figure out clipping rectangle CRect cliparea(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right-button_width, m_CachedActualSize.bottom); CPos pos(m_CachedActualSize.left, m_CachedActualSize.top); DrawText(selected, color, pos, bz+0.1f, cliparea); } bool *scrollbar=NULL, old; GUI<bool>::GetSettingPointer(this, "scrollbar", scrollbar); old = *scrollbar; if (m_Open) { if (m_HideScrollBar) *scrollbar = false; DrawList(m_ElementHighlight, "sprite_list", "sprite_selectarea", "textcolor"); if (m_HideScrollBar) *scrollbar = old; } }
void CChart::Draw() { PROFILE3("render chart"); if (!GetGUI()) return; if (m_Series.empty()) return; const float bz = GetBufferedZ(); CRect rect = GetChartRect(); const float width = rect.GetWidth(); const float height = rect.GetHeight(); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture. glDepthMask(0); // Setup the render state CMatrix3D transform = GetDefaultGuiMatrix(); CShaderDefines lineDefines; CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->Uniform(str_transform, transform); CVector2D leftBottom, rightTop; leftBottom = rightTop = m_Series[0].m_Points[0]; for (const CChartData& data : m_Series) for (const CVector2D& point : data.m_Points) { if (point.X < leftBottom.X) leftBottom.X = point.X; if (point.Y < leftBottom.Y) leftBottom.Y = point.Y; if (point.X > rightTop.X) rightTop.X = point.X; if (point.Y > rightTop.Y) rightTop.Y = point.Y; } CVector2D scale(width / (rightTop.X - leftBottom.X), height / (rightTop.Y - leftBottom.Y)); for (const CChartData& data : m_Series) { if (data.m_Points.empty()) continue; std::vector<float> vertices; vertices.reserve(data.m_Points.size() * 3); for (const CVector2D& point : data.m_Points) { vertices.push_back(rect.left + (point.X - leftBottom.X) * scale.X); vertices.push_back(rect.bottom - (point.Y - leftBottom.Y) * scale.Y); vertices.push_back(bz + 0.5f); } shader->Uniform(str_color, data.m_Color); shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); shader->AssertPointersBound(); glEnable(GL_LINE_SMOOTH); glLineWidth(1.1f); if (!g_Renderer.m_SkipSubmit) glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); glLineWidth(1.0f); glDisable(GL_LINE_SMOOTH); } tech->EndPass(); // Reset depth mask glDepthMask(1); }
void CCheckBox::Draw() { ////////// Gee: janwas, this is just temp to see it glDisable(GL_TEXTURE_2D); ////////// float square_side, buffer_zone; CStrW font_name; bool checked; int cell_id; GUI<float>::GetSetting(this, "square_side", square_side); GUI<float>::GetSetting(this, "buffer_zone", buffer_zone); GUI<CStrW>::GetSetting(this, "font", font_name); GUI<bool>::GetSetting(this, "checked", checked); GUI<int>::GetSetting(this, "cell_id", cell_id); // Get line height CFont font (font_name); float line_height = (float)font.GetHeight(); float bz = GetBufferedZ(); // Get square CRect rect; rect.left = m_CachedActualSize.left; rect.right = rect.left + square_side; if (square_side >= line_height) rect.top = m_CachedActualSize.top; else rect.top = m_CachedActualSize.top + line_height/2.f - square_side/2.f; rect.bottom = rect.top + square_side; CGUISpriteInstance *sprite, *sprite_over, *sprite_pressed, *sprite_disabled; if (checked) { GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2", sprite); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_over", sprite_over); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_pressed", sprite_pressed); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite2_disabled", sprite_disabled); } else { GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite", sprite); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_over", sprite_over); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_pressed", sprite_pressed); GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_disabled", sprite_disabled); } DrawButton(rect, bz, *sprite, *sprite_over, *sprite_pressed, *sprite_disabled, cell_id); CColor color = ChooseColor(); CPos text_pos(m_CachedActualSize.left + square_side + buffer_zone, m_CachedActualSize.top); if (square_side > line_height) text_pos.y += square_side/2.f - line_height/2.f; IGUITextOwner::Draw(0, color, text_pos, bz+0.1f, m_CachedActualSize); }
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture // most of the time, updating the framebuffer twice a frame. // Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling // (those operations cause a gpu sync, which slows down the way gpu works) void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if (!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if (!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) // TODO: Update all but camera at same speed as simulation static double last_time; const double cur_time = timer_Time(); const bool doUpdate = cur_time - last_time > 0.5; if (doUpdate) { last_time = cur_time; if (m_TerrainDirty) RebuildTerrainTexture(); } const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture. glDepthMask(0); CShaderProgramPtr shader; CShaderTechniquePtr tech; CShaderDefines baseDefines; baseDefines.Add(str_MINIMAP_BASE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines); tech->BeginPass(); shader = tech->GetShader(); // Draw the main textured quad shader->BindTexture(str_baseTex, m_TerrainTexture); const CMatrix3D baseTransform = GetDefaultGuiMatrix(); CMatrix3D baseTextureTransform; baseTextureTransform.SetIdentity(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, baseTextureTransform); DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries glEnable(GL_BLEND); CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, *territoryTransform); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); tech->EndPass(); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); CShaderDefines losDefines; losDefines.Add(str_MINIMAP_LOS, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines); tech->BeginPass(); shader = tech->GetShader(); shader->BindTexture(str_baseTex, losTexture.GetTexture()); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_textureTransform, *losTransform); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); tech->EndPass(); glDisable(GL_BLEND); PROFILE_START("minimap units"); CShaderDefines pointDefines; pointDefines.Add(str_MINIMAP_POINT, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines); tech->BeginPass(); shader = tech->GetShader(); shader->Uniform(str_transform, baseTransform); shader->Uniform(str_pointSize, 3.f); CMatrix3D unitMatrix; unitMatrix.SetIdentity(); // Center the minimap on the origin of the axis of rotation. unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f); // Rotate the map. unitMatrix.RotateZ(angle); // Scale square maps to fit. unitMatrix.Scale(unitScale, unitScale, 1.f); // Move the minimap back to it's starting position. unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f); // Move the minimap to it's final location. unitMatrix.Translate(x, y, z); // Apply the gui matrix. unitMatrix *= GetDefaultGuiMatrix(); // Load the transform into the shader. shader->Uniform(str_transform, unitMatrix); const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); if (doUpdate) { VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>(); VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>(); m_EntitiesDrawn = 0; MinimapUnitVertex v; std::vector<MinimapUnitVertex> pingingVertices; pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2); if (cur_time > m_NextBlinkTime) { m_BlinkState = !m_BlinkState; m_NextBlinkTime = cur_time + m_HalfBlinkDuration; } entity_pos_t posX, posZ; for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat() * sx; v.y = -posZ.ToFloat() * sy; // Check minimap pinging to indicate something if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration)) { v.r = 255; // ping color is white v.g = 255; v.b = 255; pingingVertices.push_back(v); } else { addVertex(v, attrColor, attrPos); ++m_EntitiesDrawn; } } } } // Add the pinged vertices at the end, so they are drawn on top for (size_t v = 0; v < pingingVertices.size(); ++v) { addVertex(pingingVertices[v], attrColor, attrPos); ++m_EntitiesDrawn; } ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); m_VertexArray.Upload(); } m_VertexArray.PrepareForRendering(); if (m_EntitiesDrawn > 0) { #if !CONFIG2_GLES if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif u8* indexBase = m_IndexArray.Bind(); u8* base = m_VertexArray.Bind(); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); if (!g_Renderer.m_SkipSubmit) glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); g_Renderer.GetStats().m_DrawCalls++; CVertexBuffer::Unbind(); #if !CONFIG2_GLES if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif } tech->EndPass(); DrawViewRect(unitMatrix); PROFILE_END("minimap units"); // Reset depth mask glDepthMask(1); }