c_render.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. // c_render.cpp
  2. // Drawing code for the graphics window
  3. // Copyright (C)/©/¸ Codemist Ltd, 1995-2001
  4. /* Signature: 66b0240a 08-Apr-2002 */
  5. /*
  6. * This code may be used and modified, and redistributed in binary
  7. * or source form, subject to the "CCL Public License", which should
  8. * accompany it. This license is a variant on the BSD license, and thus
  9. * permits use of code derived from this in either open and commercial
  10. * projects: but it does require that updates to this code be made
  11. * available back to the originators of the package.
  12. * Before merging other code in with this or linking this code
  13. * with other packages or libraries please check that the license terms
  14. * of the other material are compatible with those of this.
  15. */
  16. #ifdef GRAPHICS_WINDOW
  17. #include "cwin.hpp"
  18. // I have two serious concerns here. The first is the amount of space needed
  19. // to store descriptions of objects that I might draw. The second is the
  20. // potential performance-bottleneck of floating point arithmetic on many
  21. // PCs. To try to alleviate these difficulties I will do much of my work
  22. // using fixed point arithmetic and with data packed into 16-bit fields
  23. // in structures.
  24. // I will store 3D points (after rotation and so on) with X and Y
  25. // coordinates in the range 0 to 64K, and I will translate & clip this
  26. // so that objects at (0x8000, 0x8000) appear in the middle of my screen.
  27. // But I will leave myself a full range of integers for the Z coordinate
  28. // so that I do not have to worry so much about fine-tuning the
  29. // transformations I use in that respect.
  30. // The odd-looking range for X and Y is so I can use unsigned bitfield
  31. // components in the following structure.
  32. // If I want to do Phong shading at some stage (that puts nice highlights
  33. // onto rendered surfaces) I should extend the representation of an
  34. // XYZPoint to include a surface normal. It should be enough to use 10
  35. // bits for each of the three direction cosines, since I do not have
  36. // that many bits of discrimination in my control over display brightness.
  37. // I put the field in now so that using it later on will be easy, but
  38. // will probably not fill in the values to start with. Note that the
  39. // direction cosines need to be signed fields, so I should normalise them
  40. // to the range -511 to +511 (nb NOT 512). The typedef is in my main
  41. // header file but is replicated here to make it easier to read this code.
  42. //-- typedef struct tagXYZPoint
  43. //-- {
  44. //-- unsigned int x:16;
  45. //-- unsigned int y:16;
  46. //-- int z;
  47. //-- signed int nx:10, ny:10, nz:10;
  48. //-- unsigned int red:8, green:8, blue:8, spare:8;
  49. //-- } XYZPoint;
  50. // I will build up images out of triangles. When I need a rectangle or
  51. // bigger polygon I will just split it into triangles. I will assume that
  52. // all the vertices I will ever use have been stored in a linear array
  53. // of type XYZPoint[].
  54. // A triangle is then represented as a triple of XYZPoints each denoted
  55. // by their index values in the array, say v1, v2, v3.
  56. // The vertices should be listed in clockwise when viewed from the "outside"
  57. // of the object, and if pairs of triangles are used to form rectangles
  58. // then the diagonal of the rectangle should be given as the first pair of
  59. // vertices.
  60. // When a triangle is drawn some or all of its edges can be drawn in with
  61. // a pen that will often have a contrasting colour to that used for the
  62. // interior of the cell. The need to have only SOME edges drawn in this
  63. // way arises when larger polygons have been split into multiple triangles
  64. // for processing - the edges of the original polygon may need drawing but
  65. // synthetic interior joins do not. The three flag bits edge1, edge2 and
  66. // edge3 are used to control which (if any) edges get drawn. All edges
  67. // in an entire figure will end up drawn in the same colour: no provision is
  68. // made for giving all the edges their own separate colours.
  69. //***** What follows has not been implemented yet *****
  70. // So that axes and other line-art can be included there is special support
  71. // for straight line "triangles". These have the flag "lineflag" set and then
  72. // do not need to use vertex3, which should be set equal to vertex2.
  73. // A record with lineflag set represents a straight line segment from vertex1
  74. // to vertex2. If edge1 is set it is drawn in the outline colour (as used for
  75. // edges of proper triangles) while otherwise it uses its own R-G-B colour.
  76. // If vertex1 is equal to vertex2 when lineflag is set then the record would
  77. // appear to represent a point (and vertex3 will be equal to vertex1 and
  78. // vertex2). I am inclined to believe that I do not want to draw individual
  79. // points.
  80. typedef struct tagTriangle
  81. { // Observe that each line packs to just 16 bits.
  82. // At present I leave 15 bits spare! I used to keep a colour in
  83. // that slot but now I keep colous with vertices not faces, so do
  84. // not need that space.
  85. unsigned int lineflag:1, moved:1, spare:14;
  86. unsigned int edge1:1, vertex1:15;
  87. unsigned int edge2:1, vertex2:15;
  88. unsigned int edge3:1, vertex3:15;
  89. } Triangle;
  90. // The above layout has several uncomfortable limitations. Perhaps the
  91. // most obvious is that it can only handle 32K points. This represents
  92. // a grid 180 by 180. A brief experiment with "gnuplot" suggests that it
  93. // runs out of space well before that, and many plots I have seen demonstrated
  94. // use a grid that is more like 20 by 20, The examples in the Jenks and
  95. // Sutor book on Axiom have their most impressive pictures using under
  96. // 25K vertices (a bit tight....) and I think that only their fractal
  97. // images (eg Antoine's Necklace) would defeat the structure I have here.
  98. // I could keep my triangle records the same size but allow for up to
  99. // about 1000000 vertices by packing vertex numbers in a way that would
  100. // cross word boundaries. I will consider that possibility later on.
  101. // I will do a somewhat crude job clipping triangles that do not intersect
  102. // the part of the screen that is being re-drawn.
  103. // I will also assume that triangles never intersect, so a version
  104. // of the painter's algorithm will do for rendering.
  105. XYZPoint *points;
  106. Triangle *triangles;
  107. int triangleCount = 0;
  108. #define x_steps 27
  109. #define y_steps 29
  110. XYZPoint vertices[(x_steps+1)*(y_steps+1)];
  111. Triangle faces[x_steps*y_steps*2];
  112. // I will want to colour faces based on their Z coordinate or some other
  113. // parameter. The following function maps an integer into a colour in
  114. // such a way that increasing the integer leads to a sequence of colours
  115. // that cycles through the rainbow and then back from blue to red via
  116. // magenta.
  117. void selectColour(int z, int &red, int &green, int &blue)
  118. {
  119. while (z < 0) z += (6*255)*0x00100000;
  120. z = z % (6*255);
  121. switch (z / 255)
  122. {
  123. case 0: red = 255;
  124. green = z % 255;
  125. blue = 0;
  126. return;
  127. case 1: red = 255 - z % 255;
  128. green = 255;
  129. blue = 0;
  130. return;
  131. case 2: red = 0;
  132. green = 255;
  133. blue = z % 255;
  134. return;
  135. case 3: red = 0;
  136. green = 255 - z % 255;
  137. blue = 255;
  138. return;
  139. case 4: red = z % 255;
  140. green = 0;
  141. blue = 255;
  142. return;
  143. case 5: red = 255;
  144. green = 0;
  145. blue = 255 - z % 255;
  146. return;
  147. }
  148. }
  149. // The "raw data" section of this code is really for debugging purposes only
  150. // and will need to be replaced by something that can accept surface
  151. // specifications from some external source.
  152. typedef struct tagRealPoint
  153. {
  154. double x, y, z;
  155. } RealPoint;
  156. RealPoint rawData[x_steps+1][y_steps+1];
  157. CBrush thirtyTwoBrushes[32];
  158. void initRawData()
  159. {
  160. int x, y;
  161. for (x=0; x<=x_steps; x++)
  162. { double rx = (6.0*(double)x)/(double)x_steps - 3.0;
  163. for (y=0; y<=y_steps; y++)
  164. { int n = x+(x_steps+1)*y;
  165. double ry = (6.0*(double)y)/(double)y_steps - 3.0;
  166. double rz = 3.0*cos(3.0*sqrt(rx*rx+ry*ry));
  167. rawData[x][y].x = rx;
  168. rawData[x][y].y = ry;
  169. rawData[x][y].z = rz;
  170. }
  171. }
  172. for (int i=0; i<32; i++)
  173. { int red, green, blue;
  174. selectColour((255*6*i)/32, red, green, blue);
  175. thirtyTwoBrushes[i].CreateSolidBrush(RGB(red, green, blue));
  176. }
  177. }
  178. static doneInit = 0;
  179. // I truncate at 2^30 because that is slightly easier than using the
  180. // whole of the integer range, and the cases where it makes a difference
  181. // will not arise very often.
  182. #define IntegerRange 1073741824.0 // 2^30
  183. void CGraphicsWindow::initSurface()
  184. {
  185. if (doneInit == 0)
  186. { initRawData();
  187. doneInit = 1;
  188. }
  189. int x, y, sx, sy;
  190. points = vertices;
  191. for (x=0; x<=x_steps; x++)
  192. { for (y=0; y<=y_steps; y++)
  193. { int n = x+(x_steps+1)*y;
  194. double rx = rawData[x][y].x;
  195. double ry = rawData[x][y].y;
  196. double rz = rawData[x][y].z;
  197. double aw = xform[3][3];
  198. double ax = (xform[0][0]*rx+xform[1][0]*ry+xform[2][0]*rz+xform[3][0])/aw;
  199. double ay = (xform[0][1]*rx+xform[1][1]*ry+xform[2][1]*rz+xform[3][1])/aw;
  200. double az = (xform[0][2]*rx+xform[1][2]*ry+xform[2][2]*rz+xform[3][2])/aw;
  201. double rw = perspecDistance/(perspecDistance - az);
  202. ax *= rw;
  203. ay *= rw;
  204. if (ax < -IntegerRange) sx = 0;
  205. else if (ax > IntegerRange) sx = 0xffff;
  206. else sx = 0x8000+(int)ax;
  207. if (sx < 0) sx = 0; else if (sx > 0xffff) sx = 0xffff;
  208. points[n].x = sx;
  209. if (ay < -IntegerRange) sy = 0;
  210. else if (ay > IntegerRange) sy = 0xffff;
  211. else sy = 0x8000+(int)ay;
  212. if (sy < 0) sy = 0; else if (sy > 0xffff) sy = 0xffff;
  213. points[n].y = sy;
  214. if (az < -IntegerRange) az = -IntegerRange;
  215. else if (az > IntegerRange) az = IntegerRange;
  216. points[n].z = (int)az;
  217. int red, green, blue;
  218. selectColour((int)(400.0*rz), red, green, blue);
  219. points[n].red = red;
  220. points[n].green = green;
  221. points[n].blue = blue;
  222. points[n].spare = 0xff & (int)(100*rz);
  223. }
  224. }
  225. triangles = faces;
  226. triangleCount = 0;
  227. for (x=0; x<x_steps; x++)
  228. { for (y=0; y<y_steps; y++)
  229. { int n = x+(x_steps+1)*y;
  230. // I set things up here so that edges 1 and 2 of each triangle are the
  231. // ones that form the diagonal of the rectangle that is being divided. I
  232. // do this so that it is at least partially reasonable to select a colour
  233. // for the whole of a triangle by averaging these...
  234. triangles[triangleCount].lineflag = 0;
  235. triangles[triangleCount].edge1 = 0;
  236. triangles[triangleCount].edge2 = 1;
  237. triangles[triangleCount].edge3 = 1;
  238. triangles[triangleCount+1].lineflag = 0;
  239. triangles[triangleCount+1].edge1 = 0;
  240. triangles[triangleCount+1].edge2 = 1;
  241. triangles[triangleCount+1].edge3 = 1;
  242. // Note I make the triangles clockwise here
  243. int x1 = points[n].x, y1 = points[n].y, z1 = points[n].z;
  244. int x2 = points[n+1].x, y2 = points[n+1].y, z2 = points[n+1].z;
  245. int x3 = points[n+x_steps+1].x, y3 = points[n+x_steps+1].y, z3 = points[n+x_steps+1].z;
  246. int x4 = points[n+x_steps+2].x, y4 = points[n+x_steps+2].y, z4 = points[n+x_steps+2].z;
  247. int d1 = x4-x1, d2 = y4-y1, d3 = z4-z1;
  248. int d4 = x3-x2, d5 = y3-y2, d6 = z3-z2;
  249. if (d1*d1+d2*d2+d3*d3 >= d4*d4+d5*d5+d6*d6)
  250. { triangles[triangleCount].vertex1 = n + x_steps + 1;
  251. triangles[triangleCount].vertex2 = n + 1;
  252. triangles[triangleCount].vertex3 = n;
  253. triangles[triangleCount+1].vertex1 = n + 1;
  254. triangles[triangleCount+1].vertex2 = n + x_steps + 1;
  255. triangles[triangleCount+1].vertex3 = n + x_steps + 2;
  256. }
  257. else
  258. { triangles[triangleCount].vertex1 = n + x_steps + 2;
  259. triangles[triangleCount].vertex2 = n;
  260. triangles[triangleCount].vertex3 = n + x_steps + 1;
  261. triangles[triangleCount+1].vertex1 = n;
  262. triangles[triangleCount+1].vertex2 = n + x_steps + 2;
  263. triangles[triangleCount+1].vertex3 = n + 1;
  264. }
  265. triangleCount += 2;
  266. }
  267. }
  268. sortTriangles();
  269. }
  270. int triangleLeft(const Triangle *a)
  271. {
  272. int w, r;
  273. r = points[a->vertex1].x;
  274. if ((w = points[a->vertex2].x) < r) r = w;
  275. if ((w = points[a->vertex3].x) < r) r = w;
  276. return r;
  277. }
  278. int triangleRight(const Triangle *a)
  279. {
  280. int w, r;
  281. r = points[a->vertex1].x;
  282. if ((w = points[a->vertex2].x) > r) r = w;
  283. if ((w = points[a->vertex3].x) > r) r = w;
  284. return r;
  285. }
  286. int triangleBottom(const Triangle *a)
  287. {
  288. int w, r;
  289. r = points[a->vertex1].y;
  290. if ((w = points[a->vertex2].y) < r) r = w;
  291. if ((w = points[a->vertex3].y) < r) r = w;
  292. return r;
  293. }
  294. int triangleTop(const Triangle *a)
  295. {
  296. int w, r;
  297. r = points[a->vertex1].y;
  298. if ((w = points[a->vertex2].y) > r) r = w;
  299. if ((w = points[a->vertex3].y) > r) r = w;
  300. return r;
  301. }
  302. int triangleFar(const Triangle *a)
  303. {
  304. int w, r;
  305. r = points[a->vertex1].z;
  306. if ((w = points[a->vertex2].z) < r) r = w;
  307. if ((w = points[a->vertex3].z) < r) r = w;
  308. return r;
  309. }
  310. int triangleNear(const Triangle *a)
  311. {
  312. int w, r;
  313. r = points[a->vertex1].z;
  314. if ((w = points[a->vertex2].z) > r) r = w;
  315. if ((w = points[a->vertex3].z) > r) r = w;
  316. return r;
  317. }
  318. int orderTriangles(const void *va, const void *vb)
  319. {
  320. int za = triangleFar((const Triangle *)va);
  321. int zb = triangleFar((const Triangle *)vb);
  322. if (za < zb) return -1;
  323. else if (za > zb) return 1;
  324. else return 0;
  325. }
  326. // The next function returns 1 is the line (a1-a2) lies above (and thus
  327. // obscures) the line (b1-b2), or -1 if there is an obscuring that goes
  328. // the other way.
  329. int linesCross(XYZPoint *a1, XYZPoint *a2, XYZPoint *b1, XYZPoint *b2)
  330. {
  331. // Firstly I will discard all cases where the line segments are not incident.
  332. int l1 = a1->y-a2->y, m1 = a2->x-a1->x, n1 = a1->x*a2->y-a2->x*a1->y;
  333. int u1 = l1*b1->x+m1*b1->y+n1, u2 = l1*b2->x+m1*b2->y+n1;
  334. if (u1 >= 0 && u2 >= 0) return 0;
  335. if (u1 <= 0 && u2 <= 0) return 0;
  336. int l2 = b1->y-b2->y, m2 = b2->x-b1->x, n2 = b1->x*b2->y-b2->x*b1->y;
  337. int v1 = l2*a1->x+m2*a1->y+n2, v2 = l2*a2->x+m2*a2->y+n2;
  338. if (v1 >= 0 && v2 >= 0) return 0;
  339. if (v1 <= 0 && v2 <= 0) return 0;
  340. // Now I know that the line segments cross in their XY projections, so I
  341. // compute the Z coordinates of the intersection.
  342. double z1 = ((double)v1*(double)a2->z-(double)v2*(double)a1->z)/
  343. (double)(v1-v2);
  344. double z2 = ((double)u1*(double)b2->z-(double)u2*(double)b1->z)/
  345. (double)(u1-u2);
  346. if (z1 > z2) return 1;
  347. if (z1 < z2) return -1;
  348. // The position here is possibly nasty - the two triangles DO overlap, but
  349. // at the point where the edges cross they have the same distance. I should
  350. // do something more here, but that can come later on.
  351. return 0;
  352. }
  353. int insideTriangle(XYZPoint *a, XYZPoint *b1, XYZPoint *b2, XYZPoint *b3)
  354. {
  355. // place-holder
  356. return 0;
  357. }
  358. int triangleObscures(Triangle *a, Triangle *b)
  359. {
  360. XYZPoint *a1 = &points[a->vertex1],
  361. *a2 = &points[a->vertex2],
  362. *a3 = &points[a->vertex3];
  363. XYZPoint *b1 = &points[b->vertex1],
  364. *b2 = &points[b->vertex2],
  365. *b3 = &points[b->vertex3];
  366. int v;
  367. if ((v = linesCross(a1, a2, b1, b2)) != 0) return (v > 0);
  368. if ((v = linesCross(a1, a2, b2, b3)) != 0) return (v > 0);
  369. if ((v = linesCross(a1, a2, b3, b1)) != 0) return (v > 0);
  370. if ((v = linesCross(a2, a3, b1, b2)) != 0) return (v > 0);
  371. if ((v = linesCross(a2, a3, b2, b3)) != 0) return (v > 0);
  372. if ((v = linesCross(a2, a3, b3, b1)) != 0) return (v > 0);
  373. if ((v = linesCross(a3, a1, b1, b2)) != 0) return (v > 0);
  374. if ((v = linesCross(a3, a1, b2, b3)) != 0) return (v > 0);
  375. if ((v = linesCross(a3, a1, b3, b1)) != 0) return (v > 0);
  376. if ((v = insideTriangle(a1, b1, b2, b3)) != 0) return v;
  377. if ((v = insideTriangle(a2, b1, b2, b3)) != 0) return v;
  378. if ((v = insideTriangle(a3, b1, b2, b3)) != 0) return v;
  379. if ((v = insideTriangle(b1, a1, a2, a3)) != 0) return v;
  380. if ((v = insideTriangle(b2, a1, a2, a3)) != 0) return v;
  381. if ((v = insideTriangle(b3, a1, a2, a3)) != 0) return v;
  382. return 0;
  383. }
  384. // After setting up the list of triangles (which must be re-done each time
  385. // I rotate or re-scale) I must call the following to Z-sort the data
  386. void CGraphicsWindow::sortTriangles()
  387. {
  388. // First I do a simple and direct sort based on the lowest point in each
  389. // triangle.
  390. qsort(triangles, triangleCount, sizeof(Triangle), orderTriangles);
  391. // Now the ordering I am left with is NOT guaranteed adequate, since I might
  392. // have a tall triangle whose lowest point is very low but where some
  393. // other triangle that starts higher up is in fact underneath it where they
  394. // happen to cross. I will do something more like an insertion sort
  395. // now to try to fix up such cases.
  396. int i;
  397. for (i=0; i<triangleCount; i++) triangles[i].moved = 0;
  398. i = 0;
  399. while (i<triangleCount-1)
  400. { int l = triangleLeft(&triangles[i]),
  401. r = triangleRight(&triangles[i]),
  402. t = triangleTop(&triangles[i]),
  403. b = triangleBottom(&triangles[i]),
  404. n = triangleNear(&triangles[i]);
  405. for (int j=i+1;j<triangleCount;j++)
  406. { if (triangleFar(&triangles[j]) >= n) break;
  407. if (triangleLeft(&triangles[j]) >= r) continue;
  408. if (triangleRight(&triangles[j]) <= l) continue;
  409. if (triangleBottom(&triangles[j]) >= t) continue;
  410. if (triangleTop(&triangles[j]) <= b) continue;
  411. if (triangleObscures(&triangles[i], &triangles[j]))
  412. { if (triangles[j].moved) continue;
  413. triangles[i].moved = 1;
  414. Triangle w = triangles[j];
  415. for (int k=j-1; k>=i; k--)
  416. triangles[k+1] = triangles[k];
  417. triangles[i] = w;
  418. i--;
  419. break;
  420. }
  421. }
  422. i++;
  423. }
  424. }
  425. // Supposing that the triangles have been sorted so that the bottom-most
  426. // one is at the front of the vector, I can just paint all the data...
  427. void CGraphicsWindow::paintTriangles(CDC *dc, RECT *clip, int width, int height)
  428. {
  429. // TESTING CODE HERE
  430. initSurface();
  431. // END OF TESTING CODE
  432. Triangle *p = triangles;
  433. int i;
  434. for (i=0; i<triangleCount; i++, p++)
  435. { BOOL lineflag = p->lineflag;
  436. XYZPoint *v1 = &points[p->vertex1],
  437. *v2 = &points[p->vertex2],
  438. *v3 = &points[p->vertex3];
  439. int xscale = (65536*width)/10000,
  440. yscale = (65536*height)/10000;
  441. int xoff = width/2, yoff = height/2;
  442. int x1 = xoff + ((((int)v1->x-32768)*xscale)>>16),
  443. y1 = yoff - ((((int)v1->y-32768)*yscale)>>16);
  444. int x2 = xoff + ((((int)v2->x-32768)*xscale)>>16),
  445. y2 = yoff - ((((int)v2->y-32768)*yscale)>>16);
  446. int x3 = xoff + ((((int)v3->x-32768)*xscale)>>16),
  447. y3 = yoff - ((((int)v3->y-32768)*yscale)>>16);
  448. if (clip != NULL)
  449. { int left = clip->left,
  450. top = clip->top,
  451. right = clip->right,
  452. bottom = clip->bottom;
  453. if (x1 < left && x2 < left && x3 < left) continue;
  454. if (x1 > right && x2 > right && x3 > right) continue;
  455. if (y1 < top && y2 < top && y3 < top) continue;
  456. if (y1 > bottom && y2 > bottom && y3 > bottom) continue;
  457. }
  458. int red1 = v1->red, green1 = v1->green, blue1 = v1->blue;
  459. int red2 = v2->red, green2 = v2->green, blue2 = v2->blue;
  460. int red3 = v3->red, green3 = v3->green, blue3 = v3->blue;
  461. BOOL e1 = p->edge1, e2 = p->edge2, e3 = p->edge3;
  462. if (fullRender || !wirePreview || !viewpointShown)
  463. { if (!drawWire && drawSurface != IDM_NOSURFACE) e1 = e2 = e3 = 0;
  464. switch (drawSurface)
  465. {
  466. case IDM_NOSURFACE:
  467. break;
  468. case IDM_SURFACE:
  469. { CBrush *b = &thirtyTwoBrushes[v1->spare & 0x1f];
  470. POINT tri[3];
  471. tri[0].x = x1; tri[0].y = y1;
  472. tri[1].x = x2; tri[1].y = y2;
  473. tri[2].x = x3; tri[2].y = y3;
  474. dc->SelectObject(b);
  475. dc->SelectStockObject(NULL_PEN);
  476. dc->Polygon(tri, 3);
  477. dc->SelectStockObject(BLACK_BRUSH);
  478. break;
  479. }
  480. case IDM_SQUARES:
  481. { CBrush b(RGB((red1+red2)/2, (green1+green2)/2, (blue1+blue2)/2));
  482. POINT tri[3];
  483. tri[0].x = x1; tri[0].y = y1;
  484. tri[1].x = x2; tri[1].y = y2;
  485. tri[2].x = x3; tri[2].y = y3;
  486. dc->SelectObject(&b);
  487. dc->SelectStockObject(NULL_PEN);
  488. dc->Polygon(tri, 3);
  489. dc->SelectStockObject(BLACK_BRUSH);
  490. break;
  491. }
  492. case IDM_TRIANGLES:
  493. { CBrush b(RGB((red1+red2+red3)/3,
  494. (green1+green2+green3)/3,
  495. (blue1+blue2+blue3)/3));
  496. POINT tri[3];
  497. tri[0].x = x1; tri[0].y = y1;
  498. tri[1].x = x2; tri[1].y = y2;
  499. tri[2].x = x3; tri[2].y = y3;
  500. dc->SelectObject(&b);
  501. dc->SelectStockObject(NULL_PEN);
  502. dc->Polygon(tri, 3);
  503. dc->SelectStockObject(BLACK_BRUSH);
  504. break;
  505. }
  506. case IDM_SMOOTH:
  507. dc->SelectStockObject(NULL_PEN);
  508. SubTriangle(dc, x1, y1, red1, green1, blue1,
  509. x2, y2, red2, green2, blue2,
  510. x3, y3, red3, green3, blue3, 2);
  511. break;
  512. case IDM_HISMOOTH:
  513. dc->SelectStockObject(NULL_PEN);
  514. SubTriangle(dc, x1, y1, red1, green1, blue1,
  515. x2, y2, red2, green2, blue2,
  516. x3, y3, red3, green3, blue3, 4);
  517. break;
  518. }
  519. }
  520. if (e1 && e3)
  521. { dc->SelectStockObject(BLACK_PEN);
  522. dc->MoveTo(x3, y3);
  523. dc->LineTo(x1, y1);
  524. dc->LineTo(x2, y2);
  525. if (e2) dc->LineTo(x3, y3);
  526. }
  527. else if (e1)
  528. { dc->SelectStockObject(BLACK_PEN);
  529. dc->MoveTo(x1, y1);
  530. dc->LineTo(x2, y2);
  531. if (e2) dc->LineTo(x3, y3);
  532. }
  533. else if (e2)
  534. { dc->SelectStockObject(BLACK_PEN);
  535. dc->MoveTo(x2, y2);
  536. dc->LineTo(x3, y3);
  537. if (e3) dc->LineTo(x1, y1);
  538. }
  539. else if (e3)
  540. { dc->SelectStockObject(BLACK_PEN);
  541. dc->MoveTo(x3, y3);
  542. dc->LineTo(x1, y1);
  543. }
  544. }
  545. if (!GetUpdateRect(NULL, FALSE))
  546. { fullyRendered = fullRender;
  547. fullRender = 0;
  548. }
  549. }
  550. #endif
  551. // end of c_render.cpp