static fixed fixisqrt(fixed v) { // TODO: Proper inverse square root float sq = fixsqrt(v); if(sq == 0) sq = 1; // Prevent div-by-zero (yes, this crashes a PS1!) return fixdiv(0x10000, sq); }
/* calculates the distance between two nodes */ fixed node_dist(NODE n1, NODE n2) { #define SCALE 64 fixed dx = itofix(n1.x - n2.x) / SCALE; fixed dy = itofix(n1.y - n2.y) / SCALE; return fixsqrt(fixmul(dx, dx) + fixmul(dy, dy)) * SCALE; }
/* calculates the distance between two curve_nodes */ fixed curve_node_dist(curve_node n1, curve_node n2) { #define SCALE 64 fixed dx = itofix(n1.x - n2.x) / SCALE; fixed dy = itofix(n1.y - n2.y) / SCALE; return fixsqrt(fixmul(dx, dx) + fixmul(dy, dy)) * SCALE; }
int main(int argc, char* argv[]) { int i; for (i = 1000; i > 0; --i) { float f1 = fixed2float(fixsqrt(int2fixed(i))); float f2 = sqrtf(i); float diff = f1 - f2; printf("%d\t%.2f\t%.2f\t%.2f\n", i, f1, f2, diff); assert(fabsf(diff) < fixed2float(2)); } TIMEIT(1000, for (i = 1000; i > 0; --i) fixsqrt(int2fixed(i))); system("pause"); return 0; }
int main(void) { /* declare three 32 bit (16.16) fixed point variables */ fixed x, y, z; if (allegro_init() != 0) return 1; /* convert integers to fixed point like this */ x = itofix(10); /* convert floating point to fixed point like this */ y = ftofix(3.14); /* fixed point variables can be assigned, added, subtracted, negated, * and compared just like integers, eg: */ z = x + y; allegro_message("%f + %f = %f\n", fixtof(x), fixtof(y), fixtof(z)); /* you can't add integers or floating point to fixed point, though: * z = x + 3; * would give the wrong result. */ /* fixed point variables can be multiplied or divided by integers or * floating point numbers, eg: */ z = y * 2; allegro_message("%f * 2 = %f\n", fixtof(y), fixtof(z)); /* you can't multiply or divide two fixed point numbers, though: * z = x * y; * would give the wrong result. Use fixmul() and fixdiv() instead, eg: */ z = fixmul(x, y); allegro_message("%f * %f = %f\n", fixtof(x), fixtof(y), fixtof(z)); /* fixed point trig and square root are also available, eg: */ z = fixsqrt(x); allegro_message("fixsqrt(%f) = %f\n", fixtof(x), fixtof(z)); return 0; }
GLvoid glRotatex(GLfixed theta, GLfixed x, GLfixed y, GLfixed z) // p35 2.9.2 { int i, j, k; // Ensure we have an axis of rotation! if(x == 0 && y == 0 && z == 0) return; // Mark dirty gl_mat_gte_isdirty = GL_TRUE; // OPTIMISATION: If on a single axis we don't need to tweak as much int zeros = 0; if(x == 0) zeros++; if(y == 0) zeros++; if(z == 0) zeros++; //if(0) if(zeros == 2) { // Rotate around an axis // FIXME: get correct rotation orders int a, b; if(x != 0) { a = 1; b = 2; } else if(y != 0) { a = 2; b = 0; } else { a = 0; b = 1; } // Get matrix pointer GLint stackidx = gl_mat_stack[gl_mat_cur]; GLfixed *rot = gl_mat_rot[gl_mat_cur][stackidx]; // Get sin/cos //theta /= 360; // dropping the "degrees" requirement, using direct angles instead GLfixed tsin = fixsin(theta); GLfixed tcos = fixcos(theta); // Get old values GLfixed ta0 = rot[a*3 + 0]; GLfixed ta1 = rot[a*3 + 1]; GLfixed ta2 = rot[a*3 + 2]; GLfixed tb0 = rot[b*3 + 0]; GLfixed tb1 = rot[b*3 + 1]; GLfixed tb2 = rot[b*3 + 2]; // Write new values // TODO: get this to behave rot[a*3 + 0] = fixmulf(ta0, tcos) - fixmulf(tb0, tsin); rot[a*3 + 1] = fixmulf(ta1, tcos) - fixmulf(tb1, tsin); rot[a*3 + 2] = fixmulf(ta2, tcos) - fixmulf(tb2, tsin); rot[b*3 + 0] = fixmulf(ta0, tsin) + fixmulf(tb0, tcos); rot[b*3 + 1] = fixmulf(ta1, tsin) + fixmulf(tb1, tcos); rot[b*3 + 2] = fixmulf(ta2, tsin) + fixmulf(tb2, tcos); return; } // // GENERIC OPENGL ROTATION // // Normalise x,y,z GLfixed vlen2 = fixmul(x,x) + fixmul(y,y) + fixmul(z,z); if(vlen2 >= 0x100) { GLfixed vlen = fixsqrt(vlen2); x = fixdiv(x, vlen); y = fixdiv(y, vlen); z = fixdiv(z, vlen); } else { // Length is too small to get a sane result // Use int multiplies instead and shift later // FIXME get this working correctly vlen2 = x*x + y*y + z*z; // Skip if we get 0 if(vlen2 == 0) return; GLfixed vlen = fixsqrt(vlen2)<<8; x = fixdiv(x, vlen); y = fixdiv(y, vlen); z = fixdiv(z, vlen); } // Get sin/cos theta /= 360; GLfixed tsin = fixsin(theta); GLfixed tcos = fixcos(theta); // Generate rotation matrix GLfixed itcos = 0x10000-tcos; GLfixed base_rot[3][3] = { { fixmulf(itcos, fixmulf(x, x))+tcos, fixmulf(itcos, fixmulf(x, y))-fixmulf(tsin, z), fixmulf(itcos, fixmulf(x, z))+fixmulf(tsin, y), }, { fixmulf(itcos, fixmulf(y, x))+fixmulf(tsin, z), fixmulf(itcos, fixmulf(y, y))+tcos, fixmulf(itcos, fixmulf(y, z))-fixmulf(tsin, x), }, { fixmulf(itcos, fixmulf(z, x))-fixmulf(tsin, y), fixmulf(itcos, fixmulf(z, y))+fixmulf(tsin, x), fixmulf(itcos, fixmulf(z, z))+tcos, }, }; // Apply rotation matrix GLint stackidx = gl_mat_stack[gl_mat_cur]; GLfixed *rot = gl_mat_rot[gl_mat_cur][stackidx]; //GLfixed *trn = gl_mat_trn[gl_mat_cur][stackidx]; GLfixed oldrot[9]; //GLfixed oldtrn[3]; memcpy(oldrot, rot, sizeof(GLfixed)*9); //memcpy(oldtrn, trn, sizeof(GLfixed)*3); // FIXME: translate properly // FIXME: ensure correct order for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) { GLfixed sum = 0; for(k = 0; k < 3; k++) //sum += fixmulf(oldrot[3*i + k], base_rot[k][j]); sum += fixmulf(oldrot[3*k + j], base_rot[i][k]); rot[3*i + j] = sum; } /* for(i = 0; i < 3; i++) { GLfixed sum = 0; for(k = 0; k < 3; k++) sum += fixmulf(oldtrn[k], rot[k*3 + i]); //sum += fixmulf(oldtrn[k], rot[i*3 + k]); //sum += fixmulf(oldtrn[k], base_rot[k][i]); //sum += fixmulf(oldtrn[k], base_rot[i][k]); //trn[i] = sum; } */ }