iOS : détection de la zone de touche


21 octobre 2012

Comment détecter la zone (circulaire) d'une touche sur les iBidules ? Il faut obtenir un UITouch depuis un UIEvent et à partir de là :

float vf = 10.0;
    id valFloat = [thisTouch valueForKey:"pathMajorRadius"];
    if (valFloat != nil)    { vf = [valFloat floatValue]; }

Source : http://stackoverflow.com/questions/5179426/tap-pressure-strength-detection-using-accelerometer

iOS, relation entre CALayer et UIView


21 décembre 2011
When a layer needs to be displayed and has no valid backing store (perhaps because the layer received a setNeedsDisplay message), the system sends the display message to the layer. The -[CALayer display] method looks roughly like this:
- (void)display {
    if ([self.delegate respondsToSelector:@selector(displayLayer:)]) {
        [[self.delegate retain] displayLayer:self];
        [self.delegate release];
        return;
    }

    CABackingStoreRef backing = _backingStore;
    if (!backing) {
        backing = _backingStore = ... code here to create and configure
            the CABackingStore properly, given the layer size, isOpaque,
            contentScale, etc.
    }

    CGContextRef gc = ... code here to create a CGContext that draws into backing,
        with the proper clip region
    ... also code to set up a bitmap in memory shared with the WindowServer process

    [self drawInContext:gc];
    self.contents = backing;
}

So, if you override display, none of that happens unless you call [super display]. And if you implement displayLayer: in FooView, you have to create your own CGImage somehow and store it in the layer's contents property. The -[CALayer drawInContext:] method looks roughly like this:
- (void)drawInContext:(CGContextRef)gc {
    if ([self.delegate respondsToSelector:@selector(drawLayer:inContext:)]) {
        [[self.delegate retain] drawLayer:self inContext:gc];
        [self.delegate release];
        return;
    } else {
        CAAction *action = [self actionForKey:@"onDraw"];
        if (action) {
            NSDictionary *args = [NSDictionary dictionaryWithObject:gc forKey:@"context"];
            [action runActionForKey:@"onDraw" object:self arguments:args];
        }
    }
}

The onDraw action is not documented as far as I know. The -[UIView drawLayer:inContext:] method looks roughly like this:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)gc {
    set gc's stroke and fill color spaces to device RGB;
    UIGraphicsPushContext(gc);
    fill gc with the view's background color;
    if ([self respondsToSelector:@selector(drawRect:)]) {
        [self drawRect:CGContextGetClipBoundingBox(gc)];
    }
    UIGraphicsPopContext(gc);
}

...I used Hopper to disassemble the IOS simulator libraries...

WebGL - Doc en vrac


1 mai 2011
La doc officielle de WebGL 1.0
Les TypedArrays
OpenGL ES
OpenGL ES Shading Language
Une page de démonstration de shaders pour WebGL !!! Très bien faite !
Quand on appelle getContext on transmet un hash/object pouvant contenir :
  • alpha : bool, default true, indique si on désire un canal alpha.
  • depth : bool, default true, indique que l'on désire un z-buffer (>=16 bits).
  • stencil : bool, default false, indique que l'on désire un stencil buffer (>=8 bits).
  • antialias : bool, default true, indique que l'on désire de l'antialiasing. La méthode choisie n'est pas sous notre contrôle (multisample/supersample).
  • premultipliedAlpha : bool, default true, indique que les couleurs des pixels rendus sont prémultipliées ou pas par le canal alpha. Bien évidemment, ce paramètre est ignoré si alpha est lui-même à false.
  • preserveDrawingBuffer : bool, default false, indique qu'après la présentation du tampon de dessin les pixels sont réglés à la valeur par défaut (true) ou laissées telles quelles (false). Apparemment, mettre cet attribut à false impacte la performance d'une application, alors que j'aurai dit l'inverse...
Ainsi, pour donner un exemple, on pourra exécuter ce qui suit :
$("#canvas3D")[0].getContext("webgl", {antialias:true, depth:true, stencil:true})
Il y a tout un paquet de types dérivés de l'interface WebGLObject.
ObjetCréationUtilisationDestruction
WebGLBufferglGenBuffersglBindBufferglDeleteBuffers
WebGLFrameBufferglGenFramebuffersglBindFramebufferglDeleteFramebuffers
WebGLProgramglCreateProgramglUseProgramglDeleteProgram
WebGLRenderbufferglGenRenderbuffersglBindRenderbufferglDeleteRenderbuffers
WebGLShaderglCreateShaderglAttachShaderglDeleteShader
WebGLTextureglGenTexturesglBindTextureglDeleteTextures
WebGLUniformLocation
Pour le retour de getActiveAttrib et getActiveUniform on a un objet de type WebGLActiveInfo qui contient size, type et name. Flash/Flex : http://www.cornflex.org/?p=1 Version WebGLU : http://blog.one-geek.com/2010/11/building-videosphere-going-further-with.html#more WebGLU : http://staffwww.itn.liu.se/~perla/Siggraph2010/posters/0139.pdf

