/*******************************************************
$Id: objgfx30.cpp,v 1.5 2003/03/17 01:52:01 flameshadow Exp $
*******************************************************/
#include "objgfx30.h"
#include "defpal.inc"
#include <stdlib.h>
#include <string.h>
#include <stdio.h> // for stuff in fileExists
#include <math.h>
using namespace std;
// #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;
ogPoint * PointPtr;
};
struct ogEdgeState {
ogEdgeState* nextEdge;
int32 x;
int32 startY;
int32 wholePixelXMove;
int32 xDirection;
int32 errorTerm;
int32 errorTermAdjUp;
int32 errorTermAdjDown;
int32 count;
};
class ogEdgeTable {
public:
ogEdgeState * globalEdges;
ogEdgeState * activeEdges;
ogEdgeTable(void) { globalEdges = activeEdges = NULL; return; }
void advanceAET(void);
void buildGET(uInt32 numPoints, ogPoint * polyPoints);
void moveXSortedToAET(int32 yToMove);
void scanOutAET(ogSurface & destObject, int32 yToScan, uInt32 colour);
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;
} 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, ogPoint * polyPoints) {
int32 i, x1, y1, x2, y2, deltaX, deltaY, width, tmp;
ogEdgeState * newEdgePtr;
ogEdgeState * followingEdge;
ogEdgeState ** followingEdgeLink;
/* Creates a GET in the buffer pointed to by NextFreeEdgeStruc from
* the vertex list. Edge endpoints are flipped, if necessary, to
* guarantee all edges go top to bottom. The GET is sorted primarily
* by ascending Y start coordinate, and secondarily by ascending X
* start coordinate within edges with common Y coordinates }
*/
// Scan through the vertex list and put all non-0-height edges into
// the GET, sorted by increasing Y start coordinate}
for (i = 0; i<(int32)numPoints; i++) {
// calculate the edge height and width
x1 = polyPoints[i].x;
y1 = polyPoints[i].y;
if (i==0) {
// wrap back around to the end of the list
x2 = polyPoints[numPoints-1].x;
y2 = polyPoints[numPoints-1].y;
} else {
x2 = polyPoints[i-1].x;
y2 = polyPoints[i-1].y;
} // else i!=0
if (y1>y2) {
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
} // if y1>y2
// skip if this can't ever be an active edge (has 0 height)
deltaY = y2-y1;
if (deltaY!=0) {
newEdgePtr = new ogEdgeState;
newEdgePtr->xDirection = ((deltaX = x2-x1) > 0) ? 1 : -1;
width = 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::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 (leftX!=currentEdge->x)
destObject.ogHLine(leftX, currentEdge->x-1, yToScan, colour);
currentEdge = currentEdge->nextEdge;
} // if currentEdge != NULL
} // while
return;
} // ogEdgeTable::scanOutAET
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)
{
FILE *f = fopen(file, "r");
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;
xRes = 0;
yRes = 0;
maxX = 0;
maxY = 0;
bSize = 0;
lSize = 0;
transparentColor = 0;
BPP = 0;
redShifter = 0;
greenShifter = 0;
blueShifter = 0;
alphaShifter = 0;
redFieldPosition = 0;
greenFieldPosition = 0;
blueFieldPosition = 0;
alphaFieldPosition = 0;
antiAlias = true;
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;
uInt32 ct[32];
uInt8 r,g,b;
uInt8 orig_r, orig_g, orig_b;
if (y1 > y2) {
tmp= y1;
y1 = y2;
y2 = tmp;
tmp= x1;
x1 = x2;
x2 = tmp;
} // if
ogUnpackRGB(colour, orig_r, orig_g, orig_b);
for (i=0; i<32; i++) {
r = (i*orig_r) / 31;
g = (i*orig_g) / 31;
b = (i*orig_b) / 31;
ct[31-i] = ogRGB(r,g,b);
} // for
ogSetPixel(x1,y1,colour);
dx = (x2-x1);
if (dx>=0) xDir=1; else 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;
}
// this is incomplete.. diagonal lines don't travel through the
// center of pixels exactly
if (dx==dy) {
for (; dy != 0; dy--) {
x1+=xDir;
y1++;
ogSetPixel(x1,y1,colour);
} // for
return;
} // if dx==dy
erracc = 0;
intshift = 32-5;
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 = ((unsigned long long) dx << 32) / (unsigned long long)dy;
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, ct[wgt]);
ogSetPixel(x1+xDir, y1, ct[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 = ((unsigned long long)dy << 32) / (unsigned long long)dx;
// 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, ct[wgt]);
ogSetPixel(x1, y1+1, ct[wgt^wgtcompmask]);
} // while
} // else
ogSetPixel(x2,y2,colour);
return;
} // ogSurface::aaRawLine
uInt32
ogSurface::rawGetPixel(uInt32 x, uInt32 y) {
uInt32 result;
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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 24:
__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 32:
__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
);
} // switch
return result;
} // ogSurface::rawGetPixel
void
ogSurface::rawSetPixel(uInt32 x, uInt32 y, uInt32 colour) {
switch (BPP) {
case 8:
__asm__ __volatile__(
// { Calculate offset, prepare the pixel to be drawn }
" 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;
case 15:
case 16:
__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
" add %%ecx, %%edi \n" // add edi, ecx
// { Draw the pixel }
" mov %%ax, (%%edi) \n" // mov [edi], al
:
: "D" (buffer), "S" (lineOfs[y]), // %0, %1
"c" (x), "a" (colour) // %2, %3
);
break;
case 24:
__asm__ __volatile__(
// { Calculate offset, prepare the pixel to be drawn }
" add %%esi, %%edi \n" // add edi, esi
" add %%ecx, %%edi \n" // add edi, ecx
" add %%ecx, %%edi \n" // add edi, ecx {adjust for pixel size}
" add %%ecx, %%edi \n" // add edi, ecx {adjust for pixel size}
// { 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 32:
__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
);
} // 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
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
bool
ogSurface::ogAlias(ogSurface& SrcObject, uInt32 x1, uInt32 y1, uInt32 x2, uInt32 y2) {
uInt32 tmp;
if (dataState==ogOWNER) return false;
if (x2<x1) {
tmp= x2;
x2 = x1;
x1 = tmp;
} // if
if (y2<y1) {
tmp= y2;
y2 = y1;
y1 = tmp;
} // if
owner = &SrcObject;
buffer =((unsigned char *)(SrcObject.buffer)+x1*((SrcObject.BPP+7) >> 3));
lineOfs=((uInt32 *)SrcObject.lineOfs)+y1;
pal = SrcObject.pal;
xRes = SrcObject.xRes;
yRes = SrcObject.yRes;
maxX = (x2-x1);
maxY = (y2-y1);
bSize = 0;
lSize = 0;
transparentColor = SrcObject.transparentColor;
dataState = ogALIASING;
BPP = SrcObject.BPP;
// For 8bpp modes the next part doesn't matter
redFieldPosition = SrcObject.redFieldPosition;
greenFieldPosition = SrcObject.greenFieldPosition;
blueFieldPosition = SrcObject.blueFieldPosition;
alphaFieldPosition = SrcObject.alphaFieldPosition;
// The next part is only used by 15/16bpp
redShifter = SrcObject.redShifter;
greenShifter = SrcObject.greenShifter;
blueShifter = SrcObject.blueShifter;
alphaShifter = SrcObject.alphaShifter;
antiAlias = SrcObject.antiAlias;
return true;
} // ogSurface::ogAlias
void
ogSurface::ogArc(int32 x_center, int32 y_center, uInt32 radius,
uInt32 s_angle, uInt32 e_angle, uInt32 colour) {
int32 p;
uInt32 x, y, tmp;
double alpha;
if (radius==0) {
ogSetPixel(x_center, y_center, colour);
return;
} // if
s_angle%=361;
e_angle%=361;
if (s_angle>e_angle) {
tmp = s_angle;
s_angle = e_angle;
e_angle = 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>=s_angle) && (alpha<=e_angle))
ogSetPixel(x_center-x, y_center-y, colour);
if ((90-alpha>=s_angle) && (90-alpha<=e_angle))
ogSetPixel(x_center-y, y_center-x, colour);
if ((90+alpha>=s_angle) && (90+alpha<=e_angle))
ogSetPixel(x_center-y, y_center+x,colour);
if ((180-alpha>=s_angle) && (180-alpha<=e_angle))
ogSetPixel(x_center-x, y_center+y,colour);
if ((180+alpha>=s_angle) && (180+alpha<=e_angle))
ogSetPixel(x_center+x, y_center+y,colour);
if ((270-alpha>=s_angle) && (270-alpha<=e_angle))
ogSetPixel(x_center+y, y_center+x,colour);
if ((270+alpha>=s_angle) && (270+alpha<=e_angle))
ogSetPixel(x_center+y, y_center-x,colour);
if ((360-alpha>=s_angle) && (360-alpha<=e_angle))
ogSetPixel(x_center+x, y_center-y,colour);
if (p<0)
p+=4*x+6;
else {
p+=4*(x-y)+10;
--y;
}
++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, ogPoint* points, uInt32 segments,
uInt32 colour) {
float mu, mudelta;
int32 x1,y1,x2,y2;
uInt32 n,h;
if (points==NULL) return;
if ((numPoints<4) || (numPoints>4096) || (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 x_center, int32 y_center, uInt32 radius, uInt32 colour) {
int32 x, y, d;
x = 0;
y = radius;
d = 2*(1-radius);
while (y>=0) {
ogSetPixel(x_center+x,y_center+y,colour);
ogSetPixel(x_center+x,y_center-y,colour);
ogSetPixel(x_center-x,y_center+y,colour);
ogSetPixel(x_center-x,y_center-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;
if (!ogAvail()) return;
__asm__ __volatile__("cld\n");
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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 24:
__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 32:
__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
);
} // switch
return;
} // ogSurface::ogClear
bool
ogSurface::ogClone(ogSurface& SrcObject) {
bool created;
ogPixelFmt pixfmt;
if (SrcObject.dataState==ogNONE) return false;
SrcObject.ogGetPixFmt(pixfmt);
created = ogCreate(SrcObject.maxX+1,SrcObject.maxY+1,pixfmt);
if (!created) return false;
transparentColor = SrcObject.transparentColor;
antiAlias = SrcObject.antiAlias;
ogCopyPal(SrcObject);
ogCopy(SrcObject);
return true;
} // ogSurface::ogClone
void
ogSurface::ogCopy(ogSurface& SrcObject) {
uInt32 count, xCount, yCount;
uInt32 xx, yy;
uInt8 r, g, b;
void * srcPtr;
if (!ogAvail()) return;
if (!SrcObject.ogAvail()) return;
xCount = SrcObject.maxX+1;
if (xCount>maxX+1) xCount=maxX+1;
yCount = SrcObject.maxY+1;
if (yCount>maxY+1) yCount=maxY+1;
if ((BPP!=SrcObject.BPP) || (redShifter!=SrcObject.redShifter) ||
(blueShifter!=SrcObject.blueShifter) ||
(greenShifter!=SrcObject.greenShifter)) {
for (yy=0; yy<=yCount-1; yy++)
for (xx=0; xx<=xCount-1; xx++) {
SrcObject.ogUnpackRGB(SrcObject.ogGetPixel(xx,yy),r,g,b);
rawSetPixel(xx,yy,ogRGB(r,g,b));
} // for
} // if
else
{
xCount *= ((BPP+7) >> 3); // adjust for bpp
for (count=0; count<yCount; count++)
if ((srcPtr = SrcObject.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.
srcPtr = malloc(xCount); // allocate space
if (srcPtr!=NULL) {
SrcObject.ogCopyLineFrom(0,count,srcPtr,xCount);
ogCopyLineTo(0,count,srcPtr,xCount);
free(srcPtr);
} // if srcPtr!=NULL
} else ogCopyLineTo(0,count,srcPtr,xCount);
} // else
} // ogSurface::ogCopy
void
ogSurface::ogCopyBuf(int32 dX1, int32 dY1,
ogSurface& SrcObject, int32 sX1, int32 sY1, int32 sX2, int32 sY2) {
uInt32 pixmap[256];
int32 xx,yy,count,xCount, yCount;
uInt8 r, g, b;
void *srcPtr;
if (!ogAvail()) return;
if (!SrcObject.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>SrcObject.maxX) || ((uInt32)sX2>SrcObject.maxX) ||
( (uInt32)sY1>SrcObject.maxY) || ((uInt32)sY2>SrcObject.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 ((BPP!=SrcObject.BPP) || (redShifter!=SrcObject.redShifter) ||
(blueShifter!=SrcObject.blueShifter) ||
(greenShifter!=SrcObject.greenShifter)) {
if (SrcObject.BPP==8) {
for (xx=0; xx<256; xx++)
pixmap[xx] = ogRGB(SrcObject.pal[xx].red,
SrcObject.pal[xx].green,
SrcObject.pal[xx].blue);
for (yy=0; yy<=yCount-1; yy++)
for (xx=0; xx<=xCount-1; xx++)
rawSetPixel(dX1+xx,dY1+yy,
pixmap[SrcObject.ogGetPixel(sX1+xx,sY1+yy)]);
} // if SrcObject->bpp
else
{
for (yy=0; yy<=yCount-1; yy++)
for (xx=0; xx<=xCount-1; xx++) {
SrcObject.ogUnpackRGB(SrcObject.ogGetPixel(sX1+xx,sY1+yy),r,g,b);
rawSetPixel(dX1+xx,dY1+yy,ogRGB(r,g,b));
} // for
} // else
} // if
else
{
xCount *= (BPP+7) >> 3;
for (count=0; count<yCount; count++)
if ((srcPtr = SrcObject.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.
srcPtr = malloc(xCount); // allocate space
if (srcPtr!=NULL) {
SrcObject.ogCopyLineFrom(sX1,sY1+count,srcPtr,xCount);
ogCopyLineTo(dX1,dY1+count,srcPtr,xCount);
free(srcPtr);
} // 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) {
/*
* ogCopyLineTo()
*
* 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. ogCopyLineTo and ogCopyLineFrom 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*((BPP+7) >> 3), // dest
src, // src
size); // size
return;
} // ogSurface::ogCopyLineTo
void
ogSurface::ogCopyLineFrom(uInt32 sx, uInt32 sy, void * dst, uInt32 size) {
/*
* ogCopyLineFrom()
*
* 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. ogCopyLineTo and ogCopyLineFrom 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*((BPP+7) >> 3), // src
size); // size
return;
} // ogSurface::ogCopyLineFrom
void
ogSurface::ogCopyPal(ogSurface& SrcObject) {
if (SrcObject.pal==NULL) return;
if (pal==NULL) pal = new ogRGBA[256];
if (pal==NULL) return;
memcpy(pal, SrcObject.pal, sizeof(ogRGBA)*256);
return;
} // ogSurface::ogCopyPal
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.
*/
uInt32 yy;
if (dataState==ogOWNER) {
free(buffer);
delete [] lineOfs;
delete [] pal;
} // if datastate
BPP = _pixformat.BPP;
bSize=_xRes*_yRes*((BPP+7) >> 3);
buffer = malloc(bSize);
if (buffer==NULL) return false;
memset(buffer,0,bSize);
lSize = _yRes*sizeof(uInt32);
lineOfs = new uInt32[_yRes];
if (lineOfs == NULL) return false;
pal = new ogRGBA[256];
if (pal == NULL) return false;
// copy the default palette into the buffer
memcpy(pal,DEFAULT_PALETTE,sizeof(ogRGBA)*256);
maxX=_xRes-1;
xRes=_xRes*((BPP+7) >> 3);
maxY=_yRes-1;
yRes=_yRes;
lineOfs[0]=0;
for (yy=1; yy<=maxY; 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;
// Turn anti aliasing off by default for 8bpp modes
antiAlias = (BPP>8);
owner = this;
return true;
} // 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 = (int32)(mu3*tX1+mu2*tX2+mu*tX3+x1);
yEnd = (int32)(mu3*tY1+mu2*tY2+mu*tY3+y1);
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) / (long long)segments;
fx = ((int64)(x3-(2*x2)+x1) << 16) / (segments*segments);
fy = ((int64)(y3-(2*y2)+y1) << 16) / (long long)(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 x_center, int32 y_center,
uInt32 radius, uInt32 colour) {
int32 x, y, d;
x = 0;
y = radius;
d = 2*(1-radius);
while (y>=0) {
ogHLine(x_center-x, x_center+x, y_center-y, colour);
ogHLine(x_center-x, x_center+x, y_center+y, colour);
if (d+y>0) {
y--;
d-=2*y+1;
}
if (x>d) {
x++;
d+=2*x+1;
}
} // 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::ogFillConvexPolygon(uInt32 numPoints, ogPoint* 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++) {
!- ogHLine(workingHLineList.xLeft[i], workingHLineList.xRight[i],
!- workingHLineList.yStart+i, colour);
!- } // for
!-
!- ogPolygon(numPoints, polyPoints, colour);
!-
!- delete workingHLineList.xLeft;
!- delete workingHLineList.xRight;
!-
!- return;
!-} // ogSurface::ogFillConvexPolygon
#endif
void
ogSurface::ogFillPolygon(uInt32 numPoints, ogPoint* polyPoints, uInt32 colour) {
ogEdgeTable * edges;
int32 currentY;
if (numPoints<3) return;
/* if (numPoints==3) {
* ogFillConvexPolygon(numPoints, polyPoints, colour);
* return;
* } // if
*/
ogPolygon(numPoints, polyPoints, colour);
edges = new ogEdgeTable();
edges->buildGET(numPoints, polyPoints);
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) {
ogPoint 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;
// ogFillConvexPolygon(3,Points,colour);
ogFillPolygon(3,Points,colour);
return;
} // ogSurface::ogFillTriangle
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 transparentColor;
if (((uInt32)x>maxX) || ((uInt32)y>maxY)) return transparentColor;
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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 24:
__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 32:
__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
);
} // switch
return result;
} // ogSurface::ogGetPixel
void *
ogSurface::ogGetPtr(uInt32 x, uInt32 y) {
// return (ogAvail() ? ( (uInt8*)buffer+(lineOfs[y]+x*((BPP+7) >> 3)) ) : NULL );
return ((uInt8*)buffer+(lineOfs[y]+x*((BPP+7) >> 3)));
} // ogSurface::ogGetPtr
void
ogSurface::ogHFlip(void) {
void * tmpBuf1;
void * tmpBuf2;
uInt32 xWidth, count;
if (!ogAvail()) return;
xWidth = (maxX+1)*((BPP+7) >> 3);
tmpBuf1 = malloc(xWidth);
tmpBuf2 = malloc(xWidth);
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);
// memcpy(tmpBuf,((uInt8*)buffer+lineOfs[count]),xWidth);
// memcpy(((uInt8*)buffer+lineOfs[count]),
// ((uInt8*)buffer+lineOfs[maxY-count]),
// xWidth);
// memcpy(((uInt8*)buffer+lineOfs[maxY-count]),tmpBuf,xWidth);
} // for
free(tmpBuf2);
free(tmpBuf1);
return;
} // ogSurface::ogHFlip
void
ogSurface::ogHLine(int32 x1, int32 x2, int32 y, uInt32 colour) {
int32 tmp;
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;
__asm__ __volatile__("cld \n");
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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 24:
__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 32:
__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;
} // switch
return;
} // ogSurface::hLine
void
ogSurface::ogLine(int32 x1, int32 y1, int32 x2, int32 y2, uInt32 colour) {
if (clipLine(x1,y1,x2,y2)) {
if (antiAlias) aaRawLine(x1,y1,x2,y2,colour);
else rawLine(x1,y1,x2,y2,colour);
}
return;
} // ogSurface::ogLine
bool
ogSurface::ogLoadPal(const char *palfile) {
ogRGBA old_palette[256];
FILE *f;
uInt32 lresult;
bool result;
if (fileExists(palfile)==false) return false;
if (pal==NULL) {
pal = new ogRGBA[256];
if (pal==NULL) return false;
memcpy(pal,DEFAULT_PALETTE,sizeof(ogRGBA)*256);
} // if
memcpy(&old_palette,pal,sizeof(ogRGBA)*256);
if ((f = fopen(palfile, "rb"))==NULL) return false;
lresult = fread(pal, sizeof(ogRGBA), 256, f);
result = (lresult==256);
if (result==false) memcpy(pal,&old_palette,sizeof(ogRGBA)*256);
fclose(f);
return result;
} // ogSurface::ogLoadPal
void
ogSurface::ogPolygon(uInt32 numPoints, ogPoint* polyPoints, uInt32 colour) {
uInt32 count;
switch (numPoints) {
case 1:
ogSetPixel(polyPoints[0].x,polyPoints[0].y,colour);
break;
case 2:
ogLine(polyPoints[0].x,polyPoints[0].y,
polyPoints[1].x,polyPoints[1].y,
colour);
break;
default:
for (count=0; count<numPoints; count++)
ogLine(polyPoints[count].x,polyPoints[count].y,
polyPoints[(count+1) % numPoints].x,
polyPoints[(count+1) % numPoints].y,colour);
} // switch
return;
} // ogSurface::ogPolygon
void
ogSurface::ogRect(int32 x1, int32 y1, int32 x2, int32 y2, uInt32 colour) {
ogHLine(x1,x2,y1,colour); // Horizline has built in clipping
ogVLine(x2,y1,y2,colour); // vertline has built in clipping too
ogVLine(x1,y1,y2,colour);
ogHLine(x1,x2,y2,colour);
return;
} // ogSurface::ogRect
uInt32
ogSurface::ogRGB(uInt8 red, uInt8 green, uInt8 blue) {
uInt32 idx,colour;
uInt32 rd,gd,bd,dist,newdist;
colour = 0;
switch (BPP) {
case 8:
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;
case 15:
case 16:
colour = (red >> redShifter) << redFieldPosition |
(green >> greenShifter) << greenFieldPosition |
(blue >> blueShifter) << blueFieldPosition;
break;
case 24:
case 32:
colour = ( (red << redFieldPosition) |
(green << greenFieldPosition) |
(blue << blueFieldPosition) );
} // switch
//asm("": "=a" (lastclr));
return colour;
} // ogSurface::ogRGB
bool
ogSurface::ogSavePal(const char *palfile) {
FILE * f;
uInt32 lresult;
if (pal==NULL) return false;
if ((f = fopen(palfile, "wb"))==NULL) return false;
lresult = fwrite(pal,sizeof(ogRGBA),256,f);
fclose(f);
return (lresult == 256);
} // ogSurface::ogSavePal
void
ogSurface::ogScale(ogSurface& SrcObject) {
ogScaleBuf(0,0,maxX,maxY,SrcObject,0,0,SrcObject.maxX,SrcObject.maxY);
return;
} // ogSurface::ogScale
void
ogSurface::ogScaleBuf(int32 dX1, int32 dY1, int32 dX2, int32 dY2,
ogSurface& SrcObject,
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;
uInt8 scaleBPP;
origdX1 = origdY1 = 0; // to keep the compiler from generating a warning
if (!ogAvail()) return;
if (!SrcObject.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>SrcObject.maxX) || ((uInt32)sX2>SrcObject.maxX) ||
((uInt32)sY1>SrcObject.maxY) || ((uInt32)sY2>SrcObject.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,SrcObject,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 ( (BPP!=SrcObject.BPP) || (redShifter!=SrcObject.redShifter) ||
(blueShifter!=SrcObject.blueShifter) ||
(greenShifter!=SrcObject.greenShifter)) {
tmpBuf = new ogSurface();
if (tmpBuf==NULL) return;
if (sWidth*sHeight*((SrcObject.BPP+7)>>3)<=dWidth*dHeight*((BPP+7)>>3)) {
// 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)==false) return;
tmpBuf->ogCopyPal(SrcObject);
tmpBuf->ogCopyBuf(0,0,SrcObject,sX1,sY1,sX2,sY2);
sX2 -= sX1;
sY2 -= sY1;
sX1 = 0;
sY1 = 0;
sBuf = tmpBuf;
dBuf = this;
doCopyBuf = false; // do we do a copyBuf later?
scaleBPP = BPP;
} else {
SrcObject.ogGetPixFmt(pixFmt);
if (tmpBuf->ogCreate(dWidth,dHeight,pixFmt)==false) return;
// tmpBuf->ogCopyPal(&this);
origdX1 = dX1;
origdY1 = dY1;
dX1 = 0;
dY1 = 0;
dX2 = tmpBuf->maxX;
dY2 = tmpBuf->maxY;
sBuf = &SrcObject;
dBuf = tmpBuf;
doCopyBuf = true;
scaleBPP = SrcObject.BPP;
} // else
} else {
// pixel formats are identical
sBuf = &SrcObject;
dBuf = this;
doCopyBuf = false;
scaleBPP = BPP;
} // 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
bool
ogSurface::ogSetAntiAlias(bool _AntiAlias) {
bool tmp;
tmp = antiAlias;
antiAlias = _AntiAlias;
return tmp;
} // ogSurface::ogSetAntiAlias
void
ogSurface::ogSetPixel(int32 x, int32 y, uInt32 colour) {
if (!ogAvail()) return;
// if ((buffer==NULL) || (lineOfs==NULL)) return;
if (((uInt32)x>maxX) || ((uInt32)y>maxY)) return;
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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], al
:
: "D" (buffer), "S" (lineOfs[y]), // %0, %1
"c" (x), "m" (colour) // %2, %3
);
break;
case 24:
__asm__ __volatile__(
// { Calculate offset, prepare the pixel to be drawn }
" add %%esi, %%edi \n" // add edi, esi
" add %%ecx, %%edi \n" // add edi, ecx
" add %%ecx, %%edi \n" // add edi, ecx {adjust for pixel size}
" add %%ecx, %%edi \n" // add edi, ecx {adjust for pixel size}
// { 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 32:
__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
);
} // switch
return;
} // ogSurface::ogSetPixel
void
ogSurface::ogSetRGBPalette(uInt8 colour, uInt8 red, uInt8 green, uInt8 blue) {
if (pal==NULL) return;
pal[colour].red = red;
pal[colour].green = green;
pal[colour].blue = blue;
return;
} // ogSurface::ogSetRGBPalette
uInt32
ogSurface::ogSetTransparentColor(uInt32 colour) {
uInt32 tmp;
tmp = transparentColor;
transparentColor = colour;
return tmp;
} // ogSurface::ogSetTransparentColor
static double f(double g) { return g*g*g-g; }
void
ogSurface::ogSpline(uInt32 numPoints, ogPoint* 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];
if ((zc==NULL) || (dx==NULL) || (dy==NULL) || (wndX1==NULL) ||
(wndY1==NULL) || (px==NULL) || (py==NULL)) goto safeexit;
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 = ROUND(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 = ROUND(part+0.5f);
if (runOnce) ogLine(oldX, oldY, x, y, colour); else runOnce = true;
oldX = x;
oldY = y;
} // for j
} // for i
safeexit:
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::ogUnpackRGB(uInt32 colour, uInt8& red, uInt8& green, uInt8& blue) {
switch (BPP) {
case 8:
if (pal==NULL) {
red = 0;
green = 0;
blue = 0;
return;
}
if (colour>255) colour &= 255;
red = pal[colour].red;
green = pal[colour].green;
blue = pal[colour].blue;
break;
case 15:
case 16:
red = ((colour >> redFieldPosition) << redShifter);
green = ((colour >> greenFieldPosition) << greenShifter);
blue = ((colour >> blueFieldPosition) << blueShifter);
if ((red) && (redShifter)) red+=(1 << redShifter)-1;
if ((green) && (greenShifter)) green+=(1 << greenShifter)-1;
if ((blue) && (blueShifter)) blue+=(1 << blueShifter)-1;
break;
case 24:
case 32:
red = colour >> redFieldPosition;
green = colour >> greenFieldPosition;
blue = colour >> blueFieldPosition;
break;
default:
red = 0;
green = 0;
blue = 0;
}
return;
} // ogSurface::ogUnpackRGB
void
ogSurface::ogVFlip(void) {
if (!ogAvail()) return;
// if ((buffer==NULL) || (lineOfs==NULL)) return;
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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 24:
__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" (maxY+1) // %2, %3
);
break;
case 32:
__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
);
} // switch
return;
} // ogSurface::ogVFlip
void
ogSurface::ogVLine(int32 x, int32 y1, int32 y2, uInt32 colour) {
int32 tmp;
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;
switch (BPP) {
case 8:
__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;
case 15:
case 16:
__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 24:
__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 32:
__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
);
} // switch
return;
} // ogSurface::ogVLine
ogSurface::~ogSurface(void) {
if (dataState == ogOWNER) {
delete [] pal;
delete [] lineOfs;
free(buffer);
} // if datastate
pal = NULL;
lineOfs= NULL;
buffer = NULL;
bSize = 0;
lSize = 0;
dataState = ogNONE;
return;
} // ogSurface::~ogSurface