Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • gamedev/fggl
  • onuralpsezer/fggl
2 results
Show changes
Showing
with 1693 additions and 1132 deletions
find_package(assimp CONFIG)
if (MSVC)
target_link_libraries(${PROJECT_NAME} PUBLIC assimp::assimp)
else ()
target_link_libraries(${PROJECT_NAME} PUBLIC assimp)
endif ()
target_sources(fggl
PRIVATE
module.cpp
image.cpp
)
\ No newline at end of file
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 22/10/22.
//
#define STB_IMAGE_IMPLEMENTATION
#include "../../stb/stb_image.h"
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 18/10/22.
//
#include "fggl/data/assimp/module.hpp"
#include "fggl/debug/logging.hpp"
#include "fggl/assets/manager.hpp"
#include "fggl/mesh/mesh.hpp"
#include "../../stb/stb_image.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <filesystem>
namespace fggl::data::models {
constexpr auto convert(aiVector3D& vec) -> math::vec3 {
return {vec.x, vec.y, vec.z};
}
constexpr auto convert2(aiVector2D& vec) -> math::vec2 {
return {vec.x, vec.y};
}
constexpr auto convert2(aiVector3D& vec) -> math::vec2 {
return {vec.x, vec.y};
}
constexpr auto convert(aiColor3D& col) -> math::vec3 {
return {col.r, col.g, col.b};
}
static void process_mesh(mesh::Mesh3D& mesh, aiMesh* assimpMesh, const aiScene* scene, const std::vector<assets::AssetID>& assets) {
assert( assimpMesh != nullptr );
assert( scene != nullptr );
// process vertex data
for ( auto idx = 0U; idx < assimpMesh->mNumVertices; ++idx ) {
mesh::Vertex3D vertex{
.position = convert(assimpMesh->mVertices[idx]),
.normal = convert(assimpMesh->mNormals[idx])
};
if ( assimpMesh->mTextureCoords[0] != nullptr ) {
vertex.texPos = convert2( assimpMesh->mTextureCoords[0][idx] );
}
mesh.data.push_back(vertex);
}
// process faces (indexes)
for ( auto idx = 0U; idx < assimpMesh->mNumFaces; ++idx ) {
auto face = assimpMesh->mFaces[idx];
assert( face.mNumIndices == 3);
for ( auto vid = 0U; vid < face.mNumIndices; ++vid) {
mesh.indices.push_back( face.mIndices[vid] );
}
}
// process material
if ( assimpMesh->mMaterialIndex >= 0) {
mesh.material = assets[assimpMesh->mMaterialIndex];
}
}
static void process_node(mesh::MultiMesh3D& mesh, aiNode* node, const aiScene* scene, const std::vector<assets::AssetID>& assets) {
for ( auto idx = 0U; idx < node->mNumMeshes; ++idx ) {
auto *assimpMesh = scene->mMeshes[ node->mMeshes[idx] ];
// process assimp submesh
mesh::Mesh3D meshData;
process_mesh(meshData, assimpMesh, scene, assets);
mesh.meshes.push_back(meshData);
}
for ( auto idx = 0U; idx < node->mNumChildren; ++idx) {
process_node(mesh, node->mChildren[idx], scene, assets);
}
}
struct AssetStuff {
assets::Loader* loader;
assets::AssetManager* manager;
inline void checkLoaded(assets::AssetID asset) {
if (!manager->has(asset)) {
debug::info("triggered JIT upload for {}, use the chain loader", asset);
loader->load(asset);
}
}
inline auto isLoaded(assets::AssetID asset) const -> bool {
return manager->has(asset);
}
inline void set(assets::AssetID asset, auto* assetPtr) {
assert(assetPtr != nullptr);
manager->set(asset, assetPtr);
}
};
static auto process_texture( const aiTextureType type, const aiMaterial* assimpMat, AssetStuff& stuff, const assets::LoaderContext& config) -> std::vector<assets::AssetID> {
std::vector<assets::AssetID> matRefs;
matRefs.reserve( assimpMat->GetTextureCount(type) );
// iterate through things
for ( auto i = 0U ; i < assimpMat->GetTextureCount(type); ++i ) {
aiString texName;
assimpMat->GetTexture( type, i, &texName );
const auto texID = config.makeRef(texName.C_Str());
// trigger asset loading
stuff.checkLoaded( texID );
// assets
matRefs.push_back( texID );
}
return matRefs;
}
static auto process_mat_colour(const aiMaterial* mat, const char* name, int a1, int a2) -> math::vec3 {
aiColor3D col{0.0F, 0.0F, 0.0F};
mat->Get( name, a1, a2, col );
debug::info("read colour: {}, {}, {}, {}", name, col.r, col.g, col.b);
return convert(col);
}
static void process_material(const assets::AssetID& guid, aiMaterial* assimpMat, AssetStuff stuff, const assets::LoaderContext& config) {
auto* material = new mesh::Material();
debug::info("processing: {}", guid);
// for each material, calculate what it's name would be then request it
material->diffuseTextures = process_texture( aiTextureType_DIFFUSE, assimpMat, stuff, config );
material->normalTextures = process_texture( aiTextureType_NORMALS, assimpMat, stuff, config );
material->specularTextures = process_texture( aiTextureType_SPECULAR, assimpMat, stuff, config );
material->ambient = process_mat_colour( assimpMat, AI_MATKEY_COLOR_AMBIENT );
material->diffuse = process_mat_colour( assimpMat, AI_MATKEY_COLOR_DIFFUSE );
material->specular = process_mat_colour( assimpMat, AI_MATKEY_COLOR_SPECULAR );
stuff.set( guid, material );
}
auto load_assimp_model(assets::Loader* loader, const assets::AssetID& guid, const assets::LoaderContext& data, void* userPtr) -> assets::AssetRefRaw {
// auto *filePath = std::get<assets::AssetPath *>(data);
auto filePath = data.assetPath;
AssetStuff stuff {
.loader = loader,
.manager = (assets::AssetManager*)userPtr
};
if ( stuff.isLoaded(guid) ) {
// asset in DB, what do you want me to do?
return nullptr;
}
// assimp stuff
Assimp::Importer importer;
// import the scene from disk
const aiScene *scene = importer.ReadFile(filePath.c_str(), aiProcessPreset_TargetRealtime_Fast | aiProcess_FlipUVs);
if ( scene == nullptr || (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) != 0 || scene->mRootNode == nullptr ) {
debug::warning("unable to load required model asset");
return nullptr;
}
debug::debug("Processing assimp mesh, {} meshes, {} materials, {} textures", scene->mNumMeshes, scene->mNumMaterials, scene->mNumTextures);
// calculate the mapping from material => asset mappings
auto parentRel = std::filesystem::relative( filePath.parent_path(), filePath.parent_path().parent_path() );
std::vector<assets::AssetID> matAssets;
for ( auto idx = 0U; idx < scene->mNumMaterials; ++idx ) {
aiString matName = scene->mMaterials[idx]->GetName();
auto matRel = parentRel / matName.C_Str();
matAssets.push_back( assets::make_asset_id_rt( data.pack, matRel ) );
}
// now we can try importing the mesh data
auto* packedMesh = new mesh::MultiMesh3D();
process_node( *packedMesh, scene->mRootNode, scene, matAssets);
// now we try importing the materials
for (auto idx = 0U; idx < scene->mNumMaterials; ++idx ) {
process_material( matAssets[idx], scene->mMaterials[idx], stuff, data );
}
// FIXME asset loading system needs rework, this is bonkers.
stuff.set(guid, packedMesh);
return nullptr;
}
auto load_assimp_texture(assets::Loader* /*loader*/, const assets::AssetID& guid, const assets::LoaderContext& data, void* userPtr) -> assets::AssetRefRaw {
auto* manager = (assets::AssetManager*)userPtr;
if ( manager->has(guid) ) {
// already loaded.
return nullptr;
}
auto filePath = data.assetPath;
stbi_set_flip_vertically_on_load(1);
//load the texture data into memory
auto* image = new data::Texture2D();
image->data = stbi_load(filePath.c_str(), &image->size.x, &image->size.y, &image->channels, 3);
if ( image->data == nullptr ) {
debug::warning("error reading texture: {}", stbi_failure_reason());
return nullptr;
} else {
debug::info("image reports it loaded correctly, adding {} to database", guid);
manager->set(guid, image );
}
return nullptr;
}
auto load_tex_stb(const std::filesystem::path& filePath, assets::MemoryBlock& block) -> bool {
stbi_set_flip_vertically_on_load(1);
//load the texture data into memory
auto* image = new data::Texture2D();
image->data = stbi_load(filePath.c_str(), &image->size.x, &image->size.y, &image->channels, 3);
if ( image->data == nullptr ) {
debug::warning("error reading texture: {}", stbi_failure_reason());
delete image;
return false;
} else {
// TODO pass metadata to loader in a sensible way
block.size = image->channels * image->size.x * image->size.y;
block.data = (std::byte*)image->data;
delete image;
return true;
}
}
auto is_tex_stb(const std::filesystem::path& filePath) -> assets::AssetTypeID {
// detect jpgs
if ( filePath.extension() == ".jpg" || filePath.extension() == ".jpeg" ) {
return TEXTURE_RGBA;
}
// detect png
if ( filePath.extension() == ".png" ) {
return TEXTURE_RGBA;
}
return assets::INVALID_ASSET_TYPE;
}
auto is_model_assimp(const std::filesystem::path& filePath) -> assets::AssetTypeID {
auto ext = filePath.extension().string();
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
if ( ext == ".obj" || ext == ".fbx" ) {
return MODEL_MULTI3D;
}
return assets::INVALID_ASSET_TYPE;
}
auto extract_requirements(const std::string& packName, const std::filesystem::path& packRoot, assets::ResourceRecord& rr) -> bool {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile( rr.m_path, aiProcess_Triangulate | aiProcess_FlipUVs);
if ( !scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode ) {
debug::warning("unable to load required model asset");
return false;
}
// we want to find out about dependencies
auto baseDir = std::filesystem::relative( rr.m_path.parent_path(), packRoot );
for ( auto idx = 0U; idx < scene->mNumMaterials; ++idx) {
const auto *mat = scene->mMaterials[idx];
std::array matTypes { aiTextureType_DIFFUSE, aiTextureType_NORMALS, aiTextureType_SPECULAR };
for ( auto& matType : matTypes ) {
const auto diffCount = mat->GetTextureCount(matType);
for (auto idx2 = 0U; idx2 < diffCount; ++idx2) {
aiString texName;
mat->GetTexture(matType, idx2, &texName);
auto assetPath = baseDir / texName.C_Str();
auto assetRequired = assets::make_asset_id_rt(packName, assetPath);
rr.m_requires.push_back(assetRequired);
}
}
}
return true;
}
auto AssimpModule::factory(modules::ServiceName service, modules::Services &serviceManager) -> bool {
if ( service == MODEL_PROVIDER ) {
auto* assetLoader = serviceManager.get<assets::Loader>();
assetLoader->setFactory( MODEL_MULTI3D, load_assimp_model, assets::LoadType::PATH );
assetLoader->setFactory( TEXTURE_RGBA, load_assimp_texture, assets::LoadType::PATH );
// new loading system
auto* checkin = serviceManager.get<assets::CheckinAdapted>();
checkin->setLoader( MIME_JPG, load_tex_stb, is_tex_stb );
checkin->setLoader( MIME_PNG, load_tex_stb, is_tex_stb );
checkin->setLoader( MIME_OBJ, assets::NEEDS_CHECKIN, is_model_assimp );
checkin->setLoader( MIME_FBX, assets::NEEDS_CHECKIN, is_model_assimp );
checkin->setProcessor( MIME_OBJ, extract_requirements);
checkin->setProcessor( MIME_FBX, extract_requirements );
return false;
}
return false;
}
} // namespace fggl::data
......@@ -23,103 +23,104 @@
namespace fggl::data {
void gridVertexNormals(data::Vertex *locations) {
const int sizeX = data::heightMaxX;
const int sizeY = data::heightMaxZ;
const int gridOffset = sizeX * sizeY;
// calculate normals for each triangle
math::vec3* triNormals = new math::vec3[sizeX * sizeY * 2];
for (int i = 0; i < sizeX - 1; i++) {
for (int j = 0; j < sizeY - 1; j++) {
// calculate vertex
const auto &a = locations[i * sizeY + j].posititon;
const auto &b = locations[(i + 1) * sizeY + j].posititon;
const auto &c = locations[i * sizeY + (j + 1)].posititon;
const auto &d = locations[(i + 1) * sizeY + (j + 1)].posititon;
const auto normalA = glm::cross(b - a, a - d);
const auto normalB = glm::cross(d - c, c - b);
// store the normals
int idx1 = idx(i, j, sizeY);
int idx2 = idx1 + gridOffset;
triNormals[idx1] = glm::normalize(normalA);
triNormals[idx2] = glm::normalize(normalB);
}
}
// calculate normals for each vertex
for (int i = 0; i < sizeX; i++) {
for (int j = 0; j < sizeY; j++) {
const auto firstRow = (i == 0);
const auto firstCol = (j == 0);
const auto lastRow = (i == sizeX - 1);
const auto lastCol = (i == sizeY - 1);
auto finalNormal = glm::vec3(0.0f, 0.0f, 0.0f);
if (!firstRow && !firstCol) {
finalNormal += triNormals[idx(i - 1, j - 1, sizeY)];
}
if (!lastRow && !lastCol) {
finalNormal += triNormals[idx(i, j, sizeY)];
}
if (!firstRow && lastCol) {
finalNormal += triNormals[idx(i - 1, j, sizeY)];
finalNormal += triNormals[idx(i - 1, j, sizeY) + gridOffset];
}
if (!lastRow && !firstCol) {
finalNormal += triNormals[idx(i, j - 1, sizeY)];
finalNormal += triNormals[idx(i, j - 1, sizeY) + gridOffset];
}
locations[idx(i, j, sizeY)].normal = glm::normalize(finalNormal) * -1.0f; //FIXME the normals seem wrong.
}
}
delete[] triNormals;
}
void generateHeightMesh(const data::HeightMap& heights, data::Mesh &mesh) {
// step 1: convert height data into vertex locations
const int numElms = data::heightMaxX * data::heightMaxZ;
void gridVertexNormals(data::Vertex *locations) {
const int sizeX = data::heightMaxX;
const int sizeY = data::heightMaxZ;
const int gridOffset = sizeX * sizeY;
// calculate normals for each triangle
auto *triNormals = new math::vec3[sizeX * sizeY * 2];
for (int i = 0; i < sizeX - 1; i++) {
for (int j = 0; j < sizeY - 1; j++) {
// calculate vertex
const auto &a = locations[i * sizeY + j].posititon;
const auto &b = locations[(i + 1) * sizeY + j].posititon;
const auto &c = locations[i * sizeY + (j + 1)].posititon;
const auto &d = locations[(i + 1) * sizeY + (j + 1)].posititon;
const auto normalA = glm::cross(b - a, a - d);
const auto normalB = glm::cross(d - c, c - b);
// store the normals
int idx1 = idx(i, j, sizeY);
int idx2 = idx1 + gridOffset;
triNormals[idx1] = glm::normalize(normalA);
triNormals[idx2] = glm::normalize(normalB);
}
}
// calculate normals for each vertex
for (int i = 0; i < sizeX; i++) {
for (int j = 0; j < sizeY; j++) {
const auto firstRow = (i == 0);
const auto firstCol = (j == 0);
const auto lastRow = (i == sizeX - 1);
const auto lastCol = (i == sizeY - 1);
auto finalNormal = glm::vec3(0.0F, 0.0F, 0.0F);
if (!firstRow && !firstCol) {
finalNormal += triNormals[idx(i - 1, j - 1, sizeY)];
}
if (!lastRow && !lastCol) {
finalNormal += triNormals[idx(i, j, sizeY)];
}
if (!firstRow && lastCol) {
finalNormal += triNormals[idx(i - 1, j, sizeY)];
finalNormal += triNormals[idx(i - 1, j, sizeY) + gridOffset];
}
if (!lastRow && !firstCol) {
finalNormal += triNormals[idx(i, j - 1, sizeY)];
finalNormal += triNormals[idx(i, j - 1, sizeY) + gridOffset];
}
locations[idx(i, j, sizeY)].normal =
glm::normalize(finalNormal) * -1.0F; //FIXME the normals seem wrong.
}
}
delete[] triNormals;
}
void generateHeightMesh(const data::HeightMap &heights, data::Mesh &mesh) {
// step 1: convert height data into vertex locations
const int numElms = data::heightMaxX * data::heightMaxZ;
std::array<data::Vertex, numElms> locations{};
// iterate the
for (std::size_t x = 0; x < data::heightMaxX; x++) {
for (std::size_t z = 0; z < data::heightMaxZ; z++) {
float level = heights.getValue(x, z);
auto xPos = float(x);
auto zPos = float(z);
std::size_t idx1 = idx(x, z, data::heightMaxZ);
locations[idx1].colour = fggl::math::vec3(1.0f, 1.0f, 1.0f);
locations[idx1].posititon = math::vec3(-0.5f + xPos, level, -0.5f - zPos);
}
}
gridVertexNormals(locations.data());
mesh.restartVertex = data::heightMaxZ * data::heightMaxX;
// populate mesh
for (auto i = 0; i < numElms; i++) {
mesh.pushVertex(locations[i]);
}
for (std::size_t x = 0; x < data::heightMaxX - 1; x++) {
for (std::size_t z = 0; z < data::heightMaxZ; z++) {
for (int k=0; k < 2; k++) {
auto idx = (x+k) * data::heightMaxZ + z;
mesh.pushIndex(idx);
}
}
mesh.pushIndex(mesh.restartVertex);
}
}
for (std::size_t x = 0; x < data::heightMaxX; x++) {
for (std::size_t z = 0; z < data::heightMaxZ; z++) {
float level = heights.getValue(x, z);
auto xPos = float(x);
auto zPos = float(z);
std::size_t idx1 = idx(x, z, data::heightMaxZ);
locations[idx1].colour = fggl::math::vec3(1.0F, 1.0F, 1.0F);
locations[idx1].posititon = math::vec3(-0.5F + xPos, level, -0.5F - zPos);
}
}
gridVertexNormals(locations.data());
mesh.restartVertex = data::heightMaxZ * data::heightMaxX;
// populate mesh
for (auto i = 0; i < numElms; i++) {
mesh.pushVertex(locations[i]);
}
for (std::size_t x = 0; x < data::heightMaxX - 1; x++) {
for (std::size_t z = 0; z < data::heightMaxZ; z++) {
for (int k = 0; k < 2; k++) {
auto idx = (x + k) * data::heightMaxZ + z;
mesh.pushIndex(idx);
}
}
mesh.pushIndex(mesh.restartVertex);
}
}
}
......@@ -24,19 +24,19 @@ Mesh::Mesh() : restartVertex(Mesh::INVALID_IDX), m_verts(0), m_index(0) {
}
void Mesh::pushIndex(unsigned int idx) {
assert( idx < m_verts.size() || idx == this->restartVertex );
assert(idx < m_verts.size() || idx == this->restartVertex);
m_index.push_back(idx);
}
Mesh::IndexType Mesh::pushVertex(Vertex vert) {
auto Mesh::pushVertex(Vertex vert) -> Mesh::IndexType {
auto idx = m_verts.size();
m_verts.push_back( vert );
m_verts.push_back(vert);
return idx;
}
Mesh::IndexType Mesh::indexOf(Vertex term) {
auto Mesh::indexOf(Vertex term) -> Mesh::IndexType {
auto itr = std::find(m_verts.begin(), m_verts.end(), term);
if ( itr == m_verts.end() ){
if (itr == m_verts.end()) {
return INVALID_IDX;
}
return itr - m_verts.begin();
......@@ -47,24 +47,24 @@ void Mesh::removeDups() {
std::map<Vertex, unsigned int> mapping;
// new data
std::vector< Vertex > newVerts;
std::vector< unsigned int > newIndexes;
newIndexes.reserve( m_index.size() ); // newIndex will be same size as oldIndex
std::vector<Vertex> newVerts;
std::vector<unsigned int> newIndexes;
newIndexes.reserve(m_index.size()); // newIndex will be same size as oldIndex
unsigned int nextID = 0;
for ( auto& idx : m_index ) {
auto& vertex = m_verts[idx];
for (auto &idx : m_index) {
auto &vertex = m_verts[idx];
auto newID = nextID;
// if the vertex is known, use the existing ID, else allocate a new ID
try {
newID = mapping.at( vertex );
} catch ( std::out_of_range& e ){
mapping[ vertex ] = newID;
newVerts.push_back( vertex );
newID = mapping.at(vertex);
} catch (std::out_of_range &e) {
mapping[vertex] = newID;
newVerts.push_back(vertex);
++nextID;
}
newIndexes.push_back( newID );
newIndexes.push_back(newID);
}
// assign the replacement lists
......
......@@ -20,7 +20,7 @@
namespace fggl::data {
bool LocalStorage::factory(modules::ModuleService service, modules::Services& data) {
auto LocalStorage::factory(modules::ServiceName service, modules::Services &data) -> bool {
if (service == SERVICE_STORAGE) {
// FIXME: no easy way to set the application name
auto pathConfig = fggl::platform::calc_engine_paths("fggl-demo");
......
......@@ -17,64 +17,63 @@
#include <fggl/data/model.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <iostream>
#include <array>
#include <glm/geometric.hpp>
#include "fggl/mesh/mesh.hpp"
using namespace fggl::data;
// from https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
static glm::vec3 calcSurfaceNormal(glm::vec3 vert1, glm::vec3 vert2, glm::vec3 vert3) {
static auto calcSurfaceNormal(glm::vec3 vert1, glm::vec3 vert2, glm::vec3 vert3) -> glm::vec3 {
const glm::vec3 edge1 = vert2 - vert1;
const glm::vec3 edge2 = vert3 - vert1;
return glm::normalize( glm::cross( edge1, edge2 ) );
return glm::normalize(glm::cross(edge1, edge2));
}
static void computeNormalsDirect( fggl::data::Mesh& mesh, const fggl::data::Mesh::IndexType * colIdx, int nPoints) {
static void computeNormalsDirect(fggl::mesh::Mesh3D &mesh, const fggl::data::Mesh::IndexType *colIdx, int nPoints) {
// we're assuming all the normals are zero...
for ( int i=0; i<nPoints; i++ ) {
auto& vertex = mesh.vertex( colIdx[i] );
for (int i = 0; i < nPoints; i++) {
auto &vertex = mesh.data[colIdx[i]];
vertex.normal = glm::vec3(0.0F);
}
// We're assuming each vertex appears only once (because we're not indexed)
for (int i=0; i<nPoints; i += 3) {
auto& v1 = mesh.vertex( colIdx[ i ] );
auto& v2 = mesh.vertex( colIdx[ i + 1 ] );
auto& v3 = mesh.vertex( colIdx[ i + 2 ] );
for (int i = 0; i < nPoints; i += 3) {
auto &v1 = mesh.data[colIdx[i]];
auto &v2 = mesh.data[colIdx[i + 1]];
auto &v3 = mesh.data[colIdx[i + 2]];
const glm::vec3 normal = glm::normalize( calcSurfaceNormal( v1.posititon, v2.posititon, v3.posititon ) );
const glm::vec3 normal = glm::normalize(calcSurfaceNormal(v1.position, v2.position, v3.position));
v1.normal = normal;
v2.normal = normal;
v3.normal = normal;
}
}
static void compute_normals(fggl::data::Mesh& mesh,
const std::vector<Mesh::IndexType>& idxList, // source index
const std::vector<Mesh::IndexType>& idxMapping // source-to-mesh lookup
) {
static void compute_normals(fggl::mesh::Mesh3D &mesh,
const std::vector<Mesh::IndexType> &idxList, // source index
const std::vector<Mesh::IndexType> &idxMapping // source-to-mesh lookup
) {
// clear the normals, so the summation below works correctly
for (auto vertexIndex : idxMapping) {
auto& vertex = mesh.vertex( vertexIndex );
auto &vertex = mesh.data[vertexIndex];
vertex.normal = ILLEGAL_NORMAL;
}
// we need to calculate the contribution for each vertex
// this assumes IDXList describes a raw triangle list (ie, not quads and not a strip)
for ( std::size_t i=0; i < idxList.size(); i += 3) {
auto& v1 = mesh.vertex( idxMapping[idxList[i]] );
auto& v2 = mesh.vertex( idxMapping[idxList[i + 1]] );
auto& v3 = mesh.vertex( idxMapping[idxList[i + 2]] );
for (std::size_t i = 0; i < idxList.size(); i += 3) {
auto &v1 = mesh.data[ idxMapping[idxList[i]] ];
auto &v2 = mesh.data[ idxMapping[idxList[i + 1]] ];
auto &v3 = mesh.data[ idxMapping[idxList[i + 2]] ];
// calculate the normal and area (formula for area the math textbook)
float area = glm::length(glm::cross(v3.posititon - v2.posititon, v1.posititon - v3.posititon)) / 2;
auto faceNormal = calcSurfaceNormal(v1.posititon, v2.posititon, v3.posititon);
float area = glm::length(glm::cross(v3.position - v2.position, v1.position - v3.position)) / 2;
auto faceNormal = calcSurfaceNormal(v1.position, v2.position, v3.position);
// weight the normal according to the area of the surface (bigger area = more impact)
v1.normal += area * faceNormal;
......@@ -84,32 +83,32 @@ static void compute_normals(fggl::data::Mesh& mesh,
// re-normalise the normals
for (unsigned int vertexIndex : idxMapping) {
auto& vertex = mesh.vertex( vertexIndex );
auto &vertex = mesh.data[vertexIndex];
vertex.normal = glm::normalize(vertex.normal);
}
}
static void populateMesh(fggl::data::Mesh& mesh, const fggl::math::mat4 transform,
const int nIdx, const fggl::math::vec3* pos, const Mesh::IndexType* idx ) {
static void populateMesh(fggl::mesh::Mesh3D &mesh, const fggl::math::mat4 transform,
const int nIdx, const fggl::math::vec3 *pos, const Mesh::IndexType *idx) {
auto* colIdx = new fggl::data::Mesh::IndexType[nIdx];
auto *colIdx = new fggl::data::Mesh::IndexType[nIdx];
// generate mesh
for (int i=0; i<nIdx; i++) {
glm::vec3 rawPos = transform * glm::vec4( pos[ idx[i] ], 1.0 );
colIdx[ i ] = mesh.pushVertex( Vertex::from_pos(rawPos) );
mesh.pushIndex( colIdx[i] );
for (int i = 0; i < nIdx; i++) {
glm::vec3 rawPos = transform * glm::vec4(pos[idx[i]], 1.0);
colIdx[i] = mesh.append(fggl::mesh::Vertex3D::from_pos(rawPos));
mesh.indices.push_back(colIdx[i]);
}
computeNormalsDirect( mesh, colIdx, nIdx );
computeNormalsDirect(mesh, colIdx, nIdx);
delete[] colIdx;
}
static void populateMesh(fggl::data::Mesh& mesh,
static void populateMesh(fggl::mesh::Mesh3D &mesh,
const fggl::math::mat4 transform,
const std::vector<fggl::math::vec3>& posList,
const std::vector<fggl::data::Mesh::IndexType>& idxList) {
const std::vector<fggl::math::vec3> &posList,
const std::vector<fggl::data::Mesh::IndexType> &idxList) {
// tmp store the resulting mesh indexes (incase the mesh has multiple primatives)
std::vector<unsigned int> colIdx;
......@@ -118,12 +117,13 @@ static void populateMesh(fggl::data::Mesh& mesh,
// clion this thinks this loop is infinite, my assumption is it's gone bananas
for (std::size_t i = 0; i < posList.size(); ++i) {
glm::vec3 position = transform * fggl::math::vec4(posList[i], 1.0F);
colIdx[i] = mesh.pushVertex( Vertex::from_pos(position) );
auto vert = fggl::mesh::Vertex3D::from_pos(position);
colIdx[i] = mesh.append(vert);
}
// use the remapped indexes for the mesh
for (auto idx : idxList) {
mesh.pushIndex( colIdx[idx] );
mesh.indices.push_back(colIdx[idx]);
}
compute_normals(mesh, idxList, colIdx);
......@@ -131,7 +131,7 @@ static void populateMesh(fggl::data::Mesh& mesh,
namespace fggl::data {
static void quads2Tris(std::vector<Mesh::IndexType>& indexList, uint32_t stacks, uint32_t slices) {
static void quads2Tris(std::vector<Mesh::IndexType> &indexList, uint32_t stacks, uint32_t slices) {
const auto HORZ_SIZE = slices + 1;
for (uint32_t vertical = 0; vertical < stacks; vertical++) {
......@@ -152,19 +152,19 @@ namespace fggl::data {
}
}
void make_sphere(Mesh &mesh, const math::mat4& offset, uint32_t slices, uint32_t stacks) {
void make_sphere(fggl::mesh::Mesh3D &mesh, const math::mat4 &offset, uint32_t slices, uint32_t stacks) {
std::vector<math::vec3> positions;
float verticalAngularStride = math::PI / (float)stacks;
float horizontalAngularStride = math::TAU / (float)slices;
float verticalAngularStride = math::PI / (float) stacks;
float horizontalAngularStride = math::TAU / (float) slices;
// calculate vertex positions
for (uint32_t vertical = 0; vertical < (stacks + 1); vertical++) {
float theta = (math::HALF_PI) - verticalAngularStride * (float)vertical;
for ( uint32_t horz = 0; horz < (slices + 1); horz++ ) {
float phi = horizontalAngularStride * (float)horz;
math::vec3 position {
float theta = (math::HALF_PI) - verticalAngularStride * (float) vertical;
for (uint32_t horz = 0; horz < (slices + 1); horz++) {
float phi = horizontalAngularStride * (float) horz;
math::vec3 position{
cosf(theta) * cosf(phi),
cosf(theta) * sinf(phi),
sinf(theta)
......@@ -180,131 +180,127 @@ namespace fggl::data {
populateMesh(mesh, offset, positions, indexList);
}
} // namespace fggl::data
fggl::data::Mesh fggl::data::make_triangle() {
constexpr fggl::math::vec3 pos[]{
{-0.5F, -0.5F, 0.0F},
{0.5F, -0.5F, 0.0F},
{0.0F, 0.5F, 0.0F}
};
auto fggl::data::make_triangle() -> fggl::data::Mesh {
constexpr fggl::math::vec3 pos[]{
{-0.5F, -0.5F, 0.0F},
{0.5F, -0.5F, 0.0F},
{0.0F, 0.5F, 0.0F}
};
// add points
fggl::data::Mesh mesh;
for (auto po : pos) {
mesh.push( Vertex::from_pos(po) );
}
// add points
fggl::data::Mesh mesh;
for (auto po : pos) {
mesh.push(Vertex::from_pos(po));
}
// mesh
for (int i = 0; i < 3; ++i) {
mesh.pushIndex(i);
}
// mesh
for (int i = 0; i < 3; ++i) {
mesh.pushIndex(i);
}
return mesh;
return mesh;
}
fggl::data::Mesh fggl::data::make_quad_xy() {
constexpr fggl::math::vec3 pos[] {
auto fggl::data::make_quad_xy() -> fggl::data::Mesh {
constexpr fggl::math::vec3 pos[]{
{-0.5F, -0.5F, 0.0F},
{ 0.5F, -0.5F, 0.0F},
{ 0.5F, 0.5F, 0.0F},
{-0.5F, 0.5F, 0.0F}
{0.5F, -0.5F, 0.0F},
{0.5F, 0.5F, 0.0F},
{-0.5F, 0.5F, 0.0F}
};
constexpr int idx[] {
constexpr int idx[]{
0, 1, 3,
3, 1, 2
};
fggl::data::Mesh mesh;
std::array<int,4> colIdx{};
for (int i = 0; i < 4; ++i){
colIdx[ i ] = mesh.pushVertex( Vertex::from_pos(pos[i]));
std::array<int, 4> colIdx{};
for (int i = 0; i < 4; ++i) {
colIdx[i] = mesh.pushVertex(Vertex::from_pos(pos[i]));
}
for( auto i : idx ) {
mesh.pushIndex( colIdx[ i ] );
for (auto i : idx) {
mesh.pushIndex(colIdx[i]);
}
return mesh;
}
fggl::data::Mesh fggl::data::make_quad_xz() {
constexpr std::array<fggl::math::vec3, 4> pos {{
{-0.5F, 0.0F, -0.5F},
{0.5F, 0.0F, -0.5F},
{0.5F, 0.0F, 0.5F},
{-0.5F, 0.0F, 0.5F}
}};
constexpr std::array<int, 6> idx {{
0, 1, 3,
3, 1, 2
}};
auto fggl::data::make_quad_xz() -> fggl::data::Mesh {
constexpr std::array<fggl::math::vec3, 4> pos{{
{-0.5F, 0.0F, -0.5F},
{0.5F, 0.0F, -0.5F},
{0.5F, 0.0F, 0.5F},
{-0.5F, 0.0F, 0.5F}
}};
constexpr std::array<int, 6> idx{{
0, 1, 3,
3, 1, 2
}};
fggl::data::Mesh mesh;
std::array<int, 4> colIdx{};
for (int i = 0; i < 4; ++i){
colIdx[ i ] = mesh.pushVertex( Vertex::from_pos(pos[i]) );
for (int i = 0; i < 4; ++i) {
colIdx[i] = mesh.pushVertex(Vertex::from_pos(pos[i]));
}
for( auto i : idx ) {
mesh.pushIndex(colIdx.at( i ));
for (auto i : idx) {
mesh.pushIndex(colIdx.at(i));
}
return mesh;
}
fggl::data::Mesh fggl::data::make_cube(fggl::data::Mesh& mesh, const fggl::math::mat4& transform) {
auto fggl::data::make_cube(fggl::mesh::Mesh3D &mesh, const fggl::math::mat4 &transform) -> fggl::mesh::Mesh3D {
// done as two loops, top loop is 0,1,2,3, bottom loop is 4,5,6,7
constexpr std::array<fggl::math::vec3, 8> pos {{
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{0.5, 0.5, -0.5}, // 1
{0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
{-0.5, -0.5, -0.5}, // 4 BOTTOM LOOP
{0.5, -0.5, -0.5}, // 5
{0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
}};
constexpr std::array<Mesh::IndexType, 36> idx {{
0, 3, 1, // top
3, 2, 1,
0, 1, 4, // side 0 - 1
5, 4, 1,
1, 2, 5, // side 1 - 2
2, 6, 5,
3, 7, 2, // side 2 - 3
2, 7, 6,
0, 4, 3, // side 3 - 0
4, 7, 3,
4, 5, 7, // bottom
7, 5, 6,
}};
constexpr std::array<fggl::math::vec3, 8> pos{{
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{0.5, 0.5, -0.5}, // 1
{0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
{-0.5, -0.5, -0.5}, // 4 BOTTOM LOOP
{0.5, -0.5, -0.5}, // 5
{0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
}};
constexpr std::array<Mesh::IndexType, 36> idx{{
0, 3, 1, // top
3, 2, 1,
0, 1, 4, // side 0 - 1
5, 4, 1,
1, 2, 5, // side 1 - 2
2, 6, 5,
3, 7, 2, // side 2 - 3
2, 7, 6,
0, 4, 3, // side 3 - 0
4, 7, 3,
4, 5, 7, // bottom
7, 5, 6,
}};
populateMesh(mesh, transform, idx.size(), pos.data(), idx.data());
return mesh;
}
fggl::data::Mesh fggl::data::make_slope(fggl::data::Mesh& mesh, const fggl::math::mat4& transform) {
auto fggl::data::make_slope(fggl::mesh::Mesh3D &mesh, const fggl::math::mat4 &transform) -> fggl::mesh::Mesh3D {
// done as two loops, top loop is 0,1,2,3, bottom loop is 4,5,6,7
// FIXME remove 2 and 3 and renumber the index list accordingly
constexpr fggl::math::vec3 pos[] {
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{ 0.5, 0.5, -0.5}, // 1
{ 0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
constexpr fggl::math::vec3 pos[]{
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{0.5, 0.5, -0.5}, // 1
{0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
{-0.5, -0.5, -0.5}, // 4 BOTTOM LOOP
{ 0.5, -0.5, -0.5}, // 5
{ 0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
{0.5, -0.5, -0.5}, // 5
{0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
};
constexpr Mesh::IndexType idx[] {
constexpr Mesh::IndexType idx[]{
0, 7, 1, // ramp
7, 6, 1,
0, 1, 4, // side 0 - 1
......@@ -320,23 +316,22 @@ fggl::data::Mesh fggl::data::make_slope(fggl::data::Mesh& mesh, const fggl::math
return mesh;
}
fggl::data::Mesh fggl::data::make_ditch(fggl::data::Mesh& mesh, const fggl::math::mat4& transform) {
auto fggl::data::make_ditch(fggl::mesh::Mesh3D &mesh, const fggl::math::mat4 &transform) -> fggl::mesh::Mesh3D {
// done as two loops, top loop is 0,1,2,3, bottom loop is 4,5,6,7
// FIXME remove 2 and renumber the index list accordingly
constexpr fggl::math::vec3 pos[] {
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{ 0.5, 0.5, -0.5}, // 1
{ 0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
constexpr fggl::math::vec3 pos[]{
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{0.5, 0.5, -0.5}, // 1
{0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
{-0.5, -0.5, -0.5}, // 4 BOTTOM LOOP
{ 0.5, -0.5, -0.5}, // 5
{ 0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
{0.5, -0.5, -0.5}, // 5
{0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
};
constexpr Mesh::IndexType idx[] {
constexpr Mesh::IndexType idx[]{
0, 3, 1, // top
3, 6, 1,
0, 1, 4, // side 0 - 1
......@@ -354,21 +349,21 @@ fggl::data::Mesh fggl::data::make_ditch(fggl::data::Mesh& mesh, const fggl::math
return mesh;
}
fggl::data::Mesh fggl::data::make_point(fggl::data::Mesh& mesh, const fggl::math::mat4& transform) {
auto fggl::data::make_point(fggl::mesh::Mesh3D &mesh, const fggl::math::mat4 &transform) -> fggl::mesh::Mesh3D {
// done as two loops, top loop is 0,1,2,3, bottom loop is 4,5,6,7
constexpr fggl::math::vec3 pos[] {
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{ 0.5, 0.5, -0.5}, // 1
{ 0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
constexpr fggl::math::vec3 pos[]{
{-0.5, 0.5, -0.5}, // 0 TOP LOOP
{0.5, 0.5, -0.5}, // 1
{0.5, 0.5, 0.5}, // 2
{-0.5, 0.5, 0.5}, // 3
{-0.5, -0.5, -0.5}, // 4 BOTTOM LOOP
{ 0.5, -0.5, -0.5}, // 5
{ 0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
{0.5, -0.5, -0.5}, // 5
{0.5, -0.5, 0.5}, // 6
{-0.5, -0.5, 0.5} // 7
};
constexpr Mesh::IndexType idx[] {
constexpr Mesh::IndexType idx[]{
0, 7, 5, // top
7, 6, 5,
0, 5, 4, // side 0 - 1
......
target_sources(fggl
PRIVATE
debug.cpp
debug_draw.cpp
)
PRIVATE
debug.cpp
debug_draw.cpp
logging.cpp
)
# spdlog for cleaner logging
find_package(spdlog)
......
......@@ -20,11 +20,11 @@
using fggl::debug::DebugUI;
DebugUI::DebugUI(std::shared_ptr<fggl::display::glfw::Window>& win) : m_visible(false) {
DebugUI::DebugUI(std::shared_ptr<fggl::display::glfw::Window> &win) : m_visible(false) {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
ImGuiIO &io = ImGui::GetIO();
io.IniFilename = nullptr;
ImGui_ImplGlfw_InitForOpenGL(win->handle(), true);
......@@ -45,14 +45,14 @@ void DebugUI::frameStart() {
}
void DebugUI::draw() {
for ( auto& [name, data] : m_windows) {
if ( data.m_visible ) {
data.m_callback( &data.m_visible );
for (auto &[name, data] : m_windows) {
if (data.m_visible) {
data.m_callback(&data.m_visible);
}
}
ImGui::Render();
if ( m_visible ) {
if (m_visible) {
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
}
target_link_libraries(fggl PRIVATE imgui)
target_sources( fggl
PRIVATE
target_sources(fggl
PRIVATE
imgui_impl_glfw.cpp
imgui_impl_opengl3.cpp
)
)
target_include_directories( fggl
PRIVATE
target_include_directories(fggl
PRIVATE
include/
)
\ No newline at end of file
)
\ No newline at end of file
......@@ -42,6 +42,7 @@
// GLFW
#include <GLFW/glfw3.h>
#ifdef _WIN32
#undef APIENTRY
#define GLFW_EXPOSE_NATIVE_WIN32
......@@ -59,319 +60,296 @@
#endif
// Data
enum GlfwClientApi
{
GlfwClientApi_Unknown,
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
enum GlfwClientApi {
GlfwClientApi_Unknown,
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
};
static GLFWwindow* g_Window = NULL; // Main window
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0;
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static bool g_InstalledCallbacks = false;
static GLFWwindow *g_Window = NULL; // Main window
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0;
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
static GLFWcursor *g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static bool g_InstalledCallbacks = false;
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
static GLFWcharfun g_PrevUserCallbackChar = NULL;
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
static GLFWcharfun g_PrevUserCallbackChar = NULL;
static const char *ImGui_ImplGlfw_GetClipboardText(void *user_data) {
return glfwGetClipboardString((GLFWwindow *) user_data);
}
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
{
glfwSetClipboardString((GLFWwindow*)user_data, text);
static void ImGui_ImplGlfw_SetClipboardText(void *user_data, const char *text) {
glfwSetClipboardString((GLFWwindow *) user_data, text);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
if (g_PrevUserCallbackMousebutton != NULL)
g_PrevUserCallbackMousebutton(window, button, action, mods);
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) {
if (g_PrevUserCallbackMousebutton != NULL)
g_PrevUserCallbackMousebutton(window, button, action, mods);
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
g_MouseJustPressed[button] = true;
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
g_MouseJustPressed[button] = true;
}
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
if (g_PrevUserCallbackScroll != NULL)
g_PrevUserCallbackScroll(window, xoffset, yoffset);
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow *window, double xoffset, double yoffset) {
if (g_PrevUserCallbackScroll != NULL)
g_PrevUserCallbackScroll(window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
io.MouseWheelH += (float)xoffset;
io.MouseWheel += (float)yoffset;
ImGuiIO &io = ImGui::GetIO();
io.MouseWheelH += (float) xoffset;
io.MouseWheel += (float) yoffset;
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
ImGuiIO& io = ImGui::GetIO();
if (g_PrevUserCallbackKey != NULL && !io.WantCaptureKeyboard)
g_PrevUserCallbackKey(window, key, scancode, action, mods);
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
{
if (action == GLFW_PRESS)
io.KeysDown[key] = true;
if (action == GLFW_RELEASE)
io.KeysDown[key] = false;
}
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
void ImGui_ImplGlfw_KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) {
ImGuiIO &io = ImGui::GetIO();
if (g_PrevUserCallbackKey != NULL && !io.WantCaptureKeyboard)
g_PrevUserCallbackKey(window, key, scancode, action, mods);
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)) {
if (action == GLFW_PRESS)
io.KeysDown[key] = true;
if (action == GLFW_RELEASE)
io.KeysDown[key] = false;
}
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
#ifdef _WIN32
io.KeySuper = false;
io.KeySuper = false;
#else
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
#endif
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
if (g_PrevUserCallbackChar != NULL)
g_PrevUserCallbackChar(window, c);
void ImGui_ImplGlfw_CharCallback(GLFWwindow *window, unsigned int c) {
if (g_PrevUserCallbackChar != NULL)
g_PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharacter(c);
ImGuiIO &io = ImGui::GetIO();
io.AddInputCharacter(c);
}
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
g_Window = window;
g_Time = 0.0;
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "imgui_impl_glfw";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = g_Window;
static bool ImGui_ImplGlfw_Init(GLFWwindow *window, bool install_callbacks, GlfwClientApi client_api) {
g_Window = window;
g_Time = 0.0;
// Setup backend capabilities flags
ImGuiIO &io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |=
ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "imgui_impl_glfw";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = g_Window;
#if defined(_WIN32)
io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
#endif
// Create mouse cursors
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
// Create mouse cursors
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
#if GLFW_HAS_NEW_CURSORS
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
#else
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
#endif
glfwSetErrorCallback(prev_error_callback);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
g_PrevUserCallbackMousebutton = NULL;
g_PrevUserCallbackScroll = NULL;
g_PrevUserCallbackKey = NULL;
g_PrevUserCallbackChar = NULL;
if (install_callbacks)
{
g_InstalledCallbacks = true;
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
}
g_ClientApi = client_api;
return true;
glfwSetErrorCallback(prev_error_callback);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
g_PrevUserCallbackMousebutton = NULL;
g_PrevUserCallbackScroll = NULL;
g_PrevUserCallbackKey = NULL;
g_PrevUserCallbackChar = NULL;
if (install_callbacks) {
g_InstalledCallbacks = true;
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
}
g_ClientApi = client_api;
return true;
}
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow *window, bool install_callbacks) {
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
}
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow *window, bool install_callbacks) {
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
}
bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
bool ImGui_ImplGlfw_InitForOther(GLFWwindow *window, bool install_callbacks) {
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
}
void ImGui_ImplGlfw_Shutdown()
{
if (g_InstalledCallbacks)
{
glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
g_InstalledCallbacks = false;
}
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
{
glfwDestroyCursor(g_MouseCursors[cursor_n]);
g_MouseCursors[cursor_n] = NULL;
}
g_ClientApi = GlfwClientApi_Unknown;
void ImGui_ImplGlfw_Shutdown() {
if (g_InstalledCallbacks) {
glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
g_InstalledCallbacks = false;
}
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) {
glfwDestroyCursor(g_MouseCursors[cursor_n]);
g_MouseCursors[cursor_n] = NULL;
}
g_ClientApi = GlfwClientApi_Unknown;
}
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
{
// Update buttons
ImGuiIO& io = ImGui::GetIO();
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
g_MouseJustPressed[i] = false;
}
// Update mouse position
const ImVec2 mouse_pos_backup = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
static void ImGui_ImplGlfw_UpdateMousePosAndButtons() {
// Update buttons
ImGuiIO &io = ImGui::GetIO();
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) {
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
g_MouseJustPressed[i] = false;
}
// Update mouse position
const ImVec2 mouse_pos_backup = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
#ifdef __EMSCRIPTEN__
const bool focused = true; // Emscripten
const bool focused = true; // Emscripten
#else
const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
#endif
if (focused)
{
if (io.WantSetMousePos)
{
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
}
else
{
double mouse_x, mouse_y;
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
}
}
if (focused) {
if (io.WantSetMousePos) {
glfwSetCursorPos(g_Window, (double) mouse_pos_backup.x, (double) mouse_pos_backup.y);
} else {
double mouse_x, mouse_y;
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float) mouse_x, (float) mouse_y);
}
}
}
static void ImGui_ImplGlfw_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
else
{
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
static void ImGui_ImplGlfw_UpdateMouseCursor() {
ImGuiIO &io = ImGui::GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|| glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) {
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
} else {
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
glfwSetCursor(g_Window,
g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor]
: g_MouseCursors[ImGuiMouseCursor_Arrow]);
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
static void ImGui_ImplGlfw_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
static void ImGui_ImplGlfw_UpdateGamepads() {
ImGuiIO &io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
int axes_count = 0, buttons_count = 0;
const float *axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char *buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight, 0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
}
void ImGui_ImplGlfw_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(g_Window, &w, &h);
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step
double current_time = glfwGetTime();
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads();
void ImGui_ImplGlfw_NewFrame() {
ImGuiIO &io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt()
&& "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(g_Window, &w, &h);
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float) w, (float) h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float) display_w / w, (float) display_h / h);
// Setup time step
double current_time = glfwGetTime();
io.DeltaTime = g_Time > 0.0 ? (float) (current_time - g_Time) : (float) (1.0f / 60.0f);
g_Time = current_time;
ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads();
}
......@@ -85,10 +85,12 @@
#include "imgui.h"
#include "include/imgui_impl_opengl3.h"
#include <stdio.h>
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
// GL includes
......@@ -111,6 +113,7 @@
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
#include <glad/gl.h> // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
......@@ -148,581 +151,657 @@ using namespace gl;
#endif
// OpenGL Data
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
static GLuint g_FontTexture = 0;
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
static GLuint g_GlVersion =
0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
static GLuint g_FontTexture = 0;
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0,
g_AttribLocationVtxColor = 0; // Vertex attributes location
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
// Query for GL version (e.g. 320 for GL 3.2)
bool ImGui_ImplOpenGL3_Init(const char *glsl_version) {
// Query for GL version (e.g. 320 for GL 3.2)
#if !defined(IMGUI_IMPL_OPENGL_ES2)
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0)
{
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
const char* gl_version = (const char*)glGetString(GL_VERSION);
sscanf(gl_version, "%d.%d", &major, &minor);
}
g_GlVersion = (GLuint)(major * 100 + minor * 10);
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0) {
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
const char *gl_version = (const char *) glGetString(GL_VERSION);
sscanf(gl_version, "%d.%d", &major, &minor);
}
g_GlVersion = (GLuint) (major * 100 + minor * 10);
#else
g_GlVersion = 200; // GLES 2
g_GlVersion = 200; // GLES 2
#endif
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3";
// Setup backend capabilities flags
ImGuiIO &io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3";
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 320)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
if (g_GlVersion >= 320)
io.BackendFlags |=
ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
#if defined(IMGUI_IMPL_OPENGL_ES2)
if (glsl_version == NULL)
glsl_version = "#version 100";
if (glsl_version == NULL)
glsl_version = "#version 100";
#elif defined(IMGUI_IMPL_OPENGL_ES3)
if (glsl_version == NULL)
glsl_version = "#version 300 es";
if (glsl_version == NULL)
glsl_version = "#version 300 es";
#elif defined(__APPLE__)
if (glsl_version == NULL)
glsl_version = "#version 150";
if (glsl_version == NULL)
glsl_version = "#version 150";
#else
if (glsl_version == NULL)
glsl_version = "#version 130";
#endif
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n");
// Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
// you are likely to get a crash below.
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
const char* gl_loader = "Unknown";
IM_UNUSED(gl_loader);
if (glsl_version == NULL)
glsl_version = "#version 130";
#endif
IM_ASSERT((int) strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n");
// Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
// you are likely to get a crash below.
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
const char *gl_loader = "Unknown";
IM_UNUSED(gl_loader);
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
gl_loader = "GL3W";
gl_loader = "GL3W";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
gl_loader = "GLEW";
gl_loader = "GLEW";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
gl_loader = "GLAD";
gl_loader = "GLAD";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
gl_loader = "GLAD2";
gl_loader = "GLAD2";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
gl_loader = "glbinding2";
gl_loader = "glbinding2";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
gl_loader = "glbinding3";
gl_loader = "glbinding3";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
gl_loader = "custom";
gl_loader = "custom";
#else
gl_loader = "none";
gl_loader = "none";
#endif
// Make an arbitrary GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
// Make an arbitrary GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
return true;
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
ImGui_ImplOpenGL3_DestroyDeviceObjects();
void ImGui_ImplOpenGL3_Shutdown() {
ImGui_ImplOpenGL3_DestroyDeviceObjects();
}
void ImGui_ImplOpenGL3_NewFrame()
{
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
void ImGui_ImplOpenGL3_NewFrame() {
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData *draw_data,
int fb_width,
int fb_height,
GLuint vertex_array_object) {
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (g_GlVersion >= 310)
glDisable(GL_PRIMITIVE_RESTART);
if (g_GlVersion >= 310)
glDisable(GL_PRIMITIVE_RESTART);
#endif
#ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
#if defined(GL_CLIP_ORIGIN)
bool clip_origin_lower_left = true;
if (g_GlVersion >= 450)
{
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
if (current_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false;
}
#endif
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
bool clip_origin_lower_left = true;
if (g_GlVersion >= 450) {
GLenum current_clip_origin = 0;
glGetIntegerv(GL_CLIP_ORIGIN, (GLint *) &current_clip_origin);
if (current_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false;
}
#endif
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei) fb_width, (GLsizei) fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
#if defined(GL_CLIP_ORIGIN)
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
#endif
const float ortho_projection[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
};
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
if (!clip_origin_lower_left) {
float tmp = T;
T = B;
B = tmp;
} // Swap top and bottom if origin is upper left
#endif
const float ortho_projection[4][4] =
{
{2.0f / (R - L), 0.0f, 0.0f, 0.0f},
{0.0f, 2.0f / (T - B), 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f, 0.0f},
{(R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f},
};
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (g_GlVersion >= 330)
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
if (g_GlVersion >= 330)
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
#endif
(void)vertex_array_object;
(void) vertex_array_object;
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(vertex_array_object);
#endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
glEnableVertexAttribArray(g_AttribLocationVtxPos);
glEnableVertexAttribArray(g_AttribLocationVtxUV);
glEnableVertexAttribArray(g_AttribLocationVtxColor);
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
glBindVertexArray(vertex_array_object);
#endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
glEnableVertexAttribArray(g_AttribLocationVtxPos);
glEnableVertexAttribArray(g_AttribLocationVtxUV);
glEnableVertexAttribArray(g_AttribLocationVtxColor);
glVertexAttribPointer(g_AttribLocationVtxPos,
2,
GL_FLOAT,
GL_FALSE,
sizeof(ImDrawVert),
(GLvoid *) IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationVtxUV,
2,
GL_FLOAT,
GL_FALSE,
sizeof(ImDrawVert),
(GLvoid *) IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationVtxColor,
4,
GL_UNSIGNED_BYTE,
GL_TRUE,
sizeof(ImDrawVert),
(GLvoid *) IM_OFFSETOF(ImDrawVert, col));
}
// OpenGL3 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0)
return;
// Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData *draw_data) {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int) (draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int) (draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0)
return;
// Backup GL state
GLenum last_active_texture;
glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLuint last_program;
glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &last_program);
GLuint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &last_texture);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
#endif
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
GLuint last_sampler;
if (g_GlVersion >= 330) {
glGetIntegerv(GL_SAMPLER_BINDING, (GLint *) &last_sampler);
} else {
last_sampler = 0;
}
#endif
GLuint last_array_buffer;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint *) &last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
GLuint last_vertex_array_object;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint *) &last_vertex_array_object);
#endif
#ifdef GL_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
GLint last_polygon_mode[2];
glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4];
glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4];
glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb;
glGetIntegerv(GL_BLEND_SRC_RGB, (GLint *) &last_blend_src_rgb);
GLenum last_blend_dst_rgb;
glGetIntegerv(GL_BLEND_DST_RGB, (GLint *) &last_blend_dst_rgb);
GLenum last_blend_src_alpha;
glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint *) &last_blend_src_alpha);
GLenum last_blend_dst_alpha;
glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint *) &last_blend_dst_alpha);
GLenum last_blend_equation_rgb;
glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint *) &last_blend_equation_rgb);
GLenum last_blend_equation_alpha;
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint *) &last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
#endif
// Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0;
// Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0;
#ifndef IMGUI_IMPL_OPENGL_ES2
glGenVertexArrays(1, &vertex_array_object);
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glGenVertexArrays(1, &vertex_array_object);
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList *cmd_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
glBufferData(GL_ARRAY_BUFFER,
(GLsizeiptr) cmd_list->VtxBuffer.Size * (int) sizeof(ImDrawVert),
(const GLvoid *) cmd_list->VtxBuffer.Data,
GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(GLsizeiptr) cmd_list->IdxBuffer.Size * (int) sizeof(ImDrawIdx),
(const GLvoid *) cmd_list->IdxBuffer.Data,
GL_STREAM_DRAW);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL) {
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
else
pcmd->UserCallback(cmd_list, pcmd);
} else {
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) {
// Apply scissor/clipping rectangle
glScissor((int) clip_rect.x,
(int) (fb_height - clip_rect.w),
(int) (clip_rect.z - clip_rect.x),
(int) (clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint) (intptr_t) pcmd->GetTexID());
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else
#endif
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
}
}
// Destroy the temporary VAO
if (g_GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES,
(GLsizei) pcmd->ElemCount,
sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
(void *) (intptr_t) (pcmd->IdxOffset * sizeof(ImDrawIdx)),
(GLint) pcmd->VtxOffset);
else
#endif
glDrawElements(GL_TRIANGLES,
(GLsizei) pcmd->ElemCount,
sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
(void *) (intptr_t) (pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
}
}
// Destroy the temporary VAO
#ifndef IMGUI_IMPL_OPENGL_ES2
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteVertexArrays(1, &vertex_array_object);
#endif
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (g_GlVersion >= 330)
glBindSampler(0, last_sampler);
if (g_GlVersion >= 330)
glBindSampler(0, last_sampler);
#endif
glActiveTexture(last_active_texture);
glActiveTexture(last_active_texture);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(last_vertex_array_object);
#endif
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
glBindVertexArray(last_vertex_array_object);
#endif
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
if (last_enable_cull_face)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
if (last_enable_depth_test)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
if (last_enable_stencil_test)
glEnable(GL_STENCIL_TEST);
else
glDisable(GL_STENCIL_TEST);
if (last_enable_scissor_test)
glEnable(GL_SCISSOR_TEST);
else
glDisable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
if (g_GlVersion >= 310) {
if (last_enable_primitive_restart)
glEnable(GL_PRIMITIVE_RESTART);
else
glDisable(GL_PRIMITIVE_RESTART);
}
#endif
#ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
glPolygonMode(GL_FRONT_AND_BACK, (GLenum) last_polygon_mode[0]);
#endif
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
glViewport(last_viewport[0], last_viewport[1], (GLsizei) last_viewport[2], (GLsizei) last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei) last_scissor_box[2], (GLsizei) last_scissor_box[3]);
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
bool ImGui_ImplOpenGL3_CreateFontsTexture() {
// Build texture atlas
ImGuiIO &io = ImGui::GetIO();
unsigned char *pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels,
&width,
&height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
// Store our identifier
io.Fonts->SetTexID((ImTextureID) (intptr_t) g_FontTexture);
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
return true;
}
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->SetTexID(0);
g_FontTexture = 0;
}
void ImGui_ImplOpenGL3_DestroyFontsTexture() {
if (g_FontTexture) {
ImGuiIO &io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->SetTexID(0);
g_FontTexture = 0;
}
}
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
static bool CheckShader(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
static bool CheckShader(GLuint handle, const char *desc) {
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean) status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
if (log_length > 1) {
ImVector<char> buf;
buf.resize((int) (log_length + 1));
glGetShaderInfoLog(handle, log_length, NULL, (GLchar *) buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean) status == GL_TRUE;
}
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
static bool CheckProgram(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
static bool CheckProgram(GLuint handle, const char *desc) {
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean) status == GL_FALSE)
fprintf(stderr,
"ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n",
desc,
g_GlslVersionString);
if (log_length > 1) {
ImVector<char> buf;
buf.resize((int) (log_length + 1));
glGetProgramInfoLog(handle, log_length, NULL, (GLchar *) buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean) status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
bool ImGui_ImplOpenGL3_CreateDeviceObjects() {
// Backup GL state
GLint last_texture, last_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
GLint last_vertex_array;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#endif
// Parse GLSL version string
int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
const GLchar* vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n"
"attribute vec2 Position;\n"
"attribute vec2 UV;\n"
"attribute vec4 Color;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_130 =
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 UV;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_300_es =
"precision mediump float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_410_core =
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* fragment_shader_glsl_120 =
"#ifdef GL_ES\n"
" precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_130 =
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_300_es =
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_410_core =
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"uniform sampler2D Texture;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
// Select shaders matching our GLSL versions
const GLchar* vertex_shader = NULL;
const GLchar* fragment_shader = NULL;
if (glsl_version < 130)
{
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
}
else if (glsl_version >= 410)
{
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
}
else if (glsl_version == 300)
{
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
}
else
{
vertex_shader = vertex_shader_glsl_130;
fragment_shader = fragment_shader_glsl_130;
}
// Create shaders
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
glCompileShader(g_VertHandle);
CheckShader(g_VertHandle, "vertex shader");
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
glCompileShader(g_FragHandle);
CheckShader(g_FragHandle, "fragment shader");
g_ShaderHandle = glCreateProgram();
glAttachShader(g_ShaderHandle, g_VertHandle);
glAttachShader(g_ShaderHandle, g_FragHandle);
glLinkProgram(g_ShaderHandle);
CheckProgram(g_ShaderHandle, "shader program");
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
// Create buffers
glGenBuffers(1, &g_VboHandle);
glGenBuffers(1, &g_ElementsHandle);
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
GLint last_vertex_array;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#endif
// Parse GLSL version string
int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
const GLchar *vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n"
"attribute vec2 Position;\n"
"attribute vec2 UV;\n"
"attribute vec4 Color;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar *vertex_shader_glsl_130 =
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 UV;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar *vertex_shader_glsl_300_es =
"precision mediump float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar *vertex_shader_glsl_410_core =
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar *fragment_shader_glsl_120 =
"#ifdef GL_ES\n"
" precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
"}\n";
const GLchar *fragment_shader_glsl_130 =
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar *fragment_shader_glsl_300_es =
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar *fragment_shader_glsl_410_core =
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"uniform sampler2D Texture;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
// Select shaders matching our GLSL versions
const GLchar *vertex_shader = NULL;
const GLchar *fragment_shader = NULL;
if (glsl_version < 130) {
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
} else if (glsl_version >= 410) {
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
} else if (glsl_version == 300) {
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
} else {
vertex_shader = vertex_shader_glsl_130;
fragment_shader = fragment_shader_glsl_130;
}
// Create shaders
const GLchar *vertex_shader_with_version[2] = {g_GlslVersionString, vertex_shader};
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
glCompileShader(g_VertHandle);
CheckShader(g_VertHandle, "vertex shader");
const GLchar *fragment_shader_with_version[2] = {g_GlslVersionString, fragment_shader};
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
glCompileShader(g_FragHandle);
CheckShader(g_FragHandle, "fragment shader");
g_ShaderHandle = glCreateProgram();
glAttachShader(g_ShaderHandle, g_VertHandle);
glAttachShader(g_ShaderHandle, g_FragHandle);
glLinkProgram(g_ShaderHandle);
CheckProgram(g_ShaderHandle, "shader program");
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
g_AttribLocationVtxPos = (GLuint) glGetAttribLocation(g_ShaderHandle, "Position");
g_AttribLocationVtxUV = (GLuint) glGetAttribLocation(g_ShaderHandle, "UV");
g_AttribLocationVtxColor = (GLuint) glGetAttribLocation(g_ShaderHandle, "Color");
// Create buffers
glGenBuffers(1, &g_VboHandle);
glGenBuffers(1, &g_ElementsHandle);
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(last_vertex_array);
glBindVertexArray(last_vertex_array);
#endif
return true;
return true;
}
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
ImGui_ImplOpenGL3_DestroyFontsTexture();
void ImGui_ImplOpenGL3_DestroyDeviceObjects() {
if (g_VboHandle) {
glDeleteBuffers(1, &g_VboHandle);
g_VboHandle = 0;
}
if (g_ElementsHandle) {
glDeleteBuffers(1, &g_ElementsHandle);
g_ElementsHandle = 0;
}
if (g_ShaderHandle && g_VertHandle) {
glDetachShader(g_ShaderHandle, g_VertHandle);
}
if (g_ShaderHandle && g_FragHandle) {
glDetachShader(g_ShaderHandle, g_FragHandle);
}
if (g_VertHandle) {
glDeleteShader(g_VertHandle);
g_VertHandle = 0;
}
if (g_FragHandle) {
glDeleteShader(g_FragHandle);
g_FragHandle = 0;
}
if (g_ShaderHandle) {
glDeleteProgram(g_ShaderHandle);
g_ShaderHandle = 0;
}
ImGui_ImplOpenGL3_DestroyFontsTexture();
}
......@@ -21,16 +21,16 @@
struct GLFWwindow;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
IMGUI_IMPL_API auto ImGui_ImplGlfw_InitForOpenGL(GLFWwindow *window, bool installCallbacks) -> bool;
IMGUI_IMPL_API auto ImGui_ImplGlfw_InitForVulkan(GLFWwindow *window, bool installCallbacks) -> bool;
IMGUI_IMPL_API auto ImGui_ImplGlfw_InitForOther(GLFWwindow *window, bool installCallbacks) -> bool;
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// GLFW callbacks
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow *window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow *window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow *window, unsigned int c);
......@@ -25,16 +25,16 @@
#include "imgui.h" // IMGUI_IMPL_API
// Backend API
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API auto ImGui_ImplOpenGL3_Init(const char *glsl_version = nullptr) -> bool;
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData *draw_data);
// (Optional) Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
IMGUI_IMPL_API auto ImGui_ImplOpenGL3_CreateFontsTexture() -> bool;
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
IMGUI_IMPL_API auto ImGui_ImplOpenGL3_CreateDeviceObjects() -> bool;
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// Specific OpenGL ES versions
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
......@@ -66,22 +66,22 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// Otherwise try to detect supported Desktop OpenGL loaders..
#elif defined(__has_include)
#if __has_include(<GL/glew.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
#elif __has_include(<glad/glad.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
#elif __has_include(<glad/gl.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
#elif __has_include(<GL/gl3w.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
#elif __has_include(<glbinding/glbinding.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
#elif __has_include(<glbinding/Binding.h>)
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
#else
#error "Cannot detect OpenGL loader!"
#error "Cannot detect OpenGL loader!"
#endif
#else
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
#endif
#endif
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 11/09/22.
//
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
namespace fggl::debug {
auto demangle(const char *name) -> std::string {
int status = -4;
std::unique_ptr<char, decltype(&std::free)> res{
abi::__cxa_demangle(name, nullptr, nullptr, &status),
std::free
};
return (status == 0) ? res.get() : name;
}
}
#else
namespace fggl::debug {
std::string demangle(const char* name) {
return name;
}
}
#endif
target_sources(fggl
PRIVATE
PRIVATE
loader/loader.cpp
module.cpp
)
)
......@@ -18,29 +18,82 @@
#include "fggl/entity/loader/loader.hpp"
#include "fggl/debug/logging.hpp"
#include "fggl/scenes/game.hpp"
namespace fggl::entity {
assets::AssetRefRaw load_prototype(EntityFactory* factory, const assets::AssetGUID& guid, assets::AssetData data) {
auto* filePath = std::get<assets::AssetPath*>(data);
auto load_scene(assets::Loader* /*loader*/, const assets::AssetID& /*asset*/, const assets::LoaderContext& data, void* ptr) -> assets::AssetRefRaw {
auto* gamePtr = (scenes::Game*)ptr;
auto filePath = data.assetPath;
// We need to process the prototypes, and load them into the asset system.
auto nodes = YAML::LoadAllFromFile( filePath->c_str() );
// load assets
auto* entityFactory = gamePtr->owner().service<EntityFactory>();
auto nodes = YAML::LoadAllFromFile(filePath.c_str());
for (const auto& node : nodes) {
auto scene = node["scene"];
if ( !scene ) {
debug::warning("no scene node in YAML file...");
return nullptr;
}
// create and personalize
for (const auto& item : scene) {
// only safe if personalize is called BEFORE end of loop itr
auto personalize = [&entityFactory, &item, gamePtr](EntityManager& manager, const EntityID eid) {
for ( const auto& compConfig : item["components"]) {
auto compName = compConfig.first.as<fggl::util::GUID>();
auto& compInfo = entityFactory->getInfo(compName);
// setup config data
ComponentSpec spec;
spec.config = compConfig.second;
// re-run the factory with the modified arguments (might need to support a 'patch' function...)
compInfo.factory( spec, manager, eid, gamePtr->owner().services());
}
};
// finally, load the entity and trigger personalize
auto prefab = item["prefab"].as<fggl::util::GUID>();
auto entity = entityFactory->create(prefab, gamePtr->world(), personalize);
// metadata
if ( item["name"].IsDefined() ) {
gamePtr->world().setName(item["name"].as<std::string>(), entity);
}
if ( item["tags"].IsDefined() ) {
for ( auto tag : item["tags"] ) {
auto tagGuid = tag.as<fggl::util::GUID>();
gamePtr->world().addTag(entity, tagGuid);
}
}
}
}
return nullptr;
}
auto load_prototype(assets::Loader* /*loader*/, const assets::AssetID &/*guid*/, const assets::LoaderContext& data, EntityFactory* factory) -> assets::AssetRefRaw {
auto filePath = data.assetPath;
// We need to process the prototypes, and load them into the asset system.
auto nodes = YAML::LoadAllFromFile(filePath.c_str());
for (const auto &node : nodes) {
auto prefabs = node["prefabs"];
for ( const auto& prefab : prefabs ) {
for (const auto &prefab : prefabs) {
auto name = prefab["name"].as<fggl::util::GUID>();
#ifndef NDEBUG
debug::info("found prefab: {}", fggl::util::guidToString(name) );
#endif
debug::info("found prefab: {}", name);
// set up the components
EntitySpec entity{};
entity.parent = prefab["parent"].as<fggl::util::GUID>(NO_PARENT);
for (const auto& compEntry : prefab["components"]) {
for (const auto &compEntry : prefab["components"]) {
auto compId = compEntry.first.as<fggl::util::GUID>();
ComponentSpec compSpec{};
......@@ -48,12 +101,16 @@ namespace fggl::entity {
entity.components[compId] = compSpec;
entity.ordering.push_back(compId);
#ifndef NDEBUG
debug::trace("{} has component {}", fggl::util::guidToString(name), fggl::util::guidToString(compId));
#endif
debug::trace("prefab {} has component {}", name, compId);
}
if ( prefab["tags"].IsDefined() ) {
for ( const auto& tagNode : prefab["tags"] ) {
entity.tags.push_back( tagNode.as< util::GUID >() );
}
}
factory->define( name, entity );
factory->define(name, entity);
}
}
......
......@@ -18,31 +18,73 @@
#include "fggl/entity/module.hpp"
#include "fggl/math/types.hpp"
#include "fggl/scenes/game.hpp"
namespace fggl::entity {
void make_transform(const entity::ComponentSpec& spec, EntityManager& manager, const entity::EntityID entity){
auto& transform = manager.add<math::Transform>(entity);
transform.origin( spec.get<math::vec3>( "origin", math::VEC3_ZERO ) );
transform.euler( spec.get<math::vec3>( "rotation", math::VEC3_ZERO ) );
transform.scale( spec.get<math::vec3>( "scale", math::VEC3_ONES ) );
void make_transform(const entity::ComponentSpec &spec, EntityManager &manager, const entity::EntityID entity, modules::Services &/*svc*/) {
auto &transform = manager.add<math::Transform>(entity);
debug::trace("created transform for entity {}", (uint64_t)entity);
//FIXME won't work for patching!
transform.origin(spec.get<math::vec3>("origin", math::VEC3_ZERO));
transform.euler(spec.get<math::vec3>("rotation", math::VEC3_ZERO));
transform.scale(spec.get<math::vec3>("scale", math::VEC3_ONES));
debug::trace("created transform for entity {}", (uint64_t) entity);
}
void install_component_factories(entity::EntityFactory* factory) {
void install_component_factories(entity::EntityFactory *factory) {
factory->bind(math::Transform::guid, make_transform);
}
bool ECS::factory(modules::ModuleService service, modules::Services& services) {
if ( service == EntityFactory::service) {
auto* factory = services.create<EntityFactory>();
static auto is_scene(std::filesystem::path path) -> assets::AssetTypeID {
if ( path.extension() == ".yml" ) {
return ENTITY_SCENE;
}
return assets::INVALID_ASSET_TYPE;
}
auto get_scene_deps(const std::string& /*packName*/, std::filesystem::path /*packRoot*/, assets::ResourceRecord& rr) -> bool {
auto nodes = YAML::LoadAllFromFile( rr.m_path );
for ( auto& node : nodes ) {
auto scripts = node["scripts"];
if ( !scripts ) {
continue;
}
for (auto script : scripts) {
auto scriptName = script.as<std::string>();
auto scriptRef = assets::asset_from_user(scriptName, rr.m_pack);
rr.m_requires.push_back(scriptRef);
}
}
return true;
}
auto ECS::factory(modules::ServiceName service, modules::Services &services) -> bool {
if (service == EntityFactory::service) {
auto *factory = services.create<EntityFactory>(services);
install_component_factories(factory);
// we are responsible for prefabs...
auto* assetLoader = services.get<assets::Loader>();
assetLoader->setFactory(PROTOTYPE_ASSET, [factory](const assets::AssetGUID& a, assets::AssetData b) {
return load_prototype(factory, a, b); }, assets::LoadType::PATH );
auto *assetLoader = services.get<assets::Loader>();
assetLoader->setFactory(ENTITY_PROTOTYPE, [factory](assets::Loader* loader, const assets::AssetID& a, assets::LoaderContext b, void* ptr) {
EntityFactory* facPtr = factory;
if ( ptr != nullptr ) {
facPtr = (EntityFactory*)ptr;
}
return load_prototype(loader, a, b, facPtr);
}, assets::LoadType::PATH);
assetLoader->setFactory(ENTITY_SCENE, load_scene, assets::LoadType::PATH);
// allow auto-detection
auto *checkin = services.get<assets::CheckinAdapted>();
checkin->setLoader(MIME_SCENE, assets::NEEDS_CHECKIN, is_scene);
checkin->setProcessor(MIME_SCENE, get_scene_deps);
return true;
}
......
# Sources
find_package( glfw3 REQUIRED )
find_package(glfw3 REQUIRED)
include(CMakePrintHelpers)
cmake_print_variables(GLFW_TARGETS)
......@@ -8,11 +8,11 @@ cmake_print_variables(GLFW_TARGETS)
target_link_libraries(fggl PUBLIC glfw fggl-glad)
target_sources(fggl
PRIVATE
window.cpp
input.cpp
PRIVATE
window.cpp
input.cpp
atlas.cpp
)
)
# OpenGL backend
add_subdirectory(ogl)
......
......@@ -14,10 +14,8 @@
#include <fggl/gfx/atlas.hpp>
#include <fggl/math/types.hpp>
#include <array>
#include <vector>
#include <string>
#define STBRP_STATIC
#define STB_RECT_PACK_IMPLEMENTATION
......@@ -25,57 +23,56 @@
using Query = std::vector<fggl::gfx::Bounds2D>;
static void populate_stbrp_query(Query& query, std::vector<stbrp_rect>& data) {
for ( std::size_t i = 0; i < query.size(); i++ ) {
data.push_back({
(int)i,
query[i].size.x,
query[i].size.y,
0,
0,
0
});
}
static void populate_stbrp_query(Query &query, std::vector<stbrp_rect> &data) {
for (std::size_t i = 0; i < query.size(); i++) {
data.push_back({
(int) i,
query[i].size.x,
query[i].size.y,
0,
0,
0
});
}
}
static void unpack_stbrp_query(Query& query, std::vector<stbrp_rect>& data) {
for( const auto& rect : data ) {
query[ rect.id ].pos = { rect.x, rect.y };
}
static void unpack_stbrp_query(Query &query, std::vector<stbrp_rect> &data) {
for (const auto &rect : data) {
query[rect.id].pos = {rect.x, rect.y};
}
}
bool pack_iter(int width, int height, std::vector<stbrp_rect>& query) {
stbrp_node* tmp = new stbrp_node[width];
auto pack_iter(int width, int height, std::vector<stbrp_rect> &query) -> bool {
auto *tmp = new stbrp_node[width];
// setup context
stbrp_context context;
stbrp_init_target( &context, width, height, tmp, width );
// setup context
stbrp_context context;
stbrp_init_target(&context, width, height, tmp, width);
// see if it worked
auto result = stbrp_pack_rects( &context, query.data(), query.size() );
return result == 1;
// see if it worked
auto result = stbrp_pack_rects(&context, query.data(), query.size());
return result == 1;
}
namespace fggl::gfx {
bool pack(std::vector<Bounds2D>& pack){
// setup query structure
std::vector<stbrp_rect> query;
query.reserve( pack.size() );
populate_stbrp_query(pack, query);
// try packing into powers of 2, starting with 32, up to 4096
for ( int i=5; i <= 12; i++ ) {
int dim = i * i;
if ( pack_iter(dim, dim, query) ) {
unpack_stbrp_query(pack, query);
return true;
}
}
return false;
}
auto pack(std::vector<Bounds2D> &pack) -> bool {
// setup query structure
std::vector<stbrp_rect> query;
query.reserve(pack.size());
populate_stbrp_query(pack, query);
// try packing into powers of 2, starting with 32, up to 4096
for (int i = 5; i <= 12; i++) {
int dim = i * i;
if (pack_iter(dim, dim, query)) {
unpack_stbrp_query(pack, query);
return true;
}
}
return false;
}
} // namespace fggl::gfx