Premier programme en OpenGL sous X


22 octobre 2007

Premier code en OpenGL sous X

Il faut bien démarrer quelque part et c'est ici ! C'est sûr que c'est pas terrible, beaucoup de code pour un résultat bien consternant, mais je jette mes bases. Je dois reprendre ce qui était naturel il y a quelques années...

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/gl.h>

static  int snglBuf[] = {GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12, None};
static  int dblBuf[] =  {GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12, GLX_DOUBLEBUFFER, None};

Display*    Dpy;
Window  Win;
Bool    DoubleBuffer = True;

GLfloat XAngle = 42.0, YAngle = 82.0, ZAngle = 112.0;

int FatalError(int errorCode, char* str)
{
    printf("%s\n", str);
    return errorCode;
}

void    redraw()
{
static  Bool    DisplayListInited = False;
    if (DisplayListInited)      {
        glCallList(1);
    }   else    {
        glNewList(1, GL_COMPILE_AND_EXECUTE);
        //
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glBegin(GL_QUADS);
        glColor3f(0.0, 0.7, 0.1);       //Green
        glVertex3f(-1.0, 1.0, 1.0);
        glVertex3f(1.0, 1.0, 1.0);
        glVertex3f(1.0, -1.0, 1.0);
        glVertex3f(-1.0, -1.0, 1.0);
        glColor3f(0.9, 1.0, 0.0);       //Yellow
        glVertex3f(-1.0, 1.0, -1.0);
        glVertex3f(1.0, 1.0, -1.0);
        glVertex3f(1.0, -1.0, -1.0);
        glVertex3f(-1.0, -1.0, -1.0);
        glColor3f(0.2, 0.2, 1.0);       //Blue
        glVertex3f(-1.0, 1.0, 1.0);
        glVertex3f(1.0, 1.0, 1.0);
        glVertex3f(1.0, 1.0, -1.0);
        glVertex3f(-1.0, 1.0, -1.0);
        glColor3f(0.7, 0.0, 0.1);       //Red
        glVertex3f(-1.0, -1.0, 1.0);
        glVertex3f(1.0, -1.0, 1.0);
        glVertex3f(1.0, -1.0, -1.0);
        glVertex3f(-1.0, -1.0, -1.0);
        glEnd();
        //
        glEndList();
        DisplayListInited = True;
    }
    //On affiche réellement quelque chose...
    if (DoubleBuffer)       glXSwapBuffers(Dpy, Win);
    else                    glFlush();
}

int main(int argc, char** argv)
{
    XVisualInfo*    vi;
    Colormap    CMap;
    XSetWindowAttributes    swa;
    GLXContext  cx;
    XEvent  Event;
    Bool    NeedRedraw = False, RecalcModelView = True;
    int Dummy;
    //
    Dpy = XOpenDisplay(NULL);
    if (!Dpy)       return FatalError(1, "Couldn't open display...");
    if (!glXQueryExtension(Dpy, &Dummy, &Dummy))        return FatalError(2, "X n'a pas d'extension OpenGL.");
    //
    vi = glXChooseVisual(Dpy, DefaultScreen(Dpy), dblBuf);
    if (!vi)        {
        vi = glXChooseVisual(Dpy, DefaultScreen(Dpy), snglBuf);
        if (!vi)        return FatalError(3, "Pas de visuel RGB avec buffer de profondeur.");
        DoubleBuffer = False;
    }
    printf("DoubleBuffer : %d\n", DoubleBuffer);
    if (vi->class != TrueColor)     return FatalError(4, "J'ai besoin d'un visuel en true color !");
    //
    cx = glXCreateContext(Dpy, vi, None, True);
    if (!cx)        return FatalError(5, "Impossible de créer le contexte de rendu.");
    //
    CMap = XCreateColormap(Dpy, RootWindow(Dpy, vi->screen), vi->visual, AllocNone);
    swa.colormap = CMap;
    swa.border_pixel = 0;
    swa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask;
    Win = XCreateWindow(Dpy, RootWindow(Dpy, vi->screen), 0, 0, 300, 300, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);
    XSetStandardProperties(Dpy, Win, "glxsimple", "glxsimple", None, argv, argc, NULL);
    //
    glXMakeCurrent(Dpy, Win, cx);
    XMapWindow(Dpy, Win);
    //
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10.0);
    //
    while (True)        {
        do {
            XNextEvent(Dpy, &Event);
            switch (Event.type)     {
                case    ButtonPress:
                    RecalcModelView = True;
                    switch(Event.xbutton.button)        {
                        case    1:  XAngle += 10.0;     break;
                        case    2:  YAngle += 10.0;     break;
                        case    3:  ZAngle += 10.0;     break;
                    }
                    break;
                case    ConfigureNotify:
                    glViewport(0, 0, Event.xconfigure.width, Event.xconfigure.height);
                case    Expose:
                    NeedRedraw = True;
                    break;
            }
        } while(XPending(Dpy));
        //
        if (RecalcModelView)        {
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glTranslatef(0.0, 0.0, -3.0);
            glRotatef(XAngle, 0.1, 0.0, 0.0);
            glRotatef(YAngle, 0.0, 0.1, 0.0);
            glRotatef(ZAngle, 0.0, 0.0, 1.0);
            //
            RecalcModelView = False;
            NeedRedraw = True;
        }
        if (NeedRedraw)     {
            redraw();
            NeedRedraw = False;
        }
    }
    //
    return 0;
}

