//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ // Implementaci¢n del engine Phong/EnvMapping, Yann/Iguana //ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ #include #include #include #include #include #include "phong.h" #include "ph_fill.h" extern int tracing; #define TRACE(r,g,b) do { if (tracing) VGA_PutColor(0,r,g,b); } while(0) void *frame_buffer_adr = (void *)0xA0000; #define MAX_OBJECTS 5 #define VERY_CLOSE 10 #define BACKFACE_CULL struct O3DHeader { UWORD m_num_vertices; UWORD m_num_triangles; }; static struct CGlobalTri { UWORD m_num_obj; // En qu‚ objeto est  el triangulo UWORD m_num_tri; // Qu‚ tri ngulo dentro del objeto UWORD m_distance; // Distancia a la que est  el tri. struct CGlobalTri *m_next; // Link }; static struct CObject { struct CPoint *m_vertices; struct CNormal *m_normals; struct CTriangle *m_triangles; struct CPoint *m_xvertices; struct CPoint2D *m_proj_vertices; struct CNormal *m_xnormals; UWORD m_num_obj; // Identificador de objeto **//** UWORD m_num_vertices, m_num_triangles; BOOL m_all_ok; BOOL m_active; } s_objects[MAX_OBJECTS]; static int s_num_objects = 0; // Cu ntos son -^ static struct CGlobalTri *s_list = 0; // Lista global de tri ngulos static struct CGlobalTri *s_pool = 0, *s_next = 0; // Pool para no hacer mallocs static struct CGlobalTri *GetTri(void) { // Acceso al pool return s_next++; } static void RestartPool(void) { // Inicializar la pool s_next = s_pool; } void PH_SetMode13BufferAdr(void *p) { frame_buffer_adr = p; } void *PH_GetMode13BufferAdr(void) { return frame_buffer_adr; } static struct CObject *NewObject(void) { struct CObject *p = s_objects + s_num_objects; if (s_num_objects == MAX_OBJECTS) { puts("ORRRROOOOORRRRRRRRR!!!!!!!!!!!!!"); exit(-1); } p->m_num_obj = s_num_objects++; return p; } static void ReserveMem(struct CObject *p) { p->m_all_ok = FALSE; p->m_xvertices = calloc(p->m_num_vertices, sizeof(struct CPoint)); if (!p->m_xvertices) return; p->m_xnormals = calloc(p->m_num_vertices, sizeof(struct CNormal)); if (!p->m_xnormals) { free(p->m_xvertices); return; } p->m_proj_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint2D)); if (!p->m_proj_vertices) { free(p->m_xvertices); free(p->m_xnormals); return; } p->m_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint)); if (!p->m_vertices) { free(p->m_xvertices); free(p->m_xnormals); free(p->m_proj_vertices); return; } p->m_normals = calloc(p->m_num_vertices, sizeof(struct CNormal)); if (!p->m_normals) { free(p->m_xvertices); free(p->m_xnormals); free(p->m_proj_vertices); free(p->m_vertices); return; } p->m_triangles = calloc(p->m_num_triangles, sizeof(struct CTriangle)); if (!p->m_triangles) { free(p->m_xvertices); free(p->m_xnormals); free(p->m_proj_vertices); free(p->m_vertices); free(p->m_normals); return; } p->m_all_ok = TRUE; } HANDLE PH_BuildObj(BYTE *file_like_buffer) { struct O3DHeader hdr; struct CObject *p = NewObject(); char *q = (char *)file_like_buffer; p->m_all_ok = FALSE; memcpy(&hdr, q, sizeof(struct O3DHeader)); q += sizeof(struct O3DHeader); // Reservar memoria p->m_num_vertices = hdr.m_num_vertices; p->m_num_triangles = hdr.m_num_triangles; ReserveMem(p); if (!p->m_all_ok) { return 0; } // Leer los datos memcpy(p->m_vertices, q, p->m_num_vertices * sizeof(struct CPoint)); q += p->m_num_vertices * sizeof(struct CPoint); memcpy(p->m_normals, q, p->m_num_vertices * sizeof(struct CNormal)); q += p->m_num_vertices * sizeof(struct CNormal); memcpy(p->m_triangles, q, p->m_num_triangles * sizeof(struct CTriangle)); q += p->m_num_triangles * sizeof(struct CTriangle); p->m_all_ok = TRUE; p->m_active = TRUE; return p - s_objects + 1; } void PH_DestroyObj(HANDLE h) { struct CObject *p = s_objects + h + 1; if (!p->m_all_ok) return; if (p->m_xvertices) free(p->m_xvertices); if (p->m_xnormals) free(p->m_xnormals); if (p->m_vertices) free(p->m_vertices); if (p->m_normals) free(p->m_normals); if (p->m_triangles) free(p->m_triangles); if (p->m_proj_vertices) free(p->m_proj_vertices); s_num_objects--; // Llevar la cuenta (para automatizar m s // tarde algunas cosillas) } int PH_StartEngine(void) { // Se supone que ya se han construido todos los objetos. // Vamos a reservar la memoria que hace falta para todo el render int i; UWORD total_tris = 0; for (i = 0; i < s_num_objects; i++) { total_tris += s_objects[i].m_num_triangles; } if (!total_tris) return TRUE; // No hay objetos! s_pool = calloc(total_tris, sizeof(struct CGlobalTri)); if (!s_pool) return 0; // No hay memoria RestartPool(); return 1; } void PH_EndEngine(void) { free(s_pool); } static void ProjectVertices(struct CObject *pobj) { int i; struct CPoint *p = pobj->m_xvertices; struct CPoint2D *q = pobj->m_proj_vertices; for (i = 0; i < pobj->m_num_vertices; i++, p++, q++) { if (p->z < VERY_CLOSE) { q->x = 0; q->y = 0; continue; } q->x = (((DWORD)p->x << 8) / p->z) + 160; q->y = (((DWORD)p->y << 8) / p->z) + 100; } } static void DumpPolygons(struct CObject *p) { int i; struct CTriangle *pt = p->m_triangles; struct CPoint *pp1, *pp2, *pp3; // A¤adir todos los tri ngulos del objeto actual a la lista global, // haciendo un sencillo clipping accept/reject for (i = 0; i < p->m_num_triangles; i++, pt++) { struct CGlobalTri *pgtri; pp1 = p->m_xvertices + pt->p1; pp2 = p->m_xvertices + pt->p2; pp3 = p->m_xvertices + pt->p3; if (pp1->z < VERY_CLOSE || pp2->z < VERY_CLOSE || pp3->z < VERY_CLOSE) continue; pgtri = GetTri(); pgtri->m_num_obj = p->m_num_obj; pgtri->m_num_tri = i; pgtri->m_distance = pp1->z + pp2->z + pp3->z; pgtri->m_next = s_list; s_list = pgtri; } } void PH_DrawFrame(void) { int i; struct CGlobalTri *trav; // Comenzamos un render RestartPool(); s_list = NULL; TRACE(32,32,0); // Llamar a ProjectVertices y DumpPolygons para todos los pol¡gonos for (i = 0; i < s_num_objects; i++) { if (s_objects[i].m_active) { ProjectVertices(s_objects + i); DumpPolygons(s_objects + i); } } // Ordenar los tri ngulos de todos los objetos TRACE(16,16,16); SortTris(); // Dibujarlos todos con ph_fill, haciendo backface-culling for (trav = s_list; trav; trav = trav->m_next) { BYTE z_val[3]; struct CObject *pobj = s_objects + trav->m_num_obj; struct CTriangle *pt = pobj->m_triangles + trav->m_num_tri; TRACE(0,0,16); ex1 = pobj->m_proj_vertices[pt->p1].x; ey1 = pobj->m_proj_vertices[pt->p1].y; ex2 = pobj->m_proj_vertices[pt->p2].x; ey2 = pobj->m_proj_vertices[pt->p2].y; ex3 = pobj->m_proj_vertices[pt->p3].x; ey3 = pobj->m_proj_vertices[pt->p3].y; #ifdef BACKFACE_CULL if ((ex2-ex1)*(ey3-ey2)-(ey2-ey1)*(ex3-ex2) < 0) { continue; } #endif z_val[0] = pobj->m_xnormals[pt->p1].z; z_val[1] = pobj->m_xnormals[pt->p2].z; z_val[2] = pobj->m_xnormals[pt->p3].z; if (z_val[0] <= 0 && z_val[1] <= 0 && z_val[2] <= 0) { u1 = v1 = u2 = v2 = u3 = v3 = 0; } else { u1 = ((WORD)pobj->m_xnormals[pt->p1].x << 8) + 0x8000; v1 = ((WORD)pobj->m_xnormals[pt->p1].y << 8) + 0x8000; u2 = ((WORD)pobj->m_xnormals[pt->p2].x << 8) + 0x8000; v2 = ((WORD)pobj->m_xnormals[pt->p2].y << 8) + 0x8000; u3 = ((WORD)pobj->m_xnormals[pt->p3].x << 8) + 0x8000; v3 = ((WORD)pobj->m_xnormals[pt->p3].y << 8) + 0x8000; } TRACE(40,40,40); phong_fill(); } } ///////////////////////////////////////////////////////////////////////////// // Ordena la lista s_list, utilizando el m‚todo RADIX-SORT con ra¡z 16, // por lo que hacen falta 4 pasadas ///////////////////////////////////////////////////////////////////////////// #if 1 #define RADIX 16 #define PASSES 4 #define EXTRACT(num, pass) \ ((num >> (pass << 2)) & (RADIX-1)) #else #define RADIX 256 #define PASSES 2 #define EXTRACT(num, pass) \ ((num >> (pass << 3)) & (RADIX-1)) #endif static void SortTris(void) { WORD i, j; struct CGlobalTri *heads[RADIX], *head, **tails[RADIX], **tail, *trav, *temp_next; // Ordenar la lista de tri ngulos global head = s_list; for (i = 0; i < PASSES; i++) { // Inicializar tails for (j = 0; j < RADIX; j++) { tails[j] = heads + j; } // Recorrer la lista principal y separar en RADIX listas for (trav = head; trav; trav = temp_next) { int k; temp_next = trav->m_next; k = EXTRACT(trav->m_distance, i); *tails[k] = trav; tails[k] = &trav->m_next; } // Terminar las listas for (j = 0; j < RADIX; j++) { *tails[j] = NULL; } // A¤adir las listas a la lista principal head = NULL; tail = &head; //for (j = 0; j < RADIX; j++) { // Orden creciente for (j = RADIX - 1; j >= 0; j--) { // Orden decreciente if (heads[j]) { // A¤adir la lista n£mero 'j' al final *tail = heads[j]; tail = tails[j]; } } } s_list = head; } void PH_XFormVertices(HANDLE h, UWORD theta, UWORD phi, WORD x, WORD y, WORD z) { int i; DWORD cos_theta = Cos(theta); DWORD sin_theta = -Sin(theta); DWORD cos_phi = Cos(phi); DWORD sin_phi = Sin(phi); DWORD sinphi_sintheta = FPMult(sin_phi, sin_theta); DWORD sinphi_costheta = FPMult(sin_phi, cos_theta); DWORD cosphi_sintheta = FPMult(cos_phi, sin_theta); DWORD cosphi_costheta = FPMult(cos_phi, cos_theta); struct CPoint *p; struct CPoint *q; struct CObject *pobj = s_objects + h - 1; for (i = 0, p = pobj->m_vertices, q = pobj->m_xvertices ; i < pobj->m_num_vertices; i++, p++, q++) { /* q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta); q->y = y + p->y; q->z = z + FPMult(p->z, cos_theta) - FPMult(p->x, sin_theta); */ q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta); q->y = y - FPMult(p->x, sinphi_sintheta) + FPMult(p->y, cos_phi) + FPMult(p->z, sinphi_costheta); q->z = z - FPMult(p->x, cosphi_sintheta) - FPMult(p->y, sin_phi) + FPMult(p->z, cosphi_costheta); } } #define NONE 8 static int repr[] = { 2, 3, NONE, NONE, NONE, 4, NONE, 5, 1, NONE, 0, NONE, NONE, NONE, 7, 6 }; static BYTE u_repr[] = { 127, 90, 0, -90, -127, -90, 0, 90, 0}; // Last is for NONE static BYTE v_repr[] = { 0, 90, 127, 90, 0, -90, -127, -90, 0}; void PH_XFormNormals(HANDLE h, WORD theta, UWORD phi, WORD alpha) { int i; DWORD cos_theta, sin_theta, cos_phi, sin_phi; DWORD sinphi_sintheta; DWORD sinphi_costheta; DWORD cosphi_sintheta; DWORD cosphi_costheta; struct CObject *pobj = s_objects + h - 1; struct CNormal *r = pobj->m_normals; struct CNormal *s = pobj->m_xnormals; theta += alpha; cos_theta = Cos(theta); sin_theta = -Sin(theta); cos_phi = Cos(phi); sin_phi = Sin(phi); sinphi_sintheta = FPMult(sin_phi, sin_theta); sinphi_costheta = FPMult(sin_phi, cos_theta); cosphi_sintheta = FPMult(cos_phi, sin_theta); cosphi_costheta = FPMult(cos_phi, cos_theta); // Xform normals for (i = 0; i < pobj->m_num_vertices; i++) { /* s->x = FPMult(cos_sum, r->x) + FPMult(sin_sum, r->z); s->y = r->y; s->z = FPMult(cos_sum, r->z) - FPMult(sin_sum, r->x); */ s->x = FPMult(r->x, cos_theta) + FPMult(r->z, sin_theta); s->y = - FPMult(r->x, sinphi_sintheta) + FPMult(r->y, cos_phi) + FPMult(r->z, sinphi_costheta); s->z = - FPMult(r->x, cosphi_sintheta) - FPMult(r->y, sin_phi) + FPMult(r->z, cosphi_costheta); if (s->z <= 0) { WORD u, v, code; u = s->x; v = s->y; code = (((UWORD)(v - (u<<1))) >> 15) << 3 | (((UWORD)(u + (v<<1))) >> 15) << 2 | (((UWORD)((v<<1) - u)) >> 15) << 1 | (((UWORD)(v + (u<<1))) >> 15); s->x = u_repr[repr[code]]; s->y = v_repr[repr[code]]; } s++, r++; } } void PH_ActivateObj(HANDLE h, int active) { struct CObject *pobj = s_objects + h - 1; pobj->m_active = active; }