add UiSlider and some fix
This commit is contained in:
parent
bee2fff538
commit
d57112be35
187
Game.cpp
187
Game.cpp
@ -167,31 +167,37 @@ namespace ZL
|
||||
|
||||
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
|
||||
std::cerr << "Play button pressed: " << name << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("exitButton", [](const std::string& name) {
|
||||
Environment::exitGameLoop = true;
|
||||
});
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("settingsButton", [this](const std::string& name) {
|
||||
if (uiManager.pushMenuFromFile("../config/settings.json", this->renderer, CONST_ZIP_FILE)) {
|
||||
|
||||
uiManager.setButtonCallback("Opt1", [this](const std::string& n) {
|
||||
std::cerr << "Opt1 pressed: " << n << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("Opt2", [this](const std::string& n) {
|
||||
std::cerr << "Opt2 pressed: " << n << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("backButton", [this](const std::string& n) {
|
||||
uiManager.popMenu();
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
std::cerr << "Failed to open settings menu" << std::endl;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
uiManager.setSliderCallback("musicVolumeSlider", [this](const std::string& name, float value) {
|
||||
std::cerr << "Music volume slider changed to: " << value << std::endl;
|
||||
musicVolume = value;
|
||||
Environment::shipVelocity = musicVolume * 20.0f;
|
||||
});
|
||||
|
||||
cubemapTexture = std::make_shared<Texture>(
|
||||
std::array<TextureDataStruct, 6>{
|
||||
@ -237,62 +243,62 @@ namespace ZL
|
||||
}
|
||||
|
||||
|
||||
/* buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
|
||||
/* buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
|
||||
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 100, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 100, 0 });
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 100, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 100, 0 });
|
||||
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 0,1 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 1,0 });
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 0,1 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
button.RefreshVBO();*/
|
||||
button.RefreshVBO();*/
|
||||
/*
|
||||
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
|
||||
|
||||
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
|
||||
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
musicVolumeBar.RefreshVBO();
|
||||
musicVolumeBar.RefreshVBO();
|
||||
|
||||
|
||||
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
|
||||
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
|
||||
|
||||
float musicVolumeBarButtonButtonCenterY = 350.0f;
|
||||
float musicVolumeBarButtonButtonCenterY = 350.0f;
|
||||
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
musicVolumeBarButton.RefreshVBO();
|
||||
musicVolumeBarButton.RefreshVBO();*/
|
||||
renderer.InitOpenGL();
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
@ -412,7 +418,7 @@ namespace ZL
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
void Game::UpdateVolumeKnob() {
|
||||
/*void Game::UpdateVolumeKnob() {
|
||||
float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY);
|
||||
|
||||
auto& pos = musicVolumeBarButton.data.PositionData;
|
||||
@ -427,7 +433,6 @@ namespace ZL
|
||||
musicVolumeBarButton.RefreshVBO();
|
||||
|
||||
}
|
||||
|
||||
void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) {
|
||||
|
||||
int uiX = mouseX;
|
||||
@ -443,7 +448,8 @@ namespace ZL
|
||||
if (t > 1.0f) t = 1.0f;
|
||||
musicVolume = t;
|
||||
UpdateVolumeKnob();
|
||||
}
|
||||
}*/
|
||||
|
||||
void Game::drawUI()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
@ -452,7 +458,6 @@ namespace ZL
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
@ -460,22 +465,24 @@ namespace ZL
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
|
||||
renderer.PushMatrix();
|
||||
//renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
|
||||
//renderer.PushMatrix();
|
||||
|
||||
renderer.LoadIdentity();
|
||||
//renderer.LoadIdentity();
|
||||
|
||||
//glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID());
|
||||
//renderer.DrawVertexRenderStruct(button);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(musicVolumeBar);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(musicVolumeBarButton);
|
||||
//glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
|
||||
//renderer.DrawVertexRenderStruct(musicVolumeBar);
|
||||
|
||||
//glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
|
||||
//renderer.DrawVertexRenderStruct(musicVolumeBarButton);
|
||||
|
||||
//renderer.PopMatrix();
|
||||
//renderer.PopProjectionMatrix();
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
uiManager.draw(renderer);
|
||||
@ -602,36 +609,39 @@ namespace ZL
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
Environment::exitGameLoop = true;
|
||||
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
// 1. Îáðàáîòêà íàæàòèÿ êíîïêè ìûøè
|
||||
|
||||
int mx = event.button.x;
|
||||
int my = event.button.y;
|
||||
|
||||
std::cout << mx << " " << my << '\n';
|
||||
int uiX = mx;
|
||||
int uiY = Environment::height - my;
|
||||
|
||||
uiManager.onMouseMove(uiX, uiY);
|
||||
uiManager.onMouseDown(uiX, uiY);
|
||||
|
||||
if (uiX >= volumeBarMinX - 40 && uiX <= volumeBarMaxX + 40 &&
|
||||
uiY >= volumeBarMinY - 40 && uiY <= volumeBarMaxY + 40) {
|
||||
isDraggingVolume = true;
|
||||
UpdateVolumeFromMouse(mx, my);
|
||||
}
|
||||
else {
|
||||
Environment::tapDownHold = true;
|
||||
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
|
||||
Environment::tapDownStartPos.v[0] = event.button.x;
|
||||
Environment::tapDownStartPos.v[1] = event.button.y;
|
||||
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
|
||||
Environment::tapDownCurrentPos.v[0] = event.button.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.button.y;
|
||||
bool uiHandled = false;
|
||||
|
||||
for (const auto& button : uiManager.findButton("") ? std::vector<std::shared_ptr<UiButton>>{} : std::vector<std::shared_ptr<UiButton>>{}) {
|
||||
(void)button;
|
||||
}
|
||||
|
||||
auto pressedSlider = [&]() -> std::shared_ptr<UiSlider> {
|
||||
for (const auto& slider : uiManager.findSlider("") ? std::vector<std::shared_ptr<UiSlider>>{} : std::vector<std::shared_ptr<UiSlider>>{}) {
|
||||
(void)slider;
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
if (!uiManager.isUiInteraction()) {
|
||||
Environment::tapDownHold = true;
|
||||
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
|
||||
Environment::tapDownStartPos.v[0] = mx;
|
||||
Environment::tapDownStartPos.v[1] = my;
|
||||
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
|
||||
Environment::tapDownCurrentPos.v[0] = mx;
|
||||
Environment::tapDownCurrentPos.v[1] = my;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONUP) {
|
||||
// 2. Îáðàáîòêà îòïóñêàíèÿ êíîïêè ìûøè
|
||||
@ -642,27 +652,22 @@ namespace ZL
|
||||
|
||||
uiManager.onMouseUp(uiX, uiY);
|
||||
|
||||
isDraggingVolume = false;
|
||||
Environment::tapDownHold = false;
|
||||
if (!uiManager.isUiInteraction()) {
|
||||
Environment::tapDownHold = false;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_MOUSEMOTION) {
|
||||
// 3. Îáðàáîòêà ïåðåìåùåíèÿ ìûøè
|
||||
int mx = event.motion.x;
|
||||
int my = event.motion.y;
|
||||
|
||||
int uiX = mx;
|
||||
int uiY = Environment::height - my;
|
||||
|
||||
uiManager.onMouseMove(uiX, uiY);
|
||||
|
||||
if (isDraggingVolume) {
|
||||
// Äâèãàåì ìûøü ïî ñëàéäåðó — ìåíÿåì ãðîìêîñòü è ïîçèöèþ êðóæêà
|
||||
UpdateVolumeFromMouse(mx, my);
|
||||
}
|
||||
if (Environment::tapDownHold) {
|
||||
// Îáíîâëåíèå òåêóùåé ïîçèöèè, åñëè êíîïêà óäåðæèâàåòñÿ
|
||||
Environment::tapDownCurrentPos.v[0] = event.motion.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.motion.y;
|
||||
if (Environment::tapDownHold && !uiManager.isUiInteraction()) {
|
||||
Environment::tapDownCurrentPos.v[0] = mx;
|
||||
Environment::tapDownCurrentPos.v[1] = my;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_MOUSEWHEEL) {
|
||||
|
||||
24
Game.h
24
Game.h
@ -50,26 +50,28 @@ namespace ZL {
|
||||
std::vector<VertexRenderStruct> boxRenderArr;
|
||||
|
||||
|
||||
std::shared_ptr<Texture> buttonTexture;
|
||||
VertexRenderStruct button;
|
||||
//std::shared_ptr<Texture> buttonTexture;
|
||||
//VertexRenderStruct button;
|
||||
|
||||
std::shared_ptr<Texture> musicVolumeBarTexture;
|
||||
VertexRenderStruct musicVolumeBar;
|
||||
//std::shared_ptr<Texture> musicVolumeBarTexture;
|
||||
//VertexRenderStruct musicVolumeBar;
|
||||
|
||||
std::shared_ptr<Texture> musicVolumeBarButtonTexture;
|
||||
VertexRenderStruct musicVolumeBarButton;
|
||||
//std::shared_ptr<Texture> musicVolumeBarButtonTexture;
|
||||
//VertexRenderStruct musicVolumeBarButton;
|
||||
|
||||
|
||||
bool isDraggingVolume = false;
|
||||
//bool isDraggingVolume = false;
|
||||
|
||||
float musicVolume = 0.0f;
|
||||
float volumeBarMinX = 1190.0f;
|
||||
float volumeBarMaxX = 1200.0f;
|
||||
float volumeBarMinY = 100.0f;
|
||||
float volumeBarMaxY = 600.0f;
|
||||
float musicVolumeBarButtonButtonCenterX = 1195.0f;
|
||||
float musicVolumeBarButtonButtonRadius = 25.0f;
|
||||
void UpdateVolumeFromMouse(int mouseX, int mouseY);
|
||||
void UpdateVolumeKnob();
|
||||
//float musicVolumeBarButtonButtonCenterX = 1195.0f;
|
||||
//float musicVolumeBarButtonButtonRadius = 25.0f;
|
||||
//void UpdateVolumeFromMouse(int mouseX, int mouseY);
|
||||
//void UpdateVolumeKnob();
|
||||
|
||||
|
||||
static const size_t CONST_TIMER_INTERVAL = 10;
|
||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
||||
|
||||
248
UiManager.cpp
248
UiManager.cpp
@ -63,7 +63,94 @@ namespace ZL {
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
}
|
||||
|
||||
// UiManager implementation
|
||||
void UiSlider::buildTrackMesh() {
|
||||
trackMesh.data.PositionData.clear();
|
||||
trackMesh.data.TexCoordData.clear();
|
||||
|
||||
float x0 = rect.x;
|
||||
float y0 = rect.y;
|
||||
float x1 = rect.x + rect.w;
|
||||
float y1 = rect.y + rect.h;
|
||||
|
||||
trackMesh.data.PositionData.push_back({ x0, y0, 0 });
|
||||
trackMesh.data.TexCoordData.push_back({ 0, 0 });
|
||||
|
||||
trackMesh.data.PositionData.push_back({ x0, y1, 0 });
|
||||
trackMesh.data.TexCoordData.push_back({ 0, 1 });
|
||||
|
||||
trackMesh.data.PositionData.push_back({ x1, y1, 0 });
|
||||
trackMesh.data.TexCoordData.push_back({ 1, 1 });
|
||||
|
||||
trackMesh.data.PositionData.push_back({ x0, y0, 0 });
|
||||
trackMesh.data.TexCoordData.push_back({ 0, 0 });
|
||||
|
||||
trackMesh.data.PositionData.push_back({ x1, y1, 0 });
|
||||
trackMesh.data.TexCoordData.push_back({ 1, 1 });
|
||||
|
||||
trackMesh.data.PositionData.push_back({ x1, y0, 0 });
|
||||
trackMesh.data.TexCoordData.push_back({ 1, 0 });
|
||||
|
||||
trackMesh.RefreshVBO();
|
||||
}
|
||||
|
||||
void UiSlider::buildKnobMesh() {
|
||||
knobMesh.data.PositionData.clear();
|
||||
knobMesh.data.TexCoordData.clear();
|
||||
|
||||
float kw = vertical ? rect.w * 4.0f : rect.w * 0.5f;
|
||||
float kh = vertical ? rect.w * 4.0f : rect.h * 0.5f;
|
||||
|
||||
float cx = rect.x + rect.w * 0.5f;
|
||||
float cy = rect.y + (vertical ? (value * rect.h) : (rect.h * 0.5f));
|
||||
|
||||
float x0 = cx - kw * 0.5f;
|
||||
float y0 = cy - kh * 0.5f;
|
||||
float x1 = cx + kw * 0.5f;
|
||||
float y1 = cy + kh * 0.5f;
|
||||
|
||||
knobMesh.data.PositionData.push_back({ x0, y0, 0 });
|
||||
knobMesh.data.TexCoordData.push_back({ 0, 0 });
|
||||
|
||||
knobMesh.data.PositionData.push_back({ x0, y1, 0 });
|
||||
knobMesh.data.TexCoordData.push_back({ 0, 1 });
|
||||
|
||||
knobMesh.data.PositionData.push_back({ x1, y1, 0 });
|
||||
knobMesh.data.TexCoordData.push_back({ 1, 1 });
|
||||
|
||||
knobMesh.data.PositionData.push_back({ x0, y0, 0 });
|
||||
knobMesh.data.TexCoordData.push_back({ 0, 0 });
|
||||
|
||||
knobMesh.data.PositionData.push_back({ x1, y1, 0 });
|
||||
knobMesh.data.TexCoordData.push_back({ 1, 1 });
|
||||
|
||||
knobMesh.data.PositionData.push_back({ x1, y0, 0 });
|
||||
knobMesh.data.TexCoordData.push_back({ 1, 0 });
|
||||
|
||||
knobMesh.RefreshVBO();
|
||||
}
|
||||
|
||||
void UiSlider::draw(Renderer& renderer) const {
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
if (texTrack) {
|
||||
glBindTexture(GL_TEXTURE_2D, texTrack->getTexID());
|
||||
renderer.DrawVertexRenderStruct(trackMesh);
|
||||
}
|
||||
if (texKnob) {
|
||||
glBindTexture(GL_TEXTURE_2D, texKnob->getTexID());
|
||||
renderer.DrawVertexRenderStruct(knobMesh);
|
||||
}
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
}
|
||||
|
||||
void UiManager::loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile) {
|
||||
std::ifstream in(path);
|
||||
if (!in.is_open()) {
|
||||
@ -88,11 +175,16 @@ namespace ZL {
|
||||
root = parseNode(j["root"], renderer, zipFile);
|
||||
layoutNode(root);
|
||||
buttons.clear();
|
||||
collectButtons(root);
|
||||
sliders.clear();
|
||||
collectButtonsAndSliders(root);
|
||||
|
||||
for (auto& b : buttons) {
|
||||
b->buildMesh();
|
||||
}
|
||||
for (auto& s : sliders) {
|
||||
s->buildTrackMesh();
|
||||
s->buildKnobMesh();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<UiNode> UiManager::parseNode(const json& j, Renderer& renderer, const std::string& zipFile) {
|
||||
@ -137,8 +229,42 @@ namespace ZL {
|
||||
|
||||
node->button = btn;
|
||||
}
|
||||
else if (node->type == "Slider") {
|
||||
auto s = std::make_shared<UiSlider>();
|
||||
s->name = node->name;
|
||||
s->rect = node->rect;
|
||||
|
||||
if (!j.contains("textures") || !j["textures"].is_object()) {
|
||||
std::cerr << "UiManager: Slider '" << s->name << "' missing textures" << std::endl;
|
||||
throw std::runtime_error("UI slider textures missing");
|
||||
}
|
||||
auto t = j["textures"];
|
||||
auto loadTex = [&](const std::string& key)->std::shared_ptr<Texture> {
|
||||
if (!t.contains(key) || !t[key].is_string()) return nullptr;
|
||||
std::string path = t[key].get<std::string>();
|
||||
try {
|
||||
auto data = CreateTextureDataFromPng(path.c_str(), zipFile.c_str());
|
||||
return std::make_shared<Texture>(data);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "UiManager: failed load texture " << path << " : " << e.what() << std::endl;
|
||||
throw std::runtime_error("UI texture load failed: " + path);
|
||||
}
|
||||
};
|
||||
|
||||
s->texTrack = loadTex("track");
|
||||
s->texKnob = loadTex("knob");
|
||||
|
||||
if (j.contains("value")) s->value = j["value"].get<float>();
|
||||
if (j.contains("orientation")) {
|
||||
std::string orient = j["orientation"].get<std::string>();
|
||||
std::transform(orient.begin(), orient.end(), orient.begin(), ::tolower);
|
||||
s->vertical = (orient != "horizontal");
|
||||
}
|
||||
|
||||
node->slider = s;
|
||||
}
|
||||
|
||||
// parse children
|
||||
if (j.contains("children") && j["children"].is_array()) {
|
||||
for (const auto& ch : j["children"]) {
|
||||
node->children.push_back(parseNode(ch, renderer, zipFile));
|
||||
@ -181,11 +307,14 @@ namespace ZL {
|
||||
}
|
||||
}
|
||||
|
||||
void UiManager::collectButtons(const std::shared_ptr<UiNode>& node) {
|
||||
void UiManager::collectButtonsAndSliders(const std::shared_ptr<UiNode>& node) {
|
||||
if (node->button) {
|
||||
buttons.push_back(node->button);
|
||||
}
|
||||
for (auto& c : node->children) collectButtons(c);
|
||||
if (node->slider) {
|
||||
sliders.push_back(node->slider);
|
||||
}
|
||||
for (auto& c : node->children) collectButtonsAndSliders(c);
|
||||
}
|
||||
|
||||
bool UiManager::setButtonCallback(const std::string& name, std::function<void(const std::string&)> cb) {
|
||||
@ -198,11 +327,70 @@ namespace ZL {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UiManager::addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
|
||||
const std::string& trackPath, const std::string& knobPath, float initialValue, bool vertical) {
|
||||
|
||||
auto s = std::make_shared<UiSlider>();
|
||||
s->name = name;
|
||||
s->rect = rect;
|
||||
s->value = std::clamp(initialValue, 0.0f, 1.0f);
|
||||
s->vertical = vertical;
|
||||
|
||||
try {
|
||||
if (!trackPath.empty()) {
|
||||
auto data = CreateTextureDataFromPng(trackPath.c_str(), zipFile.c_str());
|
||||
s->texTrack = std::make_shared<Texture>(data);
|
||||
}
|
||||
if (!knobPath.empty()) {
|
||||
auto data = CreateTextureDataFromPng(knobPath.c_str(), zipFile.c_str());
|
||||
s->texKnob = std::make_shared<Texture>(data);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "UiManager: addSlider failed to load textures: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
s->buildTrackMesh();
|
||||
s->buildKnobMesh();
|
||||
|
||||
sliders.push_back(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<UiSlider> UiManager::findSlider(const std::string& name) {
|
||||
for (auto& s : sliders) if (s->name == name) return s;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UiManager::setSliderCallback(const std::string& name, std::function<void(const std::string&, float)> cb) {
|
||||
auto s = findSlider(name);
|
||||
if (!s) {
|
||||
std::cerr << "UiManager: setSliderCallback failed, slider not found: " << name << std::endl;
|
||||
return false;
|
||||
}
|
||||
s->onValueChanged = std::move(cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UiManager::setSliderValue(const std::string& name, float value) {
|
||||
auto s = findSlider(name);
|
||||
if (!s) return false;
|
||||
value = std::clamp(value, 0.0f, 1.0f);
|
||||
if (fabs(s->value - value) < 1e-6f) return true;
|
||||
s->value = value;
|
||||
s->buildKnobMesh();
|
||||
if (s->onValueChanged) s->onValueChanged(s->name, s->value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UiManager::pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile) {
|
||||
MenuState prev;
|
||||
prev.root = root;
|
||||
prev.buttons = buttons;
|
||||
prev.sliders = sliders;
|
||||
prev.pressedButton = pressedButton;
|
||||
prev.pressedSlider = pressedSlider;
|
||||
prev.path = "";
|
||||
|
||||
try {
|
||||
@ -226,11 +414,16 @@ namespace ZL {
|
||||
|
||||
root = s.root;
|
||||
buttons = s.buttons;
|
||||
sliders = s.sliders;
|
||||
pressedButton = s.pressedButton;
|
||||
pressedSlider = s.pressedSlider;
|
||||
|
||||
for (auto& b : buttons) {
|
||||
if (b) b->buildMesh();
|
||||
}
|
||||
for (auto& sl : sliders) {
|
||||
if (sl) { sl->buildTrackMesh(); sl->buildKnobMesh(); }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -240,8 +433,6 @@ namespace ZL {
|
||||
}
|
||||
|
||||
void UiManager::draw(Renderer& renderer) {
|
||||
if (!root) return;
|
||||
|
||||
renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
@ -249,6 +440,9 @@ namespace ZL {
|
||||
for (const auto& b : buttons) {
|
||||
b->draw(renderer);
|
||||
}
|
||||
for (const auto& s : sliders) {
|
||||
s->draw(renderer);
|
||||
}
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
@ -263,6 +457,22 @@ namespace ZL {
|
||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Normal;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressedSlider) {
|
||||
auto s = pressedSlider;
|
||||
float t;
|
||||
if (s->vertical) {
|
||||
t = (y - s->rect.y) / s->rect.h;
|
||||
}
|
||||
else {
|
||||
t = (x - s->rect.x) / s->rect.w;
|
||||
}
|
||||
if (t < 0.0f) t = 0.0f;
|
||||
if (t > 1.0f) t = 1.0f;
|
||||
s->value = t;
|
||||
s->buildKnobMesh();
|
||||
if (s->onValueChanged) s->onValueChanged(s->name, s->value);
|
||||
}
|
||||
}
|
||||
|
||||
void UiManager::onMouseDown(int x, int y) {
|
||||
@ -271,8 +481,24 @@ namespace ZL {
|
||||
b->state = ButtonState::Pressed;
|
||||
pressedButton = b;
|
||||
}
|
||||
else {
|
||||
// leave others
|
||||
}
|
||||
|
||||
for (auto& s : sliders) {
|
||||
if (s->rect.contains((float)x, (float)y)) {
|
||||
pressedSlider = s;
|
||||
float t;
|
||||
if (s->vertical) {
|
||||
t = (y - s->rect.y) / s->rect.h;
|
||||
}
|
||||
else {
|
||||
t = (x - s->rect.x) / s->rect.w;
|
||||
}
|
||||
if (t < 0.0f) t = 0.0f;
|
||||
if (t > 1.0f) t = 1.0f;
|
||||
s->value = t;
|
||||
s->buildKnobMesh();
|
||||
if (s->onValueChanged) s->onValueChanged(s->name, s->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,6 +516,10 @@ namespace ZL {
|
||||
}
|
||||
}
|
||||
pressedButton.reset();
|
||||
|
||||
if (pressedSlider) {
|
||||
pressedSlider.reset();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<UiButton> UiManager::findButton(const std::string& name) {
|
||||
|
||||
37
UiManager.h
37
UiManager.h
@ -45,12 +45,32 @@ namespace ZL {
|
||||
void draw(Renderer& renderer) const;
|
||||
};
|
||||
|
||||
struct UiSlider {
|
||||
std::string name;
|
||||
UiRect rect;
|
||||
std::shared_ptr<Texture> texTrack;
|
||||
std::shared_ptr<Texture> texKnob;
|
||||
|
||||
VertexRenderStruct trackMesh;
|
||||
VertexRenderStruct knobMesh;
|
||||
|
||||
float value = 0.0f;
|
||||
bool vertical = true;
|
||||
|
||||
std::function<void(const std::string&, float)> onValueChanged;
|
||||
|
||||
void buildTrackMesh();
|
||||
void buildKnobMesh();
|
||||
void draw(Renderer& renderer) const;
|
||||
};
|
||||
|
||||
struct UiNode {
|
||||
std::string type;
|
||||
UiRect rect;
|
||||
std::string name;
|
||||
std::vector<std::shared_ptr<UiNode>> children;
|
||||
std::shared_ptr<UiButton> button;
|
||||
std::shared_ptr<UiSlider> slider;
|
||||
std::string orientation = "vertical";
|
||||
float spacing = 0.0f;
|
||||
};
|
||||
@ -67,10 +87,21 @@ namespace ZL {
|
||||
void onMouseDown(int x, int y);
|
||||
void onMouseUp(int x, int y);
|
||||
|
||||
bool isUiInteraction() const {
|
||||
return pressedButton != nullptr || pressedSlider != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<UiButton> findButton(const std::string& name);
|
||||
|
||||
bool setButtonCallback(const std::string& name, std::function<void(const std::string&)> cb);
|
||||
|
||||
bool addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
|
||||
const std::string& trackPath, const std::string& knobPath, float initialValue = 0.0f, bool vertical = true);
|
||||
|
||||
std::shared_ptr<UiSlider> findSlider(const std::string& name);
|
||||
bool setSliderCallback(const std::string& name, std::function<void(const std::string&, float)> cb);
|
||||
bool setSliderValue(const std::string& name, float value); // programmatic set (clamped 0..1)
|
||||
|
||||
bool pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
|
||||
bool popMenu();
|
||||
void clearMenuStack();
|
||||
@ -78,17 +109,21 @@ namespace ZL {
|
||||
private:
|
||||
std::shared_ptr<UiNode> parseNode(const json& j, Renderer& renderer, const std::string& zipFile);
|
||||
void layoutNode(const std::shared_ptr<UiNode>& node);
|
||||
void collectButtons(const std::shared_ptr<UiNode>& node);
|
||||
void collectButtonsAndSliders(const std::shared_ptr<UiNode>& node);
|
||||
|
||||
std::shared_ptr<UiNode> root;
|
||||
std::vector<std::shared_ptr<UiButton>> buttons;
|
||||
std::vector<std::shared_ptr<UiSlider>> sliders;
|
||||
|
||||
std::shared_ptr<UiButton> pressedButton;
|
||||
std::shared_ptr<UiSlider> pressedSlider;
|
||||
|
||||
struct MenuState {
|
||||
std::shared_ptr<UiNode> root;
|
||||
std::vector<std::shared_ptr<UiButton>> buttons;
|
||||
std::vector<std::shared_ptr<UiSlider>> sliders;
|
||||
std::shared_ptr<UiButton> pressedButton;
|
||||
std::shared_ptr<UiSlider> pressedSlider;
|
||||
std::string path;
|
||||
};
|
||||
|
||||
|
||||
@ -66,6 +66,20 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
"name": "musicVolumeSlider",
|
||||
"x": 1140,
|
||||
"y": 100,
|
||||
"width": 10,
|
||||
"height": 500,
|
||||
"value": 0.5,
|
||||
"orientation": "vertical",
|
||||
"textures": {
|
||||
"track": "./resources/musicVolumeBarTexture.png",
|
||||
"knob": "./resources/musicVolumeBarButton.png"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user