Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

C-Kurs/DreiD/Musterlösung

Dies ist die main.c. Mit FIGURE kannst du eine von drei Figuren auswählen.

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include "screen.h"


/* Figur: 0=Würfel,1=Kegel,2=Ellipsoid */
#define FIGURE 1

/* Rotationsgeschwindigkeiten (frei wählbar) */

#define ROT_V_ALPHA 0.1f

#define ROT_V_BETA 0.03f

#define LIGHT_V_ALPHA 0.0f

#define LIGHT_V_BETA 0.0f
/* Drahtgitter-Modus: 1=an, 0=aus */
#define WIREFRAMES_MODE 0



/* 3x3-Matrix-Repräsentation als 2-dimensionales Array */

typedef float Matrix[3][3];


/* Aktuelle Transformation */

Matrix transform;


/* Aktuelle Zeichenfarbe mit Werten zwischen 0 und 1 */

float color_r;

float color_g;

float color_b;


/* Aktueller Lichtvektor */

float lgt_x;

float lgt_y;

float lgt_z;



/* --- Prototypen --- */

/* Gibt eine 3x3-Matrix aus und beendet das Programm */
void print_matrix(Matrix matrix);
/* Gibt einen Vektor, bestehend aus 3 floats, aus und beendet das Programm */

void print_vector(float x, float y, float z);




/*
Bildet aus zwei Winkeln die resultierende Transformationsmatrix
*/

void refresh_transformation_matrix(float alpha, float beta)

{


     /* Rotationsmatrizen */

     Matrix rot_x = {

                     {     1.0f    ,    0.0f    ,    0.0f    },

                     {     0.0f    ,  cos(beta) , -sin(beta) },

                     {     0.0f    ,  sin(beta) ,  cos(beta) }

                    };

     Matrix rot_y = {

                     {  cos(alpha),    0.0f     ,  sin(alpha)},

                     {    0.0f    ,    1.0f     ,    0.0f    },

                     { -sin(alpha),    0.0f     ,  cos(alpha)}

                    };
                    
     /* Matrix-Multiplikation */

     int i,j,k;

     for(i=0;i<3;i++)

     for(j=0;j<3;j++)

     {  

     transform[i][j] = 0;

     for(k=0;k<3;k++)

         transform[i][j] += rot_x[j][k]*rot_y[k][i];            

     }
     
     

}


/*
Rotiert den gegebenen Vektor, bestehend aus 3 Floats, entsprechend der aktuellen transform-Matrix
*/

void apply_transform(float * x,float * y,float * z)

{
    float h_x = *x;
    float h_y = *y;
    float h_z = *z;

    *x = transform[0][0] * h_x + transform[0][1] * h_y + transform[0][2] * h_z;

    *y = transform[1][0] * h_x + transform[1][1] * h_y + transform[1][2] * h_z;

    *z = transform[2][0] * h_x + transform[2][1] * h_y + transform[2][2] * h_z;

}


/*
Zeichnet ein dreidimensionales Dreieck auf die zweidimensionale Fläche entsprechend der aktuellen transform-Matrix
*/

void render_primitive(float x1,float y1,float z1, float x2,float y2,float z2, float x3,float y3,float z3)

{

    /* Koordinaten transformieren */

    apply_transform(&x1,&y1,&z1);

    apply_transform(&x2,&y2,&z2);

    apply_transform(&x3,&y3,&z3);
    
    /* Kreuzprodukt bilden */
    float v1[3] = {x2-x1,y2-y1,z2-z1};

    float v2[3] = {x3-x1,y3-y1,z3-z1}; 
    float cross_x = v1[1]*v2[2] - v1[2]*v2[1];

    float cross_y = v1[2]*v2[0] - v1[0]*v2[2];

    float cross_z = v1[0]*v2[1] - v1[1]*v2[0];
    float cross = 1/sqrt(cross_x*cross_x + cross_y*cross_y + cross_z*cross_z); //Normalisieren
    cross_x *= cross;
    cross_y *= cross;
    cross_z *= cross;
    

    /* Culling */

    if(cross_z<0)

        return;

    

    /* Licht */

    float brightness = lgt_x*cross_x + lgt_y*cross_y + lgt_z*cross_z;
    brightness = (brightness + 0.5)/1.5f;
    if(brightness>1)

        brightness = 1;

    if(brightness<0.025)

        brightness = 0.025;
    brightness = sqrt(brightness);
    
    /* Dreiecke zeichnen */

    set_color(color_r*brightness,color_g*brightness,color_b*brightness);    
    if(WIREFRAMES_MODE)
    {
        draw_line(x1,y1,x2,y2);
        draw_line(x2,y2,x3,y3);
        draw_line(x3,y3,x1,y1);
    }else

        draw_triangle(x1,y1,x2,y2,x3,y3);

}






/* ----------------Ab hier alles Vorlage---------------- */




/* Aktuelle Rotationen */

float trf_alpha = 0;

float trf_beta = 0;

float lgt_alpha = 0;

float lgt_beta = 0;
/* Anzahl der bisher gezeichneten Frames */
int c_time = 0;


/*
Gibt eine 3x3-Matrix aus und beendet das Programm
*/
void print_matrix(Matrix matrix)

{

     printf("%f  %f  %f\n",matrix[0][0],matrix[0][1],matrix[0][2]);

     printf("%f  %f  %f\n",matrix[1][0],matrix[1][1],matrix[1][2]);

     printf("%f  %f  %f\n",matrix[2][0],matrix[2][1],matrix[2][2]);

     system("PAUSE");

     exit(EXIT_SUCCESS);

}


