Пример #1
0
S_RGBA renLambertianReflectance(S_Renderer *pRenderer, const S_Coords *point, const S_Coords *normal)
{
    S_Coords    lvec;
    double      diffuse, r, g, b;
    S_RGBA      color;

    IZG_ASSERT(pRenderer && point && normal);

    /* vektor ke zdroji svetla */
    lvec = makeCoords(pRenderer->light_position.x - point->x,
                      pRenderer->light_position.y - point->y,
                      pRenderer->light_position.z - point->z);
    coordsNormalize(&lvec);

    /* ambientni cast */
    r = pRenderer->light_ambient.red * pRenderer->mat_ambient.red;
    g = pRenderer->light_ambient.green * pRenderer->mat_ambient.green;
    b = pRenderer->light_ambient.blue * pRenderer->mat_ambient.blue;

    /* difuzni cast */
    diffuse = lvec.x * normal->x + lvec.y * normal->y + lvec.z * normal->z;
    if( diffuse > 0 )
    {
        r += diffuse * pRenderer->light_diffuse.red * pRenderer->mat_diffuse.red;
        g += diffuse * pRenderer->light_diffuse.green * pRenderer->mat_diffuse.green;
        b += diffuse * pRenderer->light_diffuse.blue * pRenderer->mat_diffuse.blue;
    }
    
    /* saturace osvetleni*/
    r = MIN(1, r);
    g = MIN(1, g);
    b = MIN(1, b);

    /* kreslici barva */
    color.red = ROUND2BYTE(255 * r);
    color.green = ROUND2BYTE(255 * g);
    color.blue = ROUND2BYTE(255 * b);
    return color;
}
Пример #2
0
void studrenDrawTriangle(S_Renderer *pRenderer,
                         S_Coords *v1, S_Coords *v2, S_Coords *v3,
                         S_Coords *n1, S_Coords *n2, S_Coords *n3,
						 S_Coords *t0, S_Coords *t1, S_Coords *t2,
                         int x1, int y1,
                         int x2, int y2,
                         int x3, int y3,
						 double h1, double h2, double h3
                         )
{

	int         minx, miny, maxx, maxy;
	int         a1, a2, a3, b1, b2, b3, c1, c2, c3;
	int         s1, s2, s3;
	int         x, y, e1, e2, e3;
	double      alpha, beta, gamma, w1, w2, w3, z, u, v;
	S_RGBA      col1, col2, col3, color;

	IZG_ASSERT(pRenderer && v1 && v2 && v3 && n1 && n2 && n3);

	/* vypocet barev ve vrcholech */
	col1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1);
	col2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2);
	col3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3);

	/* obalka trojuhleniku */
	minx = MIN(x1, MIN(x2, x3));
	maxx = MAX(x1, MAX(x2, x3));
	miny = MIN(y1, MIN(y2, y3));
	maxy = MAX(y1, MAX(y2, y3));

	/* oriznuti podle rozmeru okna */
	miny = MAX(miny, 0);
	maxy = MIN(maxy, pRenderer->frame_h - 1);
	minx = MAX(minx, 0);
	maxx = MIN(maxx, pRenderer->frame_w - 1);

	/* Pineduv alg. rasterizace troj.
	   hranova fce je obecna rovnice primky Ax + By + C = 0
	   primku prochazejici body (x1, y1) a (x2, y2) urcime jako
	   (y1 - y2)x + (x2 - x1)y + x1y2 - x2y1 = 0 */

	/* normala primek - vektor kolmy k vektoru mezi dvema vrcholy, tedy (-dy, dx) */
	a1 = y1 - y2;
	a2 = y2 - y3;
	a3 = y3 - y1;
	b1 = x2 - x1;
	b2 = x3 - x2;
	b3 = x1 - x3;

	/* koeficient C */
	c1 = x1 * y2 - x2 * y1;
	c2 = x2 * y3 - x3 * y2;
	c3 = x3 * y1 - x1 * y3;

	/* vypocet hranove fce (vzdalenost od primky) pro protejsi body */
	s1 = a1 * x3 + b1 * y3 + c1;
	s2 = a2 * x1 + b2 * y1 + c2;
	s3 = a3 * x2 + b3 * y2 + c3;

	if ( !s1 || !s2 || !s3 )
	{
		return;
	}

	/* normalizace, aby vzdalenost od primky byla kladna uvnitr trojuhelniku */
	if( s1 < 0 )
	{
		a1 *= -1;
		b1 *= -1;
		c1 *= -1;
	}
	if( s2 < 0 )
	{
		a2 *= -1;
		b2 *= -1;
		c2 *= -1;
	}
	if( s3 < 0 )
	{
		a3 *= -1;
		b3 *= -1;
		c3 *= -1;
	}

	/* koeficienty pro barycentricke souradnice */
	alpha = 1.0 / ABS(s2);
	beta = 1.0 / ABS(s3);
	gamma = 1.0 / ABS(s1);

	S_RGBA newColor;
	/* vyplnovani... */
	for( y = miny; y <= maxy; ++y )
	{
		/* inicilizace hranove fce v bode (minx, y) */
		e1 = a1 * minx + b1 * y + c1;
		e2 = a2 * minx + b2 * y + c2;
		e3 = a3 * minx + b3 * y + c3;

		for( x = minx; x <= maxx; ++x )
		{
			if( e1 >= 0 && e2 >= 0 && e3 >= 0 )
			{
				/* interpolace pomoci barycentrickych souradnic
				   e1, e2, e3 je aktualni vzdalenost bodu (x, y) od primek */
				w1 = alpha * e2;
				w2 = beta * e3;
				w3 = gamma * e1;

				/* interpolace z-souradnice */
				z = w1 * v1->z + w2 * v2->z + w3 * v3->z;

				double jmenovatel = w1 / h1 + w2 / h2 + w3 / h3;
				u = (w1 * t0->x / h1) + (w2 * t1->x / h2) + (w3 * t2->x / h3);
				v = (w1 * t0->y / h1) + (w2 * t1->y / h2) + (w3 * t2->y / h3);

				u = u / jmenovatel;
				v = v / jmenovatel;

				newColor = studrenTextureValue((S_StudentRenderer *)pRenderer, u, v);


				/* interpolace barvy */
				color.red = ROUND2BYTE(w1 * col1.red + w2 * col2.red + w3 * col3.red) * (newColor.red / 255.0);
				color.green = ROUND2BYTE(w1 * col1.green + w2 * col2.green + w3 * col3.green) * (newColor.green / 255.0);
				color.blue = ROUND2BYTE(w1 * col1.blue + w2 * col2.blue + w3 * col3.blue) * (newColor.blue / 255.0);
				color.alpha = 255;

				/* vykresleni bodu */
				if( z < DEPTH(pRenderer, x, y) )
				{
					PIXEL(pRenderer, x, y) = color;
					DEPTH(pRenderer, x, y) = z;
				}
			}

			/* hranova fce o pixel vedle */
			e1 += a1;
			e2 += a2;
			e3 += a3;
		}
	}
}
Пример #3
0
void studrenDrawTriangle(S_Renderer *pRenderer,
                         S_Coords *v1, S_Coords *v2, S_Coords *v3,
                         S_Coords *n1, S_Coords *n2, S_Coords *n3,
                         int x1, int y1,
                         int x2, int y2,
                         int x3, int y3
                         )
{
    /* zaklad fce zkopirujte z render.c */
    /* ??? */
    int         minx, miny, maxx, maxy;
    int         a1, a2, a3, b1, b2, b3, c1, c2, c3;
    int         /*s1,*/ s2, s3;
    int         x, y, e1, e2, e3;
    double      alpha, beta, w1, w2, w3, z;
    S_RGBA      col1, col2, col3, color;
    S_StudentRenderer * renderer;
    S_Frag * tmpFrag;
    int next = 0;
    int i = 0;

    IZG_ASSERT(pRenderer && v1 && v2 && v3 && n1 && n2 && n3);
    renderer = (S_StudentRenderer *)pRenderer;

    /* vypocet barev ve vrcholech */
    col1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1);
    col2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2);
    col3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3);

    /* obalka trojuhleniku */
    minx = MIN(x1, MIN(x2, x3));
    maxx = MAX(x1, MAX(x2, x3));
    miny = MIN(y1, MIN(y2, y3));
    maxy = MAX(y1, MAX(y2, y3));

    /* oriznuti podle rozmeru okna */
    miny = MAX(miny, 0);
    maxy = MIN(maxy, pRenderer->frame_h - 1);
    minx = MAX(minx, 0);
    maxx = MIN(maxx, pRenderer->frame_w - 1);

    /* vektory urcene vrcholy 1-2 a 1-3 */
    a1 = x2 - x1;
    a3 = x3 - x1;
    b1 = y2 - y1;
    b3 = y3 - y1;

    /* overeni counterclockwise orientace troj. pomoci vektoroveho soucinu */
    if( (a1 * b3 - b1 * a3) < 0 )
    {
        /* spatna orientace -> prohodime vrcholy 2 a 3 */
        SWAP(x2, x3);
        SWAP(y2, y3);

        /* a take barvy vrcholu */
        SWAP(col2.red, col3.red);
        SWAP(col2.green, col3.green);
        SWAP(col2.blue, col3.blue);
        SWAP(col2.alpha, col3.alpha);
    }

    /* Pineduv alg. rasterizace troj.
       hranova fce je obecna rovnice primky Ax + By + C = 0
       primku prochazejici body (x1, y1) a (x2, y2) urcime jako
       (y1 - y2)x + (x2 - x1)y + x1y2 - x2y1 = 0 */

    /* normala primek - vektor kolmy k vektoru mezi dvema vrcholy, tedy (-dy, dx) */
    a1 = y1 - y2;
    a2 = y2 - y3;
    a3 = y3 - y1;
    b1 = x2 - x1;
    b2 = x3 - x2;
    b3 = x1 - x3;

    /* koeficient C */
    c1 = x1 * y2 - x2 * y1;
    c2 = x2 * y3 - x3 * y2;
    c3 = x3 * y1 - x1 * y3;

    /* vypocet hranove fce (vzdalenost od primky) pro protejsi body */
    /*s1 = a1 * x3 + b1 * y3 + c1;*/
    s2 = a2 * x1 + b2 * y1 + c2;
    s3 = a3 * x2 + b3 * y2 + c3;

    /* uprava koeficientu C pro korektni vyplnovani, viz "OpenGL top-left rule" */
    /* https://books.google.cz/books?id=3ljRBQAAQBAJ&pg=PA73 */
    if( (y1 == y2 && x2 > x1) || y2 < y1 )
    {
        c1 -= 1;
    }
    if( (y2 == y3 && x3 > x2) || y3 < y2 )
    {
        c2 -= 1;
    }
    if( (y3 == y1 && x1 > x3) || y1 < y3 )
    {
        c3 -= 1;
    }

    /* koeficienty pro barycentricke souradnice */
    alpha = 1.0 / (ABS(s2) + 1);
    beta = 1.0 / (ABS(s3) + 1);

    /* vyplnovani... */
    for( y = miny; y <= maxy; ++y )
    {
        /* inicilizace hranove fce v bode (minx, y) */
        e1 = a1 * minx + b1 * y + c1;
        e2 = a2 * minx + b2 * y + c2;
        e3 = a3 * minx + b3 * y + c3;

        for( x = minx; x <= maxx; ++x )
        {
            if( e1 >= 0 && e2 >= 0 && e3 >= 0 )
            {
                /* interpolace pomoci barycentrickych souradnic
                   e1, e2, e3 je aktualni vzdalenost bodu (x, y) od primek */
                w1 = alpha * e2;
                w2 = beta * e3;
                w3 = 1.0 - w1 - w2;

                /* interpolace z-souradnice */
                z = w1 * v1->z + w2 * v2->z + w3 * v3->z;

                /* interpolace barvy */
                color.red = ROUND2BYTE(w1 * col1.red + w2 * col2.red + w3 * col3.red);
                color.green = ROUND2BYTE(w1 * col1.green + w2 * col2.green + w3 * col3.green);
                color.blue = ROUND2BYTE(w1 * col1.blue + w2 * col2.blue + w3 * col3.blue);
                color.alpha = ROUND2BYTE(w1 * col1.alpha + w2 * col2.alpha + w3 * col3.alpha);

                // vykresleni bodu
                i = y * pRenderer->frame_w + x;
                next = renderer->hBuffer[i];

                if (next == -1) renderer->hBuffer[i] = fragvecPushBack(renderer->nBuffer, makeFrag(color, z, -1));
                else if(fragvecGetPtr(renderer->nBuffer, next)->depth > z) renderer->hBuffer[i] = fragvecPushBack(renderer->nBuffer, makeFrag(color, z, next));
                else
                {
                    // razeni fragmetu
                    tmpFrag = fragvecGetPtr(renderer->nBuffer, next);
                    while (tmpFrag->depth > z) tmpFrag = fragvecGetPtr(renderer->nBuffer, tmpFrag->next);
                    fragvecGetPtr(renderer->nBuffer, next)->next = fragvecPushBack(renderer->nBuffer, makeFrag(color, z, tmpFrag->next));
                }
            }

            /* hranova fce o pixel vedle */
            e1 += a1;
            e2 += a2;
            e3 += a3;
        }
    }
}
Пример #4
0
void studrenDrawTriangle(S_Renderer *pRenderer,
                         S_Coords *v1, S_Coords *v2, S_Coords *v3,
                         S_Coords *n1, S_Coords *n2, S_Coords *n3,
                         int x1, int y1,
                         int x2, int y2,
                         int x3, int y3
                         )
{

	S_StudentRenderer   * renderer;

	/* ukazatel na studentsky renderer */
	renderer = (S_StudentRenderer *)pRenderer;

	int         minx, miny, maxx, maxy;
	int         a1, a2, a3, b1, b2, b3, c1, c2, c3;
	int         /*s1,*/ s2, s3;
	int         x, y, e1, e2, e3;
	double      alpha, beta, w1, w2, w3, z;
	S_RGBA      col1, col2, col3, color;

	IZG_ASSERT(pRenderer && v1 && v2 && v3 && n1 && n2 && n3);

	/* vypocet barev ve vrcholech */
	col1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1);
	col2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2);
	col3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3);

	/* obalka trojuhleniku */
	minx = MIN(x1, MIN(x2, x3));
	maxx = MAX(x1, MAX(x2, x3));
	miny = MIN(y1, MIN(y2, y3));
	maxy = MAX(y1, MAX(y2, y3));

	/* oriznuti podle rozmeru okna */
	miny = MAX(miny, 0);
	maxy = MIN(maxy, pRenderer->frame_h - 1);
	minx = MAX(minx, 0);
	maxx = MIN(maxx, pRenderer->frame_w - 1);

	/* vektory urcene vrcholy 1-2 a 1-3 */
	a1 = x2 - x1;
	a3 = x3 - x1;
	b1 = y2 - y1;
	b3 = y3 - y1;

	/* overeni counterclockwise orientace troj. pomoci vektoroveho soucinu */
	if ((a1 * b3 - b1 * a3) < 0)
	{
		/* spatna orientace -> prohodime vrcholy 2 a 3 */
		SWAP(x2, x3);
		SWAP(y2, y3);

		/* a take barvy vrcholu */
		SWAP(col2.red, col3.red);
		SWAP(col2.green, col3.green);
		SWAP(col2.blue, col3.blue);
		SWAP(col2.alpha, col3.alpha);
	}

	/* Pineduv alg. rasterizace troj.
	hranova fce je obecna rovnice primky Ax + By + C = 0
	primku prochazejici body (x1, y1) a (x2, y2) urcime jako
	(y1 - y2)x + (x2 - x1)y + x1y2 - x2y1 = 0 */

	/* normala primek - vektor kolmy k vektoru mezi dvema vrcholy, tedy (-dy, dx) */
	a1 = y1 - y2;
	a2 = y2 - y3;
	a3 = y3 - y1;
	b1 = x2 - x1;
	b2 = x3 - x2;
	b3 = x1 - x3;

	/* koeficient C */
	c1 = x1 * y2 - x2 * y1;
	c2 = x2 * y3 - x3 * y2;
	c3 = x3 * y1 - x1 * y3;

	/* vypocet hranove fce (vzdalenost od primky) pro protejsi body */
	/*s1 = a1 * x3 + b1 * y3 + c1;*/
	s2 = a2 * x1 + b2 * y1 + c2;
	s3 = a3 * x2 + b3 * y2 + c3;

	/* uprava koeficientu C pro korektni vyplnovani, viz "OpenGL top-left rule" */
	/* https://books.google.cz/books?id=3ljRBQAAQBAJ&pg=PA73 */
	if ((y1 == y2 && x2 > x1) || y2 < y1)
	{
		c1 -= 1;
	}
	if ((y2 == y3 && x3 > x2) || y3 < y2)
	{
		c2 -= 1;
	}
	if ((y3 == y1 && x1 > x3) || y1 < y3)
	{
		c3 -= 1;
	}

	// moje deklarace
	int * index;
	S_Frag tmp_frag;

	/* koeficienty pro barycentricke souradnice */
	alpha = 1.0 / (ABS(s2) + 1);
	beta = 1.0 / (ABS(s3) + 1);

	/* vyplnovani... */
	for (y = miny; y <= maxy; ++y)
	{
		/* inicilizace hranove fce v bode (minx, y) */
		e1 = a1 * minx + b1 * y + c1;
		e2 = a2 * minx + b2 * y + c2;
		e3 = a3 * minx + b3 * y + c3;

		for (x = minx; x <= maxx; ++x)
		{
			if (e1 >= 0 && e2 >= 0 && e3 >= 0)
			{
				/* interpolace pomoci barycentrickych souradnic
				e1, e2, e3 je aktualni vzdalenost bodu (x, y) od primek */
				w1 = alpha * e2;
				w2 = beta * e3;
				w3 = 1.0 - w1 - w2;

				/* interpolace z-souradnice */
				z = w1 * v1->z + w2 * v2->z + w3 * v3->z;

				/* interpolace barvy */
				color.red = ROUND2BYTE(w1 * col1.red + w2 * col2.red + w3 * col3.red);
				color.green = ROUND2BYTE(w1 * col1.green + w2 * col2.green + w3 * col3.green);
				color.blue = ROUND2BYTE(w1 * col1.blue + w2 * col2.blue + w3 * col3.blue);
				color.alpha = ROUND2BYTE(w1 * col1.alpha + w2 * col2.alpha + w3 * col3.alpha);


				/* vykresleni bodu */
				if (z < DEPTH(pRenderer, x, y))
				{
					/*PIXEL(pRenderer, x, y) = color;
					DEPTH(pRenderer, x, y) = z;*/

					index = (int *)vecGetPtr(renderer->vecHeadBuff, y * renderer->base.frame_w + x);

					//tmp_index = *index;

					tmp_frag = makeFrag(color, z, *index);
					*index = fragvecPushBack(renderer->vecNodeBuff, tmp_frag);

					//printf("%d\n", fragvecGetPtr(renderer->vecNodeBuff, 0)->next);
				}
			}

			/* hranova fce o pixel vedle */
			e1 += a1;
			e2 += a2;
			e3 += a3;
		}
	}

	/* Razeni a pocitani vyslednych barev */
	// deklarace pro sorting
	int sortStart, sortIndex;
	int myDepth;

	// michani barev
	S_RGBA mixColor;
	double col_R, col_G, col_B, col_A;
	double aSrc;

	// pomocne fragmenty
	S_Frag * pattern;
	S_Frag myFragTMP;
	S_Frag * myFragment;

	// pruchod pro razeni
	for (y = miny; y <= maxy; ++y)
	{
		for (x = minx; x <= maxx; ++x)
		{
			// index byl deklarovan uz vyse
			index = (int *)(vecGetPtr(renderer->vecHeadBuff, y * renderer->base.frame_w + x));

			if (*index != -1)
			{
				sortStart = *index;
				
				/* K razeni je pouzit radici algoritmus Select Sort */
				while ((myFragment = fragvecGetPtr(renderer->vecNodeBuff, sortStart))->next != -1)
				{
					sortStart = myFragment->next;
					sortIndex = myFragment->next;

					// dokud se neprojde "pole" na sebe navazujicich(indexujicich) prvku
					while (sortIndex != -1)
					{
						pattern = fragvecGetPtr(renderer->vecNodeBuff, sortIndex);

						// dojde k prohozeni hodnot, najde-li se mensi hloubka
						if (pattern->depth < myFragment->depth)
						{
							myFragTMP.depth = myFragment->depth;
							myFragTMP.color = myFragment->color;
							myFragment->depth = pattern->depth;
							myFragment->color = pattern->color;
							pattern->depth = myFragTMP.depth;
							pattern->color = myFragTMP.color;
						}

						sortIndex = pattern->next;
					}
				}
			}
		}
	}

	// pruchod pro michani barev
	for (y = miny; y <= maxy; ++y)
	{
		for (x = minx; x <= maxx; ++x)
		{
			// index byl deklarovan uz vyse
			index = (int *)(vecGetPtr(renderer->vecHeadBuff, y * renderer->base.frame_w + x));

			if (*index != -1)
			{
				sortStart = *index;

				// michani barvy
				myDepth = 0;
				col_R = 0.0;
				col_G = 0.0;
				col_B = 0.0;
				col_A = 1.0;

				while (sortStart != -1)
				{
					pattern = fragvecGetPtr(renderer->vecNodeBuff, sortStart);

					aSrc = pattern->color.alpha / 255.0;

					col_R = col_A * pattern->color.red + col_R;
					col_G = col_A * pattern->color.green + col_G;
					col_B = col_A * pattern->color.blue + col_B;

					col_A = (1.0 - aSrc) * col_A;

					sortStart = pattern->next;
				}

				mixColor.alpha = 255;
				mixColor.red = ROUND2BYTE(col_R);
				mixColor.green = ROUND2BYTE(col_G);
				mixColor.blue = ROUND2BYTE(col_B);

				PIXEL(pRenderer, x, y) = mixColor;
				DEPTH(pRenderer, x, y) = myDepth;
			}
		}
	}
}
Пример #5
0
S_RGBA studrenPhongReflectance(S_Renderer *pRenderer, const S_Coords *point, const S_Coords *normal)
{
    S_Coords    lvec, eyevec, reflect;
    double      diffuse, specular, reflect_scalar;
    double      r, g, b;

    /* If = Ia + Id + Is */
    S_RGBA      color;

    IZG_ASSERT(pRenderer && point && normal);

    /* vektor ke zdroji svetla */
    lvec = makeCoords(pRenderer->light_position.x - point->x,
                      pRenderer->light_position.y - point->y,
                      pRenderer->light_position.z - point->z);
    coordsNormalize(&lvec);

    /* vektor ke kamere */
    eyevec = makeCoords(-point->x,
                        -point->y,
                        -pRenderer->camera_dist - point->z);
    coordsNormalize(&eyevec);

    /* ambientni cast -- Ia = (Al * Am) + (As * Am) */
    /* As je barva sceny, muzeme zanedbat */
    r = pRenderer->light_ambient.red * pRenderer->mat_ambient.red;
    g = pRenderer->light_ambient.green * pRenderer->mat_ambient.green;
    b = pRenderer->light_ambient.blue * pRenderer->mat_ambient.blue;

    /* difuzni cast -- Id = Dl * Dm * LambertTerm */
    /* LambertTerm = dot(N, L) */
    diffuse = lvec.x * normal->x + lvec.y * normal->y + lvec.z * normal->z;
    if( diffuse > 0 )
    {
        r += diffuse * pRenderer->light_diffuse.red * pRenderer->mat_diffuse.red;
        g += diffuse * pRenderer->light_diffuse.green * pRenderer->mat_diffuse.green;
        b += diffuse * pRenderer->light_diffuse.blue * pRenderer->mat_diffuse.blue;
    }

    /* odraziva cast -- Is = Sm * Sl * pow( max( dot(R, E), 0.0), f ) */
    /* R = reflect(-L, N) = 2 * dot(N, L) * N - L */
    reflect_scalar = 2 * (normal->x * lvec.x + normal->y * lvec.y + normal->z * lvec.z);
    reflect.x = reflect_scalar * normal->x - lvec.x;
    reflect.y = reflect_scalar * normal->y - lvec.y;
    reflect.z = reflect_scalar * normal->z - lvec.z;

    specular = pow(
        MAX(reflect.x * eyevec.x + reflect.y * eyevec.y + reflect.z * eyevec.z, 0.0f),
        ((S_StudentRenderer*)pRenderer)->mat_shininess);

    r += specular * pRenderer->light_specular.red * pRenderer->mat_specular.red;
    g += specular * pRenderer->light_specular.green * pRenderer->mat_specular.green;
    b += specular * pRenderer->light_specular.blue * pRenderer->mat_specular.blue;

    /* saturace osvetleni*/
    r = MIN(1, r);
    g = MIN(1, g);
    b = MIN(1, b);

    /* kreslici barva */
    color.red = ROUND2BYTE(255 * r);
    color.green = ROUND2BYTE(255 * g);
    color.blue = ROUND2BYTE(255 * b);
    return color;
}