RtB/src/Gui.cpp

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;
}