diff --git a/lib/objgfx/objgfx.cpp b/lib/objgfx/objgfx.cpp new file mode 100644 index 0000000..60eabd6 --- /dev/null +++ b/lib/objgfx/objgfx.cpp @@ -0,0 +1,3016 @@ +#include +#include +#include +#include +#include + +#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 p) -> void { }); + getPixel = ([] (void * ptr) -> uInt32 { return 0; }); +} // ogSurface::ogSurface() + + +void ogSurface::AARawLine(uInt32 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 erradj, erracc; + uInt32 erracctmp, intshift, wgt, wgtCompMask; + int32 dx, dy, tmp, xDir, i; + uInt8 r, g, b, a; + uInt32 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(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 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)tx1 > maxX) || ((uInt32)tx2 > maxX)) return false; + + x1 = tx1; + y1 = ty1; + x2 = tx2; + y2 = ty2; + + return true; +} // bool ogSurface::ClipLine() + +uInt32 ogSurface::RawGetPixel(uInt32 x, uInt32 y) +{ + //uInt8* ptr = (uInt8*)buffer + lineOfs[y]; // Pointer to pixel at (0,y). + void * ptr = reinterpret_cast(buffer + lineOfs[y] + x*bytesPerPix); + return getPixel(ptr); +#if 0 + uInt32 result = 0; + uInt32 * buf32; + uInt8 * buf24; + uInt16 * buf16; + uInt8 * buf8; + + switch (bytesPerPix) { + case 4: + buf32 = reinterpret_cast(buffer + lineOfs[y] + x*4); + result = *buf32; + //uInt32 * + // uInt32 * buf = static_cast(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(buffer + lineOfs[y] + x*2); + result = *buf16; + break; + case 1: + buf8 = (buffer + lineOfs[y] + x); + result = *buf8; + break; + } // switch + return result; +#endif +} // uInt32 ogSurface::RawGetPixel() + +// wu's double step line algorithm blatently borrowed from: +// http://www.edepot.com/linewu.html + +void ogSurface::RawLine(uInt32 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 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 inverseA = 255 - sA; + ogUnpack(RawGetPixel(x, y), dR, dG, dB); + uInt32 newR = (dR * inverseA + sR * sA) >> 8; + uInt32 newG = (dG * inverseA + sG * sA) >> 8; + uInt32 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(buffer + lineOfs[y] + x*bytesPerPix); + setPixel(ptr, colour); +#if 0 + //ptr = static_cast(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 x, uInt32 y, uInt8 r, uInt8 g, uInt8 b, uInt8 a) +{ + uInt32 newR, newG, newB, inverseA; + uInt8 dR, dG, dB; + uInt32 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(buffer + lineOfs[y] + x*bytesPerPix); + setPixel(ptr, colour); + +} // void ogSurface::RawSetPixel() + + +bool ogSurface::ogAlias(ogSurface& src, uInt32 x1, uInt32 y1, uInt32 x2, uInt32 y2) +{ + uInt32 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(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 radius, + uInt32 sAngle, uInt32 eAngle, uInt32 colour) +{ + int32 p; + uInt32 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 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 n, h; + mudelta = 1.0/segments; + for (n=3; n= 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 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 yy = 0; yy <= maxY; yy++) + for (uInt32 xx = 0; xx <= maxX; xx++) + RawSetPixel(xx, yy, r, g, b, a); + return; + } // if + } // if blending + + for (uInt32 yy = 0; yy <= maxY; yy++) + for (uInt32 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 pixMap[256]; + uInt32 count, xCount, yCount; + uInt32 xx, yy; + uInt8 r, g, b, a; + void * srcPtr; + + if (!ogAvail()) return; + if (!src.ogAvail()) 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 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)sX1 > src.maxX) || ((uInt32)sX2 > src.maxX) || + ( (uInt32)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 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 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 _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 newBSize; + uInt32 newLSize; + + bool status = false; + + switch (_pixFormat.BPP) { + case 8: + getPixel = ([] (void * ptr) mutable -> uInt32 { return *(reinterpret_cast(ptr)); }); + setPixel = ([] (void * ptr, uInt32 colour) -> void { *(reinterpret_cast(ptr)) = colour; }); + break; + case 15: + case 16: + getPixel = ([] (void * ptr) mutable -> uInt32 { return *(reinterpret_cast(ptr)); }); + setPixel = ([] (void * ptr, uInt32 colour) -> void { *(reinterpret_cast(ptr)) = colour; }); + break; + case 24: + getPixel = ([] (void * ptr) -> uInt32 { + uInt32 colour = 0; + uInt8* src = reinterpret_cast(ptr); + uInt8* dest = reinterpret_cast(&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 colour) -> void { + uInt8* src = reinterpret_cast(&colour); + uInt8* dest = reinterpret_cast(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 { return *(reinterpret_cast(ptr)); }); + setPixel = ([] (void * ptr, uInt32 colour) -> void { *(reinterpret_cast(ptr)) = colour; }); + break; + default: + ogSetLastError(ogBadBPP); + return false; + } // switch + + newBSize = _xRes * _yRes * ((_pixFormat.BPP + 7) >> 3); + newLSize = _yRes * sizeof(uInt32); // number of scan lines * sizeof(uInt32) + +#ifdef __UBIXOS_KERNEL__ + newBuffer = kmalloc(newBSize); +#else + newBuffer = reinterpret_cast(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 segments, uInt32 colour) +{ + double tX1, tY1, tX2, tY2, tX3, tY3, mu, mu2, mu3, mudelta; + int32 xStart, yStart, xEnd, yEnd; + uInt32 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(mu3*tX1+mu2*tX2+mu*tX3+x1 +0.5f); + yEnd = static_cast(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 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(x2-x1) << 17) / s; + ey = (static_cast(y2-y1) << 17) / s; + fx = (static_cast(x3-(2*x2)+x1) << 16) / (s*s); + fy = (static_cast(y3-(2*y2)+y1) << 16) / (s*s); + + while (--s > 0) + { + t1 = x3; + t2 = y3; + x3 = (static_cast((fx*segments+ex)*segments) / 65536L)+x1; + y3 = (static_cast((fy*segments+ey)*segments) / 65536L)+y1; + ogLine(static_cast(t1), static_cast(t2), x3, y3, colour); + } // while + + ogLine(x3, y3, x1, y1, colour); + +} // void ogSurface::ogCurve() + + +void ogSurface::ogFillCircle(int32 xCenter, int32 yCenter, uInt32 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 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 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 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 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 ogSurface::ogGetAlpha(void) +{ + return (attributes != NULL ? attributes->defaultAlpha : 255L); +} // uInt32 ogSurface::ogGetAlpha() + +uInt32 ogSurface::ogGetColorCount() +{ + if (!ogAvail() || ogGetBytesPerPix() != 1) return 0; + + uInt32 colourCount = 0; + uInt32 colourCounter[256] = {}; + for (uInt32 y = 0; y <= ogGetMaxY(); y++) + { + for (uInt32 x = 0; x <= ogGetMaxX(); x++) + { + colourCounter[ogGetPixel(x, y)]++; + } // for x + } // for y + + for (size_t index = 0; index < std::extent::value; index++) + { + if (colourCounter[index] != 0) colourCount++; + } // for index + + return colourCount; +} // void ogSurface::ogCountColors() + +uInt32 ogSurface::ogGetPixel(int32 x, int32 y) +{ + if (!ogAvail()) return ogGetTransparentColor(); + + if (((uInt32)x > maxX) || ((uInt32)y > maxY)) return ogGetTransparentColor(); + + return RawGetPixel(x, y); +} // uInt32 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 x, uInt32 y) +{ + // return (Avail() ? ( (uInt8*)buffer+(lineOfs[y]+x*((BPP+7) >> 3)) ) : NULL ); + return reinterpret_cast(buffer+(lineOfs[y]+x*bytesPerPix)); +} // void* ogSurface::ogGetPtr + +uInt32 ogSurface::ogGetTransparentColor(void) +{ + return (attributes != NULL ? attributes->transparentColor : 0); +} // ogSurface::ogGetTransparentColor + +void ogSurface::ogHFlip(void) +{ + void * tmpBuf1; + void * tmpBuf2; + uInt32 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 colour) +{ + int32 tmp; + uInt8 r, g, b, a; + + if (!ogAvail()) return; + if ((uInt32)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 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 y = 0; y <= ogGetMaxY(); y++) + { + for (uInt32 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 y = 0; y <= ogGetMaxY(); y++) + { + for (uInt32 x = 0; x <= ogGetMaxX(); x++) + { + ogSetPixel(x, y, reverseIndices[ogGetPixel(x, y)]); + } // for x + } // for y +} // void ogSurface::ogOptimize() + +uInt32 ogSurface::ogPack(uInt8 red, uInt8 green, uInt8 blue) +{ + uInt32 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 dist = 255+255+255; + for (uInt32 idx = 0; idx <= 255; idx++) + { + uInt32 rd = abs(red-pal[idx].red); + uInt32 gd = abs(green-pal[idx].green); + uInt32 bd = abs(blue-pal[idx].blue); + uInt32 newdist = rd + gd + bd; + + if (newdist < dist) + { + dist = newdist; + colour = idx; + } // if + } // for + break; + } // switch + + return colour; + +} // uInt32 ogSurface::ogPack() + +uInt32 ogSurface::ogPack(uInt8 red, uInt8 green, uInt8 blue, uInt8 alpha) +{ + uInt32 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 dist = 255+255+255; + for (uInt32 idx = 0; idx <= 255; idx++) + { + uInt32 rd = abs(red-pal[idx].red); + uInt32 gd = abs(green-pal[idx].green); + uInt32 bd = abs(blue-pal[idx].blue); + uInt32 newdist = rd + gd + bd; + + if (newdist < dist) + { + dist = newdist; + colour = idx; + } // if + } // for + break; + } // switch + + return colour; +} // uInt32 ogSurface::ogPack() + +void ogSurface::ogPolygon(uInt32 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 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 sWidth, dWidth; + uInt32 sHeight, dHeight; + int32 sx, sy, xx, yy; + uInt32 xInc, yInc; + uInt32 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)sX1 > src.maxX) || ((uInt32)sX2 > src.maxX) || + ((uInt32)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 ogSurface::ogSetAlpha(uInt32 newAlpha) +{ + if (attributes != NULL) + { + uInt32 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 colour) +{ + if (!ogAvail()) return; + + if (((uInt32)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)x > maxX) || ((uInt32)y > maxY)) return; + + RawSetPixel(x, y, r, g, b, a); +} // void ogSurface::ogSetPixel() + +uInt32 ogSurface::ogSetTransparentColor(uInt32 colour) +{ + uInt32 preColour = 0; + + if (attributes != NULL) + { + preColour = attributes->transparentColor & ogGetAlphaMasker(); + attributes->transparentColor = colour & ogGetAlphaMasker(); + } // if + + return preColour; +} // uInt32 ogSurface::ogSetTransparentColor() + +//static double f(double g) { return g*g*g-g; } + +void ogSurface::ogSpline(uInt32 numPoints, ogPoint2d* points, uInt32 segments, + uInt32 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)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)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)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)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)i < numPoints-1; i++) + { + for (j = 0; (uInt32)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(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(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 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 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 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 yy = 0; yy <= maxY; yy++) + { + for (uInt32 xx = 0; xx < maxX/2; xx++) + { + uInt32 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 colour) +{ + int32 tmp; + uInt8 r, g, b, a; + + if (!ogAvail()) return; + if ((uInt32)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 \ No newline at end of file diff --git a/lib/objgfx/objgfx/objgfx.h b/lib/objgfx/objgfx/objgfx.h new file mode 100644 index 0000000..5e210ea --- /dev/null +++ b/lib/objgfx/objgfx/objgfx.h @@ -0,0 +1,129 @@ +#pragma once + +#include +#include + +#include "ogTypes.h" +#include "ogPixelFmt.h" + +class ogSurface +{ +private: + const static double INTENSITIES[32]; + +protected: + + double version; + uInt8 * buffer; + ogSurface * owner; + ptrdiff_t * lineOfs; + ogRGBA8 * pal; + ogAttribute* attributes; + + uInt32 xRes, yRes; + uInt32 maxX, maxY; + uInt32 bSize; // buffer size (in bytes) + uInt32 lSize; // LineOfs size (in bytes) + + uInt32 BPP; // bits per pixel + uInt32 bytesPerPix; + uInt32 pixFmtID; + + uInt32 redFieldPosition; + uInt32 greenFieldPosition; + uInt32 blueFieldPosition; + uInt32 alphaFieldPosition; + + uInt32 redShifter; + uInt32 greenShifter; + uInt32 blueShifter; + uInt32 alphaShifter; + uInt32 alphaMasker; + + ogErrorCode lastError; + ogDataState dataState; + + std::function getPixel; + std::function setPixel; + + void AARawLine(uInt32, uInt32, uInt32, uInt32, uInt32); + bool ClipLine(int32&, int32&, int32&, int32&); + virtual uInt32 RawGetPixel(uInt32, uInt32); + void RawLine(uInt32, uInt32, uInt32, uInt32, uInt32); + virtual void RawSetPixel(uInt32, uInt32, uInt32); + virtual void RawSetPixel(uInt32, uInt32, uInt8, uInt8, uInt8, uInt8); + +public: + + ogSurface(void); + virtual bool ogAlias(ogSurface&, uInt32, uInt32, uInt32, uInt32); + virtual bool ogAvail(void); + void ogArc(int32, int32, uInt32, uInt32, uInt32, uInt32); + void ogBSpline(uInt32, ogPoint2d*, uInt32, uInt32); + void ogCircle(int32, int32, uInt32, uInt32); + virtual void ogClear(uInt32); + void ogClear(); + virtual bool ogClone(ogSurface&); + void ogCopy(ogSurface&); + void ogCopyBuf(int32 destX, int32 destY, ogSurface&, + int32 sourceX1, int32 sourceY1, int32 sourceX2, int32 sourceY2); + virtual void ogCopyLineTo(uInt32, uInt32, const void *, uInt32); + virtual void ogCopyLineFrom(uInt32, uInt32, void *, uInt32); + virtual void ogCopyPalette(ogSurface&); + virtual bool ogCreate(uInt32 _xRes, uInt32 _yRes, struct ogPixelFmt _pixFormat); + void ogCubicBezierCurve(int32, int32, int32, int32, + int32, int32, int32, int32, uInt32, uInt32); + void ogCurve(int32,int32, int32,int32, int32,int32, uInt32, uInt32); + void ogFillCircle(int32, int32, uInt32, uInt32); + void ogFillGouraudPolygon(uInt32, ogPoint2d*, ogRGBA8 *); + void ogFillPolygon(uInt32, ogPoint2d*, uInt32); + void ogFillRect(int32, int32, int32, int32, uInt32); + void ogFillTriangle(int32, int32, int32, int32, int32, int32, uInt32); + uInt32 ogGetAlpha(void); + uInt32 ogGetAlphaMasker(void) const { return alphaMasker; } + uInt32 ogGetBPP(void) const { return BPP; } + uInt32 ogGetColorCount(); // should probably be bigger + uInt32 ogGetBytesPerPix(void) const { return bytesPerPix; } + ogDataState ogGetDataState(void) const { return dataState; } + ogErrorCode ogGetLastError(void); + uInt32 ogGetMaxX(void) const { return maxX; } + uInt32 ogGetMaxY(void) const { return maxY; } + void ogGetPalette(ogRGBA8[]); + void ogGetPixFmt(ogPixelFmt&); + uInt32 ogGetPixFmtID(void) const { return pixFmtID; } + virtual uInt32 ogGetPixel(int32, int32); + virtual void * ogGetPtr(uInt32, uInt32); + uInt32 ogGetTransparentColor(void); + void ogHFlip(void); + virtual void ogHLine(int32 x1, int32 x2, int32 y, uInt32 colour); + bool ogIsAntiAliasing(void); + bool ogIsBlending(void); + void ogLine(int32, int32, int32, int32, uInt32); + virtual bool ogLoadPalette(const char *); + void ogOptimize(); + void ogPolygon(uInt32, ogPoint2d*, uInt32); + uInt32 ogPack(uInt8, uInt8, uInt8); + uInt32 ogPack(uInt8, uInt8, uInt8, uInt8); + void ogRect(int32, int32, int32, int32, uInt32); + bool ogSavePalette(const char *); + void ogScale(ogSurface&); + void ogScaleBuf(int32, int32, int32, int32, ogSurface&, int32, int32, int32, int32); + uInt32 ogSetAlpha(uInt32); + bool ogSetAntiAliasing(bool); + bool ogSetBlending(bool); + virtual ogErrorCode ogSetLastError(ogErrorCode); + virtual void ogSetPixel(int32, int32, uInt32); + virtual void ogSetPixel(int32, int32, uInt8, uInt8, uInt8, uInt8); + virtual void ogSetPalette(const ogRGBA8[]); + virtual void ogSetPalette(uInt8, uInt8, uInt8, uInt8, uInt8); + virtual void ogSetPalette(uInt8, uInt8, uInt8, uInt8); + uInt32 ogSetTransparentColor(uInt32); + void ogSpline(uInt32, ogPoint2d*, uInt32, uInt32); + void ogTriangle(int32, int32, int32, int32, int32, int32, uInt32); + void ogUnpack(uInt32, uInt8&, uInt8&, uInt8&); + void ogUnpack(uInt32, uInt8&, uInt8&, uInt8&, uInt8&); + virtual void ogVFlip(void); + virtual void ogVLine(int32 x, int32 y1, int32 y2, uInt32 colour); + virtual ~ogSurface(void); +}; // class ogSurface + diff --git a/lib/objgfx/objgfx/ogEdgeTable.h b/lib/objgfx/objgfx/ogEdgeTable.h new file mode 100644 index 0000000..38ee84f --- /dev/null +++ b/lib/objgfx/objgfx/ogEdgeTable.h @@ -0,0 +1,45 @@ +#ifndef OGEDGETABLE_H +#define OGEDGETABLE_H + +#include "ogTypes.h" +#include "objgfx.h" + +struct ogEdgeState +{ + ogEdgeState* nextEdge; + int32 x; + int32 startY; + int32 wholePixelXMove; + int32 xDirection; + int32 errorTerm; + int32 errorTermAdjUp; + int32 errorTermAdjDown; + int32 count; + ogRGBA8 colour; + int32 rStepY; + int32 gStepY; + int32 bStepY; + int32 aStepY; + int32 rIncY; + int32 gIncY; + int32 bIncY; + int32 aIncY; +}; + +class ogEdgeTable +{ +public: + ogEdgeState * globalEdges; + ogEdgeState * activeEdges; + ogEdgeTable(void) { globalEdges = activeEdges = nullptr; return; } + void AdvanceAET(void); + void BuildGET(uInt32 numPoints, ogPoint2d * polyPoints); + void BuildGET_G(uInt32 numPoints, ogPoint2d * polyPoints, ogRGBA8 * colours); + void MoveXSortedToAET(int32 yToMove); + void ScanOutAET(ogSurface & destObject, int32 yToScan, uInt32 colour); + void ScanOutAET_G(ogSurface & destObject, int32 yToScan); + void XSortAET(void); + ~ogEdgeTable(void); +}; // ogEdgeTable + +#endif \ No newline at end of file diff --git a/lib/objgfx/objgfx/ogImage.h b/lib/objgfx/objgfx/ogImage.h new file mode 100644 index 0000000..544b949 --- /dev/null +++ b/lib/objgfx/objgfx/ogImage.h @@ -0,0 +1,145 @@ +// ogImage.h + +#pragma once + +#include +#include +#include +#include + +#include "objgfx.h" +using namespace std; + +class mstream : public std::basic_streambuf +{ +public: + mstream(char* p, std::streamsize n) { + setg(p, p, p + n); + setp(p, p + n); + } // mStream::mStream() +}; // class mstream + +class ogHeaderAbstract +{ +public: + virtual bool Deserialize(std::istream&) = 0; + virtual bool Serialize(std::ostream&) = 0; + virtual bool IsMatch() { return false; } + virtual std::string ToString() { return ""; } + virtual size_t Size() = 0; + virtual ~ogHeaderAbstract() {}; +}; // class ogHeader + +class Win3xBitmapHeader : public ogHeaderAbstract +{ +public: + uInt16 ImageFileType; // Image file type, always 4D42h ("BM") + uInt32 FileSize; // Physical size in bytes + uInt16 Reserved1; // Always 0 + uInt16 Reserved2; // Always 0 + uInt32 ImageDataOffset; // Start of image data offset in bytes + Win3xBitmapHeader() : + ImageFileType(0), + FileSize(0), + Reserved1(0), + Reserved2(0), + ImageDataOffset(0) {} + bool Deserialize(std::istream&); + std::string ToString(); + + bool IsMatch(); + bool Serialize(std::ostream&); + size_t Size(); +}; // class Win3xBitmapHeader + +class RGBQuad : public ogHeaderAbstract +{ +public: + uInt8 rgbBlue; + uInt8 rgbGreen; + uInt8 rgbRed; + uInt8 rgbReserved; + RGBQuad() : + rgbBlue(0), + rgbGreen(0), + rgbRed(0), + rgbReserved(0) {}; + RGBQuad(ogRGBA8 paletteEntry) : + rgbBlue(paletteEntry.blue), + rgbGreen(paletteEntry.green), + rgbRed(paletteEntry.red), + rgbReserved(0) {}; + bool Deserialize(std::istream&); + bool Serialize(std::ostream&); + size_t Size(); + std::string ToString(); +}; // class RGBQuad + +class Win3xBitmapInfoHeader : public ogHeaderAbstract +{ +public: + uInt32 HeaderSize; // Size of this header + uInt32 ImageWidth; // Image width in pixels + uInt32 ImageHeight; // Image height in pixels + uInt16 NumberOfImagePlanes; // Number of planes (always 1) + uInt16 BitsPerPixel; // Bits per pixel (1, 4, 8, or 24) + uInt32 CompressionMethod; // Compression method used (0, 1, or 2) + uInt32 SizeOfBitmap; // Size of the bitmap in bytes + uInt32 HorzResolution; // Horizontal resolution in pixels per meter + uInt32 VertResolution; // Vertical resolution in pixels per meter + uInt32 NumColoursUsed; // Number of colours in the image + uInt32 NumSignificantColours; // Number of important colours in palette + Win3xBitmapInfoHeader() : + HeaderSize(0), + ImageWidth(0), + ImageHeight(0), + NumberOfImagePlanes(0), + BitsPerPixel(0), + CompressionMethod(0), + SizeOfBitmap(0), + HorzResolution(0), + VertResolution(0), + NumColoursUsed(0), + NumSignificantColours(0) { }; + bool Deserialize(std::istream&); + std::string ToString(); + bool IsMatch(); + bool Serialize(std::ostream&); + size_t Size(); +}; // class Win3xBitmapInfoHeader + +union ogImageOptions +{ +}; + +enum ogImageType { NoImage, BMP }; + +class ogImage +{ +private: + static std::map > IsImage; +protected: + ogSurface * surface; + ogImageOptions * options; + std::ostream * output; + std::istream * input; + + std::map Decode; + std::map Encode; + + bool NoOp() { return false; } + + bool DecodeBMP(); + + bool EncodeBMP(); + +public: + static ogImageType ImageType(std::istream&); + static ogImageType ImageType(const std::string& filename); + ogImage(); + bool Load(const std::string& filename, ogSurface & surface); + bool Load(std::istream&, ogSurface&); + bool Save(const std::string& filename, ogSurface& surface, ogImageType, ogImageOptions * options = NULL); + bool Save(std::ostream&, ogSurface&, ogImageType, ogImageOptions * options = NULL); +}; // class ogImage + diff --git a/lib/objgfx/objgfx/ogPixCon.h b/lib/objgfx/objgfx/ogPixCon.h new file mode 100644 index 0000000..be2a3f2 --- /dev/null +++ b/lib/objgfx/objgfx/ogPixCon.h @@ -0,0 +1,15 @@ +#pragma once + +#include "objgfx.h" +#include "ogTypes.h" + +class ogPixCon { + protected: + uInt32 srcMasker; + uInt32 srcShifter; + uInt32 dstShifter; + public: + ogPixCon(ogPixelFmt, ogPixelFmt); + uInt32 ConvPix(uInt32); +}; // ogPixCon + diff --git a/lib/objgfx/objgfx/ogPixelFmt.h b/lib/objgfx/objgfx/ogPixelFmt.h new file mode 100644 index 0000000..c4f9553 --- /dev/null +++ b/lib/objgfx/objgfx/ogPixelFmt.h @@ -0,0 +1,31 @@ +#pragma once + +#include "ogTypes.h" +#include "objgfx.h" + +struct ogPixelFmt { + const static uInt32 OG_MASKS[32]; + uInt8 BPP; + uInt8 redFieldPosition; + uInt8 greenFieldPosition; + uInt8 blueFieldPosition; + uInt8 alphaFieldPosition; + uInt8 redMaskSize; + uInt8 greenMaskSize; + uInt8 blueMaskSize; + uInt8 alphaMaskSize; + uInt8 reserved[7]; + ogPixelFmt(void); + ogPixelFmt(uInt8, uInt8, uInt8, uInt8, uInt8, + uInt8, uInt8, uInt8, uInt8); + //virtual ~ogPixelFmt(void) {} +}; // struct ogPixelFmt + +extern ogPixelFmt const OG_NULL_PIXFMT; +extern ogPixelFmt const OG_PIXFMT_8BPP; +extern ogPixelFmt const OG_PIXFMT_15BPP; +extern ogPixelFmt const OG_PIXFMT_16BPP; +extern ogPixelFmt const OG_PIXFMT_24BPP; +extern ogPixelFmt const OG_PIXFMT_32BPP; +extern ogPixelFmt const OG_MAC_PIXFMT_16BPP; + diff --git a/lib/objgfx/objgfx/ogTypes.h b/lib/objgfx/objgfx/ogTypes.h new file mode 100644 index 0000000..9364866 --- /dev/null +++ b/lib/objgfx/objgfx/ogTypes.h @@ -0,0 +1,120 @@ +// Object Graphics +// Mark Iuzzolino +// mark.iuzzolino@gmail.com +// ogTypes.h + +#pragma once + +#include + +#define ogVERSION 1.0 + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef uint8_t uInt8; +typedef uint16_t uInt16; +typedef uint32_t uInt32; +typedef uint64_t uInt64; + +enum ogDataState { ogNone, ogOwner, ogAliasing }; + +enum ogErrorCode +{ + ogOK, + ogMemAllocFail, + ogAlreadyOwner, + ogNoSurface, + ogNoPalette, + ogBadBPP, + ogSourceOutOfBounds, + ogDestOutOfBounds, + ogFileNotFound, + ogFileReadError, + ogFileWriteError, + ogNoCloning, + ogNoAliasing, + ogNoModeSupport +}; // enum ogErrorCode + +//static std::map ogErrorCodes = SetupErrorCodes(); + +struct ogRGB8 +{ + uInt8 red; + uInt8 green; + uInt8 blue; +}; + +struct ogRGBA8 +{ + uInt8 red; + uInt8 green; + uInt8 blue; + uInt8 alpha; +}; + +struct ogRGB16 +{ + uInt16 red; + uInt16 blue; + uInt16 green; +}; + +struct ogRGBA16 +{ + uInt16 red; + uInt16 green; + uInt16 blue; + uInt16 alpha; +}; + +struct ogRGB32 +{ + uInt32 red; + uInt32 green; + uInt32 blue; +}; + +struct ogRGBA32 +{ + uInt32 red; + uInt32 green; + uInt32 blue; + uInt32 alpha; +}; + +struct ogPoint2d +{ + int32 x; + int32 y; +}; + +struct ogPoint3d +{ + int32 x; + int32 y; + int32 z; +}; + +struct ogAttribute { + uInt32 transparentColor; + uInt32 defaultAlpha; + bool antiAlias; + bool blending; + + ogAttribute( + uInt32 transparentColor = 0, + uInt32 defaultAlpha = 255, + bool antiAlias = true, + bool blending = false) + { + this->transparentColor = transparentColor; + this->defaultAlpha = defaultAlpha; + this->antiAlias = antiAlias; + this->blending = blending; + } // ogAttribute() + +}; // struct ogAttribute + diff --git a/lib/objgfx/ogEdgeTable.cpp b/lib/objgfx/ogEdgeTable.cpp new file mode 100644 index 0000000..f8ff502 --- /dev/null +++ b/lib/objgfx/ogEdgeTable.cpp @@ -0,0 +1,439 @@ +#include +#include "ogEdgeTable.h" + +void ogEdgeTable::AdvanceAET(void) +{ + ogEdgeState * currentEdge; + ogEdgeState ** currentEdgePtr; + + currentEdgePtr = &activeEdges; + currentEdge = activeEdges; + while (currentEdge!=NULL) { + --currentEdge->count; + if (currentEdge->count == 0) + { + // this edge is finished, so remove it from the AET + *currentEdgePtr = currentEdge->nextEdge; + // I'm thinking I should dispose currentEdge here!? + } + else + { + // advance the edge's x coord by minimum move + currentEdge->x += currentEdge->wholePixelXMove; + // determine whether it's time for X to advance one extra + currentEdge->errorTerm += currentEdge->errorTermAdjUp; + if (currentEdge->errorTerm > 0) + { + currentEdge->x += currentEdge->xDirection; + currentEdge->errorTerm -= currentEdge->errorTermAdjDown; + } // if + currentEdgePtr = ¤tEdge->nextEdge; + } // else + currentEdge = *currentEdgePtr; + } // while +} // void ogEdgeTable::AdvanceAET() + +void ogEdgeTable::BuildGET(uInt32 numPoints, ogPoint2d * polyPoints) +{ + int32 i, x1, y1, x2, y2, deltaX, deltaY, width, tmp; + ogEdgeState * newEdgePtr; + ogEdgeState * followingEdge; + ogEdgeState ** followingEdgeLink; + + /* + * Creates a GET in the buffer pointed to by NextFreeEdgeStruc from + * the vertex list. Edge endpoints are flipped, if necessary, to + * guarantee all edges go top to bottom. The GET is sorted primarily + * by ascending Y start coordinate, and secondarily by ascending X + * start coordinate within edges with common Y coordinates } + */ + + // Scan through the vertex list and put all non-0-height edges into + // the GET, sorted by increasing Y start coordinate} + + for (i = 0; i < (int32)numPoints; i++) + { + // calculate the edge height and width + x1 = polyPoints[i].x; + y1 = polyPoints[i].y; + + if (i == 0) + { + // wrap back around to the end of the list + x2 = polyPoints[numPoints-1].x; + y2 = polyPoints[numPoints-1].y; + } + else + { + x2 = polyPoints[i-1].x; + y2 = polyPoints[i-1].y; + } // else i!=0 + + if (y1 > y2) + { + tmp = x1; + x1 = x2; + x2 = tmp; + + tmp = y1; + y1 = y2; + y2 = tmp; + } // if y1>y2 + + // skip if this can't ever be an active edge (has 0 height) + deltaY = y2-y1; + if (deltaY != 0) + { + newEdgePtr = new ogEdgeState; + newEdgePtr->xDirection = ((deltaX = x2-x1) > 0) ? 1 : -1; + width = fabs(deltaX); + newEdgePtr->x = x1; + newEdgePtr->startY = y1; + newEdgePtr->count = newEdgePtr->errorTermAdjDown = deltaY; + newEdgePtr->errorTerm = (deltaX >= 0) ? 0 : 1-deltaY; + + if (deltaY >= width) + { + newEdgePtr->wholePixelXMove = 0; + newEdgePtr->errorTermAdjUp = width; + } + else + { + newEdgePtr->wholePixelXMove = (width / deltaY) * newEdgePtr->xDirection; + newEdgePtr->errorTermAdjUp = width % deltaY; + } // else + + followingEdgeLink = &globalEdges; + while (true) { + followingEdge = *followingEdgeLink; + if ((followingEdge == NULL) || + (followingEdge->startY > y1) || + ((followingEdge->startY == y1) && + (followingEdge->x>=x1))) + { + newEdgePtr->nextEdge = followingEdge; + *followingEdgeLink = newEdgePtr; + break; + } // if + followingEdgeLink = &followingEdge->nextEdge; + } // while + } // if deltaY!=0 + } // for +} // void ogEdgeTable::BuildGET() + +void ogEdgeTable::BuildGET_G(uInt32 numPoints, ogPoint2d * polyPoints, ogRGBA8 * colours) +{ + + int32 i, x1, y1, x2, y2, deltaX, deltaY, width, tmp; + ogEdgeState * newEdgePtr; + ogEdgeState * followingEdge; + ogEdgeState ** followingEdgeLink; + ogRGBA8 c1, c2, cTmp; + + /* + * Creates a GET in the buffer pointed to by NextFreeEdgeStruc from + * the vertex list. Edge endpoints are flipped, if necessary, to + * guarantee all edges go top to bottom. The GET is sorted primarily + * by ascending Y start coordinate, and secondarily by ascending X + * start coordinate within edges with common Y coordinates } + */ + + // Scan through the vertex list and put all non-0-height edges into + // the GET, sorted by increasing Y start coordinate} + + for (i = 0; i < (int32)numPoints; i++) + { + // calculate the edge height and width + x1 = polyPoints[i].x; + y1 = polyPoints[i].y; + c1 = colours[i]; + + if (0 == i) + { + // wrap back around to the end of the list + x2 = polyPoints[numPoints-1].x; + y2 = polyPoints[numPoints-1].y; + c2 = colours[numPoints-1]; + } + else + { + x2 = polyPoints[i-1].x; + y2 = polyPoints[i-1].y; + c2 = colours[i-1]; + } // else i!=0 + + if (y1 > y2) + { + tmp = x1; + x1 = x2; + x2 = tmp; + + tmp = y1; + y1 = y2; + y2 = tmp; + + cTmp = c1; + c1 = c2; + c2 = cTmp; + } // if y1>y2 + + // skip if this can't ever be an active edge (has 0 height) + deltaY = y2-y1; + if (deltaY != 0) + { + newEdgePtr = new ogEdgeState; + newEdgePtr->colour = c1; + newEdgePtr->xDirection = ((deltaX = x2-x1) > 0) ? 1 : -1; + + newEdgePtr -> rStepY = ((c2.red - c1.red +1) << 16) / deltaY; + newEdgePtr -> gStepY = ((c2.green - c1.green +1) << 16) / deltaY; + newEdgePtr -> bStepY = ((c2.blue - c1.blue +1) << 16) / deltaY; + newEdgePtr -> aStepY = ((c2.alpha - c1.alpha +1) << 16) / deltaY; + + newEdgePtr -> rIncY = newEdgePtr -> gIncY = 0; + newEdgePtr -> bIncY = newEdgePtr -> aIncY = 0; + + width = fabs(deltaX); + newEdgePtr->x = x1; + newEdgePtr->startY = y1; + newEdgePtr->count = newEdgePtr->errorTermAdjDown = deltaY; + newEdgePtr->errorTerm = (deltaX >= 0) ? 0 : 1-deltaY; + + if (deltaY >= width) + { + newEdgePtr->wholePixelXMove = 0; + newEdgePtr->errorTermAdjUp = width; + } + else + { + newEdgePtr->wholePixelXMove = (width / deltaY) * newEdgePtr->xDirection; + newEdgePtr->errorTermAdjUp = width % deltaY; + } // else + + followingEdgeLink = &globalEdges; + while (true) { + followingEdge = *followingEdgeLink; + if ((followingEdge == NULL) || + (followingEdge->startY > y1) || + ((followingEdge->startY == y1) && + (followingEdge->x >= x1))) + { + newEdgePtr->nextEdge = followingEdge; + *followingEdgeLink = newEdgePtr; + break; + } // if + followingEdgeLink = &followingEdge->nextEdge; + } // while + } // if deltaY!=0 + } // for + return; +} // ogEdgeTable::BuildGET_G + +void ogEdgeTable::MoveXSortedToAET(int32 yToMove) +{ + ogEdgeState * AETEdge; + ogEdgeState * tempEdge; + ogEdgeState ** AETEdgePtr; + int32 currentX; + + /* The GET is Y sorted. Any edges that start at the d%%esired Y + * coordinate will be first in the GET, so we'll move edges from + * the GET to AET until the first edge left in the GET is no + * longer at the d%%esired Y coordinate. Also, the GET is X sorted + * within each Y cordinate, so each successive edge we add to the + * AET is guaranteed to belong later in the AET than the one just + * added. + */ + AETEdgePtr = &activeEdges; + while ((globalEdges != NULL) && (globalEdges->startY == yToMove)) + { + currentX = globalEdges->x; + // link the new edge into the AET so that the AET is still + // sorted by X coordinate + while (true) { + AETEdge = *AETEdgePtr; + if ((AETEdge == NULL) || (AETEdge->x >= currentX)) + { + tempEdge = globalEdges->nextEdge; + *AETEdgePtr = globalEdges; + globalEdges->nextEdge = AETEdge; + AETEdgePtr = &globalEdges->nextEdge; + globalEdges = tempEdge; + break; + } else AETEdgePtr = &AETEdge->nextEdge; + } // while true + } // while globalEdges!=NULL and globalEdges->startY==yToMove +} // void ogEdgeTable::MoveXSortedToAET() + +void ogEdgeTable::ScanOutAET(ogSurface & destObject, int32 yToScan, uInt32 colour) +{ + ogEdgeState * currentEdge; + int32 leftX; + + /* Scan through the AET, drawing line segments as each pair of edge + * crossings is encountered. The nearest pixel on or to the right + * of the left edges is drawn, and the nearest pixel to the left + * of but not on right edges is drawn + */ + currentEdge = activeEdges; + + while (currentEdge != NULL) { + leftX = currentEdge->x; + currentEdge = currentEdge->nextEdge; + + if (currentEdge != NULL) + { + if (currentEdge->x > leftX) + destObject.ogHLine(leftX, currentEdge->x-1, yToScan, colour); + currentEdge = currentEdge->nextEdge; + } // if currentEdge != NULL + } // while + + return; +} // void ogEdgeTable::ScanOutAET() + +void ogEdgeTable::ScanOutAET_G(ogSurface & destObject, int32 yToScan) +{ + ogEdgeState * currentEdge; + int32 leftX, count; + int32 rStepX, gStepX, bStepX, aStepX; + int32 rIncX, gIncX, bIncX, aIncX; + int32 lR, lG, lB, lA; + int32 rR, rG, rB, rA; + int32 dR, dG, dB, dA; + int32 dist; + + /* Scan through the AET, drawing line segments as each pair of edge + * crossings is encountered. The nearest pixel on or to the right + * of the left edges is drawn, and the nearest pixel to the left + * of but not on right edges is drawn + */ + currentEdge = activeEdges; + + while (currentEdge != NULL) + { + leftX = currentEdge->x; + + lR = currentEdge->colour.red; + lG = currentEdge->colour.green; + lB = currentEdge->colour.blue; + lA = currentEdge->colour.alpha; + + lR += currentEdge->rIncY >> 16; + lG += currentEdge->gIncY >> 16; + lB += currentEdge->bIncY >> 16; + lA += currentEdge->aIncY >> 16; + + currentEdge->rIncY += currentEdge->rStepY; + currentEdge->gIncY += currentEdge->gStepY; + currentEdge->bIncY += currentEdge->bStepY; + currentEdge->aIncY += currentEdge->aStepY; + + + currentEdge = currentEdge->nextEdge; + + if (currentEdge != NULL) + { + if (leftX != currentEdge->x) + { + rR = currentEdge->colour.red; + rG = currentEdge->colour.green; + rB = currentEdge->colour.blue; + rA = currentEdge->colour.alpha; + + rR += currentEdge->rIncY >> 16; + rG += currentEdge->gIncY >> 16; + rB += currentEdge->bIncY >> 16; + rA += currentEdge->aIncY >> 16; + + currentEdge->rIncY += currentEdge->rStepY; + currentEdge->gIncY += currentEdge->gStepY; + currentEdge->bIncY += currentEdge->bStepY; + currentEdge->aIncY += currentEdge->aStepY; + + dR = rR - lR; + dG = rG - lG; + dB = rB - lB; + dA = rA - lA; + + dist = currentEdge->x - leftX; + + rStepX = (dR << 16) / dist; + gStepX = (dG << 16) / dist; + bStepX = (dB << 16) / dist; + aStepX = (dA << 16) / dist; + rIncX = gIncX = bIncX = aIncX = 0; + + for (count = leftX; count < currentEdge->x; count++) + { + destObject.ogSetPixel(count, yToScan, + static_cast(lR + (rIncX >> 16)), + static_cast(lG + (gIncX >> 16)), + static_cast(lB + (bIncX >> 16)), + static_cast(lA + (aIncX >> 16)) ); + rIncX += rStepX; + gIncX += gStepX; + bIncX += bStepX; + aIncX += aStepX; + } // for + } + currentEdge = currentEdge->nextEdge; + } // if currentEdge != NULL + } // while + +} // void ogEdgeTable::ScanOutAET_G() + +void ogEdgeTable::XSortAET(void) +{ + ogEdgeState * currentEdge; + ogEdgeState * tempEdge; + ogEdgeState ** currentEdgePtr; + bool swapOccurred; + + if (activeEdges == NULL) return; + + do { + swapOccurred = false; + currentEdgePtr = &activeEdges; + currentEdge = activeEdges; + while (currentEdge->nextEdge != NULL) + { + if (currentEdge->x > currentEdge->nextEdge->x) + { + // the second edge has a lower x than the first + // swap them in the AET + tempEdge = currentEdge->nextEdge->nextEdge; + *currentEdgePtr = currentEdge->nextEdge; + currentEdge->nextEdge->nextEdge = currentEdge; + currentEdge->nextEdge = tempEdge; + swapOccurred = true; + } // if + currentEdgePtr = &((*currentEdgePtr)->nextEdge); + currentEdge = *currentEdgePtr; + } // while + } while (swapOccurred); +} // void ogEdgeTable::XSortAET() + +ogEdgeTable::~ogEdgeTable(void) +{ + ogEdgeState * edge; + ogEdgeState * tmpEdge; + tmpEdge = globalEdges; + // first walk the global edges and delete any non-null nodes + while (tmpEdge != NULL) + { + edge = tmpEdge; + tmpEdge = edge->nextEdge; + delete edge; + } // while + tmpEdge = activeEdges; + // next walk the activeEdges and delete any non-null nodes. Note that this should + // always be null + while (tmpEdge != NULL) + { + edge = tmpEdge; + tmpEdge = edge->nextEdge; + delete edge; + } // while + return; +} // ogEdgeTable::~ogEdgeTable() diff --git a/lib/objgfx/ogImage.cpp b/lib/objgfx/ogImage.cpp new file mode 100644 index 0000000..8d60c54 --- /dev/null +++ b/lib/objgfx/ogImage.cpp @@ -0,0 +1,576 @@ +#include +#include +#include +#include +#include +#include + +#include "ogImage.h" +#include "objgfx.h" + +bool Win3xBitmapHeader::Deserialize(std::istream& stream) +{ + if (!stream) return false; + + // Read in each field, and check for any failure. Return false on failure + if (!stream.read(reinterpret_cast(&ImageFileType), sizeof(ImageFileType))) return false; + if (!stream.read(reinterpret_cast(&FileSize), sizeof(FileSize))) return false; + if (!stream.read(reinterpret_cast(&Reserved1), sizeof(Reserved1))) return false; + if (!stream.read(reinterpret_cast(&Reserved2), sizeof(Reserved2))) return false; + if (!stream.read(reinterpret_cast(&ImageDataOffset), sizeof(ImageDataOffset))) return false; + + return true; +} // bool Win3xBitmapHeader::Deserialize() + +std::string Win3xBitmapHeader::ToString() +{ + return + "ImageFileType = " + std::to_string(ImageFileType) + "\r\n" + + "FileSize = " + std::to_string(FileSize) + "\r\n" + + "Reserved1 = " + std::to_string(Reserved1) + "\r\n" + + "Reserved2 = " + std::to_string(Reserved2) + "\r\n" + + "ImageDataOffset = " + std::to_string(ImageDataOffset) + "\r\n"; +} // string Win3xBitmapHeader::ToString() + +bool Win3xBitmapHeader::IsMatch() +{ + return + (ImageFileType == 0x4D42 && + FileSize != 0 && + Reserved1 == 0 && + Reserved2 == 0 && + ImageDataOffset != 0); +} // bool Win3xBitmapHeader::IsMatch() + +bool Win3xBitmapHeader::Serialize(std::ostream& stream) +{ + if (!stream) return false; + + // Read in each field, and check for any failure. Return false on failure + if (!stream.write(reinterpret_cast(&ImageFileType), sizeof(ImageFileType))) return false; + if (!stream.write(reinterpret_cast(&FileSize), sizeof(FileSize))) return false; + if (!stream.write(reinterpret_cast(&Reserved1), sizeof(Reserved1))) return false; + if (!stream.write(reinterpret_cast(&Reserved2), sizeof(Reserved2))) return false; + if (!stream.write(reinterpret_cast(&ImageDataOffset), sizeof(ImageDataOffset))) return false; + + return true; +} // bool Win3xBitmapHeader::Serialize() + +size_t Win3xBitmapHeader::Size() +{ + return + sizeof(ImageFileType) + + sizeof(FileSize) + + sizeof(Reserved1) + + sizeof(Reserved2) + + sizeof(ImageDataOffset); +} // size_t Win3xBitmapHeader::Size() + +bool Win3xBitmapInfoHeader::Deserialize(std::istream& stream) +{ + if (!stream) return false; + + // Read in each field, and check for any failure. Return false on failure + if (!stream.read(reinterpret_cast(&HeaderSize), sizeof(HeaderSize))) return false; + if (!stream.read(reinterpret_cast(&ImageWidth), sizeof(ImageWidth))) return false; + if (!stream.read(reinterpret_cast(&ImageHeight), sizeof(ImageHeight))) return false; + if (!stream.read(reinterpret_cast(&NumberOfImagePlanes), sizeof(NumberOfImagePlanes))) return false; + if (!stream.read(reinterpret_cast(&BitsPerPixel), sizeof(BitsPerPixel))) return false; + if (!stream.read(reinterpret_cast(&CompressionMethod), sizeof(CompressionMethod))) return false; + if (!stream.read(reinterpret_cast(&SizeOfBitmap), sizeof(SizeOfBitmap))) return false; + if (!stream.read(reinterpret_cast(&HorzResolution), sizeof(HorzResolution))) return false; + if (!stream.read(reinterpret_cast(&VertResolution), sizeof(VertResolution))) return false; + if (!stream.read(reinterpret_cast(&NumColoursUsed), sizeof(NumColoursUsed))) return false; + if (!stream.read(reinterpret_cast(&NumSignificantColours), sizeof(NumSignificantColours))) return false; + + return true; +} // bool Win3xBitmapInfoHeader::Deserialize() + +std::string Win3xBitmapInfoHeader::ToString() +{ + return + "HeaderSize = " + std::to_string(HeaderSize) + "\r\n" + + "ImageWidth = " + std::to_string(ImageWidth) + "\r\n" + + "ImageHeight = " + std::to_string(ImageHeight) + "\r\n" + + "NumberOfImagePlanes = " + std::to_string(NumberOfImagePlanes) + "\r\n" + + "BitsPerPixel = "+ std::to_string(BitsPerPixel) + "\r\n" + + "CompressionMethod = " + std::to_string(CompressionMethod) + "\r\n" + + "SizeOfBitmap = " + std::to_string(SizeOfBitmap) + "\r\n" + + "HorzResolution = " + std::to_string(HorzResolution) + "\r\n" + + "VertResolution = " + std::to_string(VertResolution) + "\r\n" + + "NumColoursUsed = " + std::to_string(NumColoursUsed) + "\r\n" + + "NumSignificantColours = " + std::to_string(NumSignificantColours) + "\r\n"; +} // string Win3xBitmapInfoHeader::ToString() + +bool Win3xBitmapInfoHeader::IsMatch() +{ + return + (HeaderSize != 0 && + ImageWidth != 0 && + ImageHeight != 0 && + CompressionMethod == 0 && + (BitsPerPixel == 8 || BitsPerPixel == 24)); +} +bool Win3xBitmapInfoHeader::Serialize(std::ostream& stream) +{ + if (!stream) return false; + + // Read in each field, and return false on failure + if (!stream.write(reinterpret_cast(&HeaderSize), sizeof(HeaderSize))) return false; + if (!stream.write(reinterpret_cast(&ImageWidth), sizeof(ImageWidth))) return false; + if (!stream.write(reinterpret_cast(&ImageHeight), sizeof(ImageHeight))) return false; + if (!stream.write(reinterpret_cast(&NumberOfImagePlanes), sizeof(NumberOfImagePlanes))) return false; + if (!stream.write(reinterpret_cast(&BitsPerPixel), sizeof(BitsPerPixel))) return false; + if (!stream.write(reinterpret_cast(&CompressionMethod), sizeof(CompressionMethod))) return false; + if (!stream.write(reinterpret_cast(&SizeOfBitmap), sizeof(SizeOfBitmap))) return false; + if (!stream.write(reinterpret_cast(&HorzResolution), sizeof(HorzResolution))) return false; + if (!stream.write(reinterpret_cast(&VertResolution), sizeof(VertResolution))) return false; + if (!stream.write(reinterpret_cast(&NumColoursUsed), sizeof(NumColoursUsed))) return false; + if (!stream.write(reinterpret_cast(&NumSignificantColours), sizeof(NumSignificantColours))) return false; + + return true; +} // bool Win3xBitmapInfoHeader::Serialize() + +size_t Win3xBitmapInfoHeader::Size() +{ + return + sizeof(HeaderSize) + + sizeof(ImageWidth) + + sizeof(ImageHeight) + + sizeof(NumberOfImagePlanes) + + sizeof(BitsPerPixel) + + sizeof(CompressionMethod) + + sizeof(SizeOfBitmap) + + sizeof(HorzResolution) + + sizeof(VertResolution) + + sizeof(NumColoursUsed) + + sizeof(NumSignificantColours); +} // size_t Win3xBitmapInfoHeader::Size() + +bool RGBQuad::Deserialize(std::istream& stream) +{ + if (!stream) return false; + + // Read in each field, and return false on failure + if (!stream.read(reinterpret_cast(&rgbBlue), sizeof(rgbBlue))) return false; + if (!stream.read(reinterpret_cast(&rgbGreen), sizeof(rgbGreen))) return false; + if (!stream.read(reinterpret_cast(&rgbRed), sizeof(rgbRed))) return false; + if (!stream.read(reinterpret_cast(&rgbReserved), sizeof(rgbReserved))) return false; + + return true; +} // bool RGBQuad::Deserialize() + +std::string RGBQuad::ToString() +{ + return "rgbRed = " + to_string(rgbRed) + "\r\n" + + "rgbGreen = " + to_string(rgbGreen) + "\r\n" + + "rgbBlue = " + to_string(rgbBlue) + "\r\n" + + "rgbReserved = " + to_string(rgbReserved) + "\r\n"; +} // string RGBQuad::ToString() + +bool RGBQuad::Serialize(std::ostream& stream) +{ + if (!stream) return false; + + // Read in each field, and return false on failure + if (!stream.write(reinterpret_cast(&rgbBlue), sizeof(rgbBlue))) return false; + if (!stream.write(reinterpret_cast(&rgbGreen), sizeof(rgbGreen))) return false; + if (!stream.write(reinterpret_cast(&rgbRed), sizeof(rgbRed))) return false; + if (!stream.write(reinterpret_cast(&rgbReserved), sizeof(rgbReserved))) return false; + + return true; +} // bool RGBQuad::Serialize() +size_t RGBQuad::Size() +{ + return + sizeof(rgbBlue) + + sizeof(rgbGreen) + + sizeof(rgbRed) + + sizeof(rgbReserved); +} // size_t RGBQuad::Size() + +bool IsBMP(std::istream& stream) +{ + + // Check for BMP + Win3xBitmapHeader bmpHeader; + bmpHeader.Deserialize(stream); + Win3xBitmapInfoHeader bmpInfoHeader; + bmpInfoHeader.Deserialize(stream); + + if (bmpHeader.IsMatch() && bmpInfoHeader.IsMatch()) + { + std::cout << bmpHeader.ToString(); + std::cout << bmpInfoHeader.ToString(); + return true; + } + return false; +} // bool IsBMP() + +/********************************************** + * ogImage + **********************************************/ +static const std::map>& CreateIsImageMap() +{ + static std::map> IsImage; + + //IsImage[NoImage] = ([&](std::istream&) -> bool { return false; }); + IsImage[BMP] = &IsBMP; + return IsImage; +} // map<> CreateIsImageMap() + +std::map> ogImage::IsImage = CreateIsImageMap(); + +ogImage::ogImage() : + surface(nullptr), + options(nullptr), + input(nullptr), + output(nullptr) +{ + Decode[NoImage] = &ogImage::NoOp; + Decode[BMP] = &ogImage::DecodeBMP; + + Encode[NoImage] = &ogImage::NoOp; + Encode[BMP] = &ogImage::EncodeBMP; + +} // ogImage::ogImage() + +bool ogImage::DecodeBMP() +{ + // ogImage::ImageType() has determined we're a BMP, so we only need to do + // minimal sanity checks on the header information. + + Win3xBitmapHeader bmpHeader; + Win3xBitmapInfoHeader bmpInfoHeader; + if (!bmpHeader.Deserialize(*input)) return false; + if (!bmpInfoHeader.Deserialize(*input)) return false; + + size_t lineSize; + size_t paddington; + char linePadding[4]; + + if (bmpInfoHeader.BitsPerPixel == 8) + { + if (!surface->ogCreate(bmpInfoHeader.ImageWidth, bmpInfoHeader.ImageHeight, OG_PIXFMT_8BPP)) return false; + + lineSize = ((bmpInfoHeader.ImageWidth+3) >> 2) << 2; // round up to the nearest 4 bytes + paddington = lineSize - bmpInfoHeader.ImageWidth; // see if we have a remainder + + if (paddington > 4) return false; // this would be odd + + RGBQuad quad; + for (unsigned colour = 0; colour < 256; colour++) + { + if (!quad.Deserialize(*input)) return false; + surface->ogSetPalette(colour, quad.rgbRed, quad.rgbGreen, quad.rgbBlue, quad.rgbReserved); + } // for colour + + for (unsigned y = surface->ogGetMaxY()+1; y --> 0 ;) // y goes to 0 + { + char * ptr = reinterpret_cast(surface->ogGetPtr(0, y)); + if (ptr == nullptr) return false; // this doesn't have to be a complete failure, fix later + if (!input->read(ptr, bmpInfoHeader.ImageWidth)) return false; + if (paddington != 0) + { + if (!input->read(linePadding, paddington)) return false; // double check this + } + } // for y + } + else if (bmpInfoHeader.BitsPerPixel == 24) + { + ogPixelFmt BMPPixelFmt(24, 16,8,0,0, 8,8,8,0); + if (!surface->ogCreate(bmpInfoHeader.ImageWidth, bmpInfoHeader.ImageHeight, OG_PIXFMT_24BPP)) return false; + size_t widthInBytes = bmpInfoHeader.ImageWidth*3; // 3 represents how many bytes per pixel + lineSize = ((widthInBytes+3) >> 2) << 2; // round up to the nearest 4 bytes + paddington = lineSize - widthInBytes; // see if we have a remainder + + if (paddington > 4) return false; + + for (unsigned y = surface->ogGetMaxY()+1; y --> 0 ;) + { + char * ptr = reinterpret_cast(surface->ogGetPtr(0, y)); + if (ptr == nullptr) return false; // this doesn't have to be a complete failure, fix later + if (!input->read(ptr, widthInBytes)) return false; + if (paddington != 0) + { + if (!input->read(linePadding, paddington)) return false; + } + } // for y + } + + return true; +} // bool ogImage::DecodeBMP() + +bool ogImage::EncodeBMP() +{ + Win3xBitmapHeader bmpHeader; + Win3xBitmapInfoHeader bmpInfoHeader; + size_t paddington; + size_t lineSize; + const char linePadding[4] = {0,0,0,0}; + ogRGBA8 ogPalette[256]; // used to get the palette from the surface + + bmpHeader.ImageFileType = 0x4D42; + bmpHeader.FileSize = 0; // fill in later + //bmpHeader.Reserved1 = 0; // set by constructor + //bmpHeader.Reserved2 = 0; // set by constructor + bmpHeader.ImageDataOffset = bmpHeader.Size() + bmpInfoHeader.Size(); + + bmpInfoHeader.HeaderSize = bmpInfoHeader.Size(); + bmpInfoHeader.ImageWidth = surface->ogGetMaxX()+1; + bmpInfoHeader.ImageHeight = surface->ogGetMaxY()+1; + bmpInfoHeader.NumberOfImagePlanes = 1; + // bmpInfoHeader.BitsPerPixel is set below + bmpInfoHeader.CompressionMethod = 0; + bmpInfoHeader.SizeOfBitmap = 0; + bmpInfoHeader.HorzResolution = 0; // option + bmpInfoHeader.VertResolution = 0; // option + + switch (surface->ogGetBPP()) + { + case 8: + bmpInfoHeader.BitsPerPixel = 8; // 8bpp, 256 colours + bmpInfoHeader.NumColoursUsed = 1 << surface->ogGetBPP(); + bmpInfoHeader.NumSignificantColours = 0; // option + + // This is hard to calculate dynamically. Sod it. + bmpHeader.ImageDataOffset += 1024;// adjust by palette size + + lineSize = ((bmpInfoHeader.ImageWidth+3) >> 2) << 2; // multiple of 4 + bmpInfoHeader.SizeOfBitmap = lineSize*bmpInfoHeader.ImageHeight; + bmpHeader.FileSize = bmpHeader.ImageDataOffset+bmpInfoHeader.SizeOfBitmap; + + // Write the headers + if (!bmpHeader.Serialize(*output)) return false; + if (!bmpInfoHeader.Serialize(*output)) return false; + + // all rows are aligned to the nearest 4 bytes. Figure out if we need to pad. + paddington = lineSize-bmpInfoHeader.ImageWidth; + + surface->ogGetPalette(ogPalette); + + for (size_t index = 0; index < sizeof(ogPalette) / sizeof(ogPalette[0]); index++) + { + RGBQuad quad(ogPalette[index]); + if (!quad.Serialize(*output)) return false; + } // for index + + for (unsigned y = surface->ogGetMaxY()+1; y --> 0 ;) // y goes to 0 + { + char * ptr = reinterpret_cast(surface->ogGetPtr(0, y)); + if (ptr != nullptr) + { + if (!output->write(ptr, bmpInfoHeader.ImageWidth)) return false; + } + + // Is there any padding to add to the end of the line? + if (paddington != 0) + { + if (!output->write(linePadding, paddington)) return false; + } + } // for y + break; + case 32: + case 24: + case 16: + case 15: + // 15, 16, and 32 bpp are all treated as 24bpp + bmpInfoHeader.BitsPerPixel = 24; + bmpInfoHeader.NumColoursUsed = 0; + bmpInfoHeader.NumSignificantColours = 0; + + lineSize = ((bmpInfoHeader.ImageWidth*3+3) >> 2) << 2; + bmpInfoHeader.SizeOfBitmap = lineSize*bmpInfoHeader.ImageHeight; + bmpHeader.FileSize = bmpHeader.ImageDataOffset+bmpInfoHeader.SizeOfBitmap; + + // Write the headers + if (!bmpHeader.Serialize(*output)) return false; + if (!bmpInfoHeader.Serialize(*output)) return false; + + // all rows are aligned to the nearest 4 bytes. Figure out if we need to pad. + paddington = lineSize-bmpInfoHeader.ImageWidth*3; // 3 represents how many bytes per pixel + uInt8 red, green, blue; + + for (unsigned y = surface->ogGetMaxY()+1; y --> 0 ;) // y goes to 0 + { + for (unsigned x = 0; x <= surface->ogGetMaxX(); x++) + { + // Unpack the pixel and write it out. + surface->ogUnpack(surface->ogGetPixel(x, y), red, green, blue); + if (!output->write(reinterpret_cast(&blue), sizeof(blue))) return false; + if (!output->write(reinterpret_cast(&green), sizeof(green))) return false; + if (!output->write(reinterpret_cast(&red), sizeof(red))) return false; + } // for x + + // Is there any padding to add to the end of the line? + if (paddington != 0) + { + if (!output->write(linePadding, paddington)) return false; + } + } // for y + break; + default: + return false; // we can't encode anything else (I'm not sure there *is* anything else) + } // switch + + + return true; +} // bool ogImage::EncodeBMP() + +ogImageType ogImage::ImageType(std::istream& input) +{ + ogImageType imageType = NoImage; + // space for the header + char header[128]; // This really should be as large as the largest header we know of + + for (size_t index = 0; index < std::extent::value; index++) + { + header[index] = 0; // clear the header + } // for index + + size_t size = sizeof(header); + + if (!input.read(header, size)) return NoImage; // This isn't necessarily true. Might just be a small image. + // Figure out how many bytes we read in. + streamsize bytesRead = input.gcount(); + + if (bytesRead != 0) + { + + // Try to determine what it really is + for (auto iType : IsImage) + { + mstream mb(header, bytesRead); + // This creates a new istream from a memory stream, + // which is wrapped adound the header. + //istream stream(&mstream(header, bytesRead)); + istream stream(&mb); + if (iType.second(stream)) // Did we find it? + { + imageType = iType.first; // Found it + break; + } // if + } // for iType + + // Now seek backwards in the stream. + input.seekg(-bytesRead, std::ios_base::cur); + } + + return imageType; +} // ogImageType ogImage::ImageType() + +ogImageType ogImage::ImageType(const std::string& filename) +{ + std::ifstream input(filename, ios::in | std::ios_base::binary); + ogImageType imageType = NoImage; + + // Sanity check + if (input) + { + // Use the stream version + imageType = ogImage::ImageType(input); + + // close the file + input.close(); + } // if + + return imageType; +} // ogImageType ogImage::ImageType() + +bool ogImage::Load(const std::string& filename, ogSurface & surface) +{ + std::cout << "Loading " << filename << std::endl; + bool success = false; // assume failure + + ifstream stream(filename, ios_base::in | ios_base::binary); + + if (stream) + { + success = Load(stream, surface); + stream.close(); + } // if stream + + return success; +} // ogSurface * ogImage::Load() + +bool ogImage::Load(std::istream& stream, ogSurface& surface) +{ + // First we need to find out what type of graphics file it is: + ogImageType imageType = ogImage::ImageType(stream); + + if (imageType == NoImage) return false; + + this->surface = &surface; + this->input = &stream; + this->options = nullptr; // shouldn't be necessary + this->output = nullptr; // shouldn't be necessary + + assert(Decode.count(imageType) == 1); // make sure we can handle it + + return (this->*Decode[imageType])(); // Decode +} // bool ogImage::Load() + +bool ogImage::Save(const std::string& filename, + ogSurface &surface, + ogImageType imageType, + ogImageOptions * options) +{ + bool success = false; // assume failure + + ofstream stream(filename, ios_base::out | ios_base::binary); // try to open the file + + if (stream) + { + // Use the stream version + success = Save(stream, surface, imageType, options); + + // close the file + stream.close(); + } // if + + return success; +} // bool ogImage::Save() + +bool ogImage::Save(std::ostream& stream, + ogSurface &surface, + ogImageType imageType, + ogImageOptions * options) +{ + bool success = false; // assume failure + + if (stream && surface.ogAvail()) + { + // Since surface is a reference, it cannot [normally] be null, + // so no checking needs to be done in any of the encoder functions. + this->surface = &surface; + this->options = options; + this->output = &stream; + + assert(Encode.count(imageType) == 1); // Sanity check + + // Call the specific encoder + success = (this->*Encode[imageType])(); + } // if + + return success; +} // bool ogImage::Save() + +#if 0 +class membuf : public basic_streambuf +{ +public: + membuf(char* p, size_t n) { + setg(p, p, p + n); + setp(p, p + n); + } +} +Usage: + +char *mybuffer; +size_t length; +// ... allocate "mybuffer", put data into it, set "length" + +membuf mb(mybuffer, length); +istream reader(&mb); +// use "reader" +#endif \ No newline at end of file diff --git a/lib/objgfx/ogPixCon.cpp b/lib/objgfx/ogPixCon.cpp new file mode 100644 index 0000000..21a8aad --- /dev/null +++ b/lib/objgfx/ogPixCon.cpp @@ -0,0 +1,148 @@ +#include "objgfx.h" +#include "ogPixCon.h" + +// ogPixCon constructor +ogPixCon::ogPixCon(ogPixelFmt srcPixFmt, ogPixelFmt dstPixFmt) { + uInt8 channelIdx[4]; + uInt8 srcFieldSize[4]; + uInt8 srcFieldPos[4]; + uInt8 dstShifters[4]; + + uInt8 tmpb; + int32 i, j; + + channelIdx[0] = 0; + channelIdx[1] = 1; + channelIdx[2] = 2; + channelIdx[3] = 3; + + srcFieldSize[0] = srcPixFmt.alphaMaskSize; + srcFieldSize[1] = srcPixFmt.redMaskSize; + srcFieldSize[2] = srcPixFmt.greenMaskSize; + srcFieldSize[3] = srcPixFmt.blueMaskSize; + + srcFieldPos[0] = srcPixFmt.alphaFieldPosition; + srcFieldPos[1] = srcPixFmt.redFieldPosition; + srcFieldPos[2] = srcPixFmt.greenFieldPosition; + srcFieldPos[3] = srcPixFmt.blueFieldPosition; + + /* + * The dest shifters are 32-(fieldPosition+fieldSize). For things like + * 24bpp where there is no alpha, the field position will be 0, and the + * field size will be 0. 32-(0+0) is 32.. and when the shift takes place + * the 32 will turn into a 0 and the shift will do nothing + */ + + dstShifters[0] = 32-(dstPixFmt.alphaFieldPosition+dstPixFmt.alphaMaskSize); + dstShifters[1] = 32-(dstPixFmt.redFieldPosition+dstPixFmt.redMaskSize); + dstShifters[2] = 32-(dstPixFmt.greenFieldPosition+dstPixFmt.greenMaskSize); + dstShifters[3] = 32-(dstPixFmt.blueFieldPosition+dstPixFmt.blueMaskSize); + + i = srcPixFmt.redMaskSize - dstPixFmt.redMaskSize; + if (i>0) + srcMasker = ogPixelFmt::OG_MASKS[dstPixFmt.redMaskSize] << (srcPixFmt.redFieldPosition+i); + else + srcMasker = ogPixelFmt::OG_MASKS[srcPixFmt.redMaskSize] << srcPixFmt.redFieldPosition; + + i = srcPixFmt.greenMaskSize - dstPixFmt.greenMaskSize; + if (i>0) + srcMasker += ogPixelFmt::OG_MASKS[dstPixFmt.greenMaskSize] << (srcPixFmt.greenFieldPosition+i); + else + srcMasker += ogPixelFmt::OG_MASKS[srcPixFmt.greenMaskSize] << srcPixFmt.greenFieldPosition; + + i = srcPixFmt.blueMaskSize - dstPixFmt.blueMaskSize; + if (i>0) + srcMasker += ogPixelFmt::OG_MASKS[dstPixFmt.blueMaskSize] << (srcPixFmt.blueFieldPosition+i); + else + srcMasker += ogPixelFmt::OG_MASKS[srcPixFmt.blueMaskSize] << srcPixFmt.blueFieldPosition; + + i = srcPixFmt.alphaMaskSize - dstPixFmt.alphaMaskSize; + if (i>0) + srcMasker += ogPixelFmt::OG_MASKS[dstPixFmt.alphaMaskSize] << (srcPixFmt.alphaFieldPosition+i); + else + srcMasker += ogPixelFmt::OG_MASKS[srcPixFmt.alphaMaskSize] << srcPixFmt.alphaFieldPosition; + + /* + * sort in descending order based on srcFieldPos (oth field will hold + * highest position value) + */ + + for (i = 1; i < 4; i++ ) + for (j = 0; j < i; j++) { + if (srcFieldPos[j] < srcFieldPos[i]) { + tmpb = srcFieldPos[j]; + srcFieldPos[j] = srcFieldPos[i]; + srcFieldPos[i] = tmpb; + + tmpb = srcFieldSize[j]; + srcFieldSize[j] = srcFieldSize[i]; + srcFieldSize[i] = tmpb; + + tmpb = channelIdx[j]; + channelIdx[j] = channelIdx[i]; + channelIdx[i] = tmpb; + } // if + } // for j + + srcShifter = ((srcFieldSize[0] << 24) | + (srcFieldSize[1] << 16) | + (srcFieldSize[2] << 8) | + (srcFieldSize[3])); + + dstShifter = ((dstShifters[channelIdx[0]] << 24) | + (dstShifters[channelIdx[1]] << 16) | + (dstShifters[channelIdx[2]] << 8) | + (dstShifters[channelIdx[3]])); + return; +} // ogPixCon::ogPixCon() + +uInt32 ogPixCon::ConvPix(uInt32 pixel) +{ + /* + _asm { + xor ebx, ebx ; // ebx <- 0 + xor edi, edi ; // edi <- 0 + + mov eax, this + + mov edx, [eax + ogPixCon::srcMasker] + mov ecx, [eax + ogPixCon::srcShifter] ; // ecx <- src shifter + mov eax, [eax + ogPixCon::dstShifter] ; // eax <- dst shifter + mov esi, pixel ; // esi <- pixel to convert + + push eax ; // save the dest shifter for later + + and esi, edx ; // esi <- esi & srcMasker + xor eax, eax ; // eax <- 0 + xor edx, edx ; // edx <- 0 + + shrd eax, esi, cl ; // copy the 1st channel + shr esi, cl ; // shift the source + mov cl, ch ; // load next shifter + shrd ebx, esi, cl ; // copy the 2nd channel + shr esi, cl ; // shift the source + shr ecx, 16 ; // load the next shifter + shrd edx, esi, cl ; // copy the 3rd channel + shr esi, cl ; // shift the source + mov cl, ch ; // load the next shifter + shrd edi, esi, cl ; // copy the 4th channel + + pop ecx ; // restore the dest shifter + + shr eax, cl ; // shift 1st src chan to dest pos + shr ecx, 8 ; // load next shifter + shr ebx, cl ; // shift 2nd src chan to dest pos + shr ecx, 8 ; // load next shifter + shr edx, cl ; // shift 3rd src chan to dest pos + shr ecx, 8 ; // load next shifter + shr edi, cl ; // shift 4th src chan to dest pos + + or eax, ebx ; // combine 1st and 2nd channels + or edx, edi ; // combine 3rd and 4th channels + nop + or eax, edx ; // combine all to form new pixel + } // _asm +*/ + return 0; +} // uInt32 ogPixCon::ConvPix() + diff --git a/lib/objgfx/ogPixelFmt.cpp b/lib/objgfx/ogPixelFmt.cpp new file mode 100644 index 0000000..dcfe9c2 --- /dev/null +++ b/lib/objgfx/ogPixelFmt.cpp @@ -0,0 +1,87 @@ +#include "ogPixelFmt.h" +#include "objgfx.h" + +ogPixelFmt::ogPixelFmt(void) : + BPP(0), + redFieldPosition(0), + greenFieldPosition(0), + blueFieldPosition(0), + alphaFieldPosition(0), + redMaskSize(0), + greenMaskSize(0), + blueMaskSize(0), + alphaMaskSize(0) +{ + for (size_t i = 0; i < 7; i++) reserved[i] = 0; +} // ogPixelFmt::ogPixelFmt() + +ogPixelFmt::ogPixelFmt( + uInt8 bitsPerPix, + uInt8 RFP, + uInt8 GFP, + uInt8 BFP, + uInt8 AFP, + uInt8 RMS, + uInt8 GMS, + uInt8 BMS, + uInt8 AMS) +{ + + BPP = bitsPerPix; + redFieldPosition = RFP; + greenFieldPosition = GFP; + blueFieldPosition = BFP; + alphaFieldPosition = AFP; + redMaskSize = RMS; + greenMaskSize = GMS; + blueMaskSize = BMS; + alphaMaskSize = AMS; + + for (size_t i = 0; i < 7; i++) reserved[i] = 0; + +} // ogPixelFmt::ogPixelFmt() + +ogPixelFmt const OG_PIXFMT_NONE = ogPixelFmt(0, 0,0,0,0, 0,0,0,0); +ogPixelFmt const OG_PIXFMT_8BPP = ogPixelFmt(8, 0,0,0,0, 0,0,0,0); +ogPixelFmt const OG_PIXFMT_15BPP = ogPixelFmt(15, 10,5,0,15, 5,5,5,1); +ogPixelFmt const OG_PIXFMT_16BPP = ogPixelFmt(16, 11,5,0,0, 5,6,5,0); +ogPixelFmt const OG_PIXFMT_24BPP = ogPixelFmt(24, 16,8,0,0, 8,8,8,0); +ogPixelFmt const OG_PIXFMT_32BPP = ogPixelFmt(32, 16,8,0,24, 8,8,8,8); +ogPixelFmt const OG_MAC_PIXFMT_16BPP = ogPixelFmt(16, 8,4,0,12, 4,4,4,4); + +const uInt32 ogPixelFmt::OG_MASKS[32] = +{ + 0x00, + 0x01, + 0x03, + 0x07, + 0x0F, + 0x1F, + 0x3F, + 0x7F, + 0x0FF, + 0x1FF, + 0x3FF, + 0x7FF, + 0x0FFF, + 0x1FFF, + 0x3FFF, + 0x7FFF, + 0x0FFFF, + 0x1FFFF, + 0x3FFFF, + 0x7FFFF, + 0x0FFFFF, + 0x1FFFFF, + 0x3FFFFF, + 0x7FFFFF, + 0x0FFFFFF, + 0x1FFFFFF, + 0x3FFFFFF, + 0x7FFFFFF, + 0x0FFFFFFF, + 0x1FFFFFFF, + 0x3FFFFFFF, + 0x7FFFFFFF +}; // OG_MASKS[] + diff --git a/sys/lib/kmalloc.c b/sys/lib/kmalloc.c index cf3bc34..078217c 100644 --- a/sys/lib/kmalloc.c +++ b/sys/lib/kmalloc.c @@ -34,6 +34,7 @@ #include #include #include +#include /* Set up three descriptor tables: