/*******************************************************
$Id$
*******************************************************/
#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