cx4fn.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #ifdef CX4_CPP
  2. #include <math.h>
  3. #define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
  4. #define sar(b, n) ((b) >> (n))
  5. #ifdef PI
  6. #undef PI
  7. #endif
  8. #define PI 3.1415926535897932384626433832795
  9. //Wireframe Helpers
  10. void Cx4::C4TransfWireFrame() {
  11. c4x = (double)C4WFXVal;
  12. c4y = (double)C4WFYVal;
  13. c4z = (double)C4WFZVal - 0x95;
  14. //Rotate X
  15. tanval = -(double)C4WFX2Val * PI * 2 / 128;
  16. c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
  17. c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
  18. //Rotate Y
  19. tanval = -(double)C4WFY2Val * PI * 2 / 128;
  20. c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
  21. c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
  22. //Rotate Z
  23. tanval = -(double)C4WFDist * PI * 2 / 128;
  24. c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
  25. c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
  26. //Scale
  27. C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
  28. C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
  29. }
  30. void Cx4::C4CalcWireFrame() {
  31. C4WFXVal = C4WFX2Val - C4WFXVal;
  32. C4WFYVal = C4WFY2Val - C4WFYVal;
  33. if(abs(C4WFXVal) > abs(C4WFYVal)) {
  34. C4WFDist = abs(C4WFXVal) + 1;
  35. C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
  36. C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
  37. } else if(C4WFYVal != 0) {
  38. C4WFDist = abs(C4WFYVal) + 1;
  39. C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
  40. C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
  41. } else {
  42. C4WFDist = 0;
  43. }
  44. }
  45. void Cx4::C4TransfWireFrame2() {
  46. c4x = (double)C4WFXVal;
  47. c4y = (double)C4WFYVal;
  48. c4z = (double)C4WFZVal;
  49. //Rotate X
  50. tanval = -(double)C4WFX2Val * PI * 2 / 128;
  51. c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
  52. c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
  53. //Rotate Y
  54. tanval = -(double)C4WFY2Val * PI * 2 / 128;
  55. c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
  56. c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
  57. //Rotate Z
  58. tanval = -(double)C4WFDist * PI * 2 / 128;
  59. c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
  60. c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
  61. //Scale
  62. C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
  63. C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
  64. }
  65. void Cx4::C4DrawWireFrame() {
  66. uint32 line = readl(0x1f80);
  67. uint32 point1, point2;
  68. int16 X1, Y1, Z1;
  69. int16 X2, Y2, Z2;
  70. uint8 Color;
  71. for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
  72. if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
  73. int32 tmp = line - 5;
  74. while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
  75. point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
  76. } else {
  77. point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
  78. }
  79. point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
  80. X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
  81. Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
  82. Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
  83. X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
  84. Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
  85. Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
  86. Color = bus.read(line + 4);
  87. C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
  88. }
  89. }
  90. void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
  91. //Transform coordinates
  92. C4WFXVal = (int16)X1;
  93. C4WFYVal = (int16)Y1;
  94. C4WFZVal = Z1;
  95. C4WFScale = read(0x1f90);
  96. C4WFX2Val = read(0x1f86);
  97. C4WFY2Val = read(0x1f87);
  98. C4WFDist = read(0x1f88);
  99. C4TransfWireFrame2();
  100. X1 = (C4WFXVal + 48) << 8;
  101. Y1 = (C4WFYVal + 48) << 8;
  102. C4WFXVal = (int16)X2;
  103. C4WFYVal = (int16)Y2;
  104. C4WFZVal = Z2;
  105. C4TransfWireFrame2();
  106. X2 = (C4WFXVal + 48) << 8;
  107. Y2 = (C4WFYVal + 48) << 8;
  108. //Get line info
  109. C4WFXVal = (int16)(X1 >> 8);
  110. C4WFYVal = (int16)(Y1 >> 8);
  111. C4WFX2Val = (int16)(X2 >> 8);
  112. C4WFY2Val = (int16)(Y2 >> 8);
  113. C4CalcWireFrame();
  114. X2 = (int16)C4WFXVal;
  115. Y2 = (int16)C4WFYVal;
  116. //Render line
  117. for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
  118. if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
  119. uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
  120. uint8 bit = 0x80 >> ((X1 >> 8) & 7);
  121. ram[addr + 0x300] &= ~bit;
  122. ram[addr + 0x301] &= ~bit;
  123. if(Color & 1) { ram[addr + 0x300] |= bit; }
  124. if(Color & 2) { ram[addr + 0x301] |= bit; }
  125. }
  126. X1 += X2;
  127. Y1 += Y2;
  128. }
  129. }
  130. void Cx4::C4DoScaleRotate(int row_padding) {
  131. int16 A, B, C, D;
  132. //Calculate matrix
  133. int32 XScale = readw(0x1f8f);
  134. int32 YScale = readw(0x1f92);
  135. if(XScale & 0x8000)XScale = 0x7fff;
  136. if(YScale & 0x8000)YScale = 0x7fff;
  137. if(readw(0x1f80) == 0) { //no rotation
  138. A = (int16)XScale;
  139. B = 0;
  140. C = 0;
  141. D = (int16)YScale;
  142. } else if(readw(0x1f80) == 128) { //90 degree rotation
  143. A = 0;
  144. B = (int16)(-YScale);
  145. C = (int16)XScale;
  146. D = 0;
  147. } else if(readw(0x1f80) == 256) { //180 degree rotation
  148. A = (int16)(-XScale);
  149. B = 0;
  150. C = 0;
  151. D = (int16)(-YScale);
  152. } else if(readw(0x1f80) == 384) { //270 degree rotation
  153. A = 0;
  154. B = (int16)YScale;
  155. C = (int16)(-XScale);
  156. D = 0;
  157. } else {
  158. A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
  159. B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
  160. C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
  161. D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
  162. }
  163. //Calculate Pixel Resolution
  164. uint8 w = read(0x1f89) & ~7;
  165. uint8 h = read(0x1f8c) & ~7;
  166. //Clear the output RAM
  167. memset(ram, 0, (w + row_padding / 4) * h / 2);
  168. int32 Cx = (int16)readw(0x1f83);
  169. int32 Cy = (int16)readw(0x1f86);
  170. //Calculate start position (i.e. (Ox, Oy) = (0, 0))
  171. //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
  172. //the function. We do Cx*A etc normally because the matrix parameters
  173. //already have the fractional parts.
  174. int32 LineX = (Cx << 12) - Cx * A - Cx * B;
  175. int32 LineY = (Cy << 12) - Cy * C - Cy * D;
  176. //Start loop
  177. uint32 X, Y;
  178. uint8 byte;
  179. int32 outidx = 0;
  180. uint8 bit = 0x80;
  181. for(int32 y = 0; y < h; y++) {
  182. X = LineX;
  183. Y = LineY;
  184. for(int32 x = 0; x < w; x++) {
  185. if((X >> 12) >= w || (Y >> 12) >= h) {
  186. byte = 0;
  187. } else {
  188. uint32 addr = (Y >> 12) * w + (X >> 12);
  189. byte = read(0x600 + (addr >> 1));
  190. if(addr & 1) { byte >>= 4; }
  191. }
  192. //De-bitplanify
  193. if(byte & 1) { ram[outidx ] |= bit; }
  194. if(byte & 2) { ram[outidx + 1] |= bit; }
  195. if(byte & 4) { ram[outidx + 16] |= bit; }
  196. if(byte & 8) { ram[outidx + 17] |= bit; }
  197. bit >>= 1;
  198. if(!bit) {
  199. bit = 0x80;
  200. outidx += 32;
  201. }
  202. X += A; //Add 1 to output x => add an A and a C
  203. Y += C;
  204. }
  205. outidx += 2 + row_padding;
  206. if(outidx & 0x10) {
  207. outidx &= ~0x10;
  208. } else {
  209. outidx -= w * 4 + row_padding;
  210. }
  211. LineX += B; //Add 1 to output y => add a B and a D
  212. LineY += D;
  213. }
  214. }
  215. #endif