Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // math_failure.cpp : Defines the entry point for the console application.
- //
- #include <stdio.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <math.h>
- #ifdef __GNUC__
- // gcc
- #include <stdint.h>
- typedef uint64_t u64;
- typedef uint32_t u32;
- typedef uint16_t u16;
- typedef uint8_t u8;
- typedef int64_t s64;
- typedef int32_t s32;
- typedef int16_t s16;
- typedef int8_t s8;
- #else
- typedef unsigned __int64 u64;
- typedef unsigned int u32;
- typedef unsigned short u16;
- typedef unsigned char u8;
- // Signed
- typedef __int64 s64;
- typedef int s32;
- typedef short s16;
- typedef char s8;
- #endif
- typedef u16 WORD;
- typedef u32 DWORD;
- typedef s32 LONG;
- #ifndef bool
- typedef int bool;
- #endif
- #ifndef true
- #define true 1
- #endif
- #ifndef false
- #define false 0
- #endif
- #ifndef min
- #define min(a,b) ((a <= b) ? a : b)
- #endif
- #ifndef max
- #define max(a,b) ((a >= b) ? a : b)
- #endif
- // Floating point
- typedef float f32;
- typedef double f64;
- // Constant signed
- typedef const s8 cs8;
- typedef const s16 cs16;
- typedef const s32 cs32;
- typedef const s64 cs64;
- // Constant unsigned
- typedef const u8 cu8;
- typedef const u16 cu16;
- typedef const u32 cu32;
- typedef const u64 cu64;
- // Constant floating point
- typedef const f64 cf64;
- typedef const f64 cf64;
- typedef struct tagBmpFileHeader {
- WORD bfType;
- DWORD bfSize;
- WORD bfReserved1;
- WORD bfReserved2;
- DWORD bfOffBits;
- } BFH;
- typedef struct tagBmpInfoHeader {
- DWORD biSize;
- LONG biWidth;
- LONG biHeight;
- WORD biPlanes;
- WORD biBitCount;
- DWORD biCompression;
- DWORD biSizeImage;
- LONG biXPelsPerMeter;
- LONG biYPelsPerMeter;
- DWORD biClrUsed;
- DWORD biClrImportant;
- } BIH;
- typedef struct SBmp
- {
- // Raw bitmap data (suitable for writing to disk)
- BFH bh;
- BIH bi;
- s8* bd;
- u32 rowWidth;
- } SBitmap;
- typedef struct SF32
- {
- f32 x;
- f32 y;
- } SXYF32;
- typedef struct SS32
- {
- s32 x;
- s32 y;
- } SXYS32;
- typedef struct SLF32
- {
- union {
- SXYF32 start; // [input] Starting point
- SXYF32 p1;
- };
- union {
- SXYF32 end; // [input] Ending point
- SXYF32 p2;
- };
- // The following are computed with vvm_math_computeLine()
- SXYF32 delta; // Delta between start and end
- SXYF32 mid; // Midpoint
- union {
- f32 length; // Length
- f32 radius; // Radius for the trig function
- };
- f32 m; // Slope
- f32 mp; // Perpendicular slope
- // Only used and computed if trig is true
- bool trig; // Should trig functions be computed?
- f32 theta; // Theta (from p1 to p2, note: add _PI to reverse the angle from p2 to p1)
- // Only used and computed if ints is true
- bool ints; // Should integer approximations be calculated?
- union {
- SXYS32 starti; // Starting x,y
- SXYS32 p1i;
- };
- union {
- SXYS32 endi; // Ending x,y
- SXYS32 p2i;
- };
- // Only used and computed if quads is true
- bool quads; // Should we compute quadrants?
- union {
- s32 start_quad; // What quadrant is start/p1 in?
- s32 p1_quad;
- };
- union {
- s32 end_quad; // What quadrant is end/p2 in?
- s32 p2_quad;
- };
- } SLineF32;
- typedef struct sb
- {
- u8 blu;
- u8 grn;
- u8 red;
- } SBgr;
- typedef struct Sba
- {
- union {
- u32 color;
- struct {
- u8 blu;
- u8 grn;
- u8 red;
- u8 alp;
- };
- };
- } SBgra;
- SBgra blackColor;
- //////////
- //
- // Computes the row width of the pixels using BGR format (3 bytes per pixel) then rounded up to
- // the nearest DWORD.
- //
- //////
- s32 iBmp_computeRowWidth(SBitmap* bmp)
- {
- s32 lnWidth;
- // Make sure our environment is sane
- if (bmp)
- {
- // See the bit counts
- if (bmp->bi.biBitCount == 24)
- {
- // 24-bit formats are rounded up to nearest DWORD
- lnWidth = bmp->bi.biWidth * 3;
- if (lnWidth % 4 == 0)
- return(lnWidth);
- // Increase the width
- lnWidth += (4 - (lnWidth % 4));
- return(lnWidth);
- } else if (bmp->bi.biBitCount == 32) {
- // 32-bit formats are also DWORD aligned, but naturally, of course. :-)
- return(bmp->bi.biWidth * 4);
- } else {
- // Uh oh, spaghetti-oh!
- return(bmp->bi.biSizeImage / bmp->bi.biHeight);
- }
- }
- // Invalid
- return(0);
- }
- //////////
- //
- // Called to create an empty bitmap
- //
- //////
- void iBmp_populateBitmapStructure(SBitmap* bmp, u32 tnWidth, u32 tnHeight, u32 tnBitCount)
- {
- if (bmp)
- {
- memset(&bmp->bi, 0, sizeof(bmp->bi));
- bmp->bi.biSize = sizeof(bmp->bi);
- bmp->bi.biWidth = tnWidth;
- bmp->bi.biHeight = tnHeight;
- bmp->bi.biCompression = 0;
- bmp->bi.biPlanes = 1;
- bmp->bi.biBitCount = (u16)((tnBitCount == 24 || tnBitCount == 32) ? tnBitCount : 24);
- bmp->bi.biXPelsPerMeter = 2835; // Assume 72 dpi
- bmp->bi.biYPelsPerMeter = 2835;
- bmp->rowWidth = iBmp_computeRowWidth(bmp);
- bmp->bi.biSizeImage = bmp->rowWidth * tnHeight;
- memset(&bmp->bh, 0, sizeof(bmp->bh));
- bmp->bh.bfType = 0x4d42; // BM file prefix
- bmp->bh.bfOffBits = sizeof(bmp->bh) + sizeof(bmp->bi);
- bmp->bh.bfSize = bmp->bh.bfOffBits + bmp->bi.biSizeImage;
- }
- }
- //////////
- //
- // Called to create a basic bitmap by the indicated size, and initially populate it to white
- //
- //////
- void iBmp_createBySize(SBitmap* bmp, u32 width, u32 height, u32 tnBitCount)
- {
- if (bmp)
- {
- // Populate the initial structure (min of 1x1, max of 7680x4320 (4x 1920x1080)
- iBmp_populateBitmapStructure(bmp, min(max(width, 1), 7680), min(max(height, 1), 4320), tnBitCount);
- // Create the HDC and DIB Section
- bmp->bd = (s8*)malloc(bmp->bi.biSizeImage);
- // Paint it white initially (the fast/easy way)
- if (bmp->bd)
- memset(bmp->bd, 255, bmp->bi.biSizeImage);
- }
- }
- //////////
- // Allocates a new structure
- //////
- SBitmap* iBmp_allocate(u32 width, u32 height, u32 tnBitCount)
- {
- SBitmap* bmp;
- // Allocate our new structure
- bmp = (SBitmap*)malloc(sizeof(SBitmap));
- // Initialize if successful
- if (bmp)
- iBmp_createBySize(bmp, width, height, tnBitCount);
- // Indicate our success or failure
- return(bmp);
- }
- //////////
- //
- // Adjusts theta into the 0..2pi range
- //
- //////
- #ifndef M_PI
- #define M_PI 3.14159265358979323846
- #endif
- const f32 _2PI = (f32)M_PI * 2.0f; // 2 * pi
- f32 iivvm_math_adjustTheta(f32 tfTheta)
- {
- // Validate theta is positive
- while (tfTheta < 0.0)
- tfTheta += _2PI;
- // Validate theta is 0..2pi
- while (tfTheta > _2PI)
- tfTheta -= _2PI;
- return(tfTheta);
- }
- //////////
- //
- // Determines the quandrant of the point
- //
- //////
- s32 iivvm_math_computeQuadrant(SXYF32* p)
- {
- if (p->x >= 0.0)
- {
- // Either 1 or 4
- if (p->y >= 0.0) return(1); // X is positive, Y is positive
- else return(4); // X is positive, Y is negative
- } else {
- // Either 2 or 3
- if (p->y >= 0.0) return(2); // X is negative, Y is positive
- else return(3); // X is negative, Y is negative
- }
- }
- void iivvm_math_computeLine(SLineF32* line)
- {
- // Midpoint = (x2-x1)/2, (y2-y1)/2
- line->mid.x = (line->p1.x + line->p2.x) / 2.0f;
- line->mid.y = (line->p1.y + line->p2.y) / 2.0f;
- // Compute our deltas
- line->delta.x = line->p2.x - line->p1.x;
- line->delta.y = line->p2.y - line->p1.y;
- // Length
- line->length = (f32)sqrt(line->delta.x*line->delta.x + line->delta.y*line->delta.y);
- // Slope = rise over run
- line->m = line->delta.y / ((line->delta.x == 0.0f) ? 0.000001f : line->delta.x);
- // Perpendicular slope = -1/m
- line->mp = -1.0f / ((line->m == 0.0) ? 0.000001f : line->m);
- //////////
- // Compute theta if need be (radius is same as length)
- /////
- if (line->trig)
- line->theta = iivvm_math_adjustTheta((f32)atan2(line->delta.y, line->delta.x));
- //////////
- // Compute the integer roundings if need be
- //////
- if (line->ints)
- {
- // Start
- line->p1i.x = (s32)line->p1.x;
- line->p1i.y = (s32)line->p1.y;
- // End
- line->p2i.x = (s32)line->p2.x;
- line->p2i.y = (s32)line->p2.y;
- }
- //////////
- // Compute the quadrants if need be
- //////
- if (line->quads)
- {
- // Quads 1..4
- line->p1_quad = iivvm_math_computeQuadrant(&line->p1);
- line->p2_quad = iivvm_math_computeQuadrant(&line->p2);
- }
- }
- void iivvm_copyLine(SLineF32* line, SXYF32* p1, SXYF32* p2, bool tlComputeLine)
- {
- // Copy
- memcpy(&line->p1, p1, sizeof(line->p1));
- memcpy(&line->p2, p2, sizeof(line->p2));
- // Compute if need be
- if (tlComputeLine)
- iivvm_math_computeLine(line);
- }
- //////////
- //
- // Called to draw or generate the bezier using 3 points
- //
- //////
- SXYF32* iivvm_canvasBezier3(s32 tnSegments, SXYF32* tfP1, SXYF32* tfP2, SXYF32* tfP3)
- {
- s32 lnI;
- f32 lfPercent, lfCosTheta1, lfSinTheta1, lfCosTheta2, lfSinTheta2;
- SXYF32 p1, p2, pbez;
- SLineF32 l1, l2; // Lines from bez->p1 to bez->p2, and bez->p2 to bez->p3
- SLineF32 lmid; // Line from l1 to l2
- SXYF32* points;
- // Allocate our return buffer
- points = (SXYF32*)malloc(tnSegments * sizeof(SXYF32));
- memset(points, 0, tnSegments * sizeof(SXYF32));
- //////////
- // Copy and compute our lines
- //////
- iivvm_copyLine(&l1, tfP1, tfP2, true);
- iivvm_copyLine(&l2, tfP2, tfP3, true);
- //////////
- // Compute our thetas for rapid use
- //////
- // L1
- lfCosTheta1 = (f32)cos(l1.theta);
- lfSinTheta1 = (f32)sin(l1.theta);
- // L2
- lfCosTheta2 = (f32)cos(l2.theta);
- lfSinTheta2 = (f32)sin(l2.theta);
- //////////
- // Now, iterate through the bezier building the points
- //////
- for (lnI = 0; lnI < tnSegments; lnI++)
- {
- //////////
- // Get our percentage
- //////
- lfPercent = (f32)lnI / (f32)tnSegments;
- //////////
- // Determine the two points for l1 and l2
- //////
- // P1, L1
- p1.x = tfP1->x + (lfPercent * l1.radius * lfCosTheta1);
- p1.y = tfP1->y + (lfPercent * l1.radius * lfSinTheta1);
- // P2, L2
- p2.x = tfP2->x + (lfPercent * l2.radius * lfCosTheta2);
- p2.y = tfP2->y + (lfPercent * l2.radius * lfSinTheta2);
- //////////
- // Construct the line between
- //////
- iivvm_copyLine(&lmid, &p1, &p2, true);
- //////////
- // Derive the position of this bezier point
- //////
- // PBEZ
- pbez.x = lmid.p1.x + (lfPercent * lmid.radius * (f32)cos(lmid.theta));
- pbez.y = lmid.p1.y + (lfPercent * lmid.radius * (f32)sin(lmid.theta));
- //////////
- // Store the point
- //////
- points[lnI].x = pbez.x;
- points[lnI].y = pbez.y;
- }
- return(points);
- }
- //////////
- //
- // Called to draw a point
- //
- //////
- void iBmp_drawPoint(SBitmap* bmp, s32 tnX, s32 tnY, SBgra color)
- {
- SBgr* lbgr;
- SBgra* lbgra;
- if (bmp)
- {
- // Make sure our coordinates are valid
- if (tnX >= 0 && tnX < bmp->bi.biWidth && tnY >= 0 && tnY < bmp->bi.biHeight)
- {
- if (bmp->bi.biBitCount == 24)
- {
- // Get our offset
- lbgr = (SBgr*)(bmp->bd + ((bmp->bi.biHeight - tnY - 1) * bmp->rowWidth) + (tnX * 3));
- // Draw it
- lbgr->red = color.red;
- lbgr->grn = color.grn;
- lbgr->blu = color.blu;
- } else if (bmp->bi.biBitCount == 32) {
- // Get our offset
- lbgra = (SBgra*)(bmp->bd + ((bmp->bi.biHeight - tnY - 1) * bmp->rowWidth) + (tnX * 4));
- // Draw it
- lbgra->red = color.red;
- lbgra->grn = color.grn;
- lbgra->blu = color.blu;
- }
- }
- }
- }
- //////////
- //
- // Called to draw an arbitary line between two points. Does
- // not handle any anti-aliasing, but rather is a brute-force
- // method to present a simple line.
- //
- /////
- void iBmp_drawArbitraryLine(SBitmap* bmp, s32 tnX1, s32 tnY1, s32 tnX2, s32 tnY2, SBgra color)
- {
- f32 lfX, lfY, lfXStep, lfYStep, lfRadius, lfDeltaX, lfDeltaY;
- // Compute the distance
- lfDeltaX = (f32)(tnX2 - tnX1);
- lfDeltaY = (f32)(tnY2 - tnY1);
- lfRadius = (f32)sqrt((lfDeltaX*lfDeltaX) + (lfDeltaY*lfDeltaY));
- if (lfRadius < 1.0f)
- return;
- // Compute our steps per pixel
- lfXStep = lfDeltaX / lfRadius;
- lfYStep = lfDeltaY / lfRadius;
- // Iterate for each point
- for (lfX = (f32)tnX1, lfY = (f32)tnY1; lfRadius > 0.0f; lfRadius--, lfX += lfXStep, lfY += lfYStep)
- iBmp_drawPoint(bmp, (s32)lfX, (s32)lfY, color);
- }
- //////////
- //
- // Draws a rectange around an arbitrary line.
- //
- //////
- #ifndef _PI2
- #define _PI2 1.570796327
- #endif
- void iBmp_drawArbitraryQuad(SBitmap* bmp, s32 tnX1, s32 tnY1, s32 tnX2, s32 tnY2, s32 tnWidth, bool tlDrawEnds, SBgra color)
- {
- f32 lfX1, lfY1, lfX2, lfY2, lfX3, lfY3, lfX4, lfY4;
- SLineF32 line;
- //////////
- // Compute the line
- /////
- line.p1.x = (f32)tnX1;
- line.p1.y = (f32)tnY1;
- line.p2.x = (f32)tnX2;
- line.p2.y = (f32)tnY2;
- iivvm_math_computeLine(&line);
- //////////
- // Draw the line
- //////
- lfX1 = line.p1.x + ((f32)cos(line.theta + _PI2) * ((f32)tnWidth / 2.0f));
- lfY1 = line.p1.y + ((f32)sin(line.theta + _PI2) * ((f32)tnWidth / 2.0f));
- lfX2 = line.p1.x + ((f32)cos(line.theta - _PI2) * ((f32)tnWidth / 2.0f));
- lfY2 = line.p1.y + ((f32)sin(line.theta - _PI2) * ((f32)tnWidth / 2.0f));
- if (tlDrawEnds)
- iBmp_drawArbitraryLine(bmp, (s32)lfX1, (s32)lfY1, (s32)lfX2, (s32)lfY2, color);
- lfX3 = line.p2.x + ((f32)cos(line.theta + _PI2) * ((f32)tnWidth / 2.0f));
- lfY3 = line.p2.y + ((f32)sin(line.theta + _PI2) * ((f32)tnWidth / 2.0f));
- lfX4 = line.p2.x + ((f32)cos(line.theta - _PI2) * ((f32)tnWidth / 2.0f));
- lfY4 = line.p2.y + ((f32)sin(line.theta - _PI2) * ((f32)tnWidth / 2.0f));
- if (tlDrawEnds)
- iBmp_drawArbitraryLine(bmp, (s32)lfX3, (s32)lfY3, (s32)lfX4, (s32)lfY4, color);
- iBmp_drawArbitraryLine(bmp, (s32)lfX1, (s32)lfY1, (s32)lfX3, (s32)lfY3, color);
- iBmp_drawArbitraryLine(bmp, (s32)lfX2, (s32)lfY2, (s32)lfX4, (s32)lfY4, color);
- }
- //////////
- //
- // Create a two-part bezier-3 line, one from upper-left to center,
- // the other from lower-right to center.
- //
- //////
- void iTest_nodeLine(SBitmap* bmp, f32 lfFactorX, f32 lfFactorY)
- {
- s32 lnI, lnWidth;
- SXYF32* points1;
- SXYF32* points2;
- SXYF32 p1, p2, p3, p4, p5;
- f32 lfWidth, lfHeight;
- lfWidth = bmp->bi.biWidth * lfFactorX / 8.0f;
- lfHeight = bmp->bi.biHeight * lfFactorY / 8.0f;
- p1.x = ((f32)bmp->bi.biWidth / 2.0f) - (lfWidth / 2.0f);
- p1.y = ((f32)bmp->bi.biHeight / 2.0f) - (lfHeight / 2.0f);
- p2.x = ((f32)bmp->bi.biWidth / 2.0f) - (lfWidth / 4.0f);
- p2.y = ((f32)bmp->bi.biHeight / 2.0f) - (lfHeight / 2.0f);
- p3.x = ((f32)bmp->bi.biWidth / 2.0f);
- p3.y = ((f32)bmp->bi.biHeight / 2.0f);
- points1 = iivvm_canvasBezier3(20, &p1, &p2, &p3);
- p4.x = ((f32)bmp->bi.biWidth / 2.0f) + (lfWidth / 4.0f);
- p4.y = ((f32)bmp->bi.biHeight / 2.0f) + (lfHeight / 2.0f);
- p5.x = ((f32)bmp->bi.biWidth / 2.0f) + (lfWidth / 2.0f);
- p5.y = ((f32)bmp->bi.biHeight / 2.0f) + (lfHeight / 2.0f);
- points2 = iivvm_canvasBezier3(20, &p5, &p4, &p3);
- lnWidth = 5;
- for (lnI = 0; lnI < 20 - 1; lnI++)
- {
- iBmp_drawArbitraryQuad(bmp, (s32)points1[lnI].x, (s32)points1[lnI].y, (s32)points1[lnI+1].x, (s32)points1[lnI+1].y, lnWidth, true, blackColor);
- iBmp_drawArbitraryQuad(bmp, (s32)points2[lnI].x, (s32)points2[lnI].y, (s32)points2[lnI+1].x, (s32)points2[lnI+1].y, lnWidth, true, blackColor);
- }
- --lnI;
- iBmp_drawArbitraryQuad(bmp, (s32)points1[lnI].x, (s32)points1[lnI].y, (s32)points2[lnI].x, (s32)points2[lnI].y, lnWidth, true, blackColor);
- free(points1);
- free(points2);
- }
- //////////
- //
- // Create an 800x600 bitmap, populate it with a double bezier-3 curve,
- // and write the bitmap to disk.
- //
- //////
- int main(int argc, char* argv[])
- {
- size_t numwritten1, numwritten2, numwritten3;
- SBitmap* bmp;
- FILE* lfh;
- //////////
- // Create the bitmap
- //////
- bmp = iBmp_allocate(800, 600, 24);
- if (!bmp)
- {
- printf("Failure allocating bitmap.\n");
- return -1;
- }
- //////////
- // Draw the node line
- //////
- blackColor.color = 0;
- iTest_nodeLine(bmp, 7.0f, 7.0f);
- //////////
- // Write the output file
- //////
- lfh = fopen("output.bmp", "wb+");
- if (!lfh)
- {
- printf("Error creating output.bmp\n");
- return -2;
- }
- numwritten1 = fwrite(&bmp->bh, 1, sizeof(bmp->bh), lfh);
- numwritten2 = fwrite(&bmp->bi, 1, sizeof(bmp->bi), lfh);
- numwritten3 = fwrite(bmp->bd, 1, bmp->bi.biSizeImage, lfh);
- fclose(lfh);
- if (!(numwritten1 == sizeof(bmp->bh) && numwritten2 == sizeof(bmp->bi) && numwritten3 == bmp->bi.biSizeImage))
- {
- printf("Error writing output.bmp\n");
- return -3;
- }
- //////////
- // Indicate our status
- //////
- printf("Success. output.bmp created.\n");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment