SDL_BlitSurface, dit "le fourbe".

C'est trop demandé de ne pas modifier un truc qu'on colle ?

Le problème exposé dans ce sujet a été résolu.

(Précision : ce message est aussi présent sur le forum C d'OC, ne faites pas les étonnés).

Salut!

A force de voir les débutants manipuler SDL en C++ comme on le ferait en C (alors que ce n'est pas safe dans le premier). Leur conseiller d'écrire un wrapper (ce qu'ils ne font pas bien entendu). Je me suis dit que coder moi-même le wrapper et le proposer en DL libre sur le forum, ça pourrait être une bonne idée (et un bon moyen de faire remarquer aux méchants débutants qu'ils sont inexcusables et voués à l'enfer, bref passons).

Il m'a semblé cohérent de décréter que ma classe SDL::Surface avait une sémantique d'entité (si vous ne savez pas ce qu'est une classe, vous pouvez passer au paragraphe suivant, ce n'est pas le coeur du problème, juste une discussion possible pour ceux qui verraient un problème côté conception). Et donc, qu'elle aurait un constructeur de copie / opérateur d'affectation par copie (elle possède également la move-semantic).

Or qui dit constructeur de copie, dit copie de la SDL::Surface, qui se doit d'être "const" en C++. Et c'est là que les problèmes arrivent.

Le moyen le plus simple de faire une copie d'une SDL_Surface (la structure C SDL), c'est de faire "création de la bonne taille + SDL_BlitSurface". Or, cette fonction prend en paramètre la surface source comme "non-const". Après quelques recherches, il s'avère que du point de vue de l'implémentation de SDL, c'est un choix voulu et assumé (on pourrait parler de sa justification d'un point de vue conception, m'enfin …).

Je me pose donc la question de ce qui serait le moins moche :

  • supprimer le "const" de la surface à coup de cast : cette méthode me plaît moyen, en particulier parce que le non-const est justifié, la structure interne de la surface source est réellement modifiée.
  • tempérer la solution précédente en utilisant un wrapping de la fonction de blit pour isoler au maximum de downcast, mais c'eest toujours pas très joli.
  • faire une deep-copy de la structure SDL_Surface : cette méthode me conviendrait mais les chances de faire une connerie sont monumentales, manipulation d'un void* + dimensions + pitch(?) + BytePerPixel, obligé de faire également une deep-copy du pixel format, etc …
  • une autre solution qui existe et que je n'ai pas vu ?*

(*) j'ai déjà regardé du côté de CreateRGBSurfaceFrom mais la lib ne fait pas de copie du pixel data donc ça veut dire une étape de manipulation supplémentaire et une implémentation différente au sein d'une même classe, cette solution est vraiment celle que je veux éviter à tout prix.

Bref. Des idées ?

Perso je ferais un downcast. SDL ne met pas de const, tu n'y peut rien. Profite en pour faire du propre. C'est ta lib qui assure ce passage là en te basant sur les infos que tu as de la SDL. Je vois pas trop ce que tu peux faire de mieux.

Justement c'est plus fort que ça, SDL ne met pas de const parce qu'il modifie effectivement la structure de la surface que l'on colle. La seule solution pour moi est de décréter que la partie modifiée (clip_rect si j'ai bien compris) ne fait pas partie de l'invariant de la classe.

Donc en gros, ça veut dire une très grosse phase de documentation histoire de savoir si c'est valide, tout ça pour l'encapsulation d'une seule fonction. Je dois admettre que ça m'enchante pas des masses ^^' , mais bon à la guerre comme à la guerre hein.

Je laisse encore le post ouvert quelque temps au cas où d'autres idées traîneraient.

Ha alors ça dépend de ton courage effectivement. En gros, si j'ai bien compris, il faut que tu arrive à savoir si ces champs auraient mérité un mutable ? Bonne chance ! Après si le but est d'aidé des débutant, je ne sais pas si ça vaut le coup d'aller jusque là, à toi de voir…

Le but n'est pas tant de fournir une aide que de fournir le wrapper déjà réalisé et quitte à faire un wrapper pour SDL, autant en faire un qui tienne la route (oui j'ai regardé les wrappers déjà existants).

Le mutable sauverait effectivement les meubles mais j'ai peur de désactiver beaucoup d'optis, du coup je vais me documenter plus ^^ .

Hum… sémantique d'entité copiable… tu cherches les ennuis ?

(pas vu ta discussion sur OCR)

Pa compris ta phrase de SDL::Surface qui doit être const. Dans quel contexte ? De quel const tu parles ? (ou alors, dans la phrase "Or qui dit constructeur de copie, dit copie de la SDL::Surface, qui se doit d'être "const" en C++. Et c'est là que les problèmes arrivent.", il fallait lire "SDL_Surface" ?) Tu as quelque chose comme ça ?

1
2
3
class Surface {
    SDL_Surface s;
};
+0 -0

Hum… sémantique d'entité copiable… tu cherches les ennuis ? ```

gbdivers

Faut que j'apprenne à relire mes posts plus consciencieusement, je voulais dire valeur bien sûr …

Pa compris ta phrase de SDL::Surface qui doit être const. Dans quel contexte ? De quel const tu parles ? (ou alors, dans la phrase "Or qui dit constructeur de copie, dit copie de la SDL::Surface, qui se doit d'être "const" en C++. Et c'est là que les problèmes arrivent.", il fallait lire "SDL_Surface" ?) Tu as quelque chose comme ça ?

1
2
3
class Surface {
    SDL_Surface s;
};

gbdivers

Plutôt comme ça :

1
2
3
4
5
6
7
namespace SDL{
class Surface{
private:
  SDL_Surface* sdl_s;

public:
  Surface(Surface const& s); //et c'est lui qui m'ennuie.

EDIT: Autant pour moi, j'avais oublié le truc pourri de la propagation de const avec les pointeurs … J'arrive pas à me l'ancrer ce truc, il est vraiment trop faible à mon goût. J'ai une autre erreur mais du coup c'est juste de l'utilisation.

C'est où le bouton pour "sujet résolu" ? O.o. Trouvé.

Je viens de lire le topique et quand j'ai lu :

Autant pour moi, j'avais oublié le truc pourri de la propagation de const avec les pointeurs

Je me suis dit "ah finalement il a fini par se rendre compte que son problème n'en est pas un" ^^

Sinon, tu peux toujours aller regarder la fonction SDL_ConvertSurface(). C'est ce que j'utilisais pour ma sur-couche de SDL_Surface dans mon Snake en C++ (je ne connaissais pas SFML et j'avais pas envie d'en prendre le temps).

+0 -0

A mes yeux, c'est un problème. Quand on met const à une fonction, on est assez content que le compilateur assure pour nous que l'invariant de la classe ne sera pas brisé, le problème c'est du coup sa sémantique dans C++ est trop faible pour exprimer ça, ici l'invariant qui nous intéresse c'est le contenu de la mémoire pointée, pas le pointeur. Du coup, il va falloir que je rajoute des checks d'invariant à la main (et ça me gonfle un peu).

J'ai fini par faire un blit en mode sale bourrin mais ça ne me plaît pas de masse, je vais jeter un oeil à convert.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte