190 lines
7.1 KiB
C++
190 lines
7.1 KiB
C++
/* ================================================================
|
|
GUI
|
|
----------------
|
|
Gui.cpp/Gui.hpp provide the class responsible for creating, destroying, and handling GUI elements.
|
|
================================================================ */
|
|
#include "Gui.hpp"
|
|
#include "Core.hpp"
|
|
#include "Log.hpp"
|
|
#include "RenderSet.hpp"
|
|
#include "RenderObject.hpp"
|
|
#include "Mesh.hpp"
|
|
#include "Texture.hpp"
|
|
|
|
Gui::Gui() {
|
|
w = core.getWidth();
|
|
h = core.getHeight();
|
|
scene = new RenderScene();
|
|
camera = new RenderCamera();
|
|
camera->setRenderMode(1); // Use orthographic mode
|
|
camera->setPitch(90.0f); // look down
|
|
camera->setPosition(0, 0, 0);
|
|
camera->setNear(-1.0f);
|
|
camera->setFar(1.0f);
|
|
camera->setRenderFlags(RenderCamera::CLEAR_DEPTH); // only clear the depth before rendering
|
|
camera->setRenderView(core.getWindowView()); // set the camera's render view to point to the main render view
|
|
camera->setSize(h*2); // set our vertical size to the height of the window - this means 1 unit will correspond to 1 pixel
|
|
camera->updateProjection(w, h); // ensure our projection is good
|
|
camera->doRefresh(); // aaand update
|
|
scene->addCamera(camera);
|
|
// This is a strange thing - we use this camera for the rendering of all children. The children modify it to match their render dimensions (so that 1 unit == 1px)
|
|
child_camera = new RenderCamera();
|
|
child_camera->setRenderMode(1); // Use orthographic mode
|
|
child_camera->setPitch(90.0f); // look down
|
|
child_camera->setPosition(0, 0, 0);
|
|
child_camera->setNear(-1.0f);
|
|
child_camera->setFar(1.0f);
|
|
child_camera->setRenderFlags(RenderCamera::CLEAR_DEPTH); // only clear the depth before rendering
|
|
child_camera->setRenderView(core.getWindowView()); // set the child_camera's render view to point to the main render view
|
|
child_camera->setSize(h*2); // set our vertical size to the height of the window - this means 1 unit will correspond to 1 pixel
|
|
child_camera->updateProjection(w, h); // ensure our projection is good
|
|
child_camera->doRefresh(); // aaand update
|
|
|
|
//
|
|
asset_manager = core.getAssetManager();
|
|
// compile our GUI program
|
|
std::string shader_file;
|
|
Asset* shader_asset;
|
|
program = new Program();
|
|
|
|
shader_file = "shaders/" + core.shader_version + "/gui_fs.glsl";
|
|
shader_asset = asset_manager->loadFile(shader_file.c_str());
|
|
if (program->addShader(shader_asset->getData(), shader_asset->getDataLength(), GL_FRAGMENT_SHADER) != 0) {
|
|
//return 1;
|
|
}
|
|
shader_asset->unloadData();
|
|
shader_file = "shaders/" + core.shader_version + "/gui_vs.glsl";
|
|
shader_asset = asset_manager->loadFile(shader_file.c_str());
|
|
if (program->addShader(shader_asset->getData(), shader_asset->getDataLength(), GL_VERTEX_SHADER) != 0) {
|
|
// return 1;
|
|
}
|
|
shader_asset->unloadData();
|
|
if (program->doCompile() != 0) {
|
|
// return 1;
|
|
}
|
|
set_basic = new RenderSet(); // create a new basic render set
|
|
set_basic->setProgram(program); // set the set's program to gui_*
|
|
scene->addSet(set_basic); // add set to the scene
|
|
// load and build our basic element mesh
|
|
Asset *asset = asset_manager->loadFile("models/plane.obj");
|
|
element_mesh = new Mesh(asset->getData(), asset->getDataLength());
|
|
element_mesh->buildMesh();
|
|
asset->unloadData();
|
|
}
|
|
Gui::~Gui() {
|
|
delete camera;
|
|
delete scene;
|
|
GuiElement *element = NULL;
|
|
std::vector<GuiElement*>::iterator element_it, element_end;
|
|
for (element_it = elements.begin(), element_end = elements.end(); element_it != element_end; ++element_it) {
|
|
element = *element_it;
|
|
delete element;
|
|
}
|
|
}
|
|
/* onEvent
|
|
This function is called by Core::doProcess and receives:
|
|
* keypresses
|
|
* motion events (touch, mouse, etc.)
|
|
|
|
If the event is to be passed to the State, this function returns 0. If the event is to be nommed, a non-zero value is returned
|
|
|
|
NOTE: element processing is started at the end of the vector and works its way to the beginning. This seems to be an okay approach to handling element priority without dealing with special "z" ordering.
|
|
*/
|
|
int Gui::onEvent(SDL_Event event) {
|
|
std::vector<GuiElement*>::reverse_iterator element_it, element_end;
|
|
GuiElement *element = NULL;
|
|
float x, y;
|
|
switch (event.type) {
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
case SDL_MOUSEBUTTONUP:
|
|
x = float(event.button.x);
|
|
y = float(event.button.y);
|
|
LOG(LOG_INFO) << FUNC_NAME << ": CHECK: " << x << "x" << y;
|
|
for (element_it = elements.rbegin(), element_end = elements.rend(); element_it != element_end; ++element_it) {
|
|
if ((*element_it)->getFlags() & GuiElement::HIDDEN) continue;
|
|
element = (*element_it)->getHit(x, y);
|
|
if (element != NULL) break;
|
|
}
|
|
break;
|
|
case SDL_FINGERDOWN:
|
|
case SDL_FINGERUP:
|
|
x = event.tfinger.x * core.getWidth();
|
|
y = event.tfinger.y * core.getHeight();;
|
|
LOG(LOG_INFO) << FUNC_NAME << ": CHECK: " << x << "x" << y;
|
|
for (element_it = elements.rbegin(), element_end = elements.rend(); element_it != element_end; ++element_it) {
|
|
if ((*element_it)->getFlags() & GuiElement::HIDDEN) continue;
|
|
element = (*element_it)->getHit(x, y);
|
|
if (element != NULL) break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (element != NULL) return 1;
|
|
return 0;
|
|
}
|
|
int Gui::addElement(GuiElement *element) {
|
|
//
|
|
if (element->object == NULL && !(element->type & GuiElement::LIST)) {
|
|
element->object = new RenderObject();
|
|
element->object->setMesh(element_mesh);
|
|
set_basic->addObject(element->object);
|
|
if (element->flags & GuiElement::HIDDEN) element->object->hide();
|
|
// FIXME: calling this here for now
|
|
element->setGeometry(element->x, element->y, element->w, element->h);
|
|
}
|
|
//element->view = new RenderView(element->w, element->h);
|
|
// Add the children as well
|
|
std::vector<GuiElement*>::iterator element_it, element_end;
|
|
for (element_it = element->children.begin(), element_end = element->children.end(); element_it != element_end; ++element_it) {
|
|
addElement(*element_it);
|
|
}
|
|
/*// Get the top-most (parent) element and only add that.
|
|
GuiElement *top_element = element->parent;
|
|
while (top_element != NULL) {
|
|
element = top_element;
|
|
top_element = top_element->parent;
|
|
}*/
|
|
if (element->parent == NULL) {
|
|
elements.push_back(element);
|
|
LOG(LOG_INFO) << FUNC_NAME << " added element " << element->text;
|
|
}
|
|
return elements.size()-1;
|
|
}
|
|
int Gui::setView(int width, int height) {
|
|
w = width;
|
|
h = height;
|
|
camera->setSize(h*2); // update vertical size
|
|
camera->updateProjection(w, h); // update projection
|
|
camera->doRefresh();
|
|
// resize and position elements
|
|
updateElements();
|
|
return 0;
|
|
}
|
|
int Gui::getWidth() {
|
|
return w;
|
|
}
|
|
int Gui::getHeight() {
|
|
return h;
|
|
}
|
|
RenderCamera* Gui::getChildCamera() {
|
|
return child_camera;
|
|
}
|
|
void Gui::updateElements() {
|
|
std::vector<GuiElement*>::iterator element_it, element_end;
|
|
GuiElement *p_element = NULL;
|
|
GuiElement *c_element = NULL;
|
|
for (element_it = elements.begin(), element_end = elements.end(); element_it != element_end; ++element_it) {
|
|
p_element = *element_it;
|
|
if (p_element->getFlags() & GuiElement::HIDDEN) continue;
|
|
p_element->doUpdate(w, h);
|
|
}
|
|
}
|
|
int Gui::doRender() {
|
|
scene->doRender();
|
|
return 0;
|
|
}
|
|
Program* Gui::getProgram() {
|
|
return program;
|
|
}
|