mercredi 30 décembre 2020

Ça vole !

Bonne nouvelle en cette fin d'année, tous les simus de vol fonctionnent !

D'une part, le passage vers Vulkan de War Thunder s'est plutôt bien passé. Il m'a fallu quelques jours pour me rendre compte que mon setup avec steam qui tourne sur son propre compte et que j'execute avec un "xhost +" passe parfois mal avel Vulkan, et qu'il me faut simplement (?) me connecter directement en tant qu'utilisateur steam pour que ça passe. Après quelques bugs graphiques rapidement corrigés par les développeurs, tou marche vraiment au poil. Seul problème, je suis toujours aussi mauvais, mais ça n'est pas la faute au jeu.

Après pas mal de bidouilles, c'est DCS qui re-marche maintenant ! J'ai probablement souffert de la même histoire de comptes séparés avec Vulkan, et il y eut un épisode où le système de license ne passait pas, mais la dernière Beta, promue en version standard, fonctionne impeccable. J'ai pu reprendre les vols en Mirage 2000 et les décrochages en P-45 (en combat, je n'arrive pas à faire grand chose d'autre avec cet appareil, misère !). J'ai dû baisser les graphismes en moyen plutôt qu'élevé, mais la qualité demeure tout à fait correcte.

Finalement, X-Plane continue de fonctionner comme une horloge. Un peu trop, peut-être, ce qui explique mon engoument récent pour la simu militaire ! Et bien sûr, bloquer 2 heures sans interruption pour faire un vol commercial est toujours un peu compliqué, quand dans War Thunder je peux m'éclater (dans tous les sens du terme) en 2 minutes chrono. J'attends cependant avec intérêt les appareils qui devraient bientôt sorir, comme le Falcon 8X.

mercredi 2 décembre 2020

Du Blender pour comprendre les saisons et le mouvement du soleil dans le ciel

Parce qu'un petit croquis vaut mieux qu'un long discours, mais que certains croquis sont quand même plus faciles à saisir en 3D et avec des animations, j'ai créé un petit système terre-soleil pour montrer le mécanisme des saisons et le mouvement du soleil dans le ciel.

