//Copyright Paul Reiche, Fred Ford. 1992-2002 /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "../units.h" #include "libs/gfxlib.h" #include "libs/graphics/context.h" #include "libs/graphics/drawable.h" #include "planets.h" #define NUM_QUADS 4 void DrawOval (RECT *pRect, BYTE num_off_pixels) { #define FIRST_QUAD (1 << 0) #define SECOND_QUAD (1 << 1) #define THIRD_QUAD (1 << 2) #define FOURTH_QUAD (1 << 3) COUNT off; COORD x, y; SIZE A, B; long Asquared, TwoAsquared, Bsquared, TwoBsquared; long d, dx, dy; BYTE quad_visible; LINE corners; POINT mp; PRIMITIVE prim[NUM_QUADS]; COUNT StartPrim; RECT ClipRect; BRESENHAM_LINE ClipLine; ClipRect.corner.x = ClipRect.corner.y = 0; corners.first.x = pRect->corner.x - ClipRect.corner.x; corners.first.y = pRect->corner.y - ClipRect.corner.y; corners.second.x = corners.first.x + pRect->extent.width - 1; corners.second.y = corners.first.y + pRect->extent.height - 1; if (corners.second.x <= corners.first.x || corners.second.y <= corners.first.y) { if (corners.second.x < corners.first.x) corners.second.x = corners.first.x; if (corners.second.y < corners.first.y) corners.second.y = corners.first.y; DrawLine (&corners); return; } ClipRect.extent.width = SIS_SCREEN_WIDTH; ClipRect.extent.height = SIS_SCREEN_HEIGHT; quad_visible = 0; mp.x = (corners.first.x + corners.second.x) >> 1; mp.y = (corners.first.y + corners.second.y) >> 1; ClipRect.corner.x = ClipRect.corner.y = 0; if (corners.first.y >= 0 && corners.first.y < ClipRect.extent.height && corners.second.x >= 0 && corners.second.x < ClipRect.extent.width) quad_visible |= FIRST_QUAD; else { ClipLine.first.x = mp.x; ClipLine.first.y = corners.first.y; ClipLine.second.x = corners.second.x; ClipLine.second.y = mp.y; if (_clip_line (&ClipRect, &ClipLine)) quad_visible |= FIRST_QUAD; } if (corners.first.y >= 0 && corners.first.y < ClipRect.extent.height && corners.first.x >= 0 && corners.first.x < ClipRect.extent.width) quad_visible |= SECOND_QUAD; else { ClipLine.first.x = mp.x; ClipLine.first.y = corners.first.y; ClipLine.second.x = corners.first.x; ClipLine.second.y = mp.y; if (_clip_line (&ClipRect, &ClipLine)) quad_visible |= SECOND_QUAD; } if (corners.second.y >= 0 && corners.second.y < ClipRect.extent.height && corners.first.x >= 0 && corners.first.x < ClipRect.extent.width) quad_visible |= THIRD_QUAD; else { ClipLine.first.x = mp.x; ClipLine.first.y = corners.second.y; ClipLine.second.x = corners.first.x; ClipLine.second.y = mp.y; if (_clip_line (&ClipRect, &ClipLine)) quad_visible |= THIRD_QUAD; } if (corners.second.y >= 0 && corners.second.y < ClipRect.extent.height && corners.second.x >= 0 && corners.second.x < ClipRect.extent.width) quad_visible |= FOURTH_QUAD; else { ClipLine.first.x = mp.x; ClipLine.first.y = corners.second.y; ClipLine.second.x = corners.second.x; ClipLine.second.y = mp.y; if (_clip_line (&ClipRect, &ClipLine)) quad_visible |= FOURTH_QUAD; } if (!quad_visible) return; StartPrim = END_OF_LIST; for (x = 0; x < NUM_QUADS; ++x) { if (quad_visible & (1 << x)) { SetPrimNextLink (&prim[x], StartPrim); SetPrimType (&prim[x], POINT_PRIM); SetPrimColor (&prim[x], _get_context_fg_color ()); StartPrim = x; } } A = pRect->extent.width >> 1; B = pRect->extent.height >> 1; x = 0; y = B; Asquared = ((long)A * A) << 1; Bsquared = ((long)B * B) << 1; do { Asquared >>= 1; Bsquared >>= 1; TwoAsquared = Asquared << 1; dy = TwoAsquared * B; } while (dy / B != TwoAsquared); TwoBsquared = Bsquared << 1; dx = 0; d = Bsquared - (dy >> 1) + (Asquared >> 2); off = 0; A += pRect->corner.x; B += pRect->corner.y; while (dx < dy) { if (off-- == 0) { prim[0].Object.Point.x = prim[3].Object.Point.x = A + x; prim[0].Object.Point.y = prim[1].Object.Point.y = B - y; prim[1].Object.Point.x = prim[2].Object.Point.x = A - x; prim[2].Object.Point.y = prim[3].Object.Point.y = B + y; DrawBatch (prim, StartPrim, 0); off = num_off_pixels; } if (d > 0) { --y; dy -= TwoAsquared; d -= dy; } ++x; dx += TwoBsquared; d += Bsquared + dx; } d += ((((Asquared - Bsquared) * 3) >> 1) - (dx + dy)) >> 1; while (y >= 0) { if (off-- == 0) { prim[0].Object.Point.x = prim[3].Object.Point.x = A + x; prim[0].Object.Point.y = prim[1].Object.Point.y = B - y; prim[1].Object.Point.x = prim[2].Object.Point.x = A - x; prim[2].Object.Point.y = prim[3].Object.Point.y = B + y; DrawBatch (prim, StartPrim, 0); off = num_off_pixels; } if (d < 0) { ++x; dx += TwoBsquared; d += dx; } --y; dy -= TwoAsquared; d += Asquared - dy; } } void DrawFilledOval (RECT *pRect) { COORD x, y; SIZE A, B; long Asquared, TwoAsquared, Bsquared, TwoBsquared; long d, dx, dy; LINE corners; PRIMITIVE prim[NUM_QUADS >> 1]; COUNT StartPrim; corners.first.x = pRect->corner.x; corners.first.y = pRect->corner.y; corners.second.x = corners.first.x + pRect->extent.width - 1; corners.second.y = corners.first.y + pRect->extent.height - 1; if (corners.second.x <= corners.first.x || corners.second.y <= corners.first.y) { if (corners.second.x < corners.first.x) corners.second.x = corners.first.x; if (corners.second.y < corners.first.y) corners.second.y = corners.first.y; DrawLine (&corners); return; } StartPrim = END_OF_LIST; for (x = 0; x < (NUM_QUADS >> 1); ++x) { SetPrimNextLink (&prim[x], StartPrim); SetPrimType (&prim[x], RECTFILL_PRIM); SetPrimColor (&prim[x], _get_context_fg_color ()); prim[x].Object.Rect.extent.height = 1; StartPrim = x; } A = pRect->extent.width >> 1; B = pRect->extent.height >> 1; x = 0; y = B; Asquared = ((long)A * A) << 1; Bsquared = ((long)B * B) << 1; do { Asquared >>= 1; Bsquared >>= 1; TwoAsquared = Asquared << 1; dy = TwoAsquared * B; } while (dy / B != TwoAsquared); TwoBsquared = Bsquared << 1; dx = 0; d = Bsquared - (dy >> 1) + (Asquared >> 2); A += pRect->corner.x; B += pRect->corner.y; while (dx < dy) { if (d > 0) { prim[0].Object.Rect.corner.x = prim[1].Object.Rect.corner.x = A - x; prim[0].Object.Rect.extent.width = prim[1].Object.Rect.extent.width = (x << 1) + 1; prim[0].Object.Rect.corner.y = B - y; prim[1].Object.Rect.corner.y = B + y; DrawBatch (prim, StartPrim, 0); --y; dy -= TwoAsquared; d -= dy; } ++x; dx += TwoBsquared; d += Bsquared + dx; } d += ((((Asquared - Bsquared) * 3) >> 1) - (dx + dy)) >> 1; while (y >= 0) { prim[0].Object.Rect.corner.x = prim[1].Object.Rect.corner.x = A - x; prim[0].Object.Rect.extent.width = prim[1].Object.Rect.extent.width = (x << 1) + 1; prim[0].Object.Rect.corner.y = B - y; prim[1].Object.Rect.corner.y = B + y; DrawBatch (prim, StartPrim, 0); if (d < 0) { ++x; dx += TwoBsquared; d += dx; } --y; dy -= TwoAsquared; d += Asquared - dy; } }