void quats2matrices( int n ){
    float  d = 1.0f/n;
    glBegin   ( GL_POINTS   );
    glColor3f ( 0.0f, 0.0f, 0.0f );
    for( int ix=-n; ix<n; ix++ ){
        float x = (ix+0.5f) * d;
        for( int iy=-n; iy<n; iy++ ){
            float y = (iy+0.5f) * d;
            for( int iz=-n; iz<n; iz++ ){
                float z = (iz+0.5f) * d;
                float r2 = x*x + y*y + z*z;
                if( r2 < 1.0f ){
                    Quat4f q;
                    Mat3f  M;
                    q.set( x, y, z, sqrt(1.0f - r2) );
                    q.toMatrix( M );
                    glColor3f ( M.a.x, M.a.y, M.a.z );
                    glVertex3f( (float)M.a.x, (float)M.a.y, (float)M.a.z );
                    //glVertex3f( (float)M.b.x, (float)M.b.y, (float)M.b.z );
                    //glVertex3f( (float)M.c.x, (float)M.c.y, (float)M.c.z );
                }
            }
        }
    }
    glEnd();
}
void draw(){
    glClearColor(0.0, 0.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT  );

    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LESS );

    float camMat[16];
    getPerspectiveMatrix( -WIDTH, WIDTH, -HEIGHT, HEIGHT, 1.0, 10.0, camMat );

    //Quat4f qCamera_; convert(qCamera,qCamera_);
    Mat3f mouseMat; qCamera.toMatrix(mouseMat);
    //printf( " (%3.3f,%3.3f,%3.3f,%3.3f) \n", qCamera.x,qCamera.y,qCamera.z,qCamera.w );
    //printf( " (%3.3f,%3.3f,%3.3f,%3.3f) \n", qCamera.x,qCamera.y,qCamera.z,qCamera.w );
    //printf( "mouseMat (%3.3f,%3.3f,%3.3f) (%3.3f,%3.3f,%3.3f) (%3.3f,%3.3f,%3.3f) \n", mouseMat.ax, mouseMat.ay, mouseMat.az,  mouseMat.bx, mouseMat.by, mouseMat.bz,   mouseMat.cx, mouseMat.cy, mouseMat.cz );

    GLuint uloc;
    uloc = glGetUniformLocation( shader1->shaderprogram, "modelPos" ); glUniform3fv      (uloc, 1, modelPos );
    //uloc = glGetUniformLocation( shader1->shaderprogram, "modelMat" ); glUniformMatrix3fv(uloc, 1, GL_FALSE, modelMat );
    uloc = glGetUniformLocation( shader1->shaderprogram, "modelMat" ); glUniformMatrix3fv(uloc, 1, GL_FALSE, (float*)&mouseMat );
    uloc = glGetUniformLocation( shader1->shaderprogram, "camMat"   ); glUniformMatrix4fv(uloc, 1, GL_FALSE, camMat   );

    // shading
    if ( render_type == 1 ){
        uloc = glGetUniformLocation( shader1->shaderprogram, "cam_pos"       ); glUniform3fv      (uloc, 1, cam_pos      );
        uloc = glGetUniformLocation( shader1->shaderprogram, "light_pos"     ); glUniform3fv      (uloc, 1, light_pos     );
        uloc = glGetUniformLocation( shader1->shaderprogram, "lightColor"    ); glUniform3fv      (uloc, 1, lightColor    );
        uloc = glGetUniformLocation( shader1->shaderprogram, "diffuseColor"  ); glUniform3fv      (uloc, 1, diffuseColor  );
        uloc = glGetUniformLocation( shader1->shaderprogram, "ambientColor"  ); glUniform3fv      (uloc, 1, ambientColor  );
        uloc = glGetUniformLocation( shader1->shaderprogram, "specularColor" ); glUniform3fv      (uloc, 1, specularColor );
    };

    //uloc = glGetUniformLocation( shader1->shaderprogram, "light_dir"); glUniform3fv(uloc, 1, light_dir  );

    object1->draw();

    SDL_GL_SwapWindow(window);

}
void draw(){

    long time_start = getCPUticks();

    glClearColor(0.0, 0.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT  );

    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LESS );

    long time_0 = getCPUticks();


    //getPerspectiveMatrix( -WIDTH, WIDTH, -HEIGHT, HEIGHT, 1.0, 10.0, camMat );
    getPerspectiveMatrix( -WIDTH, WIDTH, -HEIGHT, HEIGHT, 1.0, 20.0, camMat );

    //Quat4f qCamera_; convert(qCamera,qCamera_);
    qCamera.toMatrix(mouseMat);
    //printf( " (%3.3f,%3.3f,%3.3f,%3.3f) \n", qCamera.x,qCamera.y,qCamera.z,qCamera.w );
    //printf( " (%3.3f,%3.3f,%3.3f,%3.3f) \n", qCamera.x,qCamera.y,qCamera.z,qCamera.w );
    //printf( "mouseMat (%3.3f,%3.3f,%3.3f) (%3.3f,%3.3f,%3.3f) (%3.3f,%3.3f,%3.3f) \n", mouseMat.ax, mouseMat.ay, mouseMat.az,  mouseMat.bx, mouseMat.by, mouseMat.bz,   mouseMat.cx, mouseMat.cy, mouseMat.cz );

    // ============= Terrain

    if(RayTerrain){
        draw_TerrainRayMarch();
    }else{
        draw_TerrainMeshHeightMap();
    }

    long time_1 = getCPUticks();

    // ============= Objects
    glUseProgram(shader1->shaderprogram);

    uloc = glGetUniformLocation( shader1->shaderprogram, "camMat"   ); glUniformMatrix4fv(uloc, 1, GL_FALSE, camMat   );
    uloc = glGetUniformLocation( shader1->shaderprogram, "modelMat" ); glUniformMatrix3fv(uloc, 1, GL_FALSE, (float*)&mouseMat );
    uloc = glGetUniformLocation( shader1->shaderprogram, "modelPos" ); // glUniform3fv      (uloc, 1, modelPos );

    //object1->draw();
    object1->preDraw();
    for(int i=0; i<ninstancs; i++){
        glUniform3fv( uloc, 1, instance_points+i*3 );
        //glDrawArrays( object1->draw_mode, 0, object1->nVert);
        object1->draw_instance();
    }
    object1->afterDraw();

    long time_2 = getCPUticks();

    SDL_GL_SwapWindow(window);

    long time_3 = getCPUticks();


    double Ttot     = (time_3-time_start)*1e-6;
    double Tterrain = (time_1-time_0)*1e-6;
    double Tobject  = (time_2-time_1)*1e-6;
    double Tswap    = (time_3-time_2)*1e-6;

    printf( "Ttot %3.2f terrain %3.2f objects %3.2f swap %3.2f \n", Ttot, Tterrain, Tobject, Tswap );

}