/*
Gibt einen Vektor, bestehend aus 3 floats, aus und beendet das Programm
*/

void print_vector(float x, float y, float z)

{

     printf("%f  %f  %f\n",x,y,z);

     system("PAUSE");

     exit(EXIT_SUCCESS);

}


/*
Setzt die aktuelle Farbe für nachfolgende render_* Aufrufe
*/

void refresh_color(float r,float g, float b)

{

     color_r = r;

     color_g = g;

     color_b = b;

}

/*
Rendert dreidimensionale viereckige Fläche (bestehend aus zwei Dreiecken) 
*/
void render_face(float x1,float y1,float z1, float x2,float y2,float z2, float x3,float y3,float z3, float x4,float y4,float z4)

{

    render_primitive(x1,y1,z1,x2,y2,z2,x3,y3,z3);

    render_primitive(x1,y1,z1,x3,y3,z3,x4,y4,z4);

}


/*
Komplette Ausgabe
*/
void output()

{
    /* Transformation aktualisieren */

    refresh_transformation_matrix(trf_alpha,trf_beta);


    /* Licht-Vektor setzen */

    lgt_x = cos(lgt_beta);

    lgt_y = sin(lgt_beta);

    lgt_z = sin(lgt_alpha)*lgt_x;   
    lgt_x = cos(lgt_alpha)*lgt_x;
        

    /* Szene rendern */ 

    begin_scene();
    if(FIGURE == 1)
    {
        /* Kegel */
        int acc = 32; //Genauigkeit
    	float rad = 1.2; //Radius
    	int i;
    	float ang = 0, lst_ang;
    	for(i=1; i<acc+1; i++)
    	{
    	    refresh_color(0.8,0.8,1);
    	    lst_ang = ang;
    	    ang = (float)i/acc*2*M_PI;
            render_primitive(0,-1.2,0, sin(ang)*rad,1.2,cos(ang)*rad, sin(lst_ang)*rad,1.2,cos(lst_ang)*rad);
            if(i%2 == 0)
                refresh_color(0.1,0.1,0.5);
            else
                refresh_color(0.2,0.2,0.6);
            render_primitive(0,1.2,0, sin(lst_ang)*rad,1.2,cos(lst_ang)*rad, sin(ang)*rad,1.2,cos(ang)*rad);
        }
    }else
    if(FIGURE == 2)
    {
        /* Ellipsoid */
        refresh_color(1,1,1);
        float rad_a = 1.0f, rad_b = 1.5f; //Radius a und b
    	int acc = 14; //Genauigkeit
    	int i, j;
    	float x = -1, lst_x;
    	float ang = 0, lst_ang;
    	float rad = 0, lst_rad, anim_rad;	 
    	for(j=1; j<acc+1; j++)
        {
            lst_x = x;
            lst_rad = rad;
            x = (((float)j/acc)-0.5)*2;
            if(x>1)
                x = 1;
            rad = sqrt(1-x*x)*(1+sin(((float)c_time+x*15)*0.4f)*0.05f);
            ang = 0;
            for(i=1; i<acc+1; i++)
            {
                lst_ang=ang;
                ang=(float)i/acc*2*M_PI;
                render_face( sin(lst_ang)*lst_rad*rad_a,lst_x,cos(lst_ang)*lst_rad*rad_b, 
            	             sin(ang)*lst_rad*rad_a,lst_x,cos(ang)*lst_rad*rad_b, 
                             sin(ang)*rad*rad_a,x,cos(ang)*rad*rad_b, 
            	             sin(lst_ang)*rad*rad_a,x,cos(lst_ang)*rad*rad_b );
            }
        }
    }else{
    
        /* Würfel */

    	refresh_color(1,0,0);

    	render_face(-1,-1,1, 1,-1,1, 1,1,1, -1,1,1); //Front
    	render_face(1,-1,-1, -1,-1,-1, -1,1,-1, 1,1,-1); //Back
    	refresh_color(1,1,0);

    	render_face(-1,-1,1, -1,1,1, -1,1,-1, -1,-1,-1); //Left

    	render_face(1,1,1, 1,-1,1, 1,-1,-1, 1,1,-1); //Right

    	refresh_color(1,0.5,0);

    	render_face(1,-1,1, -1,-1,1, -1,-1,-1, 1,-1,-1); //Top
    	render_face(-1,1,1, 1,1,1, 1,1,-1, -1,1,-1); //Bottom 
    }

    end_scene();

}



int main(void)

{
    /* Fenster initialisieren */

    if(create_window(400,400,0x220000) != 0){

        printf("Fehler beim Fenster Erstellen. Bitte wende dich an einen Tutor.\n");

        return EXIT_FAILURE;

    }

    /* Startwerte setzen */
    zoom = 0.5;

    trf_alpha = M_PI/2;

    trf_beta = M_PI/3;

    lgt_alpha = M_PI*2/3;

    lgt_beta = -M_PI/4;


    /* Figur wiederholt rendern */

    while(1)

    {
        trf_alpha += ROT_V_ALPHA;

        trf_beta += ROT_V_BETA;
        lgt_alpha += LIGHT_V_ALPHA;

        lgt_beta += LIGHT_V_BETA;

    	output();
    	c_time++;

    	usleep(50000);

    }



    /* Programmende */    

    close_window();

    return EXIT_SUCCESS;

}