#include <map> #include <functional> #include <iostream> #include <fstream> #include <math.h> #include "ogTypes.h" #include "ogEdgeTable.h" #include "ogPixCon.h" #include "ogPixelFmt.h" #include "objgfx.h" const static ogRGBA8 DEFAULT_PALETTE[256] = {{0, 0, 0, 255}, // 0 {0, 0, 170, 255}, {0, 170, 0, 255}, {0, 170, 170, 255}, // 3 {170, 0, 0, 255}, {170, 0, 170, 255}, {170, 85, 0, 255}, {170, 170, 170, 255}, // 7 {85, 85, 85, 255}, {85, 85, 255, 255}, {85, 255, 85, 255}, {85, 255, 255, 255}, // 11 {255, 85, 85, 255}, {255, 85, 255, 255}, {255, 255, 85, 255}, {255, 255, 255, 255}, //15 {16, 16, 16, 255}, // 16 {32, 32, 32, 255}, {48, 48, 48, 255}, {64, 64, 64, 255}, {80, 80, 80, 255}, {96, 96, 96, 255}, {112, 112, 112, 255}, {128, 128, 128, 255}, {144, 144, 144, 255}, {160, 160, 160, 255}, {176, 176, 176, 255}, {192, 192, 192, 255}, {208, 208, 208, 255}, {224, 224, 224, 255}, {240, 240, 240, 255}, {255, 255, 255, 255}, //31 {59, 0, 0, 255}, // 32 {79, 0, 0, 255}, {103, 0, 0, 255}, {123, 0, 0, 255}, {143, 7, 7, 255}, {167, 7, 7, 255}, {187, 11, 11, 255}, {211, 15, 15, 255}, {231, 19, 19, 255}, {255, 27, 27, 255}, {255, 59, 59, 255}, {255, 91, 91, 255}, {255, 119, 119, 255}, {255, 151, 151, 255}, {255, 183, 183, 255}, {255, 215, 215, 255}, {55, 55, 0, 255}, // 48 {71, 71, 0, 255}, {87, 87, 0, 255}, {103, 103, 7, 255}, {119, 119, 7, 255}, {135, 135, 11, 255}, {155, 155, 19, 255}, {171, 171, 23, 255}, {187, 187, 31, 255}, {203, 203, 35, 255}, {219, 219, 43, 255}, {239, 239, 59, 255}, {255, 255, 63, 255}, {255, 255, 127, 255}, {255, 255, 187, 255}, {255, 255, 255, 255}, {0, 43, 0, 255}, // 64 {0, 63, 0, 255}, {0, 83, 0, 255}, {0, 103, 0, 255}, {7, 127, 7, 255}, {7, 147, 7, 255}, {11, 167, 11, 255}, {15, 187, 15, 255}, {19, 211, 19, 255}, {27, 231, 27, 255}, {59, 235, 59, 255}, {91, 239, 91, 255}, {127, 239, 127, 255}, {159, 243, 159, 255}, {195, 247, 195, 255}, {231, 251, 231, 255}, {0, 55, 55, 255}, // 80 {0, 71, 71, 255}, {0, 87, 87, 255}, {7, 103, 103, 255}, {7, 119, 119, 255}, {11, 135, 135, 255}, {19, 155, 155, 255}, {23, 171, 171, 255}, {31, 187, 187, 255}, {35, 203, 203, 255}, {43, 219, 219, 255}, {51, 235, 235, 255}, {63, 255, 255, 255}, {127, 255, 255, 255}, {187, 255, 255, 255}, {255, 255, 255, 255}, {15, 15, 55, 255}, // 96 {19, 19, 79, 255}, {27, 27, 103, 255}, {31, 31, 127, 255}, {35, 35, 155, 255}, {39, 39, 179, 255}, {43, 43, 203, 255}, {47, 47, 227, 255}, {51, 51, 255, 255}, {71, 71, 255, 255}, {91, 91, 255, 255}, {111, 111, 255, 255}, {131, 131, 255, 255}, {151, 151, 255, 255}, {175, 175, 255, 255}, {195, 195, 255, 255}, {59, 51, 59, 255}, // 112 {79, 63, 79, 255}, {103, 71, 103, 255}, {123, 75, 123, 255}, {143, 75, 143, 255}, {167, 71, 167, 255}, {187, 67, 187, 255}, {211, 55, 211, 255}, {231, 43, 231, 255}, {255, 27, 255, 255}, {255, 59, 255, 255}, {255, 91, 255, 255}, {255, 119, 255, 255}, {255, 151, 255, 255}, {255, 183, 255, 255}, {255, 215, 255, 255}, {59, 51, 59, 255}, // 128 {71, 59, 71, 255}, {83, 71, 83, 255}, {95, 83, 95, 255}, {111, 95, 111, 255}, {123, 103, 123, 255}, {135, 115, 135, 255}, {147, 127, 147, 255}, {163, 139, 163, 255}, {175, 151, 175, 255}, {187, 159, 187, 255}, {203, 171, 203, 255}, {215, 183, 215, 255}, {227, 191, 227, 255}, {239, 203, 239, 255}, {255, 215, 255, 255}, {55, 27, 27, 255}, // 144 {71, 35, 35, 255}, {91, 43, 43, 255}, {107, 55, 55, 255}, {127, 67, 67, 255}, {143, 75, 75, 255}, {163, 87, 87, 255}, {179, 99, 99, 255}, {199, 111, 111, 255}, {203, 127, 127, 255}, {211, 139, 139, 255}, {219, 159, 159, 255}, {223, 175, 175, 255}, {231, 191, 191, 255}, {239, 211, 211, 255}, {247, 231, 231, 255}, {91, 63, 27, 255}, // 160 {111, 75, 31, 255}, {127, 87, 39, 255}, {147, 103, 43, 255}, {167, 115, 51, 255}, {187, 127, 55, 255}, {207, 139, 63, 255}, {227, 155, 67, 255}, {247, 167, 75, 255}, {247, 175, 95, 255}, {247, 183, 119, 255}, {247, 195, 139, 255}, {247, 203, 159, 255}, {247, 215, 183, 255}, {247, 227, 203, 255}, {251, 239, 227, 255}, {63, 63, 31, 255}, // 176 {75, 75, 35, 255}, {87, 87, 43, 255}, {99, 99, 51, 255}, {115, 115, 55, 255}, {127, 127, 63, 255}, {139, 139, 67, 255}, {151, 151, 75, 255}, {167, 167, 83, 255}, {175, 175, 95, 255}, {183, 183, 107, 255}, {191, 191, 123, 255}, {203, 203, 139, 255}, {211, 211, 159, 255}, {219, 219, 175, 255}, {231, 231, 195, 255}, {27, 59, 47, 255}, // 192 {31, 75, 59, 255}, {39, 87, 67, 255}, {47, 103, 79, 255}, {55, 119, 91, 255}, {59, 135, 99, 255}, {67, 151, 111, 255}, {71, 167, 119, 255}, {79, 183, 127, 255}, {87, 199, 139, 255}, {91, 215, 147, 255}, {99, 231, 155, 255}, {127, 235, 183, 255}, {163, 239, 211, 255}, {195, 243, 231, 255}, {231, 251, 247, 255}, {23, 55, 55, 255}, // 208 {31, 71, 71, 255}, {39, 87, 87, 255}, {47, 103, 103, 255}, {55, 119, 119, 255}, {67, 139, 139, 255}, {75, 155, 155, 255}, {87, 171, 171, 255}, {99, 187, 187, 255}, {111, 203, 203, 255}, {123, 223, 223, 255}, {143, 227, 227, 255}, {163, 231, 231, 255}, {183, 235, 235, 255}, {203, 239, 239, 255}, {227, 247, 247, 255}, {39, 39, 79, 255}, // 224 {47, 47, 91, 255}, {55, 55, 107, 255}, {63, 63, 123, 255}, {71, 71, 139, 255}, {79, 79, 151, 255}, {87, 87, 167, 255}, {99, 99, 183, 255}, {107, 107, 199, 255}, {123, 123, 203, 255}, {139, 139, 211, 255}, {155, 155, 219, 255}, {171, 171, 223, 255}, {187, 187, 231, 255}, {207, 207, 239, 255}, {227, 227, 247, 255}, {63, 27, 63, 255}, // 240 {75, 31, 75, 255}, {91, 39, 91, 255}, {103, 47, 103, 255}, {119, 51, 119, 255}, {131, 59, 131, 255}, {147, 67, 147, 255}, {163, 75, 163, 255}, {175, 83, 175, 255}, {191, 91, 191, 255}, {199, 107, 199, 255}, {207, 127, 207, 255}, {215, 147, 215, 255}, {223, 171, 223, 255}, {231, 195, 231, 255}, {243, 219, 243, 255}}; const double ogSurface::INTENSITIES[32] = { 1.0, // 0 0.984250984251, // 1 0.968245836552, // 2 0.951971638233, // 3 0.935414346693, // 4 0.938558653544, // 5 0.901387818866, // 6 0.883883476483, // 7 0.866025403784, // 8 0.847791247891, // 9 0.829156197589, // 10 0.810092587301, // 11 0.790569415042, // 12 0.770551750371, // 13 0.75, // 14 0.728868986856, // 15 0.707106781187, // 16 0.684653196881, // 17 0.661437827766, // 18 0.637377439199, // 19 0.612372435696, // 20 0.586301969978, // 21 0.559016994375, // 22 0.53033008589, // 23 0.5, // 24 0.467707173347, // 25 0.433012701892, // 26 0.395284707521, // 27 0.353553390593, // 28 0.306186217848, // 29 0.25, // 30 0.176776695297 // 31 }; // INTENSITIES[] // ogSurface constructor ogSurface::ogSurface(void) { version = ogVERSION; dataState = ogNone; buffer = NULL; lineOfs = NULL; pal = NULL; attributes = NULL; xRes = 0; yRes = 0; maxX = 0; maxY = 0; bSize = 0; lSize = 0; BPP = 0; bytesPerPix = 0; pixFmtID = 0; redShifter = 0; greenShifter= 0; blueShifter = 0; alphaShifter= 0; redFieldPosition = 0; greenFieldPosition = 0; blueFieldPosition = 0; alphaFieldPosition = 0; alphaMasker = 0; lastError = ogOK; // Set these function pointers to do nothing (but not crash) // in case somebody actually calls them. setPixel = ([] (void * ptr, uint32_t p) -> void { }); getPixel = ([] (void * ptr) -> uint32_t { return 0; }); } // ogSurface::ogSurface() void ogSurface::AARawLine(uint32_t x1, uInt32 y1, uInt32 x2, uInt32 y2, uInt32 colour) { /* * aaRawLine * * private method * * draws an unclipped anti-aliased line from (x1,y1) to (x2,y2) using colour * */ uint32_t erradj, erracc; uint32_t erracctmp, intshift, wgt, wgtCompMask; int32 dx, dy, tmp, xDir, i; uInt8 r, g, b, a; uint32_t alphas[32]; bool oldBlending; if (y1 > y2) { tmp= y1; y1 = y2; y2 = tmp; tmp= x1; x1 = x2; x2 = tmp; } // if dx = (x2-x1); if (dx >= 0) xDir=1; else { dx = -dx; xDir=-1; } // dx = abs(dx); dy = (y2 - y1); if (dy == 0) { ogHLine(x1, x2, y1, colour); return; } if (dx == 0) { ogVLine(x1, y1, y2, colour); return; } ogUnpack(colour, r, g, b, a); if (!ogIsBlending()) a = 255; for (i = 0; i < 32; i++) { alphas[i] = static_cast<uint32_t>(INTENSITIES[i]*a + 0.5f); } // for oldBlending = ogSetBlending(true); RawSetPixel(x1, y1, r, g, b, a); // this is incomplete.. diagonal lines don't travel through the // center of pixels exactly do { if (dx == dy) { for (; dy != 0; dy--) { x1 += xDir; ++y1; RawSetPixel(x1, y1, r, g, b, a); } // for break; // pop out to the bottom and restore the old blending state } // if dx==dy erracc = 0; intshift = 32-5; wgt = 12; wgtCompMask = 31; if (dy > dx) { /* y-major. Calculate 32-bit fixed point fractional part of a pixel that * X advances every time Y advances 1 pixel, truncating the result so that * we won't overrun the endpoint along the X axis */ #ifndef __UBIXOS__ erradj = ((uInt64) dx << 32) / (uInt64)dy; #else asm volatile ( // fixed " xor %%eax, %%eax \n" " div %%ecx \n" : "=a" (erradj) : "d" (dx), "c" (dy) ); #endif while (--dy) { erracctmp = erracc; erracc += erradj; if (erracc <= erracctmp) x1 += xDir; y1++; // y-major so always advance Y /* the nbits most significant bits of erracc give us the intensity * weighting for this pixel, and the complement of the weighting for * the paired pixel. */ wgt = erracc >> intshift; ogSetPixel(x1, y1, r, g, b, alphas[wgt]); ogSetPixel(x1+xDir, y1, r, g, b, alphas[wgt ^ wgtCompMask]); } // while } else { /* x-major line. Calculate 32-bit fixed-point fractional part of a pixel * that Y advances each time X advances 1 pixel, truncating the result so * that we won't overrun the endpoint along the X axis. */ #ifndef __UBIXOS__ erradj = ((uInt64)dy << 32) / (uInt64)dx; #else asm volatile( // fixed " xor %%eax, %%eax \n" " div %%ecx \n" : "=a" (erradj) : "d" (dy), "c" (dx) ); #endif // draw all pixels other than the first and last while (--dx) { erracctmp = erracc; erracc += erradj; if (erracc <= erracctmp) y1++; x1 += xDir; // x-major so always advance X /* the nbits most significant bits of erracc give us the intensity * weighting for this pixel, and the complement of the weighting for * the paired pixel. */ wgt = erracc >> intshift; ogSetPixel(x1, y1, r, g, b, alphas[wgt]); ogSetPixel(x1, y1+1, r, g, b, alphas[wgt ^ wgtCompMask]); } // while } // else RawSetPixel(x2, y2, r, g, b, alphas[wgt]); } while (false); ogSetBlending(oldBlending); } // void ogSurface::AARawLine() bool ogSurface::ClipLine(int32& x1, int32& y1, int32& x2, int32& y2) { /* * clipLine() * * private method * * clips a line to (0,0),(maxX,maxY); returns true if * the line segment is in bounds, false if none of the line segment is * on the screen. Uses HJI's line clipping algorithm. */ int32 tx1, ty1, tx2, ty2; int32 outCode; uint32_t andResult, orResult; andResult = 15; orResult = 0; outCode = 0; if (x1 < 0) outCode+=8; if (x1 > (int32)maxX) outCode+=4; if (y1 < 0) outCode+=2; if (y1 > (int32)maxY) outCode++; andResult &= outCode; orResult |= outCode; outCode = 0; if (x2 < 0) outCode+=8; if (x2 > (int32)maxX) outCode+=4; if (y2 < 0) outCode+=2; if (y2 > (int32)maxY) outCode++; andResult &= outCode; orResult |= outCode; if (andResult > 0) return false; if (orResult == 0) return true; // some clipping is required here. tx1 = x1; ty1 = y1; tx2 = x2; ty2 = y2; if (x1 < 0) { ty1 = (x2*y1-x1*y2) / (x2-x1); tx1 = 0; } // if else { if (x2 < 0) { ty2 = (x2*y1-x1*y2) / (x2-x1); tx2 = 0; } // elseif } if (x1 > (int32)maxX) { ty1 = (y1*(x2-maxX)+y2*(maxX-x1)) / (x2-x1); tx1 = maxX; } // if else { if (x2 > (int32)maxX) { ty2 = (y1*(x2-maxX)+y2*(maxX-x1)) / (x2-x1); tx2 = maxX; } // elseif } if (((ty1 < 0) && (ty2 < 0)) || ((ty1>(int32)maxY) && (ty2>(int32)maxY))) return false; if (ty1 < 0) { tx1 = (x1*y2-x2*y1) / (y2-y1); ty1 = 0; } // if else { if (ty2 < 0) { tx2 = (x1*y2-x2*y1) / (y2-y1); ty2 = 0; } // elseif } if (ty1 > (int32)maxY) { tx1 = (x1*(y2-maxY)+x2*(maxY-y1)) / (y2-y1); ty1 = maxY; } // if else { if (ty2 > (int32)maxY) { tx2 = (x1*(y2-maxY)+x2*(maxY-y1)) / (y2-y1); ty2 = maxY; } // elseif } if (((uint32_t)tx1 > maxX) || ((uInt32)tx2 > maxX)) return false; x1 = tx1; y1 = ty1; x2 = tx2; y2 = ty2; return true; } // bool ogSurface::ClipLine() uint32_t ogSurface::RawGetPixel(uInt32 x, uInt32 y) { //uInt8* ptr = (uInt8*)buffer + lineOfs[y]; // Pointer to pixel at (0,y). void * ptr = reinterpret_cast<void *>(buffer + lineOfs[y] + x*bytesPerPix); return getPixel(ptr); #if 0 uint32_t result = 0; uint32_t * buf32; uInt8 * buf24; uInt16 * buf16; uInt8 * buf8; switch (bytesPerPix) { case 4: buf32 = reinterpret_cast<uint32_t *>(buffer + lineOfs[y] + x*4); result = *buf32; //uint32_t * // uint32_t * buf = static_cast<uInt32 *>(buffer + lineOfs[y]) _asm { mov eax, this ; mov edi, x ; mov ebx, y ; shl edi, 2 ; // adjust for pixel size mov esi, [eax + ogSurface::lineOfs] ; add edi, [esi + ebx*4] ; add edi, [eax + ogSurface::buffer] ; mov eax, [edi] ; mov result, eax ; }; break; case 3: buf24 = (buffer + lineOfs[y] + x); result = *buf24; break; case 2: buf16 = reinterpret_cast<uInt16 *>(buffer + lineOfs[y] + x*2); result = *buf16; break; case 1: buf8 = (buffer + lineOfs[y] + x); result = *buf8; break; } // switch return result; #endif } // uint32_t ogSurface::RawGetPixel() // wu's double step line algorithm blatently borrowed from: // http://www.edepot.com/linewu.html void ogSurface::RawLine(uint32_t x1, uInt32 y1, uInt32 x2, uInt32 y2, uInt32 colour) { int32 dy = y2 - y1; int32 dx = x2 - x1; int32 stepx, stepy; if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } RawSetPixel(x1, y1, colour); RawSetPixel(x2, y2, colour); if (dx > dy) { int32 length = (dx - 1) >> 2; int32 extras = (dx - 1) & 3; int32 incr2 = (dy << 2) - (dx << 1); if (incr2 < 0) { int32 c = dy << 1; int32 incr1 = c << 1; int32 d = incr1 - dx; for (int32 i = 0; i < length; i++) { x1 += stepx; x2 -= stepx; if (d < 0) { // Pattern: RawSetPixel(x1, y1, colour); // RawSetPixel(x1 += stepx, y1, colour); // x o o RawSetPixel(x2, y2, colour); // RawSetPixel(x2 -= stepx, y2, colour); d += incr1; } else { if (d < c) { // Pattern: RawSetPixel(x1, y1, colour); // o RawSetPixel(x1 += stepx, y1 += stepy, colour); // x o RawSetPixel(x2, y2, colour); // RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } else { RawSetPixel(x1, y1 += stepy, colour); // Pattern: RawSetPixel(x1 += stepx, y1, colour); // o o RawSetPixel(x2, y2 -= stepy, colour); // x RawSetPixel(x2 -= stepx, y2, colour); // } // else d += incr2; } // else } // for i if (extras > 0) { if (d < 0) { RawSetPixel(x1 += stepx, y1, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2, colour); } else if (d < c) { RawSetPixel(x1 += stepx, y1, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2, colour); } else { RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } } // if extras > 0 } else { int32 c = (dy - dx) << 1; int32 incr1 = c << 1; int32 d = incr1 + dx; for (int32 i = 0; i < length; i++) { x1 += stepx; x2 -= stepx; if (d > 0) { RawSetPixel(x1, y1 += stepy, colour); // Pattern: RawSetPixel(x1 += stepx, y1 += stepy, colour); // o RawSetPixel(x2, y2 -= stepy, colour); // o RawSetPixel(x2 -= stepx, y2 -= stepy, colour); // x d += incr1; } else { if (d < c) { RawSetPixel(x1, y1, colour); // Pattern: RawSetPixel(x1 += stepx, y1 += stepy, colour); // o RawSetPixel(x2, y2, colour); // x o RawSetPixel(x2 -= stepx, y2 -= stepy, colour); // } else { RawSetPixel(x1, y1 += stepy, colour); // Pattern: RawSetPixel(x1 += stepx, y1, colour); // o o RawSetPixel(x2, y2 -= stepy, colour); // x RawSetPixel(x2 -= stepx, y2, colour); // } d += incr2; } // else } // for i if (extras > 0) { if (d > 0) { RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } else if (d < c) { RawSetPixel(x1 += stepx, y1, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2, colour); } else { RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1, colour); if (extras > 2) { if (d > c) RawSetPixel(x2 -= stepx, y2 -= stepy, colour); else RawSetPixel(x2 -= stepx, y2, colour); } // if extras > 2 } // else } // if extras > 0 } // else } else { int32 length = (dy - 1) >> 2; int32 extras = (dy - 1) & 3; int32 incr2 = (dx << 2) - (dy << 1); if (incr2 < 0) { int32 c = dx << 1; int32 incr1 = c << 1; int32 d = incr1 - dy; for (int32 i = 0; i < length; i++) { y1 += stepy; y2 -= stepy; if (d < 0) { RawSetPixel(x1, y1, colour); RawSetPixel(x1, y1 += stepy, colour); RawSetPixel(x2, y2, colour); RawSetPixel(x2, y2 -= stepy, colour); d += incr1; } else { if (d < c) { RawSetPixel(x1, y1, colour); RawSetPixel(x1 += stepx, y1 += stepy, colour); RawSetPixel(x2, y2, colour); RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } else { RawSetPixel(x1 += stepx, y1, colour); RawSetPixel(x1, y1 += stepy, colour); RawSetPixel(x2 -= stepx, y2, colour); RawSetPixel(x2, y2 -= stepy, colour); } // else d += incr2; } // else } // for i if (extras > 0) { if (d < 0) { RawSetPixel(x1, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2, y2 -= stepy, colour); } else if (d < c) { RawSetPixel(x1, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2, y2 -= stepy, colour); } else { RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } // else } // if extras > 0 } else { int32 c = (dx - dy) << 1; int32 incr1 = c << 1; int32 d = incr1 + dy; for (int32 i = 0; i < length; i++) { y1 += stepy; y2 -= stepy; if (d > 0) { RawSetPixel(x1 += stepx, y1, colour); RawSetPixel(x1 += stepx, y1 += stepy, colour); RawSetPixel(x2 -= stepx, y2, colour); RawSetPixel(x2 -= stepx, y2 -= stepy, colour); d += incr1; } else { if (d < c) { RawSetPixel(x1, y1, colour); RawSetPixel(x1 += stepx, y1 += stepy, colour); RawSetPixel(x2, y2, colour); RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } else { RawSetPixel(x1 += stepx, y1, colour); RawSetPixel(x1, y1 += stepy, colour); RawSetPixel(x2 -= stepx, y2, colour); RawSetPixel(x2, y2 -= stepy, colour); } // else d += incr2; } // else } // for if (extras > 0) { if (d > 0) { RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2 -= stepx, y2 -= stepy, colour); } else if (d < c) { RawSetPixel(x1, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 2) RawSetPixel(x2, y2 -= stepy, colour); } else { RawSetPixel(x1 += stepx, y1 += stepy, colour); if (extras > 1) RawSetPixel(x1, y1 += stepy, colour); if (extras > 2) { if (d > c) RawSetPixel(x2 -= stepx, y2 -= stepy, colour); else RawSetPixel(x2, y2 -= stepy, colour); } // if extras > 2 } // else } // if extras > 0 } // else } // else } // void ogSurface::RawLine() void ogSurface::RawSetPixel(uint32_t x, uInt32 y, uInt32 colour) { if (ogIsBlending()) { uInt8 sR, sG, sB, sA; uInt8 dR, dG, dB; ogUnpack(colour, sR, sG, sB, sA); if (sA == 0) return; if (sA != 255) { uint32_t inverseA = 255 - sA; ogUnpack(RawGetPixel(x, y), dR, dG, dB); uint32_t newR = (dR * inverseA + sR * sA) >> 8; uint32_t newG = (dG * inverseA + sG * sA) >> 8; uint32_t newB = (dB * inverseA + sB * sA) >> 8; //mji for gtk colour = ogPack(newR, newG, newB, inverseA); colour = ogPack(newR, newG, newB, 255); } } // if void * ptr = reinterpret_cast<void *>(buffer + lineOfs[y] + x*bytesPerPix); setPixel(ptr, colour); #if 0 //ptr = static_cast<uInt8*>(buffer) + lineOfs[y]; switch (bytesPerPix) { case 4: _asm { mov eax, this ; mov edi, [eax + ogSurface::buffer] ; mov esi, [eax + ogSurface::lineOfs] ; mov ebx, [y] ; mov ecx, [x] ; // Calculate offset, prepare the pixel to be drawn mov edx, [esi + ebx * 4] nop ; add edi, edx ; nop ; shl ecx, 2 ; // adjust for pixel size add edi, ecx ; // Draw the pixel mov eax, [colour] ; mov [edi], eax ; }; // asm break; case 3: _asm { mov eax, this ; mov edi, [eax + ogSurface::buffer] ; mov esi, [eax + ogSurface::lineOfs] ; mov ebx, [y] ; mov ecx, [x] ; // Calculate offset, prepare the pixel to be drawn mov edx, [esi + ebx * 4] ; lea ecx, [ecx *2 + ecx] ; add edi, edx ; add edi, ecx ; // adjust for pixel size // Draw the pixel mov ax, word ptr [colour] ; mov bl, byte ptr [colour+2] ; mov [edi], ax ; mov [edi+2], bl ; }; // break; case 2: _asm { mov eax, this ; mov edi, [eax + ogSurface::buffer] ; mov esi, [eax + ogSurface::lineOfs] ; mov ebx, [y] ; mov ecx, [x] ; // Calculate offset, prepare the pixel to be drawn mov edx, [esi + ebx * 4] ; add edi, edx ; add ecx, ecx ; // adjust for pixel size mov ax, word ptr [colour] ; add edi, ecx ; // Draw the pixel mov [edi], ax ; }; // asm case 1: _asm { mov eax, this ; mov edi, [eax + ogSurface::buffer] ; mov esi, [eax + ogSurface::lineOfs] ; mov ebx, [y] ; mov ecx, [x] ; // Calculate offset, prepare the pixel to be drawn mov edx, [esi + ebx * 4] ; nop ; add edi, edx ; nop ; mov al, byte ptr [colour] ; add edi, ecx ; // Draw the pixel mov [edi], al ; }; break; } // switch #endif } // void ogSurface::RawSetPixel() void ogSurface::RawSetPixel(uint32_t x, uInt32 y, uInt8 r, uInt8 g, uInt8 b, uInt8 a) { uint32_t newR, newG, newB, inverseA; uInt8 dR, dG, dB; uint32_t colour; do { if (ogIsBlending()) { if (a == 0) return; if (a == 255) { colour = ogPack(r, g, b, a); break; } // if a == 255 inverseA = 255 - a; ogUnpack(RawGetPixel(x, y), dR, dG, dB); newR = (dR * inverseA + r * a) >> 8; newG = (dG * inverseA + g * a) >> 8; newB = (dB * inverseA + b * a) >> 8; //mji for gtk colour = ogPack(newR, newG, newB, inverseA); colour = ogPack(newR, newG, newB, 255); } else colour = ogPack(r, g, b, a); } while (false); void * ptr = reinterpret_cast<void *>(buffer + lineOfs[y] + x*bytesPerPix); setPixel(ptr, colour); } // void ogSurface::RawSetPixel() bool ogSurface::ogAlias(ogSurface& src, uint32_t x1, uInt32 y1, uInt32 x2, uInt32 y2) { uint32_t tmp; if (dataState == ogOwner) { ogSetLastError(ogAlreadyOwner); return false; } // if if (x2 < x1) { tmp= x2; x2 = x1; x1 = tmp; } // if if (y2 < y1) { tmp= y2; y2 = y1; y1 = tmp; } // if maxX = (x2-x1); maxY = (y2-y1); dataState = ogAliasing; bSize = 0; lSize = 0; owner = &src; buffer =(reinterpret_cast<uInt8*>(src.buffer)+x1*(src.bytesPerPix)); lineOfs=&src.lineOfs[y1]; attributes = src.attributes; pal = src.pal; xRes = src.xRes; yRes = src.yRes; BPP = src.BPP; bytesPerPix = src.bytesPerPix; pixFmtID = src.pixFmtID; // For 8bpp modes the next part doesn't matter redFieldPosition = src.redFieldPosition; greenFieldPosition = src.greenFieldPosition; blueFieldPosition = src.blueFieldPosition; alphaFieldPosition = src.alphaFieldPosition; // The next part is only used by 15/16bpp redShifter = src.redShifter; greenShifter = src.greenShifter; blueShifter = src.blueShifter; alphaShifter = src.alphaShifter; alphaMasker = src.alphaMasker; // Use the current pixel functions setPixel = src.setPixel; getPixel = src.getPixel; return true; } // bool ogSurface::ogAlias() void ogSurface::ogArc(int32 xCenter, int32 yCenter, uint32_t radius, uint32_t sAngle, uInt32 eAngle, uInt32 colour) { int32 p; uint32_t x, y, tmp; double alpha; if (radius == 0) { ogSetPixel(xCenter, yCenter, colour); return; } // if sAngle %= 361; eAngle %= 361; if (sAngle > eAngle) { tmp = sAngle; sAngle = eAngle; eAngle = tmp; } // if x = 0; y = radius; p = 3-2*radius; while (x <= y) { alpha = (180.0/3.14159265358979)*atan((double)x/(double)y); if ((alpha >= sAngle) && (alpha <= eAngle)) ogSetPixel(xCenter-x, yCenter-y, colour); if ((90-alpha >= sAngle) && (90-alpha <= eAngle)) ogSetPixel(xCenter-y, yCenter-x, colour); if ((90+alpha >= sAngle) && (90+alpha <= eAngle)) ogSetPixel(xCenter-y, yCenter+x, colour); if ((180-alpha >= sAngle) && (180-alpha <= eAngle)) ogSetPixel(xCenter-x, yCenter+y, colour); if ((180+alpha >= sAngle) && (180+alpha <= eAngle)) ogSetPixel(xCenter+x, yCenter+y, colour); if ((270-alpha >= sAngle) && (270-alpha <= eAngle)) ogSetPixel(xCenter+y, yCenter+x, colour); if ((270+alpha >= sAngle) && (270+alpha <= eAngle)) ogSetPixel(xCenter+y, yCenter-x, colour); if ((360-alpha >= sAngle) && (360-alpha <= eAngle)) ogSetPixel(xCenter+x, yCenter-y, colour); if (p < 0) p += 4*x+6; else { p += 4*(x-y)+10; --y; } // else ++x; } // while } // void ogSurface::ogArc() bool ogSurface::ogAvail() { return ((buffer != NULL) && (lineOfs != NULL)); } // bool ogSurface::ogAvail() void ogSurface::ogBSpline(uint32_t numPoints, ogPoint2d* points, uInt32 segments, uInt32 colour) { if (points == NULL) return; auto calculate = ([] (double mu, int32 p0, int32 p1, int32 p2, int32 p3) { double mu2, mu3; mu2 = mu*mu; mu3 = mu2*mu; return (int32)(0.5f+(1.0/6.0)*(mu3*(-p0+3.0*p1-3.0*p2+p3)+ mu2*(3.0*p0-6.0*p1+3.0*p2)+ mu*(-3.0*p0+3.0*p2)+(p0+4.0*p1+p2))); }); // calculate if ((numPoints < 4) || (numPoints > 255) || (segments == 0)) return; double mu, mudelta; int32 x1, y1, x2, y2; uint32_t n, h; mudelta = 1.0/segments; for (n=3; n<numPoints; n++) { mu = 0.0; x1=calculate(mu,points[n-3].x,points[n-2].x, points[n-1].x,points[n].x); y1=calculate(mu,points[n-3].y,points[n-2].y, points[n-1].y,points[n].y); mu += mudelta; for (h=0; h<segments; h++) { x2=calculate(mu,points[n-3].x,points[n-2].x, points[n-1].x,points[n].x); y2=calculate(mu,points[n-3].y,points[n-2].y, points[n-1].y,points[n].y); ogLine(x1, y1, x2, y2, colour); mu += mudelta; x1 = x2; y1 = y2; } // for h } // for n } // void ogSurface::ogBSpline() void ogSurface::ogCircle(int32 xCenter, int32 yCenter, uint32_t radius, uInt32 colour) { int32 x, y, d; x = 0; y = radius; d = 2*(1-radius); while (y >= 0) { ogSetPixel(xCenter+x, yCenter+y, colour); ogSetPixel(xCenter+x, yCenter-y, colour); ogSetPixel(xCenter-x, yCenter+y, colour); ogSetPixel(xCenter-x, yCenter-y, colour); if (d + y > 0) { --y; d -= 2*y+1; } // if if (x > d) { ++x; d += 2*x+1; } // if } // while } // void ogSurface::ogCircle() void ogSurface::ogClear(uint32_t colour) { if (!ogAvail()) return; if (ogIsBlending()) { uInt8 r, g, b, a; ogUnpack(colour, r, g, b, a); if (a == 0) return; if (a != 255) { for (uint32_t yy = 0; yy <= maxY; yy++) for (uint32_t xx = 0; xx <= maxX; xx++) RawSetPixel(xx, yy, r, g, b, a); return; } // if } // if blending for (uint32_t yy = 0; yy <= maxY; yy++) for (uint32_t xx = 0; xx <= maxX; xx++) RawSetPixel(xx, yy, colour); } // void ogSurface::ogClear() void ogSurface::ogClear() { ogClear(ogGetTransparentColor()); } // void ogSurface::ogClear() bool ogSurface::ogClone(ogSurface& src) { ogPixelFmt pixFmt; if (src.dataState == ogNone) { ogSetLastError(ogNoSurface); return false; } // if src.ogGetPixFmt(pixFmt); if (!ogCreate(src.maxX+1, src.maxY+1, pixFmt)) return false; *attributes = *src.attributes; ogCopyPalette(src); ogCopy(src); return true; } // bool ogSurface::ogClone() void ogSurface::ogCopy(ogSurface& src) { uint32_t pixMap[256]; uint32_t count, xCount, yCount; uint32_t xx, yy; uInt8 r, g, b, a; void * srcPtr; std::cout << "ogCopy" << std::endl; if (!ogAvail()) { std::cout << "ogAvail" << std::endl; return; } if (!src.ogAvail()) { std::cout << "src.ogAvail" << std::endl; return; } xCount = src.maxX+1; if (xCount > maxX+1) xCount = maxX+1; yCount = src.maxY+1; if (yCount > maxY+1) yCount = maxY+1; if (ogIsBlending()) { for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) { src.ogUnpack(src.RawGetPixel(xx, yy), r, g, b, a); RawSetPixel(xx, yy, r, g, b, a); } // for xx return; } // if blending if (pixFmtID != src.pixFmtID) { if (src.bytesPerPix == 1) { for (xx = 0; xx < 256; xx++) pixMap[xx] = ogPack(src.pal[xx].red, src.pal[xx].green, src.pal[xx].blue, src.pal[xx].alpha); for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) RawSetPixel(xx, yy, pixMap[src.RawGetPixel(xx, yy)]); } else { // if src.bytesPerPix == 1 ogPixelFmt srcPixFmt, dstPixFmt; src.ogGetPixFmt(srcPixFmt); ogGetPixFmt(dstPixFmt); ogPixCon pc(srcPixFmt, dstPixFmt); for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) RawSetPixel(xx, yy, pc.ConvPix(src.RawGetPixel(xx, yy))); } // else } else { xCount *= bytesPerPix; for (count = 0; count < yCount; count++) if ((srcPtr = src.ogGetPtr(0, count)) == NULL) { /* * if we are here then we couldn't get a direct memory pointer * from the source object. This means that it is not a normal * "memory" buffer and we have to use the implementation inspecific * interface. We let the source buffer fill a "temporary" buffer * and then we copy it to where it needs to go. */ #ifdef __UBIXOS_KERNEL__ srcPtr = kmalloc(xCount); // allocate space #else srcPtr = malloc(xCount); // allocate space #endif if (srcPtr != NULL) { src.ogCopyLineFrom(0, count, srcPtr, xCount); ogCopyLineTo(0, count, srcPtr, xCount); #ifdef __UBIXOS_KERNEL__ kfree(srcPtr); #else free(srcPtr); #endif } // if srcPtr!=NULL } else { ogCopyLineTo(0, count, srcPtr, xCount); } } // else } // void ogSurface::ogCopy() void ogSurface::ogCopyBuf(int32 dX1, int32 dY1, ogSurface& src, int32 sX1, int32 sY1, int32 sX2, int32 sY2) { uint32_t pixMap[256]; int32 xx, yy, count, xCount, yCount; uInt8 r, g, b, a; void *srcPtr; ogPixelFmt srcPixFmt, dstPixFmt; if (!ogAvail()) return; if (!src.ogAvail()) return; if ((dX1 > (int32)maxX) || (dY1 > (int32)maxY)) return; // if any of the source buffer is out of bounds then do nothing if (( (uint32_t)sX1 > src.maxX) || ((uInt32)sX2 > src.maxX) || ( (uint32_t)sY1 > src.maxY) || ((uInt32)sY2 > src.maxY)) return; if (sX1 > sX2) { int32 xSwap= sX1; sX1= sX2; sX2= xSwap; } // if if (sY1 > sY2) { int32 ySwap = sY1; sY1= sY2; sY2= ySwap; } // if xCount = abs(sX2-sX1)+1; yCount = abs(sY2-sY1)+1; if (dX1+xCount > (int32)maxX+1) xCount = maxX-dX1+1; if (dY1+yCount > (int32)maxY+1) yCount = maxY-dY1+1; if (dX1 < 0) { xCount += dX1; sX1 -= dX1; dX1 = 0; } // if if (dY1 < 0) { yCount += dY1; sY1 -= dY1; dY1 = 0; } // if if ((dX1+xCount < 0) || (dY1+yCount < 0)) return; if (ogIsBlending()) { for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) { src.ogUnpack(src.RawGetPixel(sX1+xx, sY1+yy), r, g, b, a); RawSetPixel(dX1+xx, dY1+yy, r, g, b, a); } // for xx return; } // if IsBlending if (pixFmtID != src.pixFmtID) { if (src.bytesPerPix == 1) { for (xx = 0; xx < 256; xx++) pixMap[xx] = ogPack(src.pal[xx].red, src.pal[xx].green, src.pal[xx].blue, src.pal[xx].alpha ); for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) RawSetPixel(dX1+xx,dY1+yy, pixMap[src.ogGetPixel(sX1+xx,sY1+yy)]); } else { src.ogGetPixFmt(srcPixFmt); ogGetPixFmt(dstPixFmt); ogPixCon pc(srcPixFmt, dstPixFmt); // allocate the pixel converter for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) RawSetPixel(dX1+xx, dY1+yy, pc.ConvPix(src.RawGetPixel(sX1+xx, sY1+yy))); } // else } else { xCount *= bytesPerPix; for (count = 0; count < yCount; count++) if ((srcPtr = src.ogGetPtr(sX1, sY1+count)) == NULL) { // if we are here then we couldn't get a direct memory pointer // from the source object. This means that it is not a normal // "memory" buffer and we have to use the implementation inspecific // interface. We let the source buffer fill a "temporary" buffer // and then we copy it to where it needs to go. #ifdef __UBIXOS_KERNEL__ srcPtr = kmalloc(xCount); // allocate space #else srcPtr = malloc(xCount); // allocate space #endif if (srcPtr != NULL) { src.ogCopyLineFrom(sX1, sY1+count, srcPtr, xCount); ogCopyLineTo(dX1, dY1+count, srcPtr, xCount); #ifdef __UBIXOS_KERNEL__ kfree(srcPtr); #else free(srcPtr); #endif } // if srcPtr!=NULL } else { ogCopyLineTo(dX1,dY1+count,srcPtr,xCount); } } // else } // void ogSurface::ogCopyBuf() void ogSurface::ogCopyLineTo(uint32_t dx, uInt32 dy, const void * src, uInt32 size) { /* * CopyLineTo() * * Inputs: * * dx - Destination X of the target buffer * dy - Destination Y of the target buffer * src - buffer to copy * size - size in bytes *NOT* pixels * * Copies a run of pixels (of the same format) to (x,y) of a buffer * * This method is required because of the different implementations of * copying a run of pixels to a buffer * * WARNING!!! This does *NO* error checking. It is assumed that you've * done all of that. CopyLineTo and CopyLineFrom are the only * methods that don't check to make sure you're hosing things. Don't * use this method unless YOU KNOW WHAT YOU'RE DOING!!!!!!!!! */ memcpy( buffer+lineOfs[dy]+dx*bytesPerPix, // dest src, // src size); // size } // ogSurface::ogCopyLineTo void ogSurface::ogCopyLineFrom(uint32_t sx, uInt32 sy, void * dst, uInt32 size) { /* * CopyLineFrom() * * Inputs: * * sx - Source X of the target buffer * sy - Source Y of the target buffer * dest - where to put it * size - size in bytes *NOT* pixels * * Copies a run of pixels (of the same format) to (x,y) of a buffer * * This method is required because of the different implementations of * copying a run of pixels to a buffer * * WARNING!!! This does *NO* error checking. It is assumed that you've * done all of that. CopyLineTo and CopyLineFrom are the only * methods that don't check to make sure you're hosing things. Don't * use this method unless YOU KNOW WHAT YOU'RE DOING!!!!!!!!! */ memcpy( dst, // dest (uInt8*)buffer+lineOfs[sy]+sx*bytesPerPix, // src size); // size return; } // ogSurface::ogCopyLineFrom void ogSurface::ogCopyPalette(ogSurface& src) { if (src.pal == NULL) return; if (pal == NULL) pal = new ogRGBA8[256]; if (pal == NULL) return; src.ogGetPalette(pal); // memcpy(pal, src.pal, sizeof(ogRGBA8)*256); return; } // void ogSurface::ogCopyPalette() bool ogSurface::ogCreate(uint32_t _xRes, uInt32 _yRes, ogPixelFmt _pixFormat) { /* * ogSurface::ogCreate() * Allocates memory for a buffer of size _xRes by _yRes with * the pixel format defined in _pixformat. Allocates memory * for pal and lineOfs. */ uInt8 * newBuffer = NULL; ptrdiff_t * newLineOfs = NULL; ogRGBA8 * newPal = NULL; ogAttribute * newAttributes = NULL; uint32_t newBSize; uint32_t newLSize; bool status = false; switch (_pixFormat.BPP) { case 8: getPixel = ([] (void * ptr) mutable -> uint32_t { return *(reinterpret_cast<uInt8*>(ptr)); }); setPixel = ([] (void * ptr, uint32_t colour) -> void { *(reinterpret_cast<uInt8*>(ptr)) = colour; }); break; case 15: case 16: getPixel = ([] (void * ptr) mutable -> uint32_t { return *(reinterpret_cast<uInt16*>(ptr)); }); setPixel = ([] (void * ptr, uint32_t colour) -> void { *(reinterpret_cast<uInt16*>(ptr)) = colour; }); break; case 24: getPixel = ([] (void * ptr) -> uint32_t { uint32_t colour = 0; uInt8* src = reinterpret_cast<uInt8*>(ptr); uInt8* dest = reinterpret_cast<uInt8*>(&colour); // This may break depending on endian-ness. TODO: Requires testing. *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; return colour; }); // getPixel() 24bpp lambda setPixel = ([] (void * ptr, uint32_t colour) -> void { uInt8* src = reinterpret_cast<uInt8*>(&colour); uInt8* dest = reinterpret_cast<uInt8*>(ptr); // This may break depending on endian-ness. TODO: Requires testing. *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; }); // setPixel() 24bpp lambda break; case 32: getPixel = ([] (void * ptr) -> uint32_t { return *(reinterpret_cast<uInt32*>(ptr)); }); setPixel = ([] (void * ptr, uint32_t colour) -> void { *(reinterpret_cast<uInt32*>(ptr)) = colour; }); break; default: ogSetLastError(ogBadBPP); return false; } // switch newBSize = _xRes * _yRes * ((_pixFormat.BPP + 7) >> 3); newLSize = _yRes * sizeof(uint32_t); // number of scan lines * sizeof(uInt32) #ifdef __UBIXOS_KERNEL__ newBuffer = kmalloc(newBSize); #else newBuffer = reinterpret_cast<uInt8 *>(malloc(newBSize)); #endif newLineOfs = new ptrdiff_t[_yRes]; newPal = new ogRGBA8[256]; newAttributes = new ogAttribute(); do { if ((newBuffer == NULL) || (newLineOfs == NULL) || (newPal == NULL) || (newAttributes == NULL)) { ogSetLastError(ogMemAllocFail); break; // break out of do {...} while(false) } // if // check to see if we have already allocated memory .. if so, free it if (dataState == ogOwner) { #ifdef __UBIXOS_KERNEL__ kfree(buffer); #else free((void *)buffer); #endif delete [] lineOfs; delete [] pal; delete attributes; } // if dataState buffer = newBuffer; lineOfs = newLineOfs; pal = newPal; attributes = newAttributes; bSize = newBSize; lSize = newLSize; newBuffer = NULL; newLineOfs = NULL; newPal = NULL; newAttributes = NULL; BPP = _pixFormat.BPP; bytesPerPix = (BPP + 7) >> 3; ogSetPalette(DEFAULT_PALETTE); // memcpy(pal, DEFAULT_PALETTE, sizeof(ogRGBA8)*256); maxX = _xRes -1; xRes = _xRes * bytesPerPix; maxY = _yRes -1; yRes = _yRes; // in the pascal version we go from 1 to maxY .. here we use yy < yRes // (which is the same) lineOfs[0] = 0; for (size_t yy = 1; yy < yRes; yy++) lineOfs[yy] = lineOfs[yy-1]+xRes; dataState = ogOwner; // For 8bpp modes the next part doesn't matter redFieldPosition = _pixFormat.redFieldPosition; greenFieldPosition = _pixFormat.greenFieldPosition; blueFieldPosition = _pixFormat.blueFieldPosition; alphaFieldPosition = _pixFormat.alphaFieldPosition; // The next part is only used by 15/16hpp redShifter = 8-_pixFormat.redMaskSize; greenShifter = 8-_pixFormat.greenMaskSize; blueShifter = 8-_pixFormat.blueMaskSize; alphaShifter = 8-_pixFormat.alphaMaskSize; if (_pixFormat.alphaMaskSize != 0) alphaMasker = ~(ogPixelFmt::OG_MASKS[_pixFormat.alphaMaskSize] << alphaFieldPosition); else alphaMasker = ~0; if (bytesPerPix == 1) { pixFmtID = 0x08080808; // turn anti aliasing off by default for 8bpp modes ogSetAntiAliasing(false); } else { pixFmtID = (redFieldPosition) | (greenFieldPosition << 8) | (blueFieldPosition << 16) | (alphaFieldPosition << 24); ogSetAntiAliasing(true); } // else ogClear(ogPack(0, 0, 0)); owner = this; status = true; } while(false); #ifdef __UBIXOS_KERNEL__ if (newBuffer) kfree(newBuffer); #else if (newBuffer) free(newBuffer); #endif if (newLineOfs) delete [] newLineOfs; if (newPal) delete [] newPal; if (newAttributes) delete newAttributes; return status; } // bool ogSurface::ogCreate() void ogSurface::ogCubicBezierCurve(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, int32 x4, int32 y4, uint32_t segments, uInt32 colour) { double tX1, tY1, tX2, tY2, tX3, tY3, mu, mu2, mu3, mudelta; int32 xStart, yStart, xEnd, yEnd; uint32_t n; if (segments < 1) return; if (segments > 128) segments=128; mudelta = 1.0/segments; mu = mudelta; tX1 =-x1+3*x2-3*x3+x4; tY1 =-y1+3*y2-3*y3+y4; tX2 =3*x1-6*x2+3*x3; tY2 =3*y1-6*y2+3*y3; tX3 =-3*x1+3*x2; tY3 =-3*y1+3*y2; xStart = x1; yStart = y1; for (n = 1; n < segments; n++) { mu2 = mu*mu; mu3 = mu2*mu; xEnd = static_cast<int32>(mu3*tX1+mu2*tX2+mu*tX3+x1 +0.5f); yEnd = static_cast<int32>(mu3*tY1+mu2*tY2+mu*tY3+y1 +0.5f); ogLine(xStart, yStart, xEnd, yEnd, colour); mu += mudelta; xStart = xEnd; yStart = yEnd; } // for } // void ogSurface::ogCubicBezierCurve() void ogSurface::ogCurve(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint32_t segments, uInt32 colour) { // This is currently broken. // ToDo: fix ogCurve int64 ex, ey, fx, fy; int64 t1, t2; if (segments<2) segments=2; else if (segments>128) segments=128; int64 s = segments; x2 = (x2*2)-((x1+x3)/2); y2 = (y2*2)-((y1+y3)/2); ex = (static_cast<int64>(x2-x1) << 17) / s; ey = (static_cast<int64>(y2-y1) << 17) / s; fx = (static_cast<int64>(x3-(2*x2)+x1) << 16) / (s*s); fy = (static_cast<int64>(y3-(2*y2)+y1) << 16) / (s*s); while (--s > 0) { t1 = x3; t2 = y3; x3 = (static_cast<int64>((fx*segments+ex)*segments) / 65536L)+x1; y3 = (static_cast<int64>((fy*segments+ey)*segments) / 65536L)+y1; ogLine(static_cast<int32>(t1), static_cast<int32>(t2), x3, y3, colour); } // while ogLine(x3, y3, x1, y1, colour); } // void ogSurface::ogCurve() void ogSurface::ogFillCircle(int32 xCenter, int32 yCenter, uint32_t radius, uInt32 colour) { int32 x, y, d; x = 0; y = radius; d = 4*(1-radius); while (y >= 0) { if (d + y > 0) { ogHLine(xCenter-x, xCenter+x, yCenter-y, colour); if (y != 0) ogHLine(xCenter-x, xCenter+x, yCenter+y, colour); --y; d -= 4*y+1; } // if if (x > d) { ++x; d += 4*x+1; } // if } // while } // void ogSurface::ogFillCircle() void ogSurface::ogFillGouraudPolygon(uint32_t numPoints, ogPoint2d* polyPoints, ogRGBA8 * colours) { ogEdgeTable * edges; int32 currentY = ~0; if (numPoints < 3) return; edges = new ogEdgeTable(); if (edges == NULL) return; // sanity check edges->BuildGET_G(numPoints, polyPoints, colours); if (edges->globalEdges != NULL) currentY = edges->globalEdges->startY; while ((edges->globalEdges != NULL) || (edges->activeEdges != NULL)) { edges->MoveXSortedToAET(currentY); edges->ScanOutAET_G(*this, currentY); edges->AdvanceAET(); edges->XSortAET(); ++currentY; if (currentY > (int32)maxY) break; // if we've gone past the bottom, stop } // while delete edges; } // void ogSurface::ogFillGouraudPolygon() void ogSurface::ogFillPolygon(uint32_t numPoints, ogPoint2d* polyPoints, uInt32 colour) { ogEdgeTable * edges; int32 currentY = ~0; if (numPoints < 3) return; if (!ogIsBlending()) ogPolygon(numPoints, polyPoints, colour); edges = new ogEdgeTable(); if (edges == NULL) return; // sanity check edges->BuildGET(numPoints, polyPoints); if (edges->globalEdges != NULL) currentY = edges->globalEdges->startY; while ((edges->globalEdges != NULL) || (edges->activeEdges != NULL)) { edges->MoveXSortedToAET(currentY); edges->ScanOutAET(*this, currentY, colour); edges->AdvanceAET(); edges->XSortAET(); ++currentY; if (currentY > (int32)maxY) break; // if we've gone past the bottom, stop } // while delete edges; } // void ogSurface::ogFillPolygon() void ogSurface::ogFillRect(int32 x1, int32 y1, int32 x2, int32 y2, uint32_t colour) { int32 yy, tmp; if (x2 < x1) { tmp= x2; x2 = x1; x1 = tmp; } // if if (y2 < y1) { tmp= y2; y2 = y1; y1 = tmp; } // if if ((y2 < 0) || (y1 > (int32)maxY)) return; if (y1 < 0) y1 = 0; if (y2 > (int32)maxY) y2 = maxY; for (yy = y1; yy <= y2; yy++) ogHLine(x1, x2, yy, colour); } // ogSurface::ogFillRect void ogSurface::ogFillTriangle(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint32_t colour) { ogPoint2d points[3]; points[0].x = x1; points[0].y = y1; points[1].x = x2; points[1].y = y2; points[2].x = x3; points[2].y = y3; ogFillPolygon(3, points, colour); } // void ogSurface::ogFillTriangle() uint32_t ogSurface::ogGetAlpha(void) { return (attributes != NULL ? attributes->defaultAlpha : 255L); } // uint32_t ogSurface::ogGetAlpha() uint32_t ogSurface::ogGetColorCount() { if (!ogAvail() || ogGetBytesPerPix() != 1) return 0; uint32_t colourCount = 0; uint32_t colourCounter[256] = {}; for (uint32_t y = 0; y <= ogGetMaxY(); y++) { for (uint32_t x = 0; x <= ogGetMaxX(); x++) { colourCounter[ogGetPixel(x, y)]++; } // for x } // for y for (size_t index = 0; index < std::extent<decltype(colourCounter)>::value; index++) { if (colourCounter[index] != 0) colourCount++; } // for index return colourCount; } // void ogSurface::ogCountColors() uint32_t ogSurface::ogGetPixel(int32 x, int32 y) { if (!ogAvail()) return ogGetTransparentColor(); if (((uint32_t)x > maxX) || ((uInt32)y > maxY)) return ogGetTransparentColor(); return RawGetPixel(x, y); } // uint32_t ogSurface::ogGetPixel() void ogSurface::ogGetPalette(ogRGBA8 _pal[256]) { if (pal == NULL) return; for (size_t index = 0; index <256; index++) { _pal[index].red = pal[index].red; _pal[index].green = pal[index].green; _pal[index].blue = pal[index].blue; _pal[index].alpha = pal[index].alpha; } // for index } // void ogSurface::ogGetPalette() void ogSurface::ogGetPixFmt(ogPixelFmt& pixfmt) { pixfmt.BPP = BPP; pixfmt.redFieldPosition = redFieldPosition; pixfmt.greenFieldPosition = greenFieldPosition; pixfmt.blueFieldPosition = blueFieldPosition; pixfmt.alphaFieldPosition = alphaFieldPosition; pixfmt.redMaskSize = 8-redShifter; pixfmt.greenMaskSize = 8-greenShifter; pixfmt.blueMaskSize = 8-blueShifter; pixfmt.alphaMaskSize = 8-alphaShifter; } // void ogSurface::ogGetPixFmt() void* ogSurface::ogGetPtr(uint32_t x, uInt32 y) { // return (Avail() ? ( (uInt8*)buffer+(lineOfs[y]+x*((BPP+7) >> 3)) ) : NULL ); return reinterpret_cast<uInt8*>(buffer+(lineOfs[y]+x*bytesPerPix)); } // void* ogSurface::ogGetPtr uint32_t ogSurface::ogGetTransparentColor(void) { return (attributes != NULL ? attributes->transparentColor : 0); } // ogSurface::ogGetTransparentColor void ogSurface::ogHFlip(void) { void * tmpBuf1; void * tmpBuf2; uint32_t xWidth, count; if (!ogAvail()) return; xWidth = (maxX+1)*bytesPerPix; #ifdef __UBIXOS_KERNEL__ tmpBuf1 = kmalloc(xWidth); tmpBuf2 = kmalloc(xWidth); #else tmpBuf1 = malloc(xWidth); tmpBuf2 = malloc(xWidth); #endif if ((tmpBuf1 != NULL) && (tmpBuf2 != NULL)) { for (count = 0; count <= (maxY/2); count++) { ogCopyLineFrom(0, count, tmpBuf1, xWidth); ogCopyLineFrom(0, maxY-count,tmpBuf2, xWidth); ogCopyLineTo(0, maxY-count,tmpBuf1, xWidth); ogCopyLineTo(0, count, tmpBuf2, xWidth); } // for count } #ifdef __UBIXOS_KERNEL__ kfree(tmpBuf2); kfree(tmpBuf1); #else free(tmpBuf2); free(tmpBuf1); #endif } // void ogSurface::ogHFlip() void ogSurface::ogHLine(int32 x1, int32 x2, int32 y, uint32_t colour) { int32 tmp; uInt8 r, g, b, a; if (!ogAvail()) return; if ((uint32_t)y > maxY) return; if (x1 > x2) { tmp= x1; x1 = x2; x2 = tmp; } // if if (x1 < 0) x1 = 0; if (x2 > (int32)maxX) x2 = maxX; if (x2 < x1) return; if (ogIsBlending()) { ogUnpack(colour, r, g, b, a); if (a == 0) return; if (a == 255) { for (tmp = x1; tmp <= x2; tmp++) RawSetPixel(tmp, y, r, g, b, a); return; } // if a == 255 } // if blending for (int32 xx = x1; xx <= x2; xx++) RawSetPixel(xx, y, colour); } // void ogSurface::ogHLine() bool ogSurface::ogIsAntiAliasing(void) { return (attributes != NULL ? attributes->antiAlias : false); } // bool ogSurface::ogIsAntiAliasing() bool ogSurface::ogIsBlending(void) { return (attributes != NULL ? attributes->blending : false); } // bool ogSurface::ogIsBlending() void ogSurface::ogLine(int32 x1, int32 y1, int32 x2, int32 y2, uint32_t colour) { if (ClipLine(x1,y1,x2,y2)) { if (ogIsAntiAliasing()) AARawLine(x1, y1, x2, y2, colour); else RawLine(x1, y1, x2, y2, colour); } // if clipLine return; } // void ogSurface::ogLine() bool ogSurface::ogLoadPalette(const char *palfile) { ogRGBA8 oldPalette[256]; #ifdef __UBIXOS_KERNEL__ fileDescriptor *f; This is possibly incompatible with the kernel. Will need a rewrite. #endif bool result; if (pal == NULL) { pal = new ogRGBA8[256]; if (pal == NULL) { ogSetLastError(ogMemAllocFail); return false; } // if ogSetPalette(DEFAULT_PALETTE); // memcpy(pal, DEFAULT_PALETTE, sizeof(ogRGBA8)*256); } // if ogGetPalette(oldPalette); // memcpy(&oldPalette, pal, sizeof(ogRGBA8)*256); std::ifstream file; file.open(palfile, std::ios::in | std::ios::binary); if (!file) { ogSetLastError(ogFileNotFound); return false; } // if !file size_t index = 0; while (index < sizeof(pal) / sizeof(pal[0])) { if (!(file >> pal[index].red)) break; if (!(file >> pal[index].green)) break; if (!(file >> pal[index].blue)) break; if (!(file >> pal[index].alpha)) break; index++; } //lresult = fread(pal, sizeof(ogRGBA8), 256, f); result = (index == 256); if (!result) { ogSetLastError(ogFileReadError); ogSetPalette(oldPalette); // memcpy(pal, &oldPalette, sizeof(ogRGBA8)*256); } // if file.close(); return result; } // bool ogSurface::ogLoadPalette() void ogSurface::ogOptimize() { if (!ogAvail() || ogGetBytesPerPix() != 1) return; int colourCounter[256] = {}; // count of how much that colour is used size_t swapIndices[256]; // swap indices size_t reverseIndices[256]; // reverse indices ogRGBA8 pal[256]; // We also swap the palette entries // First acquire a count of all the colours used for (uint32_t y = 0; y <= ogGetMaxY(); y++) { for (uint32_t x = 0; x <= ogGetMaxX(); x++) { colourCounter[ogGetPixel(x, y)]++; } // for x } // for y colourCounter[ogGetTransparentColor()] = INT_MAX; // set 0 so high it's always first //SortDescending(colourCounter, swapIndices, 256); // Sort them in descending order for (size_t i = 0; i < 256; i++) swapIndices[i] = i; for (size_t k = 1; k < 256; k++) { for (size_t i = 0; i <256 - k; i++) { if (colourCounter[swapIndices[i]] < colourCounter[swapIndices[i+1]]) { size_t temp = swapIndices[i]; swapIndices[i] = swapIndices[i+1]; swapIndices[i+1] = temp; } // if } // for i } // for k ogGetPalette(pal); for (size_t i = 0; i < 256; i++) { reverseIndices[swapIndices[i]] = i; //cout << "colourCounter[" << i << "] = " << swapIndices[i] << endl; // Also swap the palette entries ogSetPalette(i, pal[swapIndices[i]].red, pal[swapIndices[i]].green, pal[swapIndices[i]].blue); } // for i for (uint32_t y = 0; y <= ogGetMaxY(); y++) { for (uint32_t x = 0; x <= ogGetMaxX(); x++) { ogSetPixel(x, y, reverseIndices[ogGetPixel(x, y)]); } // for x } // for y } // void ogSurface::ogOptimize() uint32_t ogSurface::ogPack(uInt8 red, uInt8 green, uInt8 blue) { uint32_t colour = 0; switch (bytesPerPix) { case 4: colour = ( (red << redFieldPosition) | (green << greenFieldPosition) | (blue << blueFieldPosition) | (ogGetAlpha() << alphaFieldPosition) ); break; case 3: colour = ( (red << redFieldPosition) | (green << greenFieldPosition) | (blue << blueFieldPosition) ); break; case 2: colour = ((red >> redShifter) << redFieldPosition) | ((green >> greenShifter) << greenFieldPosition) | ((blue >> blueShifter) << blueFieldPosition) | ((ogGetAlpha() >> alphaShifter) << alphaFieldPosition); break; case 1: uint32_t dist = 255+255+255; for (uint32_t idx = 0; idx <= 255; idx++) { uint32_t rd = abs(red-pal[idx].red); uint32_t gd = abs(green-pal[idx].green); uint32_t bd = abs(blue-pal[idx].blue); uint32_t newdist = rd + gd + bd; if (newdist < dist) { dist = newdist; colour = idx; } // if } // for break; } // switch return colour; } // uint32_t ogSurface::ogPack() uint32_t ogSurface::ogPack(uInt8 red, uInt8 green, uInt8 blue, uInt8 alpha) { uint32_t colour = 0; switch (bytesPerPix) { case 4: colour = ( (red << redFieldPosition) | (green << greenFieldPosition) | (blue << blueFieldPosition) | (alpha << alphaFieldPosition) ); break; case 3: colour = ( (red << redFieldPosition) | (green << greenFieldPosition) | (blue << blueFieldPosition) ); break; case 2: colour = ((red >> redShifter) << redFieldPosition) | ((green >> greenShifter) << greenFieldPosition) | ((blue >> blueShifter) << blueFieldPosition) | ((alpha >> alphaShifter) << alphaFieldPosition); break; case 1: uint32_t dist = 255+255+255; for (uint32_t idx = 0; idx <= 255; idx++) { uint32_t rd = abs(red-pal[idx].red); uint32_t gd = abs(green-pal[idx].green); uint32_t bd = abs(blue-pal[idx].blue); uint32_t newdist = rd + gd + bd; if (newdist < dist) { dist = newdist; colour = idx; } // if } // for break; } // switch return colour; } // uint32_t ogSurface::ogPack() void ogSurface::ogPolygon(uint32_t numPoints, ogPoint2d* polyPoints, uInt32 colour) { if (polyPoints == NULL) return; if (numPoints == 1) { ogSetPixel(polyPoints[0].x, polyPoints[0].y, colour); } else { for (size_t count = 0; count < numPoints; count++) ogLine(polyPoints[count].x, polyPoints[count].y, polyPoints[(count+1) % numPoints].x, polyPoints[(count+1) % numPoints].y, colour); } } // void ogSurface::ogPolygon() void ogSurface::ogRect(int32 x1, int32 y1, int32 x2, int32 y2, uint32_t colour) { if ((x1 == x2) || (y1 == y2)) { if ((x1 == x2) && (y1 == y2)) ogSetPixel(x1, y1, colour); else ogLine(x1, y1, x2, y2, colour); } else { if (y1 > y2) { int32 tmp= y1; y1 = y2; y2 = tmp; } // if ogHLine(x1, x2, y1, colour); // Horizline has built in clipping ogVLine(x1, y1+1, y2-1, colour); // vertline has built in clipping too ogVLine(x2, y1+1, y2-1, colour); ogHLine(x1, x2, y2, colour); } // else } // void ogSurface::ogRect() void ogSurface::ogScale(ogSurface& src) { ogScaleBuf(0, 0, maxX, maxY, src, 0, 0, src.maxX, src.maxY); return; } // ogSurface::ogScale void ogSurface::ogScaleBuf(int32 dX1, int32 dY1, int32 dX2, int32 dY2, ogSurface& src, int32 sX1, int32 sY1, int32 sX2, int32 sY2) { uint32_t sWidth, dWidth; uint32_t sHeight, dHeight; int32 sx, sy, xx, yy; uint32_t xInc, yInc; uint32_t origdX1, origdY1; ogPixelFmt pixFmt; ogSurface * tmpBuf; ogSurface * sBuf; ogSurface * dBuf; bool doCopyBuf; origdX1 = origdY1 = 0; // to keep the compiler from generating a warning if (!ogAvail()) return; if (!src.ogAvail()) return; if (sX1 > sX2) { xx = sX1; sX1= sX2; sX2= xx; } if (sY1 > sY2) { yy = sY1; sY1= sY2; sY2= yy; } // if any part of the source falls outside the buffer then don't do anything if (((uint32_t)sX1 > src.maxX) || ((uInt32)sX2 > src.maxX) || ((uint32_t)sY1 > src.maxY) || ((uInt32)sY2 > src.maxY)) return; if (dX1 > dX2) { xx = dX1; dX1= dX1; dX2= xx; } if (dY1 > dY2) { yy = dY1; dY1= dY2; dY2= yy; } dWidth = (dX2-dX1)+1; if (dWidth <= 0) return; dHeight = (dY2-dY1)+1; if (dHeight <= 0) return; sWidth = (sX2-sX1)+1; sHeight = (sY2-sY1)+1; // convert into 16:16 fixed point ratio xInc = (sWidth << 16) / dWidth; yInc = (sHeight << 16) / dHeight; if (dX2 > (int32)maxX) { xx = (xInc*(dX1-maxX)) >> 16; sX1 -= xx; sWidth -= xx; dWidth -= (dX1-maxX); dX1 = maxX; } if (dY2 > (int32)maxY) { yy = (yInc*(dY2-maxY)) >> 16; sY2 -= yy; sHeight -= yy; dHeight -= (dY2-maxY); dY2 = maxY; } if (dX1 < 0) { xx = (xInc*(-dX1)) >> 16; sX1 += xx; sWidth -= xx; dWidth += dX1; dX1 = 0; } if (dY1 < 0) { yy = (yInc*(-dY1)) >> 16; sY1 += yy; sHeight -= yy; dHeight += dY1; dY1 = 0; } if ((dWidth <= 0) || (dHeight <= 0)) return; if ((sWidth <= 0) || (sHeight <= 0)) return; // Do a quick check to see if the scale is 1:1 .. in that case just copy // the image if ((dWidth == sWidth) && (dHeight == sHeight)) { ogCopyBuf(dX1, dY1, src, sX1, sY1, sX2, sY2); return; } tmpBuf = NULL; /* * Alright.. this is how we're going to optimize the case of different * pixel formats. We are going to use copyBuf() to automagically do * the conversion for us using tmpBuf. Here's how it works: * If the source buffer is smaller than the dest buffer (ie, we're making * something bigger) we will convert the source buffer first into the dest * buffer's pixel format. Then we do the scaling. * If the source buffer is larger than the dest buffer (ie, we're making * something smaller) we will scale first and then use copyBuf to do * the conversion. * This method puts the onus of conversion on the copyBuf() function which, * while not excessively fast, does the job. * The case in which the source and dest are the same size is handled above. * */ if (pixFmtID != src.pixFmtID) { tmpBuf = new ogSurface(); if (tmpBuf == NULL) return; if (sWidth*sHeight*src.bytesPerPix <= dWidth*dHeight*bytesPerPix) { // if the number of pixels in the source buffer is less than the // number of pixels in the dest buffer then... ogGetPixFmt(pixFmt); if (!tmpBuf->ogCreate(sWidth, sHeight, pixFmt)) return; tmpBuf->ogCopyPalette(src); tmpBuf->ogCopyBuf(0, 0, src, sX1, sY1, sX2, sY2); sX2 -= sX1; sY2 -= sY1; sX1 = 0; sY1 = 0; sBuf = tmpBuf; dBuf = this; doCopyBuf = false; // do we do a copyBuf later? } else { src.ogGetPixFmt(pixFmt); if (!tmpBuf->ogCreate(dWidth,dHeight,pixFmt)) return; tmpBuf->ogCopyPalette(*this); origdX1 = dX1; origdY1 = dY1; dX1 = 0; dY1 = 0; dX2 = tmpBuf->maxX; dY2 = tmpBuf->maxY; sBuf = &src; dBuf = tmpBuf; doCopyBuf = true; } // else } else { // pixel formats are identical sBuf = &src; dBuf = this; doCopyBuf = false; } // else sy = sY1 << 16; for (yy = dY1; yy <= dY2; yy++) { sx = 0; for (xx = dX1; xx <= dX2; xx++) { dBuf->RawSetPixel(xx, yy, sBuf->RawGetPixel(sX1+(sx >> 16),(sy>>16))); sx += xInc; } // for xx sy += yInc; } // for yy if ((doCopyBuf) && (tmpBuf != NULL)) ogCopyBuf(origdX1, origdY1, *tmpBuf, 0, 0, tmpBuf->maxX, tmpBuf->maxY); delete tmpBuf; } // void ogSurface::ogScaleBuf() uint32_t ogSurface::ogSetAlpha(uInt32 newAlpha) { if (attributes != NULL) { uint32_t tmp = attributes->defaultAlpha; attributes->defaultAlpha = newAlpha; return tmp; } else { return newAlpha; } } // ogSurface::ogSetAlpha bool ogSurface::ogSetAntiAliasing(bool antiAliasing) { if (attributes != NULL) { bool previousAA = attributes->antiAlias; attributes->antiAlias = antiAliasing; return previousAA; } else { return antiAliasing; // fail quietly } } // bool ogSurface::ogSetAntiAliasing() bool ogSurface::ogSetBlending(bool _blending) { bool tmp; if (attributes != NULL) { tmp = attributes->blending; attributes->blending = _blending; return tmp; } else return _blending; } // bool ogSurface::ogSetBlending() ogErrorCode ogSurface::ogSetLastError(ogErrorCode latestError) { ogErrorCode tmp = lastError; lastError = latestError; return tmp; } // ogErrorCode ogSurface::ogSetLastError() void ogSurface::ogSetPalette(const ogRGBA8 newPal[256]) { if (pal == NULL) return; for (size_t index = 0; index < 256; index++) { pal[index].red = newPal[index].red; pal[index].green = newPal[index].green; pal[index].blue = newPal[index].blue; pal[index].alpha = newPal[index].alpha; } // for index } // void ogSurface::ogSetPalette() void ogSurface::ogSetPalette(uInt8 colour, uInt8 red, uInt8 green, uInt8 blue, uInt8 alpha) { if (pal == NULL) return; pal[colour].red = red; pal[colour].green = green; pal[colour].blue = blue; pal[colour].alpha = alpha; } // void ogSurface::ogSetPalette() void ogSurface::ogSetPalette(uInt8 colour, uInt8 red, uInt8 green, uInt8 blue) { if (pal == NULL) return; pal[colour].red = red; pal[colour].green = green; pal[colour].blue = blue; pal[colour].alpha = ogGetAlpha(); } // void ogSurface::ogSetPalette() void ogSurface::ogSetPixel(int32 x, int32 y, uint32_t colour) { if (!ogAvail()) return; if (((uint32_t)x > maxX) || ((uInt32)y > maxY)) return; RawSetPixel(x, y, colour); } // void ogSurface::ogSetPixel() void ogSurface::ogSetPixel(int32 x, int32 y, uInt8 r, uInt8 g, uInt8 b, uInt8 a) { if (!ogAvail()) return; if (((uint32_t)x > maxX) || ((uInt32)y > maxY)) return; RawSetPixel(x, y, r, g, b, a); } // void ogSurface::ogSetPixel() uint32_t ogSurface::ogSetTransparentColor(uInt32 colour) { uint32_t preColour = 0; if (attributes != NULL) { preColour = attributes->transparentColor & ogGetAlphaMasker(); attributes->transparentColor = colour & ogGetAlphaMasker(); } // if return preColour; } // uint32_t ogSurface::ogSetTransparentColor() //static double f(double g) { return g*g*g-g; } void ogSurface::ogSpline(uint32_t numPoints, ogPoint2d* points, uInt32 segments, uint32_t colour) { int32 i, oldY, oldX, x, y, j; double part, t, xx, yy, tmp; double * zc; double * dx; double * dy; double * u; double * wndX1; double * wndY1; double * px; double * py; auto f = ([] (double g) -> double { return g*g*g*-g; }); bool runOnce; if ((numPoints < 2) || (points == NULL)) return; zc = new double[numPoints]; dx = new double[numPoints]; dy = new double[numPoints]; u = new double[numPoints]; wndX1 = new double[numPoints]; wndY1 = new double[numPoints]; px = new double[numPoints]; py = new double[numPoints]; do { if (zc == NULL) break; if (dx == NULL) break; if (dy == NULL) break; if (wndX1 == NULL) break; if (wndY1 == NULL) break; if (px == NULL) break; if (py == NULL) break; for (i = 0; (uint32_t)i < numPoints; i++) { zc[i] = dx[i] = dy[i] = u[i] = wndX1[i] = wndY1[i] = px[i] = py[i] = 0.0f; } runOnce = false; oldX = oldY = 0; x = points[0].x; y = points[0].y; for (i = 1; (uint32_t)i < numPoints; i++) { xx = points[i-1].x - points[i].x; yy = points[i-1].y - points[i].y; t = sqrt(xx*xx + yy*yy); zc[i] = zc[i-1]+t; } // for u[0] = zc[1] - zc[0] +1; for (i = 1; (uint32_t)i < numPoints-1; i++) { u[i] = zc[i+1]-zc[i]+1; tmp = 2*(zc[i+1]-zc[i-1]); dx[i] = tmp; dy[i] = tmp; wndY1[i] = 6.0f*((points[i+1].y-points[i].y)/u[i]- (points[i].y-points[i-1].y)/u[i-1]); wndX1[i] = 6.0f*((points[i+1].x-points[i].x)/u[i]- (points[i].x-points[i-1].x)/u[i-1]); } // for for (i = 1; (uint32_t)i < numPoints-2; i++) { wndY1[i+1] = wndY1[i+1]-wndY1[i]*u[i]/dy[i]; dy[i+1] = dy[i+1]-u[i]*u[i]/dy[i]; wndX1[i+1] = wndX1[i+1]-wndX1[i]*u[i]/dx[i]; dx[i+1] = dx[i+1]-u[i]*u[i]/dx[i]; } // for for (i = numPoints-2; i > 0; i--) { py[i] = (wndY1[i]-u[i]*py[i+1])/dy[i]; px[i] = (wndX1[i]-u[i]*px[i+1])/dx[i]; } // for for (i = 0; (uint32_t)i < numPoints-1; i++) { for (j = 0; (uint32_t)j <= segments; j++) { part = zc[i]-(((zc[i]-zc[i+1])/segments)*j); t = (part-zc[i])/u[i]; part = t * points[i+1].y + (1.0-t)*points[i].y + u[i] * u[i] * ( f(t) * py[i+1] + f(1.0-t) * py[i]) /6.0; // y = Round(part); y = static_cast<int32>(part+0.5f); part = zc[i]-(((zc[i]-zc[i+1])/segments)*j); t = (part-zc[i])/u[i]; part = t*points[i+1].x+(1.0-t)*points[i].x+u[i]*u[i]*(f(t)*px[i+1]+ f(1.0-t)*px[i])/6.0; // x = Round(part); x = static_cast<int32>(part+0.5f); if (runOnce) ogLine(oldX, oldY, x, y, colour); else runOnce = true; oldX = x; oldY = y; } // for j } // for i } while (false); delete [] py; delete [] px; delete [] wndY1; delete [] wndX1; delete [] u; delete [] dy; delete [] dx; delete [] zc; } // void ogSurface::ogSpline() void ogSurface::ogTriangle(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint32_t colour) { ogLine(x1, y1, x2, y2,colour); ogLine(x2, y2, x3, y3,colour); ogLine(x3, y3, x1, y1,colour); } // void ogSurface::ogTriangle() void ogSurface::ogUnpack(uint32_t colour, uInt8& red, uInt8& green, uInt8& blue) { switch (bytesPerPix) { case 4: case 3: red = colour >> redFieldPosition; green = colour >> greenFieldPosition; blue = colour >> blueFieldPosition; break; case 2: red = ((colour >> redFieldPosition) << redShifter); green = ((colour >> greenFieldPosition) << greenShifter); blue = ((colour >> blueFieldPosition) << blueShifter); if (red != 0) red += ogPixelFmt::OG_MASKS[redShifter]; if (green != 0) green += ogPixelFmt::OG_MASKS[greenShifter]; if (blue != 0) blue += ogPixelFmt::OG_MASKS[blueShifter]; break; case 1: if (pal == NULL) { red = green = blue = 0; return; } // if pal == null if (colour > 255) colour &= 255; red = pal[colour].red; green = pal[colour].green; blue = pal[colour].blue; break; default: red = 0; green = 0; blue = 0; } // switch } // void ogSurface::ogUnpack() void ogSurface::ogUnpack(uint32_t colour, uInt8& red, uInt8& green, uInt8& blue, uInt8& alpha) { switch (bytesPerPix) { case 4: red = colour >> redFieldPosition; green = colour >> greenFieldPosition; blue = colour >> blueFieldPosition; alpha = colour >> alphaFieldPosition; break; case 3: red = colour >> redFieldPosition; green = colour >> greenFieldPosition; blue = colour >> blueFieldPosition; alpha = ogGetAlpha(); break; case 2: red = ((colour >> redFieldPosition) << redShifter); green = ((colour >> greenFieldPosition) << greenShifter); blue = ((colour >> blueFieldPosition) << blueShifter); if (red != 0) red += ogPixelFmt::OG_MASKS[redShifter]; if (green != 0) green += ogPixelFmt::OG_MASKS[greenShifter]; if (blue != 0) blue += ogPixelFmt::OG_MASKS[blueShifter]; if (alphaShifter != 8) { alpha = (colour >> alphaFieldPosition) << alphaShifter; if (alpha != 0) alpha += ogPixelFmt::OG_MASKS[alphaShifter]; } else alpha = ogGetAlpha(); break; case 1: if (pal == NULL) { red = green = blue = alpha = 0; return; } // if pal == null if (colour > 255) colour &= 255; red = pal[colour].red; green = pal[colour].green; blue = pal[colour].blue; alpha = pal[colour].alpha; break; default: red = green = blue = alpha = 0; } // switch return; } // void ogSurface::ogUnpack() void ogSurface::ogVFlip() { if (!ogAvail()) return; for (uint32_t yy = 0; yy <= maxY; yy++) { for (uint32_t xx = 0; xx < maxX/2; xx++) { uint32_t swapColour = RawGetPixel(xx, yy); RawSetPixel(xx, yy, RawGetPixel(maxX-xx, yy)); RawSetPixel(maxX-xx, yy, swapColour); } // for xx } // for yy } // void ogSurface::ogVFlip() void ogSurface::ogVLine(int32 x, int32 y1, int32 y2, uint32_t colour) { int32 tmp; uInt8 r, g, b, a; if (!ogAvail()) return; if ((uint32_t)x > maxX) return; if (y1 > y2) { tmp= y1; y1 = y2; y2 = tmp; } // if if (y1 < 0) y1 = 0; if (y2 > (int32)maxY) y2 = maxY; if (y2 < y1) return; if (ogIsBlending()) { ogUnpack(colour, r, g, b, a); if (a == 0) return; if (a != 255) { for (tmp = y1; tmp <= y2; tmp++) RawSetPixel(x, tmp, r, g, b, a); return; } // if } // if blending for (int32 yy = y1; yy <= y2; yy++) { RawSetPixel(x, yy, colour); } } // void ogSurface::ogVLine() ogSurface::~ogSurface(void) { if (dataState == ogOwner) { delete [] pal; delete [] lineOfs; delete attributes; #ifdef __UBIXOS_KERNEL__ kfree(buffer); #else free(buffer); #endif } // if datastate == ogOwner pal = NULL; lineOfs= NULL; buffer = NULL; attributes = NULL; bSize = 0; lSize = 0; dataState = ogNone; return; } // ogSurface::~ogSurface