Evolutions du moteur 3D soft

20. juin 2009

Je viens de rajouter la gestion d’une source lumineuse à mon moteur 3D soft.

Notre modèle objet est donc composé des entités suivantes:

  • Scene
  • Objet
  • Camera
  • Light

La scène est composée d’une liste d’objets, d’une lumière et d’une caméra active.

Un objet est composé d’une liste de vertices (des points 3D) et de faces. Chaque face est responsable de son rendu.

Pour optimiser un peu tout ça, j’ai rajouté une classe qui simule les buffers de travail dans une image (la classe UnsafeBitmap).

La prochaine étape va être d’accèlerer le rendu en refaisant l’algorithme de remplissage de faces (rastérisation).

Tout ceci se trouve ici.

3D, .Net, Win32, Windows

Support de plus de 3Go de RAM sous Vista 32 bits

10. janvier 2009

Je viens tout juste d’installer Windows 7 (build 7000) sur ma machine. C’est vraiment un OS très prometteur qui risque bien de nous faire oublier les désagréments de Vista.

Un truc qui m’a intrigué (parmi tant d’autres) est le support direct des 4Go de RAM de ma machine.

Hélas, Visual Studio 2008 marche pour l’instant très mal sous Windows 7.

Retour donc sous Vista.

Cette histoire de 4Go m’a toutefois chiffonné. Sous Vista de base, mon système me donnait 3Go de dispo alors que sous Vista SP1 j’avais bien 4Go.

Après une petite enquête il s’avère que Vista ne donne accès aux processus qu’à 3,12 Go (c’est précis) car il faut savoir que le matériel utilise un peu de la mémoire physique pour travailler (mapping de certains ressources comme la carte son, carte graphique, etc…).

Heureusement, il existe une technique toute bête pour demander à Vista de ne plus se limiter à 3,x Go (avec un maximum a 4Go de toute manière).

Il suffit pour cela de lancer une console en mode administrator et de taper la commande suivante:

BCDEdit /set PAE forceenable

Le mode PAE est un mode étendu des processeurs x86 qui permet d’avoir un adressage sur 36 bits (contre 32 normalement). Ceci permet donc théoriquement d’avoir 64Go de RAM.

Toutefois sous Vista 32 bits cela permettra uniquement d’avoir droit à 4Go (dans l’absolu bien sûr) par processus.

On pourrait alors se demander pourquoi Microsoft n’active pas par défaut ce mode? Tout simplement parce que finalement ca ne sert à rien. Le matériel va continuer à prendre sa place, donc on ne disposera finalement que de 3,x Go et la gestion de l’adressage en 36bits plutôt qu’en 32bits ralentit le système.

Win32, Windows

Interop Win32 avec le Cross Fade Control

9. décembre 2008

Lors d'une super session à la PDC 2008, j'ai découvert une API Win32 utilisée dans la gestion des styles visuels nommée BufferedPaintRenderAnimation. Cette dernière est notamment utilisée dans les boutons sur Vista pour faire l'effet de fondu.

