/*============================================================================= Name : prim2d.c Purpose : Functions to draw 2D primitives. Created 6/26/1997 by lmoloney Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #define WIN32_LEAN_AND_MEAN #include #include "glinc.h" #include #include #include "types.h" #include "debug.h" #include "main.h" #include "render.h" #include "prim2d.h" #include "glcaps.h" #include "glcompat.h" /*============================================================================= Data: =============================================================================*/ sdword primModeEnabled = FALSE; /*============================================================================= Functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : primModeSetFunction2 Description : Enables the primitive drawing mode. Inputs : void Outputs : sets primModeEnabled TRUE Return : void ----------------------------------------------------------------------------*/ void primModeSetFunction2(void) { glShadeModel(GL_FLAT); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); //perform no transformations on the 2D primitives glLoadIdentity(); glMatrixMode(GL_MODELVIEW); rndLightingEnable(FALSE); //mouse is self-illuminated rndTextureEnable(FALSE); glDisable(GL_DEPTH_TEST); primModeEnabled = TRUE; } /*----------------------------------------------------------------------------- Name : primModeClearFunction2 Description : Disables the primitive drawing mode. Inputs : void Outputs : sets primModeEnabled FALSE Return : void ----------------------------------------------------------------------------*/ void primModeClearFunction2(void) { glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); rndLightingEnable(TRUE); //and lighting rndTextureEnable(TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); primModeEnabled = FALSE; } /*----------------------------------------------------------------------------- Name : primTriSolid2 Description : Draw a solid 2D triangle Inputs : tri - pointer to triangle structure containing coordinates of corners c - color to draw it in Outputs : Return : void ----------------------------------------------------------------------------*/ void primTriSolid2(triangle *tri, color c) { if (glcActive()) { glcTriSolid2(tri, c); } else { glColor3ub(colRed(c), colGreen(c), colBlue(c)); glBegin(GL_TRIANGLES); glVertex2f(primScreenToGLX(tri->x0), primScreenToGLY(tri->y0)); glVertex2f(primScreenToGLX(tri->x1), primScreenToGLY(tri->y1)); glVertex2f(primScreenToGLX(tri->x2), primScreenToGLY(tri->y2)); glEnd(); } } /*----------------------------------------------------------------------------- Name : primTriOutline2 Description : Draw a 2D triangle outline Inputs : tri - pointer to triangle structure containing coordinates of corners thickness - thickness of the lines c - color to draw it in Outputs : Return : void ----------------------------------------------------------------------------*/ void primTriOutline2(triangle *tri, sdword thickness, color c) { if (glcActive()) { glcTriOutline2(tri, thickness, c); } else { glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINE_LOOP); glVertex2f(primScreenToGLX(tri->x0), primScreenToGLY(tri->y0)); glVertex2f(primScreenToGLX(tri->x1), primScreenToGLY(tri->y1)); glVertex2f(primScreenToGLX(tri->x2), primScreenToGLY(tri->y2)); glEnd(); glPopAttrib(); } } /*----------------------------------------------------------------------------- Name : primRectSolidTextured2 Description : Draw a solid 2d rectangle with the current texture mapped thereupon. Inputs : rect - pointer to rectangle structure containing coordinates. Outputs : .. Return : void ----------------------------------------------------------------------------*/ #define COORD(S,T,X,Y) \ glTexCoord2f(S, T); \ glVertex2f(primScreenToGLX(X), primScreenToGLY(Y)); void primRectSolidTextured2(rectangle *rect) { glColor3ub(255, 255, 255); rndTextureEnvironment(RTE_Replace); rndTextureEnable(TRUE); glBegin(GL_QUADS); COORD(0.0f, 0.0f, rect->x0, rect->y0); COORD(0.0f, 1.0f, rect->x0, rect->y1 - 1); COORD(1.0f, 1.0f, rect->x1, rect->y1 - 1); COORD(1.0f, 0.0f, rect->x1, rect->y0); glEnd(); rndTextureEnable(FALSE); rndTextureEnvironment(RTE_Modulate); } void primRectSolidTexturedFullRect2(rectangle *rect) { glColor3ub(255, 255, 255); rndTextureEnvironment(RTE_Replace); rndTextureEnable(TRUE); glBegin(GL_QUADS); COORD(0.0f, 0.0f, rect->x0, rect->y0); COORD(0.0f, 1.0f, rect->x0, rect->y1); COORD(1.0f, 1.0f, rect->x1, rect->y1); COORD(1.0f, 0.0f, rect->x1, rect->y0); glEnd(); rndTextureEnable(FALSE); rndTextureEnvironment(RTE_Modulate); } void primRectSolidTexturedFullRectC2(rectangle *rect, color c) { glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c)); rndTextureEnable(TRUE); glBegin(GL_QUADS); COORD(0.0f, 0.0f, rect->x0, rect->y0); COORD(0.0f, 1.0f, rect->x0, rect->y1); COORD(1.0f, 1.0f, rect->x1, rect->y1); COORD(1.0f, 0.0f, rect->x1, rect->y0); glEnd(); rndTextureEnable(FALSE); } #undef COORD /*----------------------------------------------------------------------------- Name : primRectSolid2 Description : Draw a solid 2d rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. c - color to draw it in. Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primRectSolid2(rectangle *rect, color c) { if (glcActive()) { glcRectSolid2(rect, c); } else { glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c)); glBegin(GL_QUADS); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0)); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0)); glEnd(); } } /*----------------------------------------------------------------------------- Name : primRectTranslucentRGL2 Description : helper for primRectTranslucent2, rGL(sw) only (will temporarily disable stippling) Inputs : rect - rectangle structure containing coordinates c - color of the rectangle Outputs : Return : ----------------------------------------------------------------------------*/ void primRectTranslucentRGL2(rectangle* rect, color c) { GLboolean blendOn; GLboolean stippleOn; blendOn = glIsEnabled(GL_BLEND); stippleOn = glIsEnabled(GL_POLYGON_STIPPLE); if (!blendOn) glEnable(GL_BLEND); if (stippleOn) glDisable(GL_POLYGON_STIPPLE); glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c)); glBegin(GL_QUADS); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0)); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0)); glEnd(); if (!blendOn) glDisable(GL_BLEND); if (stippleOn) glEnable(GL_POLYGON_STIPPLE); } /*----------------------------------------------------------------------------- Name : primRectTranslucent2 Description : Draw a translucent 2d rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. c - color to draw it in. Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primRectTranslucent2(rectangle* rect, color c) { GLboolean blendOn; if (RGL && RGLtype == SWtype) { primRectTranslucentRGL2(rect, c); return; } blendOn = glIsEnabled(GL_BLEND); if (!blendOn) glEnable(GL_BLEND); if (glcActive()) { glcRectTranslucent2(rect, c); } else { glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c)); glBegin(GL_QUADS); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0)); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0)); glEnd(); } if (!blendOn) glDisable(GL_BLEND); } /*----------------------------------------------------------------------------- Name : primRectOutline2 Description : Draw an outline 2d rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. thickness - thickness of the lines c - color to draw it in. Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primRectOutline2(rectangle *rect, sdword thickness, color c) { sdword bottom; if (glcActive()) { glcRectOutline2(rect, thickness, c); return; } bottom = rect->y1 - 1; glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINE_LOOP); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0)); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(bottom)); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(bottom)); glEnd(); glPopAttrib(); } /*----------------------------------------------------------------------------- Name : primRectShaded2 Description : Draw a shaded 2d rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. c - pointer to 4 color values to draw it in. Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primRectShaded2(rectangle *rect, color *c) { if (glcActive()) { glcRectShaded2(rect, c); return; } glShadeModel(GL_SMOOTH); glBegin(GL_QUADS); glColor3ub(colRed(c[0]), colGreen(c[0]), colBlue(c[0])); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0)); glColor3ub(colRed(c[1]), colGreen(c[1]), colBlue(c[1])); glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1)); glColor3ub(colRed(c[2]), colGreen(c[2]), colBlue(c[2])); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1)); glColor3ub(colRed(c[3]), colGreen(c[3]), colBlue(c[3])); glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0)); glEnd(); } /*----------------------------------------------------------------------------- Name : primRectUnion2 Description : Compute the union of 2 2d rectangles Inputs : result - destination of union rect r0, r1 - rectangles to compute union of Outputs : fills reslult with union rect Return : void Notes : The x1/y1 parameters of the rectangles should be larger than the x0/y0 members. If no union exists (rectangles do not overlap), the x0 and/or y0 members of the reslult will be the same as the x1 and/or y1 members. ----------------------------------------------------------------------------*/ void primRectUnion2(rectangle *result, rectangle *r0, rectangle *r1) { result->x0 = max(r0->x0, r1->x0); //get min/max bounds result->y0 = max(r0->y0, r1->y0); result->x1 = min(r0->x1, r1->x1); result->y1 = min(r0->y1, r1->y1); result->x0 = min(result->x0, result->x1); //make sure not negative width/height result->y0 = min(result->y0, result->y1); } /*----------------------------------------------------------------------------- Name : primRealRectUnion2 Description : Same as above, just with real numbers instead Inputs : Outputs : Return : Notes : ----------------------------------------------------------------------------*/ void primRealRectUnion2(realrectangle *result, realrectangle *r0, realrectangle *r1) { result->x0 = max(r0->x0, r1->x0); //get min/max bounds result->y0 = max(r0->y0, r1->y0); result->x1 = min(r0->x1, r1->x1); result->y1 = min(r0->y1, r1->y1); result->x0 = min(result->x0, result->x1); //make sure not negative width/height result->y0 = min(result->y0, result->y1); } // FIXME void CirclePoints(int x, int y, color c, int cx, int cy) { glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPointSize(4.0f); glBegin(GL_POINTS); dbgMessagef("\nCirclePoints %d %d %d %d", x, y, cx, cy); glVertex2i(x + cx, y + cy); glVertex2i(y + cx, x + cy); glVertex2i(y + cx, -x + cy); glVertex2i(x + cx, -y + cy); glVertex2i(-x + cx, -y + cy); glVertex2i(-y + cx, x + cy); glVertex2i(-x + cx, y + cy); glEnd(); glPointSize(1.0f); } // FIXME void primCircleSegment(uword cx, uword cy, uword r, color c) { int x, y; real32 d; x = 0; y = r; d = (real32)5/(real32)4 - (real32)r; CirclePoints(x, y, c, cx, cy); while (y > x) { if (d < 0) { d = d + 2*x + 3; x++; } else { d = d + 2*(x-y) + 5; x++; y--; } CirclePoints(x, y, c, cx, cy); } } /*----------------------------------------------------------------------------- Name : primOvalArcOutline2 Description : Draw an outline section of an oval. Inputs : o - oval structure describing location and size on-screen degStarts, degEnd - degree stations of start and end of line thickness - thickness of lines segments - number of line segments for a complete oval c - color to draw outline in Outputs : .. Return : void Note : The coordinate system used will be the engineering system where up (x = 0, y = -1) is 0 rad. ----------------------------------------------------------------------------*/ void primOvalArcOutline2(oval *o, real32 radStart, real32 radEnd, sdword thickness, sdword segments, color c) { sdword segment, endSegment; real32 angle, angleInc; real32 centreX, centreY, width, height; real32 x, y, lastX, lastY; if (glcActive()) { centreX = (real32)o->centreX; centreY = (real32)o->centreY; width = (real32)o->radiusX; height = (real32)o->radiusY; } else { centreX = primScreenToGLX(o->centreX); //get floating-point version of oval attributes centreY = primScreenToGLY(o->centreY); width = primScreenToGLScaleX(o->radiusX); height = primScreenToGLScaleY(o->radiusY); } segment = (sdword)(radStart * (real32)segments / (2.0f * PI));//get starting segment endSegment = (sdword)(radEnd * (real32)segments / (2.0f * PI) - 0.01f);//get ending segment glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINE_STRIP); x = centreX + (real32)sin((double)radStart) * width; //first vertex y = centreY + (real32)cos((double)radStart) * height; if (glcActive()) { lastX = x; lastY = y; } else { glVertex2f(x, y); } segment++; angle = (real32)segment * (2.0f * PI / (real32)segments); angleInc = (2.0f * PI / (real32)segments); for (; segment <= endSegment; segment++) { //for start and all complete segments x = centreX + (real32)sin((double)angle) * width; y = centreY + (real32)cos((double)angle) * height; if (glcActive()) { glcLine2((sdword)lastX, (sdword)lastY, (sdword)x, (sdword)y, thickness, c); lastX = x; lastY = y; } else { glVertex2f(x, y); } angle += angleInc; //update angle } x = centreX + (real32)sin((double)radEnd) * width; y = centreY + (real32)cos((double)radEnd) * height; if (glcActive()) { glcLine2((sdword)lastX, (sdword)lastY, (sdword)x, (sdword)y, thickness, c); } else { glVertex2f(x, y); //draw last vertex } glEnd(); glPopAttrib(); } /*----------------------------------------------------------------------------- Name : primCircleOutline2 Description : Draw a circle Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void primGLCircleOutline2(real32 x, real32 y, real32 radius, sdword nSegments, color c) { sdword index; double angle, angleInc = 2.0 * PI / (double)nSegments; real32 radiusY = radius * MAIN_WindowWidth / MAIN_WindowHeight; glColor3ub(colRed(c), colGreen(c), colBlue(c)); glBegin(GL_LINE_STRIP); glVertex2f(x, y + radiusY); for (index = 0, angle = angleInc; index <= nSegments; index++, angle += angleInc) { glVertex2f(x + (real32)sin(angle) * radius, y + (real32)cos(angle) * radiusY); } glEnd(); } /*----------------------------------------------------------------------------- Name : primErrorMessagePrint Description : Print any errors generated by rendering system Inputs : line, file - location function called from Outputs : checks error messages and prints out any errors found Return : ----------------------------------------------------------------------------*/ void primErrorMessagePrintFunction(char *file, sdword line) { GLenum errorEnum; //there can be multiple errors simultaneously. detect them all //in one call to this fn for debugging simplicity for (;;) { errorEnum = glGetError(); if (errorEnum == GL_NO_ERROR) { return; } else { //#ifndef khentschel if (RGLtype != GLtype) //#endif { dbgWarningf(file, line, "glGetError returned '%s'", rgluErrorString(errorEnum)); } } } } /*----------------------------------------------------------------------------- Name : primLine2 Description : Draw a line 1 pixel wide Inputs : c - attributes of line to be drawn x0, y0, x1, y1 - start/end of line segment Outputs : Sets GL_COLOR Return : void ----------------------------------------------------------------------------*/ void primLine2(sdword x0, sdword y0, sdword x1, sdword y1, color c) { bool blendon; if (glcActive()) { glcLine2(x0, y0, x1, y1, 1, c); return; } if (!glCapFeatureExists(GL_LINE_SMOOTH)) { primNonAALine2(x0, y0, x1, y1, c); return; } blendon = glIsEnabled(GL_BLEND); if (!blendon) glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glColor3ub(colRed(c), colGreen(c), colBlue(c)); glBegin(GL_LINES); glVertex2f(primScreenToGLX(x0), primScreenToGLY(y0)); glVertex2f(primScreenToGLX(x1), primScreenToGLY(y1)); glEnd(); glDisable(GL_LINE_SMOOTH); if (!blendon) glDisable(GL_BLEND); } /*----------------------------------------------------------------------------- Name : primNonAALine2 Description : Draw a non-antialiased line 1 pixel wide Inputs : c - attributes of line to be drawn x0, y0, x1, y1 - start/end of line segment Outputs : sets GL_COLOR Return : ----------------------------------------------------------------------------*/ void primNonAALine2(sdword x0, sdword y0, sdword x1, sdword y1, color c) { glColor3ub(colRed(c), colGreen(c), colBlue(c)); glBegin(GL_LINES); glVertex2f(primScreenToGLX(x0), primScreenToGLY(y0)); glVertex2f(primScreenToGLX(x1), primScreenToGLY(y1)); glEnd(); } /*----------------------------------------------------------------------------- Name : primLineThick2 Description : Draw a line "thickness" pixels wide Inputs : c - attributes of line to be drawn x0, y0, y1, y1 - start/end of line segment thickness - width of line Outputs : Sets GL_COLOR Return : void ----------------------------------------------------------------------------*/ void primLineThick2(sdword x0, sdword y0, sdword x1, sdword y1, sdword thickness, color c) { glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glColor3ub(colRed(c), colGreen(c), colBlue(c)); glBegin(GL_LINES); glVertex2f(primScreenToGLX(x0), primScreenToGLY(y0)); glVertex2f(primScreenToGLX(x1), primScreenToGLY(y1)); glEnd(); glPopAttrib(); } /*----------------------------------------------------------------------------- Name : primLineLoopStart2 Description : Start a line-loop by setting up color and thickness Inputs : thickness, c - attributes of lines to be drawn Outputs : Sets GL_COLOR and GL_LINE_THICKNESS Return : void Note : Must be matched with a primLineLoopEnd2 and have only primLineLoopPoint calls inbetween ----------------------------------------------------------------------------*/ static bool LLblendon; void primLineLoopStart2(sdword thickness, color c) { if (glCapFeatureExists(GL_LINE_SMOOTH)) { LLblendon = glIsEnabled(GL_BLEND); glEnable(GL_LINE_SMOOTH); if (!LLblendon) glEnable(GL_BLEND); } glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINE_LOOP); } /*----------------------------------------------------------------------------- Name : primLineLoopPoint3F Description : Insert a point in a line-loop Inputs : x, y - unconverted floating-point screen coordinates Outputs : calls glVertex with the coordinates Return : ----------------------------------------------------------------------------*/ void primLineLoopPoint3F(real32 x, real32 y) { glVertex2f(x, y); } /*----------------------------------------------------------------------------- Name : primLineLoopEnd2 Description : End a line - loop sequence Inputs : void Outputs : Return : void ----------------------------------------------------------------------------*/ void primLineLoopEnd2(void) { glEnd(); glPopAttrib(); if (glCapFeatureExists(GL_LINE_SMOOTH)) { if (!LLblendon) glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); } } /*----------------------------------------------------------------------------- Name : cparam Description : blends a single color component Inputs : a - component a, b - com b, t - lerp parm Outputs : Return : blended component ----------------------------------------------------------------------------*/ /* uword cparam(uword a, uword b, real32 t) { uword c; real32 bt = (real32)1 - t; c = (uword)((real32)a * t + (real32)b * bt); if (c > 255) return 255; else return c; } */ /*----------------------------------------------------------------------------- Name : decRect Description : decrease size of a rectangle Inputs : rect - the rectangle, width - amount to dec Outputs : rect is modified Return : ----------------------------------------------------------------------------*/ void decRect(rectangle *rect, uword width) { rect->x0 = rect->x0 + width; rect->y0 = rect->y0 + width; rect->x1 = rect->x1 - width; rect->y1 = rect->y1 - width; } /*----------------------------------------------------------------------------- Name : primSeriesOfRects Description : draws a series of rects decreasing in size and color Inputs : rect - starting rectangle, width - width, fore - fg, back - fg, steps - number of rects Outputs : Return : ----------------------------------------------------------------------------*/ void primSeriesOfRects(rectangle *rect, uword width, color fore, color back, uword steps) { // ignore width rectangle drect; real32 cfrac, frac; uword i; color Color; cfrac = (real32)1.0 / (real32)steps; steps++; frac = (real32)1.0; Color = fore; memcpy(&drect, rect, sizeof(rectangle)); for (i = 0; i < steps; i++) { decRect(&drect, 1); primRectOutline2(&drect, 2, Color); frac -= cfrac; Color = colBlend(fore, back, frac); } } #define SX(x) primScreenToGLX(x) #define SY(y) primScreenToGLY(y) #define X0 rect->x0 #define Y0 rect->y0 #define X1 rect->x1 #define Y1 rect->y1 #define SEGS 4 /*----------------------------------------------------------------------------- Name : primRectSolid2 Description : Draw a solid 2d rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. c - color to draw it in, xb - x offset, yb - y offset Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primBeveledRectSolid(rectangle *rect, color c, uword xb, uword yb) { bool cull; if (glcActive()) { glcBeveledRectSolid2(rect, c, (sdword)xb, (sdword)yb); return; } cull = glIsEnabled(GL_CULL_FACE) ? TRUE : FALSE; glDisable(GL_CULL_FACE); glBegin(GL_POLYGON); glColor3ub(colRed(c), colGreen(c), colBlue(c)); glVertex2f(SX(X0+xb), SY(Y0)); glVertex2f(SX(X1-xb), SY(Y0)); glVertex2f(SX(X1), SY(Y0+yb)); glVertex2f(SX(X1), SY(Y1-yb)); glVertex2f(SX(X1-xb), SY(Y1)); glVertex2f(SX(X0+xb), SY(Y1)); glVertex2f(SX(X0), SY(Y1-yb)); glVertex2f(SX(X0), SY(Y0+yb)); glEnd(); if (cull) { glEnable(GL_CULL_FACE); } } /*----------------------------------------------------------------------------- Name : primBeveledRectOutline Description : Draw an outline 2d beveled rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. thickness - thickness of the lines c - color to draw it in, xb - x offset, yb - y offset Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primBeveledRectOutline(rectangle *rect, sdword thickness, color c, uword xb, uword yb) { glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINE_LOOP); glVertex2f(SX(X0+xb), SY(Y0)); glVertex2f(SX(X1-xb), SY(Y0)); glVertex2f(SX(X1), SY(Y0+yb)); glVertex2f(SX(X1), SY(Y1-yb)); glVertex2f(SX(X1-xb), SY(Y1)); glVertex2f(SX(X0+xb), SY(Y1)); glVertex2f(SX(X0), SY(Y1-yb)); glVertex2f(SX(X0), SY(Y0+yb)); glEnd(); glPopAttrib(); } /*----------------------------------------------------------------------------- Name : primRoundRectOutline Description : Draw an outline 2d rounded rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. thickness - thickness of the lines c - color to draw it in, xb - x offset, yb - y offset Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primRoundRectOutline(rectangle *rect, sdword thickness, color c, uword xb, uword yb) { oval o; sdword segs = SEGS; glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINES); glVertex2f(SX(X0+xb), SY(Y0)); glVertex2f(SX(X1-xb), SY(Y0)); glVertex2f(SX(X1), SY(Y0+yb)); glVertex2f(SX(X1), SY(Y1-yb)); glVertex2f(SX(X1-xb), SY(Y1)); glVertex2f(SX(X0+xb), SY(Y1)); glVertex2f(SX(X0), SY(Y1-yb)); glVertex2f(SX(X0), SY(Y0+yb)); glEnd(); glPopAttrib(); // if (xb > 4 || yb > 4) // segs *= 2; // upper left o.centreX = X0+xb; o.centreY = Y0+yb; o.radiusX = xb; o.radiusY = yb; primOvalArcOutline2(&o, 3*PI/2, TWOPI, 2, segs, c); // upper right o.centreX = X1-xb; primOvalArcOutline2(&o, (real32)0, PI/2, 2, segs, c); // lower right o.centreY = Y1-yb; primOvalArcOutline2(&o, PI/2, PI, 2, segs, c); // lower left o.centreX = X0+xb; primOvalArcOutline2(&o, PI, 3*PI/2, 2, segs, c); } /*----------------------------------------------------------------------------- Name : primMaskedRoundRectOutline Description : Draw an outline 2d rounded rectangle. Inputs : rect - pointer to rectangle structure containing coordinates. thickness - thickness of the lines, mask - OL_* mask for roundedness c - color to draw it in, xb - x offset, yb - y offset Outputs : .. Return : void ----------------------------------------------------------------------------*/ void primMaskedRoundRectOutline(rectangle *rect, sdword thickness, color c, uword xb, uword yb, uword mask) { oval o; sdword segs = SEGS; glColor3ub(colRed(c), colGreen(c), colBlue(c)); glPushAttrib(GL_LINE_BIT); glLineWidth((GLfloat)thickness); glBegin(GL_LINES); glVertex2f(SX(X0+xb), SY(Y0)); glVertex2f(SX(X1-xb), SY(Y0)); glVertex2f(SX(X1), SY(Y0+yb)); glVertex2f(SX(X1), SY(Y1-yb)); glVertex2f(SX(X1-xb), SY(Y1)); glVertex2f(SX(X0+xb), SY(Y1)); glVertex2f(SX(X0), SY(Y1-yb)); glVertex2f(SX(X0), SY(Y0+yb)); if (!(mask & OL_UL)) { glVertex2f(SX(X0), SY(Y0)); glVertex2f(SX(X0+xb), SY(Y0)); glVertex2f(SX(X0), SY(Y0)); glVertex2f(SX(X0), SY(Y0+yb)); } if (!(mask & OL_LL)) { glVertex2f(SX(X0), SY(Y1)); glVertex2f(SX(X0+xb), SY(Y1)); glVertex2f(SX(X0), SY(Y1)); glVertex2f(SX(X0), SY(Y1-yb)); } if (!(mask & OL_UR)) { glVertex2f(SX(X1-xb), SY(Y0)); glVertex2f(SX(X1), SY(Y0)); glVertex2f(SX(X1), SY(Y0)); glVertex2f(SX(X1), SY(Y0+yb)); } if (!(mask & OL_LR)) { glVertex2f(SX(X1), SY(Y1-yb)); glVertex2f(SX(X1), SY(Y1)); glVertex2f(SX(X1), SY(Y1)); glVertex2f(SX(X1-xb), SY(Y1)); } glEnd(); glPopAttrib(); if (xb > 4 || yb > 4) segs *= 2; // upper left o.centreX = X0+xb; o.centreY = Y0+yb; o.radiusX = xb; o.radiusY = yb; if (mask & OL_UL) primOvalArcOutline2(&o, 3*PI/2, TWOPI, 2, segs, c); // upper right o.centreX = X1-xb; if (mask & OL_UR) primOvalArcOutline2(&o, 0.0f, PI/2, 2, segs, c); // lower right o.centreY = Y1-yb; if (mask & OL_LR) primOvalArcOutline2(&o, PI/2, PI, 2, segs, c); // lower left o.centreX = X0+xb; if (mask & OL_LL) primOvalArcOutline2(&o, PI, 3*PI/2, 2, segs, c); } #undef SEGS #undef Y1 #undef X1 #undef Y0 #undef X0 #undef SY #undef SX /*----------------------------------------------------------------------------- Name : primSeriesOfBeveledRects Description : draws a series of rects decreasing in size and color Inputs : rect - starting rectangle, width - width, fore - fg, back - fg, steps - number of rects, xb - x offset, yb - y offset Outputs : Return : ----------------------------------------------------------------------------*/ void primSeriesOfBeveledRects(rectangle *rect, uword width, color fore, color back, uword steps, uword xb, uword yb) { // ignore width rectangle drect; real32 cfrac, frac; uword i; color Color; cfrac = (real32)1.0 / (real32)steps; steps++; frac = (real32)1.0; Color = fore; memcpy(&drect, rect, sizeof(rectangle)); for (i = 0; i < steps; i++) { decRect(&drect, 1); primBeveledRectOutline(&drect, 2, Color, xb, yb); frac -= cfrac; Color = colBlend(fore, back, frac); } } /*----------------------------------------------------------------------------- Name : primSeriesOfRoundRects Description : draws a series of rects decreasing in size and color Inputs : rect - starting rectangle, width - width, fore - fg, back - fg, steps - number of rects, xb - x offset, yb - y offset Outputs : Return : ----------------------------------------------------------------------------*/ void primSeriesOfRoundRects(rectangle *rect, uword width, color fore, color back, uword steps, uword xb, uword yb) { // ignore width rectangle drect; real32 cfrac, frac; uword i; color Color; cfrac = (real32)1.0 / (real32)steps; steps++; frac = (real32)1.0; Color = fore; memcpy(&drect, rect, sizeof(rectangle)); for (i = 0; i < steps; i++) { decRect(&drect, 1); primRoundRectOutline(&drect, 2, Color, xb, yb); frac -= cfrac; Color = colBlend(fore, back, frac); } } /*----------------------------------------------------------------------------- Name : partCircleSolid2 Description : Render a 2d circle, like the 3D one. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void primCircleSolid2(sdword x, sdword y, sdword rad, sdword nSlices, color c) { sdword index; GLfloat v[3]; double theta; vector centre; real32 radiusX, radiusY; bool cull; if (glcActive()) { rectangle r; r.x0 = x - rad; r.y0 = y - rad; r.x1 = x + rad; r.y1 = y + rad; glcRectSolid2(&r, c); return; } cull = glIsEnabled(GL_CULL_FACE) ? TRUE : FALSE; centre.x = primScreenToGLX(x); centre.y = primScreenToGLY(y); radiusX = primScreenToGLScaleX(rad); radiusY = primScreenToGLScaleY(rad); glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c)); v[0] = centre.x; v[1] = centre.y; glDisable(GL_CULL_FACE); glBegin(GL_TRIANGLE_FAN); glVertex2f(v[0], v[1]); for (index = 0, theta = 0.0; index < nSlices; index++) { v[0] = centre.x + (real32)(sin(theta)) * radiusX; v[1] = centre.y + (real32)(cos(theta)) * radiusY; theta += 2.0 * PI / (double)nSlices; glVertex2f(v[0], v[1]); } v[0] = centre.x; v[1] = centre.y + radiusY; glVertex2f(v[0], v[1]); glEnd(); if (cull) { glEnable(GL_CULL_FACE); } } /*----------------------------------------------------------------------------- Name : primCircleBorder Description : Draw a special type of circle with a solid inner with a alpha ramped outer ring. Inputs : x, y - location of centre of image radInner - radius of the inner circle radOuter - total radius of the inner and outer circles nSlices - number of radial slices must be multiple of 2 colInner - color of inner circle colOuter - color of the outer edge Outputs : Return : void ----------------------------------------------------------------------------*/ #pragma optimize("", off) //intel compiler pukes on this function so compile it without optimizations void primCircleBorder(sdword x, sdword y, sdword radInner, sdword radOuter, sdword nSlices, color colInner) { sdword index; real32 centreX, centreY; double theta, addAmount; real32 radXInner, radXOuter, radYInner, radYOuter; real32 x0, y0, x1, y1, x2, y2; real32 sinTheta, cosTheta; ubyte red = colRed(colInner); ubyte green = colGreen(colInner); ubyte blue = colBlue(colInner); dbgAssert(nSlices >= 3); centreX = primScreenToGLX(x); //make floating-point versions of parameters centreY = primScreenToGLY(y); radXInner = primScreenToGLScaleX(radInner); radYInner = primScreenToGLScaleY(radInner); radXOuter = primScreenToGLScaleX(radOuter); radYOuter = primScreenToGLScaleY(radOuter); addAmount = (double)(2.0f * PI / (real32)(nSlices - 1)); theta = addAmount; x0 = x2 = centreX; y0 = centreY - radYInner; y2 = centreY - radYOuter; glShadeModel(GL_SMOOTH); glEnable(GL_BLEND); for (index = 0; index < nSlices; index++) { glBegin(GL_TRIANGLE_FAN); glColor4ub(red, green, blue, 255); glVertex2f(x0, y0); //2 common points glVertex2f(centreX, centreY); sinTheta = (real32)sin(theta); cosTheta = (real32)cos(theta); x0 = centreX + sinTheta * radXInner; y0 = centreY + cosTheta * radYInner; glVertex2f(x0, y0); //complete glColor4ub(red, green, blue, 0); x1 = centreX + sinTheta * radXOuter; y1 = centreY + cosTheta * radYOuter; glVertex2f(x1, y1); //complete glVertex2f(x2, y2); x2 = x1; y2 = y1; glEnd(); theta += addAmount; } glDisable(GL_BLEND); glShadeModel(GL_FLAT); } #pragma optimize("", on) /*----------------------------------------------------------------------------- Name : primBlurryPoint2 Description : Renders a 2D blurry dot in a specified color. Inputs : x, y - location of the point on-screen c - color to draw it in Outputs : Return : void ----------------------------------------------------------------------------*/ #define PD1_FuzzyPointYStart -1 #define PD1_FuzzyPointYEnd 2 #define PD1_FuzzyPointXStart -1 #define PD1_FuzzyPointXEnd 2 #define PD1_FuzzyPointHeight 4 #define PD1_FuzzyPointWidth 4 #define PD2_FuzzyPointYStart -2 #define PD2_FuzzyPointYEnd 3 #define PD2_FuzzyPointXStart -2 #define PD2_FuzzyPointXEnd 3 #define PD2_FuzzyPointHeight 6 #define PD2_FuzzyPointWidth 6 /* ubyte p2dAlphaArray[PD1_FuzzyPointWidth][PD1_FuzzyPointHeight] = { {0x10, 0x20, 0x10}, {0x20, 0x3f, 0x20}, {0x10, 0x20, 0x10}, }; */ //1x1 pixel alpha'd out /* ubyte p2dAlphaArray1[PD1_FuzzyPointWidth][PD1_FuzzyPointHeight] = { {0x07, 0x0e, 0x0e, 0x07}, {0x0e, 0x1d, 0x1d, 0x0e}, {0x0e, 0x1d, 0x1c, 0x0e}, {0x07, 0x0e, 0x0e, 0x07}, }; */ //1x1 pixel alpha'd out ubyte p2dAlphaArray1[PD1_FuzzyPointWidth][PD1_FuzzyPointHeight] = { {(0x0e * 2), (0x1c * 2), (0x1c * 2), (0x0e * 2)}, {(0x1c * 2), (0x3a * 2), (0x3a * 2), (0x1c * 2)}, {(0x1c * 2), (0x3a * 2), (0x3a * 2), (0x1c * 2)}, {(0x0e * 2), (0x1c * 2), (0x1c * 2), (0x0e * 2)}, }; //2x2 pixel alpha'd out ubyte p2dAlphaArray2[PD2_FuzzyPointWidth][PD2_FuzzyPointHeight] = { {(0x04 * 2), (0x09 * 2), (0x13 * 2), (0x13 * 2), (0x09 * 2), (0x04 * 2)}, {(0x0a * 2), (0x1a * 2), (0x2d * 2), (0x2d * 2), (0x1a * 2), (0x0a * 2)}, {(0x13 * 2), (0x2d * 2), (0x4f * 2), (0x4f * 2), (0x2d * 2), (0x13 * 2)}, {(0x13 * 2), (0x2d * 2), (0x4f * 2), (0x4f * 2), (0x2d * 2), (0x13 * 2)}, {(0x0a * 2), (0x1a * 2), (0x2d * 2), (0x2d * 2), (0x1a * 2), (0x0a * 2)}, {(0x04 * 2), (0x09 * 2), (0x13 * 2), (0x13 * 2), (0x09 * 2), (0x04 * 2)} }; void primBlurryPoint2(sdword x, sdword y, color c) { sdword iX, iY; ubyte *alpha, red = colRed(c), green = colGreen(c), blue = colBlue(c); glEnable(GL_BLEND); glBegin(GL_POINTS); alpha = &p2dAlphaArray1[0][0]; for (iY = PD1_FuzzyPointYStart; iY <= PD1_FuzzyPointYEnd; iY++) { for (iX = PD1_FuzzyPointXStart; iX <= PD1_FuzzyPointXEnd; iX++, alpha++) { glColor4ub(red, green, blue, *alpha); glVertex2f(primScreenToGLX((x + iX)), primScreenToGLY((y + iY))); } } glEnd(); glColor4ub(0, 0, 0, 0xff); glDisable(GL_BLEND); } void primBlurryPoint22(sdword x, sdword y, color c) { sdword iX, iY; ubyte *alpha, red = colRed(c), green = colGreen(c), blue = colBlue(c); glEnable(GL_BLEND); glBegin(GL_POINTS); alpha = &p2dAlphaArray2[0][0]; for (iY = PD2_FuzzyPointYStart; iY <= PD2_FuzzyPointYEnd; iY++) { for (iX = PD2_FuzzyPointXStart; iX <= PD2_FuzzyPointXEnd; iX++, alpha++) { glColor4ub(red, green, blue, *alpha); glVertex2f(primScreenToGLX((x + iX)), primScreenToGLY((y + iY))); } } glEnd(); glColor4ub(0, 0, 0, 0xff); glDisable(GL_BLEND); } /*----------------------------------------------------------------------------- Name : primPointLineIntersection Description : Computes an intersection of a point and a line segment Inputs : xp/yp - location of point x/y|0/1 - endpoints of the line segment Outputs : Return : positive/negative for different sides ----------------------------------------------------------------------------*/ real32 primPointLineIntersection(real32 xp, real32 yp, real32 x0, real32 y0, real32 x1, real32 y1) { return((y0 - y1) * xp + (x1 - x0) * yp + (x0 * y1 - y0 * x1)); }