Pour compiler ça, si on suppose que le code est sauvé dans un fichier simplegl.c, on lance :

gcc -o simplegl -lGL -lX11 simplegl.c

Le résulat du gloubi-boulga ci-dessus ? Et bien voilà, bow you sucker !

Wrapper MySQL


21 septembre 2007

Classe : MySQL wrapper

Une classe qui utilise dlopen (équivalent de LoadLibrary sous Win32) pour ne pas avoir à lier libmysqlclient à un programme. Comme dans n'importe quel wrapper : il n'y a rien ici de bien compliqué ou de bien intéressant. C'est juste un bout de code utile pour se simplifier la vie.

#include "dlfcn.h"
#include <mysql.h>

class   MySQL
{
    public:
        MySQL()
        {
            handle = NULL;
            LibHandle = dlopen("/usr/local/mysql/lib/mysql/libmysqlclient.so", RTLD_LAZY);
            //Tous les dlsym dont on a besoin
            MySQL_Init = (MYSQL* (*)(MYSQL*))dlsym(LibHandle, "mysql_init");
            MySQL_Close = (void (*)(MYSQL*))dlsym(LibHandle, "mysql_close");
            MySQL_Real_Connect = (MYSQL* (*)(MYSQL *, const char *, const char *, const char *, const char *, unsigned int, const char *, unsigned long))dlsym(LibHandle, "mysql_real_connect");
            MySQL_Error = (const char*(*)(MYSQL*)) dlsym(LibHandle, "mysql_error");
            MySQL_Real_Query = (int (*)(MYSQL *, const char *, unsigned long)) dlsym(LibHandle, "mysql_real_query");
            MySQL_Use_Result = (MYSQL_RES* (*)(MYSQL*)) dlsym(LibHandle, "mysql_use_result");
            MySQL_Store_Result = (MYSQL_RES* (*)(MYSQL*)) dlsym(LibHandle, "mysql_store_result");
            MySQL_Fetch_Row = (MYSQL_ROW (*)(MYSQL_RES *)) dlsym(LibHandle, "mysql_fetch_row");
            MySQL_Free_Result = (void (*)(MYSQL_RES*))dlsym(LibHandle, "mysql_free_result");
            MySQL_End_Library = (void (*)())dlsym(LibHandle, "mysql_library_end");
            MySQL_Server_Init = (void (*)())dlsym(LibHandle, "mysql_server_init");
            MySQL_Server_End = (void (*)())dlsym(LibHandle, "mysql_server_end");
        }
        ~MySQL()
        {
            MySQL_Close(handle);
            MySQL_Server_End();
            dlclose(LibHandle);
        }
        bool    init()
        {
            handle = MySQL_Init(NULL);
            return handle != NULL;
        }
        void    serverInit()                {   MySQL_Server_Init();    }
        bool    connect(char* dbName, char* userName, char* passwd)
        {
            MYSQL*  Handle = MySQL_Real_Connect(handle, NULL, userName, passwd, dbName, 0, NULL, 0);
            return Handle == handle;
        }
        bool    query(const char* query)
        {
            bool    Ret = MySQL_Real_Query(handle, query, strlen(query)) == 0;
            if (!Ret)       return false;
            rows = MySQL_Store_Result(handle);
            return rows != NULL;
        }
        bool    freeResult()                {   MySQL_Free_Result(rows);    }
        bool    fetchRow(MYSQL_ROW& row)
        {
            row = MySQL_Fetch_Row(rows);
            return !(row == NULL);
        }

    protected:
        void*   LibHandle;
        MYSQL*  handle;
        MYSQL_RES*  rows;
        //Les pointeurs vers les fonctions de la lib MySQL
        MYSQL*  (*MySQL_Init)(MYSQL*);
        void    (*MySQL_Close)(MYSQL*);
        MYSQL* (*MySQL_Real_Connect)(MYSQL *, const char *, const char *, const char *, const char *, unsigned int , const char *, unsigned long );
        const char* (*MySQL_Error)(MYSQL*);
        int (*MySQL_Real_Query)(MYSQL *, const char *, unsigned long);
        MYSQL_RES* (*MySQL_Store_Result)(MYSQL*);
        MYSQL_RES* (*MySQL_Use_Result)(MYSQL*);
        MYSQL_ROW (*MySQL_Fetch_Row)(MYSQL_RES *);
        void    (*MySQL_Free_Result)(MYSQL_RES*);
        void    (*MySQL_End_Library)();
        void    (*MySQL_Server_Init)();
        void    (*MySQL_Server_End)();
};