Après avoir rapidement créé une terre avec les textures de couleurs, bump et reflets trouvées ici, je l'ai installée penchée de 24.5° sur son axe, et j'ai installé une caméra à sa surface. Ensuite, on peut faire tourner pour voir comment le soleil l'éclaire. Fun, et très joli grace à Eevee qui permet d'avoir un très beau rendu en temps réel (même s'il faut tricher un peu et planquer une lumière dans le soeil).

dimanche 22 novembre 2020

War Thunder - C'est difficile, en fait !

Je continue à balancer du plomb (et parfois des bombes) dans War Thunder. J'essaie un peu tous les modes : le mode arcade, qui est juste un vieux bazar avec des avions partout, le mode réaliste avec des batailles un peu plus lentes et une tenue de l'avion plus réaliste, et enfin le mode simulation dans lequel on a plusieurs heures pour tenter de remplir le maximum d'objectifs et avec le contrôle de l'avion le plus manuel.

Je me pensais plutôt bon, car j'arrivais à allumer dans le mode arcade plusieurs avions à chaque fois, et me retrouver généralement dans le top 5. J'ai donc pris des niveaux et amélioré mes avions tout doucement, jusqu'à ce que le jeu me passe passer à un niveau de bataille supérieur... Et là, ça a été la catastrophe ! Je me suis fait exploser avec régularité, impossible de faire plus que quelques coups certainement pas critiques.

Alors, en mode arcade, la plupart des joueurs utilisent la souris en vue à la troisième personne, et se contentent de pointer vers l'indicateur de visée pour toucher à chaque fois, car l'avion est dans un mode semi-automatique où il va en gros là où on lui demande d'aller, tandis que je me bats avec mon bâton de joie, mon palonnier et ma manette des gaz depuis le cockpit virtuel. Forcément, ça n'aide pas.

Ensuite, j'ai choisi l'arbre français. Résultat, les avions ne sont pas tous terribles, et en particulier ont bien peu de munitions. Heureusement, je viens de débloquer le VG-33, qui est un petit bijou : rapide, avec plein de munitions, excellente maniabilité, on en veut. Il faut juste faire attention à ne pas se faire toucher, parce que c'est un avion en bois, et que le bois, ça n'arrête pas très bien les balles.

J'arrive également à m'amuser avec les bombardiers lourds : je monte bien haut, là où les chasseurs ne prendront pas la peine de venir me chercher, et je détruit les cibles au sol. Enfin, en théorie, parce que ma visée n'est pas très précises, et à 4000 mètres d'altitude, la bombe a le temps de bien se décaler...

Je vais m'accrocher et tenter de m'améliorer !

dimanche 15 novembre 2020

La bataille pour réinstaller Windows

J'avais posté sur LinuxFR il y a deux semaines mes mésaventures lorsque j'ai voulu réinstaller Windows sur un Dell portable. Depuis, j'ai découvert les joies de la XBox, en particulier la nécessité de payer un abonnement pour pouvoir jouer en ligne... Mais au moins, on arrête de se battre avec des jeux qui ne marchent qu'à moitié. Certes, parfois ça plante un peu, mais un redémarrage du jeu est suffisant pour que ça remarche.

J'ai donc découvert les joies de Roblox, et en particulier de Murder Mystery, j'ai un peu essayé Fortnite pour voir ce que font les djeunz de nos jours, sur chaude recommandation familiale j'ai acheté Overcooked 2, un petite jeu d'arcarde multijoueur dans lequel l'on incarne une équipe de cuistots qui doivent préparer des plats le plus rapidement possible, et War Thunder, que je venais juste de découvrir sur Steam grace à Ate. Puisque DCS World ne fonctionne plus sous Proton depuis des mois, c'est avec joie que je reprends la simulation de vol militaire, puisque War Thunder est natif Linux (hourra !). Bon, alors, des fois, il faut bien se battre un peu avec la ligne de commande pour que ça passe, mais ça passe. Petite préférence pour le PC pour la partie avions, parce qu'avec un HOTAS, c'est quand même autre chose, et la XBox pour la partie chars, parce que le pad. J'accroche bien sur la simu de vol, et je vais certainement avoir l'occasion d'en reparler.

mardi 6 octobre 2020

C++ 20 et modules

Ouh là là, c'est prise de tête ! J'ai tenté de comprendre comment fonctionnent les modules C++20, et c'est un vieux bazar. Pour comprendre toutes les subtilités de la fonctionnalité, je vous renvoie à l'excellent blog de vector<bool>, et en particulier aux articles suivants:

Lecture très saine, mais plutôt ardue. Je ne suis plus trop convaincu de l'intérêt de la fonctionnalité ! Les questions qui demeurent : comment est-ce que les systèmes de build vont traiter la chose ? Et au delà de la spécification touffue, quelle devrait être la doctrine d'utilisation ?

Pas d'expérimentations pour le moment, car gcc ne sait pas encore faire !

dimanche 4 octobre 2020

X-Plane - Une soirée de Brest à Orly

Petit vol tranquillou sur le Eclipse 550 NG entre Brest et Orly. Depuis la mise à jour de X-Plane pour utiliser Vulkan, c'est vraiment un plaisir que de voler parmi les nuages à plus de 30 images par seconde. L'arrivée sur Orly au crépuscule était de toute beauté, et j'ai posé l'appareil en douceur après avoir fait de mon mieux pour suivre les procédures.

mercredi 30 septembre 2020

Le comité C++ prend enfin les vrais problèmes à bras le corps !

J'avoue, il m'arrive parfois de me planter lamentablement et d'initialiser une std::string avec un pointeur null. Comme ça marche avec un char *, on ne fait pas attention, et hop !

std::string a(nullptr);

Le souci, c'est que c'est un comportement non défini. Dans la pratique, ça crashe. Mais ne craignez rien ! Cette proposition suggère la mise en place d'une surcharge supprimée prenant un nullptr:

constexpr basic_string(nullptr_t) = delete;

Simple, mais génial: quand on passe un pointeur null, c'est cette surcharge, meilleure, qui est choisie, et ensuite le compilo hurle parce que la méthode est supprimée. Alors certes, ça ne couvre pas le cas où l'on passe une variable pointeur initialisée à null, parce que le compilo, même s'il pouvait déduire à la compilation que le pointeur est nul, doit quand même choisir la surcharge char *. Mais ça couvre quand même tout un tas de cas stupides qui ne peuvent clairement pas marcher.

Je soutiens unilatéralement cette proposition, et j'espère qu'elle atterrira dans C++23 !

samedi 5 septembre 2020

Petit vol tranquille à Annecy

Il n'y a pas que Flight Simulator 2020 qui sait montrer de jolis décors ! En combinant X-Plane avec XEurope et une tuile Orthophoto, voici une plaisante soirée à Annecy.

jeudi 3 septembre 2020

Taylor Swift dans Blender - On se la retente

Je reprends mes tentatives de modéliser la chanteuse. C'est pas comme si on la reconnaissait du premier coup d'oeil, mais il faut bien démarrer quelque part. Je ne suis pas mécontent du nez, mais les joues sont peut-être un petit peu creuses. Par rapport à ma précédente tentative, je tente de faire l'ensemble du modèle d'une seule pièce. Il va donc falloir connecter ce cou aux épaules, et puis faire tout le reste... Et ne pas oublier les oreilles, sauf à lui faire une chevelure suffisamment touffue pour les cacher.

Ça ne sera pas à utiliser en gros plan, mais de loin, peut-être qu'il y aura quelque chose à en tirer.

vendredi 7 août 2020

C++17- variants, visiteurs, et duck typing

Je continue à m'amuser avec les visiteurs de variants, et je trouve d'autres manières de les utiliser. En particulier, il est possible de faire du duck typing, ou typage implicite, de manière très simple et très naturelle.

C'est à dire ? Eh bien, imaginez que vous ayez des objets qui ont des méthodes et des attributs en commun. Le duck typing, c'est de considérer une interface implicite avec ces méthodes et ces attributs. Ne pas avoir à créer une interface implicite, c'est en particulier la possibilité de travailler avec des objets que l'on ne contrôle pas (bibliothèques tierces, par exemple).

Voyons ça avec un petit exemple. Nous avons 3 classes, qui ont en commun la méthode makeNoise(), et l'on veut pouvoir les mettre dans une collection et appeler cette méthode. En programmation objet classique, l'on aurait une interface Noisy, par exemple, et l'on dériverait chaque classe de cette interface. Mais disons pour le besoin de l'exercice que ce n'est pas possible. Eh bien, collons les dans un variant, puis appelons la méthode makeNoise à l'aide d'un visiteur et d'une lambda générique. Et hop, ça marche !

#include <iostream>
#include <variant>
#include <vector>

class Duck
{
public:
  void walk()
  {
    std::cout << "Walk!" << std::endl;
  }
  
  void makeNoise()
  {
    std::cout << "Coin !" << std::endl;
  }
};

class Cat
{
public:
  void purr()
  {
    std::cout << "Rrrron, rrron" << std::endl;
  }
  
  void makeNoise()
  {
    std::cout << "Miaou !" << std::endl;
  }
};

class Dog
{
public:
  void moveTail()
  {
    std::cout << "Tail moving" << std::endl;
  }
  
  void makeNoise()
  {
    std::cout << "Ouaf !" << std::endl;
  }
};

int main()
{
  using AnimalsT = std::variant<Duck, Cat, Dog>;
  
  std::vector<AnimalsT> animals({Cat(), Dog(), Cat(), Duck()});

  for(auto && animal : animals)
  {
    std::visit([](auto && arg)
               {
                 arg.makeNoise();
               },
      animal);
  }
  
  return 0;
}

Le résultat est bien évidemment:

Miaou !
Ouaf !
Miaou !
Coin !

vendredi 31 juillet 2020

C++ 17 - De la magie avec std::visit et if constexpr

Le if constepr, voilà une fonctionnalité qu'elle est intéressante ! Elle permet en effet d'évaluer des conditions durant la phase de compilation, mais mieux, elle permet d'éviter la compilation des autres branches et donc du code qui sinon pourrait de pas compiler. C'est pas clair ? Voyons un exemple. Imaginons une fonction "increment" qui puisse prendre n'importe quel type numérique et l'incrémenter. On veut aussi que cela marche avec une chaîne, et dans ce cas il faut transformer la chaîne en entier, l'incrémenter, puis en refaire une chaîne. Bien sûr, la meilleure manière de faire est d'avoir une fonction template pour le cas général et une fonction prenant une std::string pour ce cas particulier, mais voyons quand même ce que cela donne.

En particulier, il est évident que ce code ne compile pas. En effet, inc(5) va provoquer une erreur de compilation dans la branche où on appelle std::stoi sur l'entier, et inc(std::string(8)) va provoquer une erreur dans la branche où on l'incrémente de 1.

#include <type_traits>
#include <string>
#include <iostream>

template<typename T>
T inc(T value)
{
  if(std::is_same_v<T, std::string>)
  {
    return std::to_string(std::stoi(value) + 1);
  }
  else
  {
    return value + 1;
  }
}

int main()
{
  std::cout << inc(5) << std::endl;
  std::cout << inc(std::string("8")) << std::endl;
  
  return 0;
}

Mais miracle, si l'on remplace notre if par un if constepr...

template<typename T>
T inc(T value)
{
  if constexpr(std::is_same_v<T, std::string>)
  {
    return std::to_string(std::stoi(value) + 1);
  }
  else
  {
    return value + 1;
  }
}

Alors ça compile gentiment ! À la compilation, la condition est évaluée, et le code non pertinent est simplement éliminé. Génial, non ?

Voici un exemple un peu plus utile. Nous avons un variant, et voulons en extraire n'importe quelle valeur arithmétique en la convertissant vers un double. Avec std::visit et if constexpr, c'est plutôt simple. Dans notre visiteur, nous pouvons directement vérifier si le type est arithmétique à l'aide d'un constexpr (sur le type decay, pour enlever les modificateurs constant et référence), et l'on peut ensuite utiliser directement le type. Sans le if constexpr, il aurait fallu créer une série de fonctions avec des std::enable_if de partout. C'est donc beaucoup, beaucoup mieux. Les if constexpr, c'est bon, mangez-en.

#include <type_traits>
#include <string>
#include <iostream>
#include <variant>

using VariantT = std::variant<std::string, int, double, unsigned short>;

bool getArithmeticValue(const VariantT & variant, double & value)
{
  return std::visit
    ([&value](auto && arg)
     {
       using T = std::decay_t<decltype(arg)>;
       if constexpr(std::is_arithmetic_v<T>)
       {
         value = static_cast<double>(arg);
         return true;
       }
       else
       {
         return false;
       }
     },
     variant);
}

int main()
{
  VariantT v1(std::string("abc"));
  VariantT v2(int(5));
  VariantT v3(double(2.3));

  double v = 0;
  std::cout << getArithmeticValue(v1, v) << std::endl;
  std::cout << getArithmeticValue(v2, v) << std::endl;
  std::cout << v << std::endl;
  std::cout << getArithmeticValue(v3, v) << std::endl;
  std::cout << v << std::endl;
  
  return 0;
}

samedi 25 juillet 2020

Minons les astéroïdes

Et on va dire que ça va aller ! Voici le rendu final de mon vaisseau spatial. J'ai rajouté une antenne, une rambarde, et basta !

jeudi 23 juillet 2020

X-plane 1.50 et A350 1.6 - Gros Beta !

Enfin, la Beta X-plane 1.50 fonctionne ! Et elle fonctionne même rudement bien. J'avais fini par comprendre que ce qui tuait les perfs, c'était la combinaison des nuages et de l'antialiasing. Donc j'avais le choix entre voler par ciel bleu, ou voir tous les pixels sur les bords de mon tableau du même nom. Et là, avec la 1.50 Beta, enfin, je peux combiner les deux, et atteindre entre 0 et 60 images par seconde avec l'antialias X8. Et qu'en plus, on a même pas besoin de redémarrer pour l'enclencher. Bonheur.

Alors, ce n'est pas encore parfait, et il y a quelques plantages et autres bugs d'affichage. Les avions tiers qui n'ont pas encore été mis à jour n'arrivent pas à afficher les écrans popup correctement. Mais ça va venir, et c'est extrêmement encourageant.

Toujours dans la série des Beta, j'ai mis à jour l'A350 de Flight Factor, et c'est la joie ! Enfin, des SID, des STAR, la gestion de la consommation de kérosène, le top of descent... Youpie ! Pour fêter ça, je me suis fait mon petit Orly / Toulouse habituel, mais il m'a fallu aller au plumard avant d'avoir eu le temps d'arriver. Mais ce n'est que partie remise. Transatlantiques, nous voilà !

mardi 14 juillet 2020

X-Plane - Quelques courses

Parce qu'il fallait bien profiter des soldes, je me suis lâché, et j'ai ajouté deux avions dans le hangar. Tout d'abord, le déjà classique A321 de Toliss, avec lequel je compte bien faire quelques procédures de panne moteur et autres joyeusetés (voir à ce sujet les excellents tutos de FalconEye), mais également du trans-atlantique: la variante LR de l'A321 peut faire jusqu'à 4000 nautiques, alors qu'un Paris New-York est légèrement au dessus des 3000 nautiques. Pour Los Angeles et pour Pékin, ce sera un peu plus tendu. Mais n'ayez crainte ! Flight Factor va sortir la mise à jour de son A350 sous peu.

Mais revenons à nos agneaux. Je tiens donc dans mes petites mains potelées l'Eclipse 550 NG, modélisé par Aerobask. C'est une très belle bête, qui se pilote gentiment, et qui a une avionique tout à fait intéressante en la personne du Garmin GTN 750, écran tactile, les plans de vol en deux coups de cuillère à pot, sympa. Histoire de coller à l'histoire et d'accompagner notre ex-Premier ministre, j'ai fait un petit vol depuis Le Bourget jusqu'à l'aéroport du Havre.

Voici donc la bête, en extérieur et en intérieur. Je sense que cet avion va remplacer le Cirrus Vision SF50 dans mon cœur pour les petits vols sans prétentions !

Manche et manette Airbus - Ils l'ont fait !

Contre toute attente (en tous cas la mienne !), Thrustmaster a sorti une réplique du manche et de la manette des gaz de l'Airbus A320. Apparemment, ça vient juste de sortir, c'est plutôt cool, et plutôt bien reçu par la communauté. Les revues du manche sur Youtube sont bonnes. La manette des gaz, ce n'est pas encore pour tout de suite car juste en précommande, mais elle est belle comme tout. L'ensemble semble viser le milieu de gamme et les simuleux faisant beaucoup de liner.

C'est intéressant de voir que ce genre de matos voit le jour maintenant. Je suppose que la venue très prochaine de Flight Simulator 2020 n'y est pas pour rien ! Ce n'est probablement pas suffisant pour me faire lâcher mon Warthog Hotas, qui ne joue pas dans la même gamme, mais c'est hyper tentant.

vendredi 3 juillet 2020

Minage d'astéroïdes

Mon vaisseau spatial de classe VERMINE, pour VÉhicule de Reconnaissance et MINage dans l'Espace, commence à prendre forme. Je me suis inspiré de bateaux cargos, et j'ai tenté d'ajouter une touche suffisamment spatiale à la chose, avec des gros moteurs fluo, et des antennes sur le toit. Le tout est beaucoup trop propre : je vais devoir travailler pour donner un aspect buriné à la chose.

Je me suis complètement lâché sur le "glare" (l'éblouissement ?), avec le bleu des moteurs et le blanc du reflet du soleil sur la coque qui provoquent de grands halos de lumière. Mais on est épique ou on ne l'est pas.

dimanche 21 juin 2020

Dans l'espace

Je suis d'une humeur très spatiale, ces temps-ci. Voici deux rendus, tout d'abord d'une planète de type Saturne, avec des anneaux de gaz et de roche, et ensuite d'un astéroïde construit sur le même modèle que ceux de l'anneau, mais avec plus de détails.

L’astéroïde est fait à partir d'un cube très lourdement subdivisé, auquel on a ajouté un modificateur "displace" avec une texture Voronoi. Tout d'abord, on créé une texture avec une taille assez élevée, afin d'avoir un objet avec pas trop d'arêtes, qui soit bien découpé. Ensuite, l'on peut ajouter des détails. Je trouve que le 4ème niveau de poids donne un effet particulièrement intéressant. Et finalement, on rajoute une texture normale avec un bête bruit très détaillé.

Pour le fond étoilé, voici mes nœuds "world". Je créé une texture de bruit très fine, que je passe à travers une color ramp pour ne garder que des points éparpillés. Voici mes étoiles. Ensuite, j'aimerais bien leur donner des couleurs différentes, alors je créé une autre texture de bruit, fine aussi, mais moins, histoire que des étoiles proches aient des teintes proches, parce que pourquoi pas, et je la passe à travers une color ramp qui contient toutes les teintes qui m'intéressent : du rouge, du jaune, du blanc, du bleu. Ensuite, je combine ces deux textures à travers un nœud "hue saturation value", pour utiliser les couleurs de la deuxième texture, mais avec la luminosité contrôlée par la première texture. Et voilà, des étoiles gentiment colorées !

Notez également dans la deuxième image, un "glare" assez fort, contrôlé via le compositeur, et qui donne un aspect "spatial". Les lumières sont fortes (100 000 W pour la lumière mon soleil) pour avoir de beaux contrastes.

L'on notera à quel point on peut faire de fort jolies choses avec Eevee : c'est typiquement le genre de scènes où ce moteur temps réel donne de très belles choses. En revanche, quelques tests d'animation montrent ses limites: avec une forme compliquée comme celle de mon astéroïde, les ombres sont finalement assez imprécises, ce qui n'est pas gênant pour une image seule, mais provoque des sauts intempestifs quand elles sont animées.

Maintenant, reste à améliorer les vaisseaux, et à animer le tout un minimum, histoire de profiter des jeux de lumière.

jeudi 11 juin 2020

C++14 - std::string_view veut jouer avec std::set

Petite expérience du matin (chagrin ?) : Comment faire un find sur un std::set en utilisant string_view ?

Revenons en arrière. Tout d'abord, qu'est-ce que std::string_view, et pourquoi voudrait-on l'utiliser pour faire un find ?

Vous avez peut-être remarqué que l'objet std::string est loin d'être gratuit. Non seulement les copies peuvent être chères (modulo COW et SSO, m'enfin bref), mais en plus le reste du monde conspire contre nous entre les chaînes codées en dur qui sont des const char *, et de nombreuses bibliothèques ne veulent pas en entendre parler. Voyez par exemple cette recherche dans un std::set : en passant un paramètre const char *, il se cache en fait la construction d'un objet std::string, et donc une allocation.

#include <set>
#include <string>
#include <iostream>

#include <stdlib.h>

int number_of_allocs = 0;

void* operator new(std::size_t size) {
  ++number_of_allocs;
  void *p = malloc(size);
  if(!p) throw std::bad_alloc();
  return p;
}

void* operator new  [](std::size_t size) {
  ++number_of_allocs;
  void *p = malloc(size);
  if(!p) throw std::bad_alloc();
  return p;
}

void* operator new  [](std::size_t size, const std::nothrow_t&) throw() {
  ++number_of_allocs;
  return malloc(size);
}
void* operator new   (std::size_t size, const std::nothrow_t&) throw() {
  ++number_of_allocs;
  return malloc(size);
}


void operator delete(void* ptr) throw() { free(ptr); }
void operator delete (void* ptr, const std::nothrow_t&) throw() { free(ptr); }
void operator delete[](void* ptr) throw() { free(ptr); }
void operator delete[](void* ptr, const std::nothrow_t&) throw() { free(ptr); }

int main()
{
  std::cout << number_of_allocs << std::endl;
  
  std::set<std::string> str({"a", "b", "c"});
  
  std::cout << number_of_allocs << std::endl;
  
  // Longue chaine pour éviter le SSO
  str.find("abceuhaoeuhaotuhaoutnohusaocamhamknomhucra,huh");
  
  std::cout << number_of_allocs << std::endl;

  return 0;
}

La punition est immédiate, le programme affiche 0, 3 et 4, parce que la chaîne dans le find a été convertie en std::string et a provoqué une allocation.

Si l'on s'amuse plutôt à passer un std::string_view, dans ce cas, le programme ne compile pas, car il n'y a pas de création implicite de std::string d'après une std::string_view.

  str.find(std::string_view("abceuhaoeuhaotuhaoutnohusaocamhamknomhucra,huh"));

Entre en scène la nouvelle surcharge de la fonction find, datant du C++14, qui prend un paramètre template qui doit être comparable avec une clé "de manière transparente", sans conversion nécessaire. Ah ah! Pile ce qu'il nous faut. Il faut juste donner au std::set un comparateur transparent, comme std::less, et cela fonctionne.

[...]
int main()
{
  std::cout << number_of_allocs << std::endl;
  
  std::set<std::string, std::less<> > str({"a", "b", "c"});
  
  std::cout << number_of_allocs << std::endl;
  
  str.find(std::string_view("abceuhaoeuhaotuhaoutnohusaocamhamknomhucra,huh"));
  
  std::cout << number_of_allocs << std::endl;

  return 0;
}

Victoire, le programme affiche 0, 3, 3, et a donc économisé l'allocation ! Mieux encore, la version où l'on passe juste la chaîne en const char * a également économisé son allocation, le std::string_view n'étant là que pour empêcher la conversion implicite.

Première conclusion : ajoutez des std::less<> à vos std::set et std::map prenant des chaînes !

Deuxième conclusion : pensez à creer un comparateur manuel si vous faites ce genre de magie avec vos propres objets

Troisème conclusion : passez à C++20 pour faire la même chose avec std::unordered_set et std::unordered_map. Je vous en recauserai peut-être quand j'aurai mis à jour mon compilo.

Références:
https://en.cppreference.com/w/cpp/string/basic_string_view
https://en.cppreference.com/w/cpp/container/unordered_set/find
https://stackoverflow.com/questions/9927856/how-to-use-operator-new-to-count-number-of-times-of-dynamic-memory-allocation
https://stackoverflow.com/questions/35525777/use-of-string-view-for-map-lookup

jeudi 7 mai 2020

Lanternes en vidéo

Une lanterne posée sur le sol, c'est rigolo, mais une lanterne qui tombe du plafond, c'est encore mieux ! Voici un rendu rapide (enfin, c'était la modélisation qui était rapide, le rendu, lui, a quand même pris 6 heures) de la lanterne du post précédent qui chute et rebondit sur le sol. Il a suffi de laisser faire le moteur physique de Blender, et le tour était joué. On admirera les effets de lumière sur le sol quand la lanterne le percute.

Une lanterne

Petite scène rapide avec une lanterne. C'était finalement beaucoup plus facile que prévu : simplement se mettre une petite loupiote dans le cube (aïe !) et utiliser pour le cube un shader translucide coloré. Le tour est joué !

Il y a probablement moyen d'en faire une vidéo...

dimanche 3 mai 2020

Ça y'est, j'ai mis le truc dans le machin !

C'était sport, mais j'ai enfin réussi à ravitailler en vol avec DCS World et le Mirage 2000 ! Comme quoi, l'entraînement finit par porter ses fruits. Les trucs qui m'ont bien aidé :

  • Le trim ! Quand l'avion est bien trimé horizontalement, les corrections sur le manche se font à peu près autour de la zone neutre, ce qui est bien plus reposant pour le bras, et semble plus intuitif.
  • Gérer sa manette des gaz en pompant autour d'un point d'équilibre correspondant à peu près à la vitesse cible. Pour accélérer, ajouter un filet de gaz, puis revenir au point d'équilibre. Pour ralentir, réduire un peu puis remettre les gaz. Cela aide à garder un petit différentiel de vitesse, et accessoirement à éviter de se prendre un réacteur en pleine poire.

Dans la petite dizaine de secondes pendant laquelle j'ai réussi à rester connecter, j'ai pu pomper environ 400 kg de fuel, ce qui est vachement généreux de la part de DCS. Dans la réalité, c'est plutôt 10 minutes pour faire le plein, et rester stable tout ce temps me semble bien au dessus de mes forces !

mercredi 29 avril 2020

Inverse kinematics et tourelle de tank

Petite démo d'une simulation inverse kinematics pour préparer ma tourelle de tank. Par rapport à mes précédents essais, j'ai ajouté des contraintes de rotation afin que la tourelle ne puisse que tourner sur l'axe Z, tandis que le canon est limité a 40° dans l'axe Y. Je peux ensuite animer l'ensemble à l'aide d'une contrainte IK qui va faire pointer le canon vers un os (que je fais marcher sur un chemin). Le résultat, une belle (enfin, une moche) tourelle !

Prochaine étape : lui faire tirer des projectiles.

lundi 27 avril 2020

Encore 7 jours pour essayer tout un tas de modules gratuits sur DCS World

Depuis 1 semaine, DCS propose la plus grande partie de ses modules gratuitement, pour 2 semaines (ce qui nous laisse donc 1 semaine, si mes calculs sont justes). C'est l'occasion de tester tout un tas de modules pour lesquels on n'aurait pas forcément cassé sa tirelire, mais également pour la petite minorité qui fait tourner DCS sous Linux de vérifier si le module fonctionne avant de l'acheter.

J'avais donc l’œil fermement dirigé vers le JF-17, apparemment particulièrement bien modélisé, et je me suis empressé de le télécharger. Petite déception: autant l'avion fonctionne impeccable, autant j'ai chez moi des freezes systématiques dès que je veux quitter la mission, ce qui est un petit peu gonflant. Exit donc le JF-17.

Je zieutais également la carte Normandie, malgré des avis plutôt mitigés, histoire de donner un peu vie au P-51D. Là encore, déception : non seulement la carte (vendue 8 balles) ne suffit pas car il faut également le pack WW2 (hop, 25 balles supplémentaires), mais surtout, chez moi encore (ne généralisons pas!), impossible de charger la carte au sein du jeu, j'ai un freeze. Exit donc la carte Normandie, comme quoi j'ai bien fait d'essayer avant d'acheter.

Un autre module que je voulais essayer, c'est le FW-109, avion de la 2ème guerre mondiale, côté Allemand. Une fois passé la gêne de combattre pour les Nazis, le fait est que c'est un très bel avion, probablement bien plus aisé à prendre en main que le Mustang, ce qui ne m'empêche pas par ailleurs de me faire descendre en moins de 2. Belle bête donc, mais Nazi + 40 balles = grosse hésitation quand j'ai déjà le Mustang pour jouer. Ceci dit, pour quelqu'un qui n'aurait pas encore de warbird mais qui voudrait en faire, très bonne option.

Avec également des problèmes de chargement au niveau de l'A-10 et du F-16, c'est finalement assez décevant ! J'ai l'impression d'avoir eu beaucoup de chance que les modules que j'ai achetés sans avoir testé avant, soit le M-2000, le F-18 et le P-51D, fonctionnent très bien.

vendredi 17 avril 2020

Animation d'un tank dans Blender

Voici un sujet qui a fait couler beaucoup d'encre virtuelle ! Si animer une chenille dans une seule direction est quelque chose de relativement aisé, cela devient incroyablement plus complexe lorsqu'il s'agit de permettre le déplacement dans n'importe quelle direction, avec en plus la gestion du différentiel lors des rotations. Ce tutoriel reprend les techniques de base d'animation des chenilles, alors que celui là propose carrément de simuler une chenille en utilisant le moteur physique !

C'est finalement une approche de suivi de chemin décrite dans le premier tutoriel que j'ai sélectionnée. Ça marche plutôt pas mal, même si cela ne gère pas le différentiel entre les chenilles gauche et droite. Ceci dit, je suppose qu'il doit être possible d'ajuster le driver pour prendre en compte cette rotation. Ça reste un fudge, mais cela devrait être amplement suffisant pour ce que je vais en faire.

mercredi 15 avril 2020

DCS - Faire fonctionner les interrupteurs du Warthog Hotas - Un exemple avec le P-51D

C'est pas tout d'avoir tout plein de boutons sur la manette, mais encore faut-il pouvoir s'en servir !

La principale difficulté avec la manette du Warthog Hotas est de configurer correctement les interrupteurs à 2 ou 3 positions. En effet, contrairement à un bouton que l'on pousse, et qui envoie une impulsion, les interrupteurs sont soit en position fermée, et alors ils envoient un signal continu, ou en position ouverte, et ils n'envoient pas de signal. Sans configuration spécifique, cela donne de drôles de choses, comme par exemple de devoir pousser et tirer pour activer un système, et de pousser et tirer encore une fois pour le désactiver. Or, ce qu'on veut, c'est activer en poussant, et désactiver en tirant.

Ça tombe bien, parce que DCS World sait faire. Avec le mythique P-51D par exemple, il existe d'excellents bindings, comme celui là par exemple, mais souvent soit ils ne fonctionnent pas sur les versions plus récentes de DCS World, soit ils se basent sur le logiciel de configuration du Warthog TARGET, qui ne tourne pas sous Linux et dont j'aimerais donc me passer.

Heureusement, il existe un (très) long thread qui explique exactement comment faire pour configurer tout ça manuellement. Et pour s'y retrouver, vous n'aurez même pas besoin de tout lire ! En effet, un commentateur a eu la bonne idée de créer un PDF qui explique tout, et qui est disponible sur ce post.

L'approche est vraiment la plus agréable: tout comme certains modules (par exemple le Mirage 2000) fournissent de nombreuses commandes du type "machin ON else OFF" qui réagissent très bien avec les interrupteurs du HOTAS (ou du 3M comme un dit en français), l'idée est d'ajouter nos propres "machin ON else OFF" afin de les retrouver dans le menu de configuration des commandes et de pouvoir y lier des interrupteurs.

Il faut donc aller modifier le fichier "default.lua" situé dans le sous-répertoire Input/.../Joystick de votre module (pour le P51-D, par exemple, il est situé dans Mods/aircraft/P-51D/Input/P-51D/joystick). Dans ce fichier, il faut retrouver les commandes qui nous intéresse, et créer une nouvelle version de ces commandes, avec un nouveau nom (par exemple en rajoutant le ON else OFF) et peut-être bien une nouvelle catégorie (je mets tout dans "Custom" histoire de m'y retrouver ensuite). Voici par exemple les lignes que j'ai rajouté:

{down = device_commands.Button_11, up = device_commands.Button_11, cockpit_device_id  = devices.ENGINE_SYSTEM, value_down = 0.0, value_up = 0.1, name = _('Mixture IDLE CUT OFF else RUN'), category = _('Custom')},
{down = device_commands.Button_11, up = device_commands.Button_11, cockpit_device_id  = devices.ENGINE_SYSTEM, value_down = 0.2, value_up = 0.1, name = _('Mixture EMERGENCY FULL RICH else RUN'), category = _('Custom')},
{down = device_commands.Button_8, up = device_commands.Button_8, cockpit_device_id  = devices.K14_GUNSIGHT, value_down = 1.0, value_up = 0.0,  name = _('Gunsight gyromotor power ON else OFF'), category = _('Custom')},
{down = device_commands.Button_7, up = device_commands.Button_7, cockpit_device_id  = devices.FRONT_SWITCH_BOX, value_down = 1.0, value_up = 0.0, name = _('Gun safety switch GUN CAMERA SIGHT else OFF'), category = _('Custom')},
{down = device_commands.Button_2, up = device_commands.Button_2, cockpit_device_id  = devices.FRONT_SWITCH_BOX, value_down = 0.3, value_up = 0.0,  name = _('Ignition switch BOTH else OFF'), category = _('Custom')},
{down = device_commands.Button_11, up = device_commands.Button_11, cockpit_device_id  = devices.FRONT_SWITCH_BOX, value_down = 0.3, value_up = 0.0, name = _('Bomb-rocket selector switch ROCKETS else SAFE'), category = _('Custom')},
{down = device_commands.Button_11, up = device_commands.Button_11, cockpit_device_id  = devices.FRONT_SWITCH_BOX, value_down = 0.2, value_up = 0.0, name = _('Bomb-rocket selector switch BOTH else SAFE'), category = _('Custom')},
{down = device_commands.Button_7, up = device_commands.Button_7, cockpit_device_id  = devices.WEAPON_CONTROL, value_down = 0.0, value_up = 0.1, name = _('Rockets release control switch OFF else SINGLE'), category = _('Custom')},
{down = device_commands.Button_7, up = device_commands.Button_7, cockpit_device_id  = devices.WEAPON_CONTROL, value_down = 0.2, value_up = 0.1, name = _('Rockets release control switch AUTO else SINGLE'), category = _('Custom')},
{down = device_commands.Button_12, up = device_commands.Button_12, cockpit_device_id = devices.ENGINE_CONTROL_PANEL, value_down = 1.0, value_up = 0.0, name = _('Fuel Booster ON else OFF'), category = _('Custom')},
{down = device_commands.Button_10, up = device_commands.Button_10, cockpit_device_id  = devices.ENGINE_CONTROL_PANEL, value_down = 1.0, value_up = 0.0, name = _('Starter Switch Cover Close else Open'), category = _('Custom')},
{down = device_commands.Button_3, up = device_commands.Button_3, cockpit_device_id  = devices.FUEL_SYSTEM, value_down = 1.0, value_up = 0.0, name = _('Fuel shut-off valve ON else OFF'), category = _('Custom')},

Prenons par exemple le plus simple, le "Gunsight gyromotor". J'ai simplement recopié la ligne du gyromotor, ajouté un up = device_commands.Button_8, un value_up = 0.0 pour indiquer que je veux retourner à la valeur 0.0 (c'est à dire off) lorsque l'interrupteur repasse à zéro, et j'ai changé le nom et la catégorie. Ensuite, au sein du jeu, je peux voir dans la configuration des commandes une nouvelle catégorie ("Custom", ou "Personnalisé" car il semble que j'ai choisi une catégorie pour laquelle il a une traduction), mon nouveau "Gunsight gyromotor power ON else OFF". Je le lie à l'interrupteur qui va bien, et youpie, on a un interrupteur qui fonctionne !

C'est parfois un poil plus compliqué pour d'autres commandes, pour lesquelles il va falloir retrouver la bonne valeur pour le value_down en s'inspirant des autres commandes déjà fournies, mais dans l'ensemble ça se fait très bien.

Je n'ai plus qu'à faire une nouvelle plaque laminée pour le P-51D !

vendredi 13 mars 2020

DCS - Ravitaillement en vol

Cela fait plus d'une semaine que je passe une partie de mes soirées à tenter de faire un ravitaillement en vol en Mirage-2000 dans DCS. Quelle plaie !

C'est vraiment difficile : l'approche vers l'avion ravitailleur se passe plutôt bien, j'arrive à être à peu près stable à quelques mètres du panier, mais alors, pour finaliser, il n'y a plus personne. La difficulté est que chaque action sur les commandes modifie plusieurs paramètres : l'on approche par exemple un poil bas du panier, alors on tire sur le manche, mais cela ralentit. On donne un poil de gaz, et pouf, on se retrouve au dessus et devant l'avion. Non seulement ça se joue au pouillème, mais en plus il faut apprendre a coordonner le manche, la manette et le palonnier d'une manière plutôt contre-intuitive pour aller viser dans le panier à 10 centimètres près.

Ça me rend complètement fou.

vendredi 21 février 2020

Tacview, DCS World et Linux

Il ne m'a pas fallu beaucoup de temps à faire du combat air/air dans DCS World pour comprendre l'intérêt de l'outil Tacview. En effet, lorsque l'on commence à comprendre les tactiques d'approche et d'évitement, on aimerait bien comprendre comment on a pu se faire dégommer par ce missile venu de nulle part. L'approche de Tacview est de fournir un petit plugin à DCS World (et X-Plane, et de nombreux autres softs de simu aérienne) qui enregistre les paramètres du vol, et qui permet de les rejouer dans leur interface, et donc d'observer manœuvres, départ (et arrivée !) de missiles, et ainsi de suite.

Maintenant, Tacview, c'est Windows-only. Mais de nos jours, Windows-only, c'est tout relatif. Alors, je n'avais pas spécialement envie de me lancer dans une complexe configuration de Wine, mais heureusement, Tacview est disponible directement dans Steam, et on peut donc laisser Steamplay faire sa magie (qui consiste, comme nous le verrons plus tard, à créer pour chaque application une espèce de chroot Windows minimal avec ses dépendances).

Tacview ayant démarré comme un grand, reste encore à enregistrer ses vols DCS World. Normalement, l'installeur trouve DCS World et copie les scripts au bon endroit, mais là, il est dans sa petite chroot Windows. Il faut donc copier manuellement les scripts. C'est expliqué sur le site Tacview, il faut donc l'adapter à ProtonDB. Il suffit de faire ceci, depuis la racine de son répertoire home (en supposant que c'est là qu'est le répertoire .steam qui contient les jeux) :

cp ~/.steam/steam/steamapps/common/Tacview/DCS/* ~/steam/steamapps/compatdata/223750/pfx/drive_c/users/steamuser/Saved\ Games/DCS/

Alors, qu'est ce que ça fait ? Ça copie le plugin DCS dans la chroot Windows (certains parlent de préfixe) de DCS World, le numéro magique, 223750, étant l'ID de l'application DCS World. Et là, en démarrant DCS World, on voit bien le plugin dans les options spéciales. Tout va bien !

Après un petit vol, on peut vérifier l'existence d'un fichier .acmi dans le répertoire "~/.steam/steam/steamapps/compatdata/223750/pfx/drive_c/users/steamuser/My Documents/Tacview", qui est donc dans le "My documents" du préfixe de DCS World. Sauf que forcément, depuis Tacview, on ne voit rien (puisque lui est dans son propre préfixe. Faut suive !). Une solution simple consiste simplement à faire un lien symbolique Tacview. Par exemple:

cd "~/.steam/steam/steamapps/compatdata/1174860/pfx/drive_c/users/steamuser/My Documents/Tacview"

ln -n "~/.steam/steam/steamapps/compatdata/223750/pfx/drive_c/users/steamuser/My Documents/Tacview" DCS

Et là, depuis Tacview, l'on peut charger un fichier, aller dans "My documents", puis dans le répertoire Tacview, puis dans le répertoire DCS, et hop, les vols sont là !

mercredi 29 janvier 2020

Plaque low-cost pour Warthog Hotas - Partie 2

Voilà, voilà, c'est fait, et c'est moins pire que je ne pensais ! Il a fallu se battre un peu avec la lamination à froid, qui n'adhère que d'un côté, mais je m'en suis sorti, et c'est plutôt utilisable.

lundi 20 janvier 2020

Plaque low-cost pour Warthog Hotas

Le souci, lorsque l'on a autant de boutons sur ses manettes, c'est de ne plus savoir ce qu'ils contrôlent. Alors afin de s'en souvenir (et aussi de faire joli !), de grands cinglés créent leurs propres plaques à poser par dessus leur manette des gaz, et cela donne des choses vraiment jolies. Pour des jeux plus grand public, comme Elite Dangerous, c'est carrément un business !

Ces plaques là, très pro, sont faites avec des plaques acryliques ou encore métalliques. Mais est-ce qu'on peut faire quelque chose à bas coût avec du matériel un peu plus standard ? C'est ce que j'essaie de découvrir.

Mon plan : imprimer sur papier simple ou légèrement cartonné, à partir des patrons de Arrowdynamixx fournis sur le forum X-Plane, mes propres plaques adaptées à chacun de mes avions favoris. Les laminer ensuite à froid, et basta, on devrait avoir quelque chose de raisonnablement solide et joli sans avoir besoin d'outillage spécialisé.

Ma première étape fut d'imprimer un patron représentant juste les contours, puis de le découper pour vérifier que la taille est correcte, et enfin choisir les fonctions de chaque bouton pour les rajouter au crayon à papier. Voici donc mon patron pour le Cirrus SF-50, le petit mono-réacteur fourni de base sur X-Plane.

Malheureusement, le papier trop fin laisse passer l'affichage luminescent. Il faudra donc soit utiliser un papier plus épais (à voir comment mon imprimante va le prendre), ou trouver comment éteindre les LED de la manette sous Linux (apparemment, il y a une astuce).

Prochaine étape, faire la plaque au propre avec Inkscape, puis faire l'impression et le laminage. Si cela fonctionne comme attendu, il ne me restera plus alors qu'à créer les plaques pour mes autres avions favoris : A320, A350, Diamond DA62, peut-être le Boeing 737, et peut-être bien également le Mirage 2000 de DCS World.

samedi 4 janvier 2020

Warthog HOTAS

C'est l'événement de ce début d'année, le Père Noël ayant été généreux, je suis maintenant l'heureux possesseur d'un Warthog HOTAS (pour "hands on throttle and stick", c'est à dire un joystick et une manette des gaz) et d'un palonnier TFRP. Et ça change la vie, aussi bien dans X-Plane que dans DCS World (et aussi dans Kerbal Space Program, mais on y reviendra).

Le HOTAS est de toute beauté, bien lourd, avec tout plein de boutons partout pour tout configurer comme on a envie. La manette des gaz vient avec deux poignées pour les gaz, un axe supplémentaire bien pratique pour les volets, et tout un tas de boutons que j'ai configuré dans X-Plane pour les trains d'atterrissage, le frein de parc, l'ouverture de la verrière (fun !), ou encore l'inversion de poussée des réacteurs et l'armement des aérofreins.

Le joystick, lui, monté sur une énorme plaque de métal, ne bougera pas. Muni d'un nombre impressionnant de boutons et de chapeaux, réplique du véritable A-10 oblige, on le sent bien dans la main et c'est un plaisir de faire les atterrissages manuels de gros porteurs.

Le palonnier, lui, est nettement moins impressionnant (mais nettement moins cher aussi). J'ai longuement hésité entre cet entrée de gamme et d'autres beaucoup plus sérieux, comme le MFG Crosswind, ou encore le Slaw Device, mais mon choix se confirme comme étant le bon: à moins de faire de l'hélico, là où la précision des pédales est fondamentale, ou beaucoup de GA (general aviation, c'est à dire pas de l'avion de ligne), c'est vraiment overkill. Pour gérer quelques virages avant et après la phase en pilote automatique, et pour le roulage, c'est amplement suffisant, surtout si l'on contrôle la roulette de nez avec la molette située sur la manette des gaz (qui manque cependant de précision, probablement le seul point noir de la manette).

Reste qu'il faut passer du temps à configurer tout ça. En particulier, il est à noter que les boutons métalliques à deux ou trois états ont généralement un état de moins: c'est à dire que l'enclencher correspond à une pression de bouton, et le dés-enclencher correspond au relâchement du bouton. Ce qui veut dire que si vous mettez, par exemple, la montée du train d'atterrissage sur la position haute, vous n'avez par défaut pas de position basse dans l'interface X-plane, par exemple, pour y configurer la descente du train d'atterrissage.

La solution officielle est d'utiliser le logiciel de configuration fourni par Thrustmaster, qui ne fonctionne que sous Windows. Heureusement pour nous autres Linuxiens, X-Plane comme DCS World proposent des fichiers de configuration supplémentaires pour créer des boutons virtuels correspondant aux positions relâchées de tous les boutons (voir les explications ici). Dans X-Plane version 1.41, le fichier pour Linux (HOTAS Warthog Throttle - Linux.joy) est incomplet, et il faut le compléter avec le fichier pour Windows (Joystick - HOTAS Warthog - Windows.joy). J'ai donc gardé l'en tête du premier, puis le corps du deuxième, et tout marche impeccable (à part un échange des axes gaz et volets, mais c'est bénin).

J'ai maintenant hâte de continuer à configurer mon HOTAS aux petits oignons pour X-Plane, et de commencer sérieusement à l'utiliser avec DCS World. Quant à Kerbal Space Program, les problèmes de contrôleurs sous Linux semblant avoir été résolus, ce sera l'occasion de tester en profondeur.

vendredi 3 janvier 2020

Bonne année !

Je vous souhaite à toutes et à tous une excellente année 2020, pleine de bonnes choses !

Petite année pour le blog, avec un minimum historique de 17 messages. J'étais bien parti, et puis la fin de l'année ayant apporté pas mal de changements, j'ai complètement oublié de venir vous causer. Je n'ai plus qu'à prendre une nouvelle fois la résolution d'être un peu plus loquace. Restez branché !