Je vous propose donc ici un petit contrôle .Net qui encapsule ce service:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class CrossFadeControl : Control
    {
        public enum FadeDirection
        {
            SourceDestination,
            DestinationSource
        }

        enum BP_ANIMATIONSTYLE
        {
            BPAS_NONE,
            BPAS_LINEAR,
            BPAS_CUBIC,
            BPAS_SINE
        }

        enum BP_BUFFERFORMAT
        {
            BPBF_COMPATIBLEBITMAP,
            BPBF_DIB,
            BPBF_TOPDOWNDIB,
            BPBF_TOPDOWNMONODIB
        }

        [StructLayout(LayoutKind.Sequential)]
        struct BP_ANIMATIONPARAMS
        {
            public int cbSize;
            public int dwFlags;
            public BP_ANIMATIONSTYLE style;
            public int dwDuration;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct BP_PAINTPARAMS
        {
            int cbSize;
            int dwFlags;
            IntPtr prcExclude;
            IntPtr pBlendFunction;
        }

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintInit();

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintUnInit();

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintRenderAnimation(IntPtr hWnd, IntPtr hDc);

        [DllImport("uxtheme.dll")]
        extern static IntPtr BeginBufferedAnimation(IntPtr hwnd, IntPtr hdcTarget, 
            ref Rectangle rcTarget,
            BP_BUFFERFORMAT dwFormat, IntPtr pPaintParams, ref BP_ANIMATIONPARAMS pAnimationParams,
            out IntPtr phdcFrom,
            out IntPtr phdcTo);

        [DllImport("uxtheme.dll")]
        extern static int EndBufferedAnimation(IntPtr hbpAnimation, bool fUpdateTarget);

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintStopAllAnimations(IntPtr handle);

        int animDuration = 0;
        int targetAnimationDuration = 500;
        Image source;
        Image destination;
        FadeDirection direction;

        public FadeDirection Direction
        {
            get { return direction; }
            set { direction = value; }
        }

        public Image Source
        {
            get { return source; }
            set { source = value; }
        }

        public Image Destination
        {
            get { return destination; }
            set { destination = value; }
        }

        public int TargetAnimationDuration
        {
            get { return targetAnimationDuration; }
            set { targetAnimationDuration = value; }
        }

        public CrossFadeControl()
        {
            InitializeComponent();
            BufferedPaintInit();
        }

        ~CrossFadeControl()
        {
            BufferedPaintUnInit();
        }

        public void StartAnimation()
        {
            animDuration = targetAnimationDuration;
            Invalidate();
        }

        Image GetSource()
        {
            switch (direction)
            {
                case FadeDirection.SourceDestination:
                    return source;
                case FadeDirection.DestinationSource:
                    return destination;
            }
            return source;
        }

        Image GetDestination()
        {
            switch (direction)
            {
                case FadeDirection.SourceDestination:
                    return destination;
                case FadeDirection.DestinationSource:
                    return source;
            }
            return destination;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (source == null || destination == null)
            {
                base.OnPaint(pe);
                return;
            }

            IntPtr hdc = pe.Graphics.GetHdc();

            if (BufferedPaintRenderAnimation(Handle, hdc) == 0)
            {
                if (animDuration == 0)
                {
                    pe.Graphics.ReleaseHdc(hdc);
                    pe.Graphics.DrawImage(GetSource(), ClientRectangle);

                    return;
                }

                BP_ANIMATIONPARAMS animParams = new BP_ANIMATIONPARAMS();
                animParams.cbSize = Marshal.SizeOf(animParams);
                animParams.style = BP_ANIMATIONSTYLE.BPAS_LINEAR;
                animParams.dwDuration = animDuration;

                IntPtr hdcFrom, hdcTo;
                Rectangle rect = ClientRectangle;
                IntPtr hbpAnimation = BeginBufferedAnimation(Handle, hdc, ref rect, 
                    BP_BUFFERFORMAT.BPBF_COMPATIBLEBITMAP,
                     IntPtr.Zero, ref animParams, out hdcFrom, out hdcTo);

                if (hbpAnimation != IntPtr.Zero)
                {
                    if (hdcFrom != IntPtr.Zero)
                    {
                        Graphics gfx = Graphics.FromHdc(hdcFrom);
                        gfx.DrawImage(GetSource(), ClientRectangle);
                        gfx.Dispose();
                    }
                    if (hdcTo != IntPtr.Zero)
                    {
                        Graphics gfx = Graphics.FromHdc(hdcTo);
                        gfx.DrawImage(GetDestination(), ClientRectangle);
                        gfx.Dispose();
                    }
                    animDuration = 0;
                    EndBufferedAnimation(hbpAnimation, true);
                }
            }
            pe.Graphics.ReleaseHdc(hdc);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            BufferedPaintStopAllAnimations(Handle);
            Invalidate();
        }
    }
}

 

Grâce aux propriétés Source et Destination, il est possible de fournir les images qui vont servir de source et de cible pour le fading. La propriété Direction permet de dire si l'on passe de la source à la destination ou inversement.

Finalement, la propriété TargetAnimationDuration donne, comme son nom l'indique, la durée de l'animation.

Amusez vous avec ce contrôle, cela fera plaisir aux développeurs Win32 chez Microsoft^^.

.Net, Win32

Gérer sa propre fonction de messages avec le Compact Framework 2.0 (Pour Smartphone)

30. mai 2008

Contrairement aux Windows Forms, il n'est pas directement possible avec le .NET CF 2.0(SmartPhone) de surcharger la WndProc de ses formulaires.

Hors c'est parfois super utile!

Dans mon cas je voulais déclencher du code dès que l'utilisateur touche l'écran ou le clavier sans avoir à pourrir mon code avec des verrues de partout.

Le résultat c'est cadeau pour vous :) :

public partial class RootForm : Form
{
    private const int GWL_WNDPROC = -4;

    delegate IntPtr WndProcHandler(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);

    [DllImport("coredll.dll", EntryPoint = "GetWindowLong")]
    private static extern IntPtr GetWindowLong(IntPtr hwnd, int index);

    [DllImport("coredll.dll")]
    static extern int SetWindowLong(IntPtr hwnd, int index, IntPtr wndProc);

    [DllImport("coredll.dll")]
    static extern IntPtr CallWindowProc(IntPtr prevWndFunc, IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);

    private IntPtr prevWndProc = IntPtr.Zero;
    private WndProcHandler wndProc;

    public RootForm()
    {
        InitializeComponent();

        wndProc = new WndProcHandler(WndProc);

        prevWndProc = GetWindowLong(this.Handle, GWL_WNDPROC);

        int success = SetWindowLong(this.Handle, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(wndProc));
    }

    private IntPtr WndProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        // Mon code juste ici!
        return CallWindowProc(prevWndProc, hwnd, msg, wParam, lParam);
    } 
}

 

Hope this help!

.Net, Win32, Windows Mobile

Windows Vista et les ListView Win32

10. mars 2008

Comme je viens de perdre une demi-journée sur le sujet, je vais en faire profiter la communauté.

J'avais une listview win32 somme toute classique qui depuis deux jours avait la délicatesse d'émettre un "DING!!!" à chaque fois que je changais sa sélection.

Comme c'est juste très lourd et que je ne suis pas mélomane, j'ai cherché pourquoi. Il s'agit en fait d'un bug du control panel qui, lorsque l'on à l'outre-cuidance de changer les sons par défaut de Vista, se permet de mettre le "Windows Default Sound" sur l'événement de sélection des listviews. Oui je sais ca vient de loin.

Pour régler ca il "suffit" de supprimer cette clé dans la base de registre : HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\CCSelect

Sinon, il pleut à Toulouse.

Win32