Skip to content

Commit

Permalink
#575 add ability to access flecs::iter from each, add more C++ query …
Browse files Browse the repository at this point in the history
…examples
  • Loading branch information
SanderMertens committed Jan 8, 2022
1 parent 39ffd94 commit 36d0572
Show file tree
Hide file tree
Showing 25 changed files with 637 additions and 23 deletions.
16 changes: 16 additions & 0 deletions examples/cpp/queries/ad_hoc_query/include/ad_hoc_query.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef AD_HOC_QUERY_H
#define AD_HOC_QUERY_H

/* This generated file contains includes for project dependencies */
#include "ad_hoc_query/bake_config.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

#endif

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */

#ifndef AD_HOC_QUERY_BAKE_CONFIG_H
#define AD_HOC_QUERY_BAKE_CONFIG_H

/* Headers of public dependencies */
#include <flecs.h>

#endif

11 changes: 11 additions & 0 deletions examples/cpp/queries/ad_hoc_query/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "ad_hoc_query",
"type": "application",
"value": {
"use": [
"flecs"
],
"language": "c++",
"public": false
}
}
37 changes: 37 additions & 0 deletions examples/cpp/queries/ad_hoc_query/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <ad_hoc_query.h>
#include <iostream>

struct Position {
double x, y;
};

struct Velocity {
double x, y;
};

int main(int, char *[]) {
flecs::world ecs;

// Create a few test entities for a Position, Velocity query
ecs.entity("e1")
.set<Position>({10, 20})
.set<Velocity>({1, 2});

ecs.entity("e2")
.set<Position>({10, 20})
.set<Velocity>({3, 4});

// This entity will not match as it does not have Position, Velocity
ecs.entity("e3")
.set<Position>({10, 20});

// Ad hoc queries are bit slower to iterate than flecs::query, but are
// faster to create, and in most cases require no allocations. Under the
// hood this API uses flecs::filter, which can be used directly for more
// complex queries.
ecs.each([](flecs::entity e, Position& p, Velocity& v) {
p.x += v.x;
p.y += v.y;
std::cout << e.name() << ": {" << p.x << ", " << p.y << "}\n";
});
}
34 changes: 29 additions & 5 deletions examples/cpp/queries/basics/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,42 @@ int main(int, char *[]) {
ecs.entity("e3")
.set<Position>({10, 20});

// Iterate entities matching the query

// The next lines show the different ways in which a query can be iterated.
// Note how the 'const' qualifier matches the query template arguments.

// The each() function iterates each entity individually and accepts an
// entity argument plus arguments for each query component:
q.each([](flecs::entity e, Position& p, const Velocity& v) {
p.x += v.x;
p.y += v.y;
std::cout << e.name() << ": {" << p.x << ", " << p.y << "}\n";
});

// Ad hoc queries are bit slower to iterate than queries, but are faster to
// create as they don't require setting up a cache.
ecs.each([](flecs::entity e, Position& p, Velocity& v) {
// You can omit the flecs::entity argument if it's not needed:
q.each([](Position& p, const Velocity& v) {
p.x += v.x;
p.y += v.y;
std::cout << e.name() << ": {" << p.x << ", " << p.y << "}\n";
std::cout << "{" << p.x << ", " << p.y << "}\n";
});

// Each also accepts flecs::iter + index (for the iterated entity) arguemnts
// currently being iterated. A flecs::iter has lots of information on what
// is being iterated, which is demonstrated in the "iter" example.
q.each([](flecs::iter& it, size_t i, Position& p, const Velocity& v) {
p.x += v.x;
p.y += v.y;
std::cout << it.entity(i).name() << ": {" << p.x << ", " << p.y << "}\n";
});

// Iter is a bit more verbose, but allows for more control over how entities
// are iterated as it provides multiple entities in the same callback.
q.iter([](flecs::iter& it, Position *p, const Velocity *v) {
for (auto i : it) {
p[i].x += v[i].x;
p[i].y += v[i].y;
std::cout << it.entity(i).name() <<
": {" << p[i].x << ", " << p[i].y << "}\n";
}
});
}
16 changes: 16 additions & 0 deletions examples/cpp/queries/instancing/include/instancing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef INSTANCING_H
#define INSTANCING_H

/* This generated file contains includes for project dependencies */
#include "instancing/bake_config.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

#endif

24 changes: 24 additions & 0 deletions examples/cpp/queries/instancing/include/instancing/bake_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */

#ifndef INSTANCING_BAKE_CONFIG_H
#define INSTANCING_BAKE_CONFIG_H

/* Headers of public dependencies */
#include <flecs.h>

#endif

11 changes: 11 additions & 0 deletions examples/cpp/queries/instancing/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "instancing",
"type": "application",
"value": {
"use": [
"flecs"
],
"language": "c++",
"public": false
}
}
97 changes: 97 additions & 0 deletions examples/cpp/queries/instancing/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include <instancing.h>
#include <iostream>

/* Instancing is the ability of queries to iterate results with fields that have
* different numbers of elements. The term "instancing" is borrowed from
* graphics APIs, where it means reusing the same data for multiple "instances".
*
* Query instancing works in much the same way. By default queries match all
* components on the same entity. It is however possible to request data from
* other entities, like getting the Position from the entity's parent.
*
* Instancing refers to the ability of queries to iterate components for
* multiple entities while at the same time providing "instanced" components,
* which are always provided one element at a time.
*
* Instancing is often used in combination with parent-child relationships and
* prefabs, but is applicable to any kind of query where some of the terms are
* matched on N entities, and some on a single entity.
*
* By default queries are not instanced, which means that if a result contains
* mixed fields, entities will be iterated one by one instead of in batches.
* This is safer, as code doesn't have to do anything different for owned and
* shared fields, but does come at a performance penalty.
*
* The each() iterator function always uses an instanced iterator under the
* hood. This is transparent to the application, but improves performance. For
* this reason using each() can be faster than using uninstanced iter().
*/

struct Position {
double x, y;
};

struct Velocity {
double x, y;
};

int main(int, char *[]) {
flecs::world ecs;

// Create a query for Position, Velocity. We'll create a few entities that
// have Velocity as owned and shared component.
auto q = ecs.query_builder<Position, const Velocity>()
.arg(1).set(flecs::Self) // Ensure Position is never shared
.instanced() // create instanced query
.build();

// Create a prefab with Velocity. Prefabs are not matched with queries.
auto prefab = ecs.prefab("p")
.set<Velocity>({1, 2});

// Create a few entities that own Position & share Velocity from the prefab.
ecs.entity("e1").is_a(prefab)
.set<Position>({10, 20});

ecs.entity("e2").is_a(prefab)
.set<Position>({10, 20});

// Create a few entities that own all components
ecs.entity("e3")
.set<Position>({10, 20})
.set<Velocity>({3, 4});

ecs.entity("e4")
.set<Position>({10, 20})
.set<Velocity>({3, 4});


// Iterate the instanced query. Note how when a query is instanced, it needs
// to check whether a field is owned or not in order to know how to access
// it. In the case of an owned field it is iterated as an array, whereas
// in the case of a shared field, it is accessed as a pointer.
q.iter([](flecs::iter& it, Position *p, const Velocity *v) {

// Check if Velocity is owned, in which case it's accessed as array.
// Position will always be owned, since we set the term to Self.
if (it.is_owned(2)) { // Velocity is term 2
std::cout << "Velocity is owned" << std::endl;
for (auto i : it) {
p[i].x += v[i].x;
p[i].y += v[i].y;
std::cout << it.entity(i).name() <<
": {" << p[i].x << ", " << p[i].y << "}\n";
}

// If Velocity is shared, access the field as a pointer.
} else {
std::cout << "Velocity is shared" << std::endl;
for (auto i : it) {
p[i].x += v->x;
p[i].y += v->y;
std::cout << it.entity(i).name() <<
": {" << p[i].x << ", " << p[i].y << "}\n";
}
}
});
}
16 changes: 16 additions & 0 deletions examples/cpp/queries/iter/include/iter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef ITER_H
#define ITER_H

/* This generated file contains includes for project dependencies */
#include "iter/bake_config.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

#endif

24 changes: 24 additions & 0 deletions examples/cpp/queries/iter/include/iter/bake_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
)
(.)
.|.
| |
_.--| |--._
.-'; ;`-'& ; `&.
\ & ; & &_/
|"""---...---"""|
\ | | | | | | | /
`---.|.|.|.---'
* This file is generated by bake.lang.c for your convenience. Headers of
* dependencies will automatically show up in this file. Include bake_config.h
* in your main project file. Do not edit! */

#ifndef ITER_BAKE_CONFIG_H
#define ITER_BAKE_CONFIG_H

/* Headers of public dependencies */
#include <flecs.h>

#endif

11 changes: 11 additions & 0 deletions examples/cpp/queries/iter/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "iter",
"type": "application",
"value": {
"use": [
"flecs"
],
"language": "c++",
"public": false
}
}
Loading

0 comments on commit 36d0572

Please sign in to comment.