Main Page | Data Structures | File List | Data Fields | Globals

3d.c

00001 /*=========================================================================
00002 
00003 GFX - a small graphics library 
00004 
00005 Copyright (C) 2004  Rafael de Oliveira Jannone
00006 
00007 This library is free software; you can redistribute it and/or
00008 modify it under the terms of the GNU Lesser General Public
00009 License as published by the Free Software Foundation; either
00010 version 2.1 of the License, or (at your option) any later version.
00011 
00012 This library is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 Lesser General Public License for more details.
00016 
00017 You should have received a copy of the GNU Lesser General Public
00018 License along with this library; if not, write to the Free Software
00019 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021 Contact the author:
00022         by e-mail : rafael AT jannone DOT org
00023         homepage  : http://jannone.org/gfxlib
00024         ICQ UIN   : 10115284
00025 
00026 See the License at http://www.gnu.org/copyleft/lesser.txt
00027 
00028 =========================================================================*/
00029 
00030 // 3D.H : 3D graphics and vectors functions
00031 
00032 /* === WARNING ==
00033 
00034         This is a work-in-progress, meaning that most of this code is unstable
00035         and it's subject to future changes.  Also, most of it is very hackish,
00036         not properly cleaned up nor tested.
00037 
00038    === WARNING == */
00039 
00040 #include <stdlib.h>
00041 #include <math.h>
00042 #include "line.h"
00043 #include "3d.h"
00044 
00045 int *tcos, *tsin;
00046 
00047 void create_lookup_tables() {
00048         double M_PI = 8.0 * atan(1.0);
00049 
00050         int c;
00051         double a;
00052 
00053         tcos = newa(int, 256);
00054         tsin = newa(int, 256);
00055 
00056         for (c = 0; c < 256; c++) {
00057                 a = M_PI * c / 128;
00058                 tcos[c] = (int)(cos(a) * 64);
00059                 tsin[c] = (int)(sin(a) * 64);
00060         }
00061 }
00062 
00063 void destroy_lookup_tables() {
00064         free(tcos);
00065         free(tsin);
00066 }
00067 
00068 mesh_t* mesh_new(int pcount, int tcount) {
00069         mesh_t* r = new(mesh_t);
00070         r->pcount = pcount;
00071         r->tcount = tcount;
00072         r->points = newa(vector_t, pcount);
00073         r->triangles = newa(triangle_t, tcount);
00074         return r;
00075 }
00076 
00077 void mesh_delete(mesh_t* mesh) {
00078         free(mesh->points);
00079         free(mesh->triangles);
00080         free(mesh);
00081 }
00082 
00083 void vector_cross_product (vector_t* v1, vector_t* v2, vector_t* r) {
00084         int x, y, z;
00085         x = mulfx(v1->y, v2->z) - mulfx(v1->z, v2->y);
00086         y = mulfx(v1->z, v2->x) - mulfx(v1->x, v2->z);
00087         z = mulfx(v1->x, v2->y) - mulfx(v1->y, v2->x);
00088         r->x = x; r->y = y; r->z = z;
00089 }
00090 
00091 int vector_cross_product_z (vector_t* v1, vector_t* v2) {
00092         return mulfx(v1->x, v2->y) - mulfx(v1->y, v2->x);
00093 }
00094 
00095 int vector_dot_product (vector_t* v1, vector_t* v2) {
00096         return mulfx(v1->x, v2->x) + mulfx(v1->y, v2->y) + mulfx(v1->z, v2->z);
00097 }
00098 
00099 int vector_length_squared (vector_t *v) {
00100         return sqrfx(v->x) + sqrfx(v->y) + sqrfx(v->z);
00101 }
00102 
00103 int vector_length(vector_t *v) {
00104         return sqrtfx(vector_length_squared(v));
00105 }
00106 
00107 void vector_normalize(vector_t *p, vector_t *r) {
00108         int d = vector_length(p);
00109         if (d != 0) {
00110                 r->x = divfx(p->x, d);
00111                 r->y = divfx(p->y, d);
00112                 r->z = divfx(p->z, d);
00113         }
00114 }
00115 
00116 void vector_scalar(vector_t *v, int s, vector_t* r) {
00117         r->x = mulfx(v->x, s);
00118         r->y = mulfx(v->y, s);
00119         r->z = mulfx(v->z, s);
00120 }
00121 
00122 void vector_add(vector_t *v1, vector_t *v2, vector_t *r) {
00123         r->x = v1->x + v2->x;
00124         r->y = v1->y + v2->y;
00125         r->z = v1->z + v2->z;
00126 }
00127 
00128 void vector_subtract (vector_t *v1, vector_t *v2, vector_t *r) {
00129         r->x = v1->x - v2->x;
00130         r->y = v1->y - v2->y;
00131         r->z = v1->z - v2->z;
00132 }
00133 
00134 int vector_distance (vector_t *v1, vector_t *v2) {
00135         vector_t r;
00136         vector_subtract(v1, v2, &r);
00137         return vector_length(&r);
00138 }
00139 
00140 void vector_rotate(vector_t* p, u_char angle_x, u_char angle_y, u_char angle_z, vector_t* r) {
00141         int x, y, z;
00142         int ca, sa;
00143 
00144         // z
00145         ca = tcos[angle_z]; sa = tsin[angle_z];
00146         x = p->x; y = p->y; z = p->z;
00147         r->x = (mulfx(ca, x) - mulfx(sa, y));
00148         r->y = (mulfx(sa, x) + mulfx(ca, y));
00149         r->z = z;
00150 
00151         // y
00152         ca = tcos[angle_y]; sa = tsin[angle_y];
00153         x = r->x; y = r->y; z = r->z;
00154         r->x = (mulfx(ca, x) - mulfx(sa, z));
00155         r->z = (mulfx(sa, x) + mulfx(ca, z));
00156 
00157         // x
00158         ca = tcos[angle_x]; sa = tsin[angle_x];
00159         x = r->x; y = r->y; z = r->z;
00160         r->y = (mulfx(ca, y) - mulfx(sa, z));
00161         r->z = (mulfx(sa, y) + mulfx(ca, z));
00162 }
00163 
00164 void object_apply_transformations(object_t* obj, vector_t* pbuffer, int x, int y) {
00165         mesh_t* mesh = obj->mesh;
00166         vector_t* m = mesh->points;
00167         int c = mesh->pcount;
00168         while (c--) {
00169                 vector_rotate(m, obj->rot_x, obj->rot_y, obj->rot_z, pbuffer);
00170                 pbuffer->z += obj->trans_z;
00171                 pbuffer->z /= 128;
00172                 pbuffer->x = ((pbuffer->x + obj->trans_x) / pbuffer->z) + x;
00173                 pbuffer->y = ((pbuffer->y + obj->trans_y) / pbuffer->z) + y;
00174                 ++pbuffer;
00175                 ++m;
00176         }
00177 }
00178 
00179 void object_render_wireframe(surface_t* s, object_t* obj, vector_t* pbuffer) {
00180         int c, diff;
00181         vector_t *i, *j, *k, q1, q2;
00182         mesh_t* mesh = obj->mesh;
00183         vector_t* m = mesh->points;
00184         triangle_t* t = mesh->triangles;
00185 
00186         object_apply_transformations(obj, pbuffer, 128, 96); // FIXME: must use surface center
00187 
00188         m = mesh->points;
00189         diff = (char*)pbuffer - (char*)m;
00190         for (c = 0; c < mesh->tcount; c++) {
00191                 i = (vector_t*)((char*)t->vertexes[0] + diff);
00192                 j = (vector_t*)((char*)t->vertexes[1] + diff);
00193                 k = (vector_t*)((char*)t->vertexes[2] + diff);
00194 
00195                 vector_subtract(j, i, &q1);
00196                 vector_subtract(k, i, &q2);
00197                 if (vector_cross_product_z(&q1, &q2) > 0) {
00198                         surface_line(s, i->x, i->y, j->x, j->y);
00199                         surface_line(s, j->x, j->y, k->x, k->y);
00200                         surface_line(s, k->x, k->y, i->x, i->y);
00201                 }
00202                 t++;
00203         }       
00204 }
00205 
00206 void object_render_flatshading(surface_t* s, object_t* obj, vector_t* pbuffer, int* low, int* high, vector_t* light) {
00207         int c, diff;
00208         int l, top, bottom;
00209         vector_t *i, *j, *k, q1, q2, N;
00210         mesh_t* mesh = obj->mesh;
00211         vector_t* m = mesh->points;
00212         triangle_t* t = mesh->triangles;
00213         int li;
00214 
00215         object_apply_transformations(obj, pbuffer, 128, 96); // FIXME: must use surface center
00216 
00217         m = mesh->points;
00218         diff = (char*)pbuffer - (char*)m;
00219         for (c = 0; c < mesh->tcount; c++) {
00220                 i = (vector_t*)((char*)t->vertexes[0] + diff);
00221                 j = (vector_t*)((char*)t->vertexes[1] + diff);
00222                 k = (vector_t*)((char*)t->vertexes[2] + diff);
00223 
00224                 vector_subtract(j, i, &q1);
00225                 vector_subtract(k, i, &q2);
00226                 vector_cross_product(&q1, &q2, &N);
00227 
00228                 if (N.z > 0) {
00229                         vector_normalize(&N, &N);
00230                         li = vector_dot_product(&N, light) * 5;
00231                         li = f2i(li);
00232                         li = (li < 0) ? 0 : ((li > 4) ? 4 : li);
00233 
00234                         // FIXME: can optimize memset's by covering only "top" to "bottom" lines
00235                         // in this case we should require clean buffers to start with.
00236                         // and we should clean them after rendering.
00237                         memset(low, MODE2_HEIGHT << 1, 64);     // FIXME: must use surface height
00238                         memset(high, MODE2_HEIGHT << 1, 0);     // FIXME: must use surface height
00239 
00240                         // calculate polygon
00241                         calculate_side(i->x, i->y, j->x, j->y, low, high);
00242                         calculate_side(j->x, j->y, k->x, k->y, low, high);
00243                         calculate_side(k->x, k->y, i->x, i->y, low, high);
00244 
00245                         top = (i->y < j->y) ? ((i->y < k->y) ? i->y : k->y) : ((j->y < k->y) ? j->y : k->y);
00246                         bottom = (i->y > j->y) ? ((i->y > k->y) ? i->y : k->y) : ((j->y > k->y) ? j->y : k->y);
00247 
00248                         for (l = top; l <= bottom; l++) {
00249                                 surface_hline(s, low[l], l, high[l], DITHER(li, l));
00250                         }
00251                 }
00252                 t++;
00253         }       
00254 }

Generated on Thu Mar 3 19:55:01 2005 for GFX lib by  doxygen 1.4.1