/******************************************************* $Id: objgfx40.cpp 89 2016-01-12 00:20:40Z reddawg $ *******************************************************/ #ifndef __UBIXOS_KERNEL__ extern "C" { #include <stdlib.h> #include <string.h> #include <stdio.h> #include <math.h> } #endif #ifdef __UBIXOS_KERNEL__ extern "C" { #include <math.h> #include <lib/kmalloc.h> #include <lib/string.h> #include <vfs/vfs.h> #include <vfs/file.h> } #define abs(a) (((a) < 0) ? -(a) : (a)) #endif #include <objgfx40/objgfx40.h> #include <objgfx40/ogPixCon.h> #include <objgfx40/ogPixelFmt.h> #include <objgfx40/defpal.inc> #ifdef __UBIXOS__ #include <libcpp.h> #endif const uInt32 OG_MASKS[32] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647 }; // OG_MASKS[] const float 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[] // #include "../ubixos-home/src/sys/include/ubixos/types.h" // #define ROUND(f) (int)((f) + ((f) > 0 ? 0.5 : -0.5)) struct ogHLine { int32 xStart; int32 xEnd; }; struct ogHLineList { int32 length; int32 yStart; int32 * xLeft; int32 * xRight; }; struct ogPointListHeader { int32 length; ogPoint2d * PointPtr; }; 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 = NULL; 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); }; // ogEdgeState 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 return; } // 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 (0 == i) { // 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 = abs(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 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 = abs(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 desired 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 desired 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 return; } // 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; } // 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, lR + (rIncX >> 16), lG + (gIncX >> 16), lB + (bIncX >> 16), lA + (aIncX >> 16) ); rIncX += rStepX; gIncX += gStepX; bIncX += bStepX; aIncX += aStepX; } // for } currentEdge = currentEdge->nextEdge; } // if currentEdge != NULL } // while return; } // 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); return; } // 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 static bool fileExists(const char *file) { #ifdef __UBIXOS_KERNEL__ fileDescriptor *f = fopen(file, "rb"); #else FILE *f = fopen(file, "rb"); #endif if (!f) return false; fclose(f); return true; } static int32 calculate(float mu, int32 p0, int32 p1, int32 p2, int32 p3); // 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; return; } // 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<uInt32>(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 */ // erradj = ((uInt64) dx << 32) / (uInt64)dy; __asm__ __volatile__ ( " xor %%eax, %%eax \n" " div %1 \n" " mov %%eax, %2 \n" : : "d" (dx), "b" (dy), "m" (erradj) ); 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. */ // erradj = ((uInt64)dy << 32) / (uInt64)dx; __asm__ __volatile__ ( " xor %%eax, %%eax \n" " div %1 \n" " mov %%eax, %2 \n" : : "d" (dy), "b" (dx), "m" (erradj) ); // 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); return; } // ogSurface::AARawLine uInt32 ogSurface::RawGetPixel(uInt32 x, uInt32 y) { uInt32 result; switch (bytesPerPix) { case 4: __asm__ __volatile__( " shl $2, %%ecx \n" // shl ecx, 2 {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx " mov (%%edi),%%eax \n" // eax,word ptr [edi] " mov %%eax, %3 \n" // mov result, eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "m" (result) // %2, %3 ); break; case 3: __asm__ __volatile__( " mov %%ecx, %%eax \n" // mov eax, ecx - adjust for pixel size " add %%ecx, %%ecx \n" // add ecx, ecx - adjust for pixel size " add %%eax, %%ecx \n" // add ecx, eax - adjust for pixel size " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx " movzwl (%%edi),%%eax \n" // edx,word ptr [edi] " xor %%eax, %%eax \n" " mov 2(%%edi), %%al \n" // mov al, [edi+2] " shl $16, %%eax \n" // shl eax, 16 " mov (%%edi), %%ax \n" // mov ax, [edi] " mov %%eax, %3 \n" // mov result, eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "m" (result) // %2, %3 ); break; case 2: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%ecx \n" // add ecx, ecx {adjust for pixel size} " add %%ecx, %%edi \n" // add edi, ecx " movzwl (%%edi),%%eax \n" // movzx edx,word ptr [edi] " mov %%eax, %0 \n" // mov result, eax : "=m" (result) : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x) // , "m" (result) // %2, %3 ); break; case 1: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx " movzbl (%%edi),%%eax \n" // movzx edx,byte ptr [edi] " mov %%eax, %3 \n" // mov result, eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "m" (result) // %2, %3 ); break; } // switch return result; } // ogSurface::RawGetPixel void ogSurface::RawSetPixel(uInt32 x, uInt32 y, uInt32 colour) { uInt32 newR, newG, newB, inverseA; uInt8 sR, sG, sB, sA; uInt8 dR, dG, dB; do { if (ogIsBlending()) { ogUnpack(colour, sR, sG, sB, sA); if (sA == 0) return; if (sA == 255) break; inverseA = 255 - sA; ogUnpack(RawGetPixel(x, y), dR, dG, dB); newR = (dR * inverseA + sR * sA) >> 8; newG = (dG * inverseA + sG * sA) >> 8; newB = (dB * inverseA + sB * sA) >> 8; colour = ogPack(newR, newG, newB, inverseA); } // if } while (false); switch (bytesPerPix) { case 4: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } " shl $2, %%ecx \n" // shl eax, 2 {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%eax, (%%edi) \n" // mov [edi], eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 3: __asm__ __volatile__( // Calculate offset, prepare the pixel to be drawn " leal (%%ecx, %%ecx, 2), %%ecx \n" // lea ecx, [ecx + ecx*2] " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%ax, (%%edi) \n" // mov [edi], ax " shr $16, %%eax \n" // shr eax, 16 " mov %%al, 2(%%edi)\n" // mov [edi+2],al : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 2: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } " add %%ecx, %%ecx \n" // add ecx, ecx {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi // " mov %3, %%eax \n" // mov eax, colour " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%ax, (%%edi) \n" // mov [edi], ax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 1: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } // " add (%%esi,%%ebx,4), %%edi \n" // add edi, [esi + ebx * 4] " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%al, (%%edi) \n" // mov [edi], al : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; } // switch return; } // 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; colour = ogPack(newR, newG, newB, inverseA); } else colour = ogPack(r, g, b, a); } while (false); switch (bytesPerPix) { case 4: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } " shl $2, %%ecx \n" // shl eax, 2 {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%eax, (%%edi) \n" // mov [edi], eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 3: __asm__ __volatile__( // Calculate offset, prepare the pixel to be drawn " leal (%%ecx, %%ecx, 2), %%ecx \n" // lea ecx, [ecx + ecx*2] " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%ax, (%%edi) \n" // mov [edi], ax " shr $16, %%eax \n" // shr eax, 16 " mov %%al, 2(%%edi)\n" // mov [edi+2],al : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 2: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } " add %%ecx, %%ecx \n" // add ecx, ecx {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi // " mov %3, %%eax \n" // mov eax, colour " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%ax, (%%edi) \n" // mov [edi], ax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 1: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } // " add (%%esi,%%ebx,4), %%edi \n" // add edi, [esi + ebx * 4] " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%al, (%%edi) \n" // mov [edi], al : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; } // switch return; } // ogSurface::RawSetPixel 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; } // ogSurface::ClipLine // 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 } // ogSurface::RawLine #if 0 void ogSurface::RawLine(uInt32 x1, uInt32 y1, uInt32 x2, uInt32 y2, uInt32 colour) { /* * ogSurface::RawLine() * * private method; draws an unclipped line from (x1,y1) to (x2,y2) * */ int32 tc; if (!ogAvail()) return; switch (BPP) { case 8: __asm__ __volatile__( " mov $1, %%ecx \n" // mov ecx, 1 " bt $15, %%eax \n" // bt eax, 15 " jnc rlxPositive8 \n" " or $-1, %%ecx \n" // or ecx, -1 " neg %%eax \n" // neg eax "rlxPositive8: \n" " add %%eax, %%eax \n" // add eax, eax " bt $15, %%ebx \n" // bt ebx, 15 " jnc rlyPositive8 \n" " neg %%edx \n" // neg edx " neg %%ebx \n" // neg ebx "rlyPositive8: \n" " add %%ebx, %%ebx \n" // add ebx, ebx " cmp %%ebx, %%eax \n" // cmp eax, ebx " jle rlyGreater8 \n" " push %%ecx \n" // push ecx " mov %%eax, %%ecx \n" // mov ecx, eax " mov %%ebx, %6 \n" // mov tc, ebx " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" // pop ecx "rlxTop8: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%al, (%%edi) \n" // mov [edi], al " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone8 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddY8 \n" " add %%edx, %%edi \n" // add edi, edx " sub %%eax, %6 \n" // sub tc, eax "rlNoAddY8: \n" " add %%ecx, %%edi \n" // add edi, ecx " add %%ebx, %6 \n" // add tc, ebx " jmp rlxTop8 \n" "rlyGreater8: \n" " push %%ecx \n" // push ecx " mov %%ebx, %%ecx \n" // mov ecx, ebx " mov %%eax, %6 \n" // mov tc, eax " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" "rlyTop8: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%al, (%%edi) \n" // mov [edi], al " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone8 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddX8 \n" " add %%ecx, %%edi \n" // add edi, ecx " sub %%ebx, %6 \n" // sub tc, ebx "rlNoAddX8: \n" " add %%edx, %%edi \n" // add edi, edx " add %%eax, %6 \n" // add tc, eax " jmp rlyTop8 \n" "rlDone8: \n" : : "D" ((uInt8 *)buffer+lineOfs[y1]+x1), // %0 "S" ((uInt8 *)buffer+lineOfs[y2]+x2), // %1 "a" (x2-x1), "b" (y2-y1), // %2, %3 "d" (xRes), "m" (colour), // %4, %5 "m" (tc) // %6 ); break; case 15: case 16: __asm__ __volatile__( " mov $1, %%ecx \n" // mov ecx, 1 " bt $15, %%eax \n" // bt eax, 15 " jnc rlxPositive16 \n" " or $-1, %%ecx \n" // or ecx, -1 " neg %%eax \n" // neg eax "rlxPositive16: \n" " add %%eax, %%eax \n" // add eax, eax " bt $15, %%ebx \n" // bt ebx, 15 " jnc rlyPositive16 \n" " neg %%edx \n" // neg edx " neg %%ebx \n" // neg ebx "rlyPositive16: \n" " add %%ebx, %%ebx \n" // add ebx, ebx " cmp %%ebx, %%eax \n" // cmp eax, ebx " jle rlyGreater16 \n" " push %%ecx \n" // push ecx " mov %%eax, %%ecx \n" // mov ecx, eax " mov %%ebx, %6 \n" // mov tc, ebx " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" // pop ecx "rlxTop16: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%ax, (%%edi) \n" // mov [edi], ax " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone16 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddY16 \n" " add %%edx, %%edi \n" // add edi, edx " sub %%eax, %6 \n" // sub tc, eax "rlNoAddY16: \n" " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ebx, %6 \n" // add tc, ebx " jmp rlxTop16 \n" "rlyGreater16: \n" " push %%ecx \n" // push ecx " mov %%ebx, %%ecx \n" // mov ecx, ebx " mov %%eax, %6 \n" // mov tc, eax " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" "rlyTop16: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%ax, (%%edi) \n" // mov [edi], ax " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone16 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddX16 \n" " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " sub %%ebx, %6 \n" // sub tc, ebx "rlNoAddX16: \n" " add %%edx, %%edi \n" // add edi, edx " add %%eax, %6 \n" // add tc, eax " jmp rlyTop16 \n" "rlDone16: \n" : : "D" ((uInt8 *)buffer+lineOfs[y1]+(x1 << 1)), // %0 "S" ((uInt8 *)buffer+lineOfs[y2]+(x2 << 1)), // %1 "a" (x2-x1), "b" (y2-y1), // %2, %3 "d" (xRes), "m" (colour), // %4, %5 "m" (tc) // %6 ); break; case 24: __asm__ __volatile__( " mov $1, %%ecx \n" // mov ecx, 1 " bt $15, %%eax \n" // bt eax, 15 " jnc rlxPositive24 \n" " or $-1, %%ecx \n" // or ecx, -1 " neg %%eax \n" // neg eax "rlxPositive24: \n" " add %%eax, %%eax \n" // add eax, eax " bt $15, %%ebx \n" // bt ebx, 15 " jnc rlyPositive24 \n" " neg %%edx \n" // neg edx " neg %%ebx \n" // neg ebx "rlyPositive24: \n" " add %%ebx, %%ebx \n" // add ebx, ebx " cmp %%ebx, %%eax \n" // cmp eax, ebx " jle rlyGreater24 \n" " push %%ecx \n" // push ecx " mov %%eax, %%ecx \n" // mov ecx, eax " mov %%ebx, %6 \n" // mov tc, ebx " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" // pop ecx "rlxTop24: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%ax, (%%edi) \n" // mov [edi], ax " shr $16, %%eax \n" // shr eax, 16 " mov %%al, 2(%%edi)\n" // mov [edi+2],al " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone24 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddY24 \n" " add %%edx, %%edi \n" // add edi, edx " sub %%eax, %6 \n" // sub tc, eax "rlNoAddY24: \n" " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ecx, %%edi \n" // add edi, ecx " add %%ebx, %6 \n" // add tc, ebx " jmp rlxTop24 \n" "rlyGreater24: \n" " push %%ecx \n" // push ecx " mov %%ebx, %%ecx \n" // mov ecx, ebx " mov %%eax, %6 \n" // mov tc, eax " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" "rlyTop24: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%ax, (%%edi) \n" // mov [edi], ax " shr $16, %%eax \n" // shr eax, 16 " mov %%al, 2(%%edi)\n" // mov [edi+2],al " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone24 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddX24 \n" " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ecx, %%edi \n" // add edi, ecx " sub %%ebx, %6 \n" // sub tc, ebx "rlNoAddX24: \n" " add %%edx, %%edi \n" // add edi, edx " add %%eax, %6 \n" // add tc, eax " jmp rlyTop24 \n" "rlDone24: \n" : : "D" ((uInt8 *)buffer+lineOfs[y1]+(x1*3)), // %0 "S" ((uInt8 *)buffer+lineOfs[y2]+(x2*3)), // %1 "a" (x2-x1), "b" (y2-y1), // %2, %3 "d" (xRes), "m" (colour), // %4, %5 "m" (tc) // %6 ); break; case 32: __asm__ __volatile__( " mov $1, %%ecx \n" // mov ecx, 1 " bt $15, %%eax \n" // bt eax, 15 " jnc rlxPositive32 \n" " or $-1, %%ecx \n" // or ecx, -1 " neg %%eax \n" // neg eax "rlxPositive32: \n" " add %%eax, %%eax \n" // add eax, eax " bt $15, %%ebx \n" // bt ebx, 15 " jnc rlyPositive32 \n" " neg %%edx \n" // neg edx " neg %%ebx \n" // neg ebx "rlyPositive32: \n" " add %%ebx, %%ebx \n" // add ebx, ebx " cmp %%ebx, %%eax \n" // cmp eax, ebx " jle rlyGreater32 \n" " push %%ecx \n" // push ecx " mov %%eax, %%ecx \n" // mov ecx, eax " mov %%ebx, %6 \n" // mov tc, ebx " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" // pop ecx "rlxTop32: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%eax, (%%edi)\n" // mov [edi], eax " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone32 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddY32 \n" " add %%edx, %%edi \n" // add edi, edx " sub %%eax, %6 \n" // sub tc, eax "rlNoAddY32: \n" " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ebx, %6 \n" // add tc, ebx " jmp rlxTop32 \n" "rlyGreater32: \n" " push %%ecx \n" // push ecx " mov %%ebx, %%ecx \n" // mov ecx, ebx " mov %%eax, %6 \n" // mov tc, eax " shr $1, %%ecx \n" // shr ecx, 1 " sub %%ecx, %6 \n" // sub tc, ecx " pop %%ecx \n" "rlyTop32: \n" " push %%eax \n" // push eax " mov %5, %%eax \n" // mov eax, colour " mov %%eax, (%%edi)\n" // mov [edi], eax " pop %%eax \n" // pop eax " cmp %%edi, %%esi \n" // cmp esi, edi " je rlDone32 \n" " cmp $0, %6 \n" // cmp tc, 0 " jl rlNoAddX32 \n" " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ecx, %%edi \n" // add edi, ecx " add %%ecx, %%edi \n" // add edi, ecx - pix size " add %%ecx, %%edi \n" // add edi, ecx " sub %%ebx, %6 \n" // sub tc, ebx "rlNoAddX32: \n" " add %%edx, %%edi \n" // add edi, edx " add %%eax, %6 \n" // add tc, eax " jmp rlyTop32 \n" "rlDone32: \n" : : "D" ((uInt8 *)buffer+lineOfs[y1]+(x1 << 2)), // %0 "S" ((uInt8 *)buffer+lineOfs[y2]+(x2 << 2)), // %1 "a" (x2-x1), "b" (y2-y1), // %2, %3 "d" (xRes), "m" (colour), // %4, %5 "m" (tc) // %6 ); break; } // switch return; } // ogSurface::RawLine #endif 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 =((unsigned char *)(src.buffer)+x1*(src.bytesPerPix)); lineOfs=((uInt32 *)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; return true; } // 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 return; } // ogSurface::ogArc bool ogSurface::ogAvail(void) { return ((buffer != NULL) && (lineOfs != NULL)); } // ogSurface::ogAvail static int32 calculate(float mu, int32 p0, int32 p1, int32 p2, int32 p3) { float 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 void ogSurface::ogBSpline(uInt32 numPoints, ogPoint2d* points, uInt32 segments, uInt32 colour) { float mu, mudelta; int32 x1, y1, x2, y2; uInt32 n, h; if (points == NULL) return; if ((numPoints < 4) || (numPoints > 255) || (segments == 0)) return; mudelta = 1.0/segments; for (n=3; n<numPoints; n++) { mu = 0.0; x1=calculate(mu,points[n-3].x,points[n-2].x, points[n-1].x,points[n].x); y1=calculate(mu,points[n-3].y,points[n-2].y, points[n-1].y,points[n].y); mu += mudelta; for (h=0; h<segments; h++) { x2=calculate(mu,points[n-3].x,points[n-2].x, points[n-1].x,points[n].x); y2=calculate(mu,points[n-3].y,points[n-2].y, points[n-1].y,points[n].y); ogLine(x1, y1, x2, y2, colour); mu += mudelta; x1 = x2; y1 = y2; } // for h } // for n return; } // ogSurface::ogBSpline void ogSurface::ogCircle(int32 xCenter, int32 yCenter, uInt32 radius, uInt32 colour) { int32 x, y, d; x = 0; y = radius; d = 2*(1-radius); while (y >= 0) { ogSetPixel(xCenter+x, yCenter+y, colour); ogSetPixel(xCenter+x, yCenter-y, colour); ogSetPixel(xCenter-x, yCenter+y, colour); ogSetPixel(xCenter-x, yCenter-y, colour); if (d + y > 0) { --y; d -= 2*y+1; } // if if (x > d) { ++x; d += 2*x+1; } // if } // while return; } // ogSurface::ogCircle void ogSurface::ogClear(uInt32 colour) { uInt32 height = 0; uInt32 xx, yy; uInt8 r, g, b, a; if (!ogAvail()) return; do { if (ogIsBlending()) { ogUnpack(colour, r, g, b, a); if (a == 0) return; if (a == 255) break; for (yy = 0; yy <= maxY; yy++) for (xx = 0; xx <= maxX; xx++) RawSetPixel(xx, yy, r, g, b, a); return; } // if } while (false); __asm__ __volatile__("cld\n"); switch (bytesPerPix) { case 4: __asm__ __volatile__( " add (%%esi), %%edi \n" // add edi, [esi] " mov %%ecx, %%esi \n" // mov esi, ecx " inc %%edx \n" // inc edx (maxX) " inc %%ebx \n" // inc ebx (maxY) " mov %%edx, %%ecx \n" // mov ecx, edx " shl $2, %%ecx \n" // shl ecx, 2 " sub %%ecx, %%esi \n" // sub esi, ecx // adjust for pix size "loop32: \n" " mov %%edx, %%ecx \n" // mov ecx, edx " rep \n" " stosl \n" " add %%esi, %%edi \n" // add edi, esi " dec %%ebx \n" " jnz loop32 \n" : : "D" (buffer), "S" (lineOfs), // %0, %1 "a" (colour), "b" (maxY), // %2, %3 "c" (xRes), "d" (maxX) // %4, %5 ); break; case 3: __asm__ __volatile__( " add (%%esi), %%edi \n" // add edi, [esi] " mov %%ecx, %%esi \n" // mov esi, ecx " inc %%edx \n" // inc edx (maxX) " inc %%ebx \n" // inc ebx (maxY) " sub %%edx, %%esi \n" // sub esi, edx // adjust for pix size " mov %%ebx, %6 \n" // mov height, ebx " sub %%edx, %%esi \n" // sub esi, edx // adjust for pix size " mov %%eax, %%ebx \n" // mov ebx, eax " sub %%edx, %%esi \n" // sub esi, edx // adjust for pix size " shr $16, %%ebx \n" // shr ebx, 16 "oloop24: \n" " mov %%edx, %%ecx \n" // mov ecx, edx "iloop24: \n" " mov %%ax,(%%edi) \n" // mov [edi],ax " movb %%bl,2(%%edi) \n" // mov [edi+2],bl " add $3, %%edi \n" // add edi, 3 " dec %%ecx \n" // dec ecx " jnz iloop24 \n" " add %%esi, %%edi \n" // add edi, esi " decl %6 \n" // dec height " jnz oloop24 \n" : : "D" (buffer), "S" (lineOfs), // %0, %1 "a" (colour), "b" (maxY), // %2, %3 "c" (xRes), "d" (maxX), // %4, %5 "m" (height) // %6 ); break; case 2: __asm__ __volatile__( " add (%%esi), %%edi \n" // add edi, [esi] " mov %%ecx, %%esi \n" // mov esi, ecx " inc %%edx \n" // inc edx (maxX) " inc %%ebx \n" // inc ebx (maxY) " sub %%edx, %%esi \n" // sub esi, edx " sub %%edx, %%esi \n" // sub esi, edx // adjust for pix size " mov %%ax, %%cx \n" // mov cx, ax " shl $16, %%eax \n" // shl eax, 16 " mov %%cx, %%ax \n" // mov ax, cx "loop16: \n" " mov %%edx, %%ecx \n" // mov ecx, edx " shr $1, %%ecx \n" // shr ecx, 1 " rep \n" " stosl \n" " jnc noc16 \n" " stosw \n" "noc16: \n" " add %%esi, %%edi \n" // add edi, esi " dec %%ebx \n" " jnz loop16 \n" : : "D" (buffer), "S" (lineOfs), // %0, %1 "a" (colour), "b" (maxY), // %2, %3 "c" (xRes), "d" (maxX) // %4, %5 ); break; case 1: __asm__ __volatile__( " add (%%esi), %%edi \n" // add edi, [esi] " mov %%ecx, %%esi \n" // mov esi, ecx " inc %%edx \n" // inc edx (maxY) " inc %%ebx \n" // inc ebx (maxX) " sub %%edx, %%esi \n" // sub esi, edx " mov %%al, %%ah \n" // mov ah, al " mov %%ax, %%cx \n" // mov cx, ax " shl $16, %%eax \n" // shl eax, 16 " mov %%cx, %%ax \n" // mov ax, cx "loop8: \n" " push %%edx \n" " mov %%edx, %%ecx \n" // mov ecx, edx " and $3, %%edx \n" // and edx, 3 " shr $2, %%ecx \n" // shr ecx, 2 " rep \n" " stosl \n" " mov %%edx, %%ecx \n" // mov ecx, edx " rep \n" " stosb \n" " pop %%edx \n" " add %%esi, %%edi \n" // add edi, esi " dec %%ebx \n" " jnz loop8 \n" : : "D" (buffer), "S" (lineOfs), // %0, %1 "a" (colour), "b" (maxY), // %2, %3 "c" (xRes), "d" (maxX) // %4, %5 ); break; } // switch return; } // ogSurface::ogClear bool ogSurface::ogClone(ogSurface& src) { bool created; ogPixelFmt pixFmt; if (src.dataState == ogNone) { ogSetLastError(ogNoSurface); return false; } // if src.ogGetPixFmt(pixFmt); created = ogCreate(src.maxX+1, src.maxY+1, pixFmt); if (!created) return false; *attributes = *src.attributes; ogCopyPalette(src); ogCopy(src); return true; } // 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 = new ogPixCon(srcPixFmt, dstPixFmt); for (yy = 0; yy < yCount; yy++) for (xx = 0; xx < xCount; xx++) RawSetPixel(xx, yy, pc->ConvPix(src.RawGetPixel(xx, yy))); delete pc; } // 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 } // 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; ogPixCon * pc; 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) { xx = sX1; sX1= sX2; sX2= xx; } // if if (sY1 > sY2) { yy = sY1; sY1= sY2; sY2= yy; } // 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 } // 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); pc = new ogPixCon(srcPixFmt, dstPixFmt); // allocate the pixel converter if (pc == NULL) return; 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))); } // for xx delete pc; // destroy the pixel converter } // 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 } // 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( (uInt8*)buffer+lineOfs[dy]+dx*bytesPerPix, // dest src, // src size); // size return; } // 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; } // 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. */ void * newBuffer = NULL; uInt32 * newLineOfs = NULL; ogRGBA8 * newPal = NULL; ogAttributes* newAttributes = NULL; uInt32 newBSize; uInt32 newLSize; uInt32 yy; bool status = false; switch (_pixFormat.BPP) { case 8: case 15: case 16: case 24: case 32: 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 = malloc(newBSize); #endif newLineOfs = new uInt32[_yRes]; newPal = new ogRGBA8[256]; newAttributes = new ogAttributes(); 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(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 (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 = ~(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; } // 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) { float 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<int32>(mu3*tX1+mu2*tX2+mu*tX3+x1 +0.5f); yEnd = static_cast<int32>(mu3*tY1+mu2*tY2+mu*tY3+y1 +0.5f); ogLine(xStart, yStart, xEnd, yEnd, colour); mu += mudelta; xStart = xEnd; yStart = yEnd; } // for return; } // ogSurface::ogCubicBezierCurve void ogSurface::ogCurve(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uInt32 segments, uInt32 colour) { int64 ex, ey, fx, fy; int64 t1, t2; if (segments<2) segments=2; else if (segments>128) segments=128; x2 = (x2*2)-((x1+x3)/2); y2 = (y2*2)-((y1+y3)/2); ex = ((int64)(x2-x1) << 17) / segments; ey = ((int64)(y2-y1) << 17) / (int64)segments; fx = ((int64)(x3-(2*x2)+x1) << 16) / (segments*segments); fy = ((int64)(y3-(2*y2)+y1) << 16) / (int64)(segments*segments); while (--segments > 0) { t1 = x3; t2 = y3; x3 = ((int64)((fx*segments+ex)*segments) / 65536L)+x1; y3 = ((int64)((fy*segments+ey)*segments) / 65536L)+y1; ogLine(t1, t2, x3, y3, colour); } // while ogLine(x3, y3, x1, y1, colour); return; } // 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 return; } // ogSurface::ogFillCircle #if 0 !-/* Scan converts an edge from (X1,Y1) to (X2,Y2), not including the !- * point at (X2,Y2). This avoids overlapping the end of one line with !- * the start of the next, and causes the bottom scan line of the !- * polygon not to be drawn. If SkipFirst != 0, the point at (X1,Y1) !- * isn't drawn. For each scan line, the pixel closest to the scanned !- * line without being to the left of the scanned line is chosen !- */ !-static void index_forward(int32 & index, uInt32 numPoints) { !- index = (index + 1) % numPoints; !- return; !-} // index_forward !- !-static void index_backward(int32 & index, uInt32 numPoints) { !- index = (index - 1 + numPoints) % numPoints; !- return; !-} // index_forward !- !-static void index_move(int32 & index, uInt32 numPoints, int32 direction) { !- if (direction > 0) !- index_forward(index, numPoints); !- else !- index_backward(index, numPoints); !- return; !-} // index_move !- !-static void scanEdge(int32 x1, int32 y1, int32 x2, int32 y2, !- uInt32 & eIdx, int32 * xList) { !- int32 y, deltaX, deltaY; !- float inverseSlope; !- !- deltaX = x2 - x1; !- deltaY = y2 - y1; !- if (deltaY <= 0) return; !- inverseSlope = deltaX / deltaY; !- !- // Store the X coordinate of the pixel closest to but not to the !- // left of the line for each Y coordinate between Y1 and Y2, not !- // including Y2 !- y = y1; !- do { !- xList[eIdx] = x1+ (int32)(0.5f+((y-y1)*inverseSlope)); !- y++; !- eIdx++; !- } while (y<y2); !- return; !-} // scanEdge !- !-void !-ogSurface::FillConvexPolygon(uInt32 numPoints, ogPoint2d* polyPoints, uInt32 colour) { !- int32 i, minIndexL, maxIndex, minIndexR, temp; !- int32 minPointY, maxPointY, leftEdgeDir; !- int32 topIsFlat, nextIndex, curIndex, prevIndex; !- int32 deltaXN, deltaYN, deltaXP, deltaYP; !- ogHLineList workingHLineList; !- uInt32 edgePointIdx; !- uInt32 vetexIdx; !- !- if (numPoints<2) return; !- minIndexL = maxIndex = 0; !- minPointY = maxPointY = polyPoints[0].y; !- for (i = 1; i < (int32)numPoints; i++) { !- if (polyPoints[i].y < minPointY) { !- minIndexL = i; !- minPointY = polyPoints[i].y; // new top !- } else if (polyPoints[i].y > maxPointY) { !- maxIndex = i; !- maxPointY = polyPoints[i].y; // new bottom !- } // else if !- } // for !- !- if (minPointY == maxPointY) return; !- !- // scan in ascending order to find the last top-edge point !- minIndexR = minIndexL; !- while (polyPoints[minIndexR].y == minPointY) index_forward(minIndexR, numPoints); !- index_backward(minIndexR, numPoints); // back up to last top-edge point !- !- // now scan in descending order to find the first top-edge point !- while (polyPoints[minIndexL].y == minPointY) index_backward(minIndexL, numPoints); !- index_forward(minIndexL, numPoints); !- !- // figure out which direction through the vertex list from the top !- // vertex is the left edge and which is the right !- leftEdgeDir = -1; !- !- topIsFlat = (polyPoints[minIndexL].x==polyPoints[minIndexR].x) ? 0 : 1; !- if (topIsFlat==1) { !- if (polyPoints[minIndexL].x > polyPoints[minIndexR].x) { !- leftEdgeDir = 1; !- temp = minIndexL; !- minIndexL = minIndexR; !- minIndexR = temp; !- } !- } else { !- // Point to the downward end of the first line of each of the !- // two edges down from the top !- nextIndex = minIndexR; !- index_forward(nextIndex, numPoints); !- prevIndex = minIndexL; !- index_forward(prevIndex, numPoints); !- !- deltaXN = polyPoints[nextIndex].x - polyPoints[minIndexL].x; !- deltaYN = polyPoints[nextIndex].y - polyPoints[minIndexL].y; !- deltaXP = polyPoints[prevIndex].x - polyPoints[minIndexL].x; !- deltaYP = polyPoints[prevIndex].y - polyPoints[minIndexL].y; !- if (deltaXN * deltaYP - deltaYN * deltaXP < 0) { !- leftEdgeDir = 1; !- temp = minIndexL; !- minIndexL = minIndexR; !- minIndexR = temp; !- } // if !- } // else !- !- /* Set the # of scan lines in the polygon, skipping the bottom edge !- * and also skipping the top vertex if the top isn't flat because !- * in that case the top vertex has a right edge component, and set !- * the top scan line to draw, which is likewise the second line of !- * the polygon unles the top if flat !- */ !- !- workingHLineList.length = maxPointY - minPointY; !- if (workingHLineList.length <= 0) return; !- workingHLineList.yStart = minPointY; !- !- // get memory in which to srote the line list we generate !- workingHLineList.xLeft = workingHLineList.xRight = NULL; !- if ((workingHLineList.xLeft = new int32[workingHLineList.length]) == NULL) return; !- if ((workingHLineList.xRight = new int32[workingHLineList.length]) == NULL) { !- delete workingHLineList.xLeft; !- return; !- } !- memset(workingHLineList.xLeft,0,workingHLineList.length*sizeof(int32)); !- memset(workingHLineList.xRight,0,workingHLineList.length*sizeof(int32)); !- !- // scan the left edge and store the boundary points int he list !- // Initial pointer for storing scan converted left-edge coords !- edgePointIdx = 0; !- !- // start from the top of the left edge !- curIndex = prevIndex = minIndexL; !- !- do { !- index_move(curIndex, numPoints, leftEdgeDir); !- scanEdge(polyPoints[prevIndex].x, !- polyPoints[prevIndex].y, !- polyPoints[curIndex].x, !- polyPoints[curIndex].y, !- edgePointIdx, !- workingHLineList.xLeft); !- prevIndex = curIndex; !- } while (curIndex != maxIndex); !- !- edgePointIdx = 0; !- curIndex = prevIndex = minIndexR; !- // Scan convert the right edge, top to bottom. X coordinates are !- // adjusted 1 to the left, effectively causing scan conversion of !- // the nearest points to the left of but not exactly on the edge } !- do { !- index_move(curIndex, numPoints, -leftEdgeDir); !- scanEdge(polyPoints[prevIndex].x, !- polyPoints[prevIndex].y, !- polyPoints[curIndex].x, !- polyPoints[curIndex].y, !- edgePointIdx, !- workingHLineList.xRight); !- prevIndex = curIndex; !- } while (curIndex != maxIndex); !- !- ogPolygon(numPoints, polyPoints, colour); !- !- for (i = 0; i < workingHLineList.length; i++) { !- HLine(workingHLineList.xLeft[i], workingHLineList.xRight[i], !- workingHLineList.yStart+i, colour); !- } // for !- !- ogPolygon(numPoints, polyPoints, colour); !- !- delete workingHLineList.xLeft; !- delete workingHLineList.xRight; !- !- return; !-} // ogSurface::FillConvexPolygon #endif 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; return; } // 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; return; } // 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); return; } // ogSurface::ogFillTriangle uInt32 ogSurface::ogGetAlpha(void) { if (attributes != NULL) return attributes->defaultAlpha; else return 255L; } // ogSurface::ogGetAlpha ogErrorCode ogSurface::ogGetLastError(void) { ogErrorCode tmp = lastError; lastError = ogOK; return tmp; } // ogSurface::ogGetLastError void ogSurface::ogGetPalette(ogRGBA8 _pal[256]) { memcpy(_pal, pal, sizeof(_pal)); return; } // 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; return; } // ogSurface::ogGetPixFmt uInt32 ogSurface::ogGetPixel(int32 x, int32 y) { uInt32 result; if (!ogAvail()) return ogGetTransparentColor(); if (((uInt32)x > maxX) || ((uInt32)y > maxY)) return ogGetTransparentColor(); switch (bytesPerPix) { case 4: __asm__ __volatile__( " shl $2, %%ecx \n" // shl ecx, 2 {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx " mov (%%edi),%%eax \n" // eax,word ptr [edi] " mov %%eax, %3 \n" // mov result, eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "m" (result) // %2, %3 ); break; case 3: __asm__ __volatile__( " leal (%%ecx, %%ecx, 2), %%ecx \n" // lea ecx, [ecx + ecx*2] // " mov %%ecx, %%eax \n" // mov eax, ecx - adjust for pixel size // " add %%ecx, %%ecx \n" // add ecx, ecx - adjust for pixel size // " add %%eax, %%ecx \n" // add ecx, eax - adjust for pixel size " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx " movzwl (%%edi),%%eax \n" // edx,word ptr [edi] " xor %%eax, %%eax \n" " mov 2(%%edi), %%al \n" // mov al, [edi+2] " shl $16, %%eax \n" // shl eax, 16 " mov (%%edi), %%ax \n" // mov ax, [edi] " mov %%eax, %3 \n" // mov result, eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "m" (result) // %2, %3 ); break; case 2: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%ecx \n" // add ecx, ecx {adjust for pixel size} " add %%ecx, %%edi \n" // add edi, ecx " movzwl (%%edi),%%eax \n" // movzx edx,word ptr [edi] " mov %%eax, %0 \n" // mov result, eax : "=m" (result) : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x) // , "m" (result) // %2, %3 ); break; case 1: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx " movzbl (%%edi),%%eax \n" // movzx edx,byte ptr [edi] " mov %%eax, %3 \n" // mov result, eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "m" (result) // %2, %3 ); break; } // switch return result; } // ogSurface::ogGetPixel void * ogSurface::ogGetPtr(uInt32 x, uInt32 y) { // return (Avail() ? ( (uInt8*)buffer+(lineOfs[y]+x*((BPP+7) >> 3)) ) : NULL ); return ((uInt8*)buffer+(lineOfs[y]+x*bytesPerPix)); } // ogSurface::ogGetPtr uInt32 ogSurface::ogGetTransparentColor(void) { if (attributes != NULL) return attributes->transparentColor; else return 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 return; } // 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 __asm__ __volatile__("cld \n"); switch (bytesPerPix) { case 4: __asm__ __volatile__( " sub %%ebx, %%ecx \n" // sub ecx, ebx " add %%esi, %%edi \n" // add edi, esi " inc %%ecx \n" " shl $2, %%ebx \n" // shl ebx, 2 " add %%ebx, %%edi \n" // add edi, ebx " rep \n" " stosl \n" : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "a" (colour), "b" (x1), // %2, %3 "c" (x2) // %4 ); break; case 3: __asm__ __volatile__( " sub %%ebx, %%ecx \n" // sub ecx, ebx " add %%esi, %%edi \n" // add edi, esi " add %%ebx, %%ebx \n" // add ebx, ebx - pix size " inc %%ecx \n" // inc ecx " add %%edx, %%ebx \n" // add ebx, edx - pix size " add %%ebx, %%edi \n" // add edi, ebx " mov %%eax, %%ebx \n" // mov ebx, eax " shr $16, %%ebx \n" // shr ebx, 16 "hLlop24: \n" " mov %%ax, (%%edi) \n" // mov [edi], ax " mov %%bl, 2(%%edi)\n" // mov [edi+2], bl " add $3, %%edi \n" // add edi, 3 " dec %%ecx \n" // dec ecx " jnz hLlop24 \n" : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "a" (colour), "b" (x1), // %2, %3 "c" (x2), "d" (x1) // %4, %5 ); break; case 2: __asm__ __volatile__( " sub %%ebx, %%ecx \n" // sub ecx, ebx " add %%ebx, %%ebx \n" // add ebx, ebx - pix size " inc %%ecx \n" // inc ecx " add %%ebx, %%edi \n" // add edi, ebx " add %%esi, %%edi \n" // add edi, esi " xor %%edx, %%edx \n" // xor edx, edx " mov %%ax, %%dx \n" // mov dx, ax " shl $16, %%eax \n" // shl eax, 16 " add %%edx, %%eax \n" // add eax, edx " shr $1, %%ecx \n" // shr ecx, 1 " rep \n" " stosl \n" " jnc hLnoc16 \n" " stosw \n" "hLnoc16: \n" : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "a" (colour), "b" (x1), // %2, %3 "c" (x2) // %4 ); break; case 1: __asm__ __volatile__( " add %%ebx, %%edi \n" // add edi, ebx " add %%esi, %%edi \n" // add edi, esi " and $0xff, %%eax \n" // and eax, 0ffh " sub %%ebx, %%ecx \n" // sub ecx, ebx " mov %%al, %%ah \n" // mov ah, al " inc %%ecx \n" // inc ecx " mov %%eax, %%ebx \n" // mov ebx, eax " shl $16, %%ebx \n" // shl ebx, 16 " add %%ebx, %%eax \n" // add eax, ebx " mov %%ecx, %%edx \n" // mov edx, ecx " mov $4, %%ecx \n" // mov ecx, 4 " sub %%edi, %%ecx \n" // sub ecx, edi " and $3, %%ecx \n" // and ecx, 3 " sub %%ecx, %%edx \n" // sub edx, ecx " jle LEndBytes \n" " rep \n" " stosb \n" " mov %%edx, %%ecx \n" // mov ecx, edx " and $3, %%edx \n" // and edx, 3 " shr $2, %%ecx \n" // shr ecx, 2 " rep \n" " stosl \n" "LEndBytes: \n" " add %%edx, %%ecx \n" // add ecx, edx " rep \n" " stosb \n" : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "a" (colour), "b" (x1), // %2, %3 "c" (x2) ); break; } // switch return; } // ogSurface::ogHLine bool ogSurface::ogIsAntiAliasing(void) { if (attributes != NULL) return attributes->antiAlias; else return false; } // ogSurface::ogIsAntiAliasing bool ogSurface::ogIsBlending(void) { if (attributes != NULL) return attributes->blending; else return false; } // 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; } // ogSurface::ogLine bool ogSurface::ogLoadPalette(const char *palfile) { ogRGBA8 oldPalette[256]; #ifdef __UBIXOS_KERNEL__ fileDescriptor *f; #else FILE *f; #endif uInt32 lresult; bool result; if (!fileExists(palfile)) { ogSetLastError(ogFileNotFound); return false; } // if 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); if ((f = fopen(palfile, "rb")) == NULL) return false; lresult = fread(pal, sizeof(ogRGBA8), 256, f); result = (lresult == 256); if (!result) { ogSetLastError(ogFileReadError); ogSetPalette(oldPalette); // memcpy(pal, &oldPalette, sizeof(ogRGBA8)*256); } // if fclose(f); return result; } // ogSurface::ogLoadPalette void ogSurface::ogPolygon(uInt32 numPoints, ogPoint2d* polyPoints, uInt32 colour) { uInt32 count; if (numPoints == 1) ogSetPixel(polyPoints[0].x, polyPoints[0].y, colour); else for (count = 0; count < numPoints; count++) ogLine(polyPoints[count].x, polyPoints[count].y, polyPoints[(count+1) % numPoints].x, polyPoints[(count+1) % numPoints].y, colour); return; } // ogSurface::ogPolygon void ogSurface::ogRect(int32 x1, int32 y1, int32 x2, int32 y2, uInt32 colour) { int32 tmp; 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) { 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 return; } // ogSurface::ogRect uInt32 ogSurface::ogPack(uInt8 red, uInt8 green, uInt8 blue) { uInt32 idx, colour; uInt32 rd, gd, bd, dist, newdist; 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: colour = 0; dist = 255+255+255; for (idx = 0; idx <= 255; idx++) { rd = abs(red-pal[idx].red); gd = abs(green-pal[idx].green); bd = abs(blue-pal[idx].blue); newdist = rd + gd + bd; if (newdist < dist) { dist = newdist; colour = idx; } // if } // for break; } // switch return colour; } // ogSurface::ogPack uInt32 ogSurface::ogPack(uInt8 red, uInt8 green, uInt8 blue, uInt8 alpha) { uInt32 idx, colour; uInt32 rd, gd, bd, dist, newdist; 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: colour = 0; dist = 255+255+255; for (idx = 0; idx <= 255; idx++) { rd = abs(red-pal[idx].red); gd = abs(green-pal[idx].green); bd = abs(blue-pal[idx].blue); newdist = rd + gd + bd; if (newdist < dist) { dist = newdist; colour = idx; } // if } // for break; } // switch return colour; } // ogSurface::ogPack bool ogSurface::ogSavePalette(const char *palfile) { #ifdef __UBIXOS_KERNEL__ fileDescriptor *f; #else FILE * f; #endif uInt32 lresult; if (pal == NULL) { ogSetLastError(ogNoPalette); return false; } if ((f = fopen(palfile, "wb"))==NULL) return false; lresult = fwrite(pal,sizeof(ogRGBA8),256,f); fclose(f); if (lresult == 256) return true; else { ogSetLastError(ogFileWriteError); return false; } // else } // ogSurface::ogSavePal 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; return; } // ogSurface::ogScaleBuf uInt32 ogSurface::ogSetAlpha(uInt32 _newAlpha) { uInt32 tmp; if (attributes != NULL) { tmp = attributes->defaultAlpha; attributes->defaultAlpha = _newAlpha; return tmp; } else return _newAlpha; } // ogSurface::ogSetAlpha bool ogSurface::ogSetAntiAliasing(bool _antiAliasing) { bool tmp; if (attributes != NULL) { tmp = attributes->antiAlias; attributes->antiAlias = _antiAliasing; return tmp; } else return _antiAliasing; } // ogSurface::ogSetAntiAliasing bool ogSurface::ogSetBlending(bool _blending) { bool tmp; if (attributes != NULL) { tmp = attributes->blending; attributes->blending = _blending; return tmp; } else return _blending; } // ogSurface::ogSetBlending; ogErrorCode ogSurface::ogSetLastError(ogErrorCode latestError) { ogErrorCode tmp = lastError; lastError = latestError; return tmp; } // ogSurface::ogSetLastError void ogSurface::ogSetPalette(const ogRGBA8 newPal[256]) { if (pal == NULL) return; memcpy(pal, newPal, sizeof(pal)); return; } // ogSurface::ogSetPalette void ogSurface::ogSetPixel(int32 x, int32 y, uInt32 colour) { uInt32 newR, newG, newB, inverseA; uInt8 sR, sG, sB, sA; uInt8 dR, dG, dB; if (!ogAvail()) return; if (((uInt32)x > maxX) || ((uInt32)y > maxY)) return; do { if (ogIsBlending()) { ogUnpack(colour, sR, sG, sB, sA); if (sA == 0) return; if (sA == 255) break; inverseA = 255 - sA; ogUnpack(RawGetPixel(x, y), dR, dG, dB); newR = (dR * inverseA + sR * sA) >> 8; newG = (dG * inverseA + sG * sA) >> 8; newB = (dB * inverseA + sB * sA) >> 8; colour = ogPack(newR, newG, newB, inverseA); } // if } while (false); switch (bytesPerPix) { case 4: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } " shl $2, %%ecx \n" // shl eax, 2 {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%eax, (%%edi) \n" // mov [edi], eax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 3: __asm__ __volatile__( // Calculate offset, prepare the pixel to be drawn " leal (%%ecx, %%ecx, 2), %%ecx \n" // lea ecx, [ecx + ecx*2] " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%ax, (%%edi) \n" // mov [edi], ax " shr $16, %%eax \n" // shr eax, 16 " mov %%al, 2(%%edi)\n" // mov [edi+2],al : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 2: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } " add %%ecx, %%ecx \n" // add ecx, ecx {adjust for pixel size} " add %%esi, %%edi \n" // add edi, esi // " mov %3, %%eax \n" // mov eax, colour " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%ax, (%%edi) \n" // mov [edi], ax : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; case 1: __asm__ __volatile__( // { Calculate offset, prepare the pixel to be drawn } // " add (%%esi,%%ebx,4), %%edi \n" // add edi, [esi + ebx * 4] " add %%esi, %%edi \n" // add edi, esi " add %%ecx, %%edi \n" // add edi, ecx // { Draw the pixel } " mov %%al, (%%edi) \n" // mov [edi], al : : "D" (buffer), "S" (lineOfs[y]), // %0, %1 "c" (x), "a" (colour) // %2, %3 ); break; } // switch return; } // 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); return; } // ogSurface::ogSetPixel 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; return; } // 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(); return; } // ogSurface::ogSetPalette uInt32 ogSurface::ogSetTransparentColor(uInt32 colour) { uInt32 tmp = 0; if (attributes != NULL) { tmp = attributes->transparentColor & ogGetAlphaMasker(); attributes->transparentColor = colour & ogGetAlphaMasker(); } // if return tmp; } // 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; float part, t, xx, yy, tmp; float * zc; float * dx; float * dy; float * u; float * wndX1; float * wndY1; float * px; float * py; bool runOnce; if ((numPoints < 2) || (points == NULL)) return; zc = new float[numPoints]; dx = new float[numPoints]; dy = new float[numPoints]; u = new float[numPoints]; wndX1 = new float[numPoints]; wndY1 = new float[numPoints]; px = new float[numPoints]; py = new float[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<int32>(part+0.5f); part = zc[i]-(((zc[i]-zc[i+1])/segments)*j); t = (part-zc[i])/u[i]; part = t*points[i+1].x+(1.0-t)*points[i].x+u[i]*u[i]*(f(t)*px[i+1]+ f(1.0-t)*px[i])/6.0; // x = Round(part); x = static_cast<int32>(part+0.5f); if (runOnce) ogLine(oldX, oldY, x, y, colour); else runOnce = true; oldX = x; oldY = y; } // for j } // for i } while (false); delete [] py; delete [] px; delete [] wndY1; delete [] wndX1; delete [] u; delete [] dy; delete [] dx; delete [] zc; return; } // 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); return; } // 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 += OG_MASKS[redShifter]; if (green != 0) green += OG_MASKS[greenShifter]; if (blue != 0) blue += 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 return; } // 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 += OG_MASKS[redShifter]; if (green != 0) green += OG_MASKS[greenShifter]; if (blue != 0) blue += OG_MASKS[blueShifter]; if (alphaShifter != 8) { alpha = (colour >> alphaFieldPosition) << alphaShifter; if (alpha != 0) alpha += 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; } // ogSurface::ogUnpack void ogSurface::ogVFlip(void) { uInt32 height; if (!ogAvail()) return; switch (bytesPerPix) { case 4: __asm__ __volatile__( " add %%edi, %%esi \n" // add esi, edi "vf32lop: \n" " push %%esi \n" // push esi " push %%edi \n" // push edi "vf32lop2: \n" " mov (%%edi),%%eax \n" // mov eax, [edi] " mov (%%esi),%%ecx \n" // mov ecx, [esi] " mov %%eax,(%%esi) \n" // mov [esi], eax " mov %%ecx,(%%edi) \n" // mov [edi], ecx " add $4, %%edi \n" // add edi, 4 " sub $4, %%esi \n" // sub esi, 4 " cmp %%esi, %%edi \n" // cmp edi, esi " jbe vf32lop2 \n" " pop %%edi \n" // pop edi " pop %%esi \n" // pop esi " add %%ebx, %%esi \n" // add esi, ebx " add %%ebx, %%edi \n" // add edi, ebx " dec %%edx \n" " jnz vf32lop \n" : : "D" ((char *)buffer+lineOfs[0]), "S" (maxX*4), // %0, %1 "b" (xRes), "d" (maxY+1) // %2, %3 ); break; case 3: height = maxY + 1; __asm__ __volatile__( " add %%edi, %%esi \n" // add esi, edi "vf24lop: \n" " push %%esi \n" // push esi " push %%edi \n" // push edi "vf24lop2: \n" " mov (%%edi),%%ax \n" // mov ax, [edi] " mov 2(%%edi),%%dl \n" // mov dl, [edi+2] " mov (%%esi),%%cx \n" // mov cx, [esi] " mov 2(%%esi),%%dh \n" // mov dh, [esi+2] " mov %%ax,(%%esi) \n" // mov [esi], ax " mov %%dl,2(%%esi) \n" // mov [esi+2], dl " mov %%cx,(%%edi) \n" // mov [edi], cx " mov %%dh,2(%%edi) \n" // mov [edi+2], dh " add $3, %%edi \n" // add edi, 3 " sub $3, %%esi \n" // sub esi, 3 " cmp %%esi, %%edi \n" // cmp edi, esi " jbe vf24lop2 \n" " pop %%edi \n" // pop edi " pop %%esi \n" // pop esi " add %%ebx, %%esi \n" // add esi, ebx " add %%ebx, %%edi \n" // add edi, ebx " decl %3 \n" // dec height " jnz vf24lop \n" : : "D" ((char *)buffer+lineOfs[0]), "S" (maxX*3), // %0, %1 "b" (xRes), "m" (height) // %2, %3 ); break; case 2: __asm__ __volatile__( " add %%edi, %%esi \n" // add esi, edi "vf16lop: \n" " push %%esi \n" // push esi " push %%edi \n" // push edi "vf16lop2: \n" " mov (%%edi),%%ax \n" // mov ax, [edi] " mov (%%esi),%%cx \n" // mov cx, [esi] " mov %%ax,(%%esi) \n" // mov [esi], ax " mov %%cx,(%%edi) \n" // mov [edi], cx " add $2, %%edi \n" // add edi, 2 " sub $2, %%esi \n" // sub esi, 2 " cmp %%esi, %%edi \n" // cmp edi, esi " jbe vf16lop2 \n" " pop %%edi \n" // pop edi " pop %%esi \n" // pop esi " add %%ebx, %%esi \n" // add esi, ebx " add %%ebx, %%edi \n" // add edi, ebx " dec %%edx \n" " jnz vf16lop \n" : : "D" ((char *)buffer+lineOfs[0]), "S" (maxX*2), // %0, %1 "b" (xRes), "d" (maxY+1) // %2, %3 ); break; case 1: __asm__ __volatile__( " add %%edi, %%esi \n" // add esi, edi "vf8lop: \n" " push %%esi \n" // push esi " push %%edi \n" // push edi "vf8lop2: \n" " mov (%%edi),%%al \n" // mov al, [edi] " mov (%%esi),%%ah \n" // mov ah, [esi] " mov %%al,(%%esi) \n" // mov [esi], al " mov %%ah,(%%edi) \n" // mov [edi], ah " inc %%edi \n" // inc edi " dec %%esi \n" // dec esi " cmp %%esi, %%edi \n" // cmp edi, esi " jbe vf8lop2 \n" " pop %%edi \n" // pop edi " pop %%esi \n" // pop esi " add %%ebx, %%esi \n" // add esi, ebx " add %%ebx, %%edi \n" // add edi, ebx " dec %%edx \n" " jnz vf8lop \n" : : "D" ((char *)buffer+lineOfs[0]), "S" (maxX), // %0, %1 "b" (xRes), "d" (maxY+1) // %2, %3 ); break; } // switch return; } // 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 switch (bytesPerPix) { case 4: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " shl $2, %%ebx \n" // shl ebx, 2 - pix size " mov %6, %%esi \n" // mov esi, y1 " sub %%esi, %%ecx \n" // sub ecx, esi " add %%ebx, %%edi \n" // add edi, ebx " inc %%ecx \n" // inc ecx "vLlop32: \n" " mov %%eax, (%%edi)\n" // mov [edi], eax " add %%edx, %%edi \n" // add edi, edx " dec %%ecx \n" // dec ecx " jnz vLlop32 \n" : : "D" (buffer), "S" (lineOfs[y1]), // %0, %1 "a" (colour), "b" (x), // %2, %3 "c" (y2), "d" (xRes), // %4, %5 "m" (y1) // %6 ); break; case 3: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " mov %%ebx, %%esi \n" // mov esi, ebx - pix size " add %%ebx, %%ebx \n" // add ebx, ebx - pix size " add %%esi, %%ebx \n" // add ebx, esi - pix size " mov %6, %%esi \n" // mov esi, y1 " sub %%esi, %%ecx \n" // sub ecx, esi " add %%ebx, %%edi \n" // add edi, ebx " inc %%ecx \n" // inc ecx " mov %%eax, %%ebx \n" // mov ebx, eax " shr $16, %%ebx \n" // shr ebx, 16 "vLlop24: \n" " mov %%ax, (%%edi) \n" // mov [edi], eax " mov %%bl, 2(%%edi)\n" // mov [edi+2], bl " add %%edx, %%edi \n" // add edi, edx " dec %%ecx \n" // dec ecx " jnz vLlop24 \n" : : "D" (buffer), "S" (lineOfs[y1]), // %0, %1 "a" (colour), "b" (x), // %2, %3 "c" (y2), "d" (xRes), // %4, %5 "m" (y1) // %6 ); break; case 2: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " add %%ebx, %%ebx \n" // add ebx, ebx - pix size " mov %6, %%esi \n" // mov esi, y1 " sub %%esi, %%ecx \n" // sub ecx, esi " add %%ebx, %%edi \n" // add edi, ebx " inc %%ecx \n" // inc ecx "vLlop16: \n" " mov %%ax, (%%edi) \n" // mov [edi], ax " add %%edx, %%edi \n" // add edi, edx " dec %%ecx \n" // dec ecx " jnz vLlop16 \n" : : "D" (buffer), "S" (lineOfs[y1]), // %0, %1 "a" (colour), "b" (x), // %2, %3 "c" (y2), "d" (xRes), // %4, %5 "m" (y1) // %6 ); break; case 1: __asm__ __volatile__( " add %%esi, %%edi \n" // add edi, esi " mov %6, %%esi \n" // mov esi, y1 " sub %%esi, %%ecx \n" // sub ecx, esi " add %%ebx, %%edi \n" // add edi, ebx " inc %%ecx \n" // inc ecx "vLlop8: \n" " mov %%al, (%%edi) \n" // mov [edi], al " add %%edx, %%edi \n" // add edi, edx " dec %%ecx \n" // dec ecx " jnz vLlop8 \n" : : "D" (buffer), "S" (lineOfs[y1]), // %0, %1 "a" (colour), "b" (x), // %2, %3 "c" (y2), "d" (xRes), // %4, %5 "m" (y1) // %6 ); break; } // switch return; } // 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 pal = NULL; lineOfs= NULL; buffer = NULL; attributes = NULL; bSize = 0; lSize = 0; dataState = ogNone; return; } // ogSurface::~ogSurface