479 lines
No EOL
12 KiB
C++
479 lines
No EOL
12 KiB
C++
#include "TRACK.h"
|
|
#include "SCENE.h"
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct
|
|
{
|
|
unsigned char uc_Size;
|
|
unsigned char uc_ColorMapType;
|
|
unsigned char uc_ImageTypeCode;
|
|
unsigned short uw_Origin;
|
|
unsigned short uw_PaletteLength;
|
|
unsigned char uc_BPCInPalette;
|
|
unsigned short uw_Left;
|
|
unsigned short uw_Top;
|
|
unsigned short uw_Width;
|
|
unsigned short uw_Height;
|
|
unsigned char uc_BPP;
|
|
unsigned char ucDescriptorByte;
|
|
} MyTGAHeader;
|
|
#pragma pack(pop)
|
|
|
|
BOOL WORLD::SaveTGA(char *path, MAP *source, MAP *alpha)
|
|
{
|
|
// version bourrine, calage direct de l'aplha dans la source et les
|
|
MyTGAHeader header;
|
|
|
|
START_RASTER(TGA_SAVE);
|
|
|
|
if (alpha != NULL)
|
|
{
|
|
if (alpha->SX != source->SX ||
|
|
alpha->SY != source->SY)
|
|
{
|
|
STOP_RASTER(TGA_SAVE);
|
|
return false;
|
|
}
|
|
s32 *pSrcBASE = source->GetBase();
|
|
s32 *pAlphaBASE = alpha->GetBase();
|
|
for (int i=0; i<source->SX*source->SY; i++)
|
|
{
|
|
pSrcBASE[i] = (pSrcBASE[i] & 0xFFFFFF) | ((pAlphaBASE[i] & 0xFF) << 24);
|
|
}
|
|
}
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
header.uc_ImageTypeCode = 2;
|
|
header.uw_Width = source->SX;
|
|
header.uw_Height = source->SY;
|
|
header.uc_BPP = 32;
|
|
header.ucDescriptorByte = 0x8;
|
|
|
|
FILE *f;
|
|
f = CC_fopen(path, "wb");
|
|
if (!f)
|
|
{
|
|
STOP_RASTER(TGA_SAVE);
|
|
return false;
|
|
}
|
|
fwrite(&header, sizeof(header), 1, f);
|
|
fwrite(source->GetBase(), sizeof(char), source->SX * source->SY * 4, f);
|
|
|
|
CC_fclose(f);
|
|
|
|
STOP_RASTER(TGA_SAVE);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawPoint(MAP *source, MAP *buffer, int x, int y, u32 RGB, int Opacity, int Diam)
|
|
{
|
|
u32 inRGB;
|
|
int inOpacity;
|
|
|
|
s32 pos;
|
|
u32 baseColor;
|
|
int distToCenter;
|
|
int Opacity255;
|
|
|
|
s32 *pSrcBASE = source->GetBase();
|
|
s32 *pBufferBASE = buffer->GetBase();
|
|
for (int toDrawY=y-Diam+1; toDrawY<=y+Diam-1; toDrawY++) {
|
|
if (toDrawY < 0 || toDrawY >= source->SY) continue;
|
|
for (int toDrawX=x-Diam+1; toDrawX<=x+Diam-1; toDrawX++) {
|
|
if (toDrawX < 0 || toDrawX >= source->SX) continue;
|
|
distToCenter = Diam*Diam - ((toDrawX - x)*(toDrawX - x) + (toDrawY - y)*(toDrawY - y));
|
|
if (distToCenter < 0) continue;
|
|
pos = toDrawX + (source->SY - toDrawY - 1)*source->PITCH;
|
|
baseColor = *(pSrcBASE + pos);
|
|
if (Opacity > 0)
|
|
inOpacity = Opacity;
|
|
else
|
|
inOpacity = -Opacity*distToCenter/(Diam*Diam);
|
|
if (pBufferBASE[pos] >= inOpacity) continue;
|
|
|
|
|
|
Opacity255 = inOpacity*256/100;
|
|
if (Opacity255 > 255) Opacity255 = 255;
|
|
inOpacity = 100*(inOpacity - pBufferBASE[pos])/(100 - pBufferBASE[pos]);
|
|
|
|
inRGB = (((((Opacity255) )*inOpacity + ((baseColor & 0xFF000000) >> 24)*(100 - inOpacity)) / 100) << 24) +
|
|
(((((RGB & 0x00FF0000) >> 16)*inOpacity + ((baseColor & 0x00FF0000) >> 16)*(100 - inOpacity)) / 100) << 16) +
|
|
(((((RGB & 0x0000FF00) >> 8)*inOpacity + ((baseColor & 0x0000FF00) >> 8)*(100 - inOpacity)) / 100) << 8) +
|
|
(((((RGB & 0x000000FF) )*inOpacity + ((baseColor & 0x000000FF) )*(100 - inOpacity)) / 100));
|
|
*(pSrcBASE + pos) = inRGB;
|
|
|
|
pBufferBASE[pos] = pBufferBASE[pos] + inOpacity - (pBufferBASE[pos]*inOpacity)/100;
|
|
}
|
|
}
|
|
}
|
|
|
|
void InvertPixel(MAP *source, int x, int y)
|
|
{
|
|
if (x < 0 || x >= source->SX ||
|
|
y < 0 || y >= source->SY) return;
|
|
|
|
int pos = x + (source->SY - y - 1)*source->PITCH;
|
|
u32 baseColor = *(source->GetBase() + pos);
|
|
|
|
*(source->GetBase() + pos) = ~baseColor & 0xFFFFFF;
|
|
}
|
|
|
|
void circlePoints(MAP *source, int cx, int cy, int x, int y)
|
|
{
|
|
if (x == 0) {
|
|
InvertPixel(source, cx, cy + y);
|
|
InvertPixel(source, cx, cy - y);
|
|
InvertPixel(source, cx + y, cy);
|
|
InvertPixel(source, cx - y, cy);
|
|
} else
|
|
if (x == y) {
|
|
InvertPixel(source, cx + x, cy + y);
|
|
InvertPixel(source, cx - x, cy + y);
|
|
InvertPixel(source, cx + x, cy - y);
|
|
InvertPixel(source, cx - x, cy - y);
|
|
} else
|
|
if (x < y) {
|
|
InvertPixel(source, cx + x, cy + y);
|
|
InvertPixel(source, cx - x, cy + y);
|
|
InvertPixel(source, cx + x, cy - y);
|
|
InvertPixel(source, cx - x, cy - y);
|
|
InvertPixel(source, cx + y, cy + x);
|
|
InvertPixel(source, cx - y, cy + x);
|
|
InvertPixel(source, cx + y, cy - x);
|
|
InvertPixel(source, cx - y, cy - x);
|
|
}
|
|
}
|
|
|
|
void circleMidpoint(MAP *source, int xCenter, int yCenter, int radius)
|
|
{
|
|
int x = 0;
|
|
int y = radius;
|
|
int p = (5 - radius*4)/4;
|
|
|
|
circlePoints(source, xCenter, yCenter, x, y);
|
|
while (x < y) {
|
|
x++;
|
|
if (p < 0) {
|
|
p += 2*x+1;
|
|
} else {
|
|
y--;
|
|
p += 2*(x-y)+1;
|
|
}
|
|
circlePoints(source, xCenter, yCenter, x, y);
|
|
}
|
|
}
|
|
|
|
|
|
void Brensenham(int xa, int ya, int xb, int yb, MAP *source, MAP *buffer, u32 RGB, int Opacity, int Diam)
|
|
{
|
|
/* pour tracer une droite a partir de 2 points : (xa,ya) et (xb,yb) */
|
|
int x,y,dx,dy,incrmX,incrmY,dp,NE,SE;
|
|
|
|
dx = xb-xa;
|
|
dy = yb-ya;
|
|
|
|
if (dx>0)
|
|
incrmX = 1;
|
|
else {
|
|
incrmX = -1;
|
|
dx *= -1;
|
|
}
|
|
|
|
if (dy>0)
|
|
incrmY = 1;
|
|
else {
|
|
incrmY = -1;
|
|
dy *= -1;
|
|
}
|
|
|
|
|
|
if (dx>=dy) {
|
|
dp=2*dy-dx;
|
|
SE=2*dy;
|
|
NE=2*(dy-dx);
|
|
|
|
y=ya;
|
|
for(x=xa;x!=xb;x+=incrmX) {
|
|
/* affichePixel(x,y,couleur) */
|
|
DrawPoint(source, buffer, x, y, RGB, Opacity, Diam);
|
|
|
|
if (dp<=0) /* on choisit le pixel E */
|
|
dp += SE;
|
|
else {
|
|
dp += NE;
|
|
y+=incrmY;
|
|
}
|
|
}
|
|
}
|
|
else if (dx<dy) {
|
|
dp=2*dx-dy;
|
|
SE=2*dx;
|
|
NE=2*(dx-dy);
|
|
|
|
x=xa;
|
|
for(y=ya;y!=yb;y+=incrmY) {
|
|
/* affichePixel(x,y,couleur) */
|
|
DrawPoint(source, buffer, x, y, RGB, Opacity, Diam);
|
|
|
|
if (dp<=0) /* on choisit le pixel E */
|
|
dp += SE;
|
|
else {
|
|
dp += NE;
|
|
x+=incrmX;
|
|
}
|
|
}
|
|
}
|
|
} /* Brensenham */
|
|
|
|
|
|
void WORLD::Paint(MAP *source, POINT pt, POINT prevPt, u32 RGB, int Opacity, int Diam)
|
|
{
|
|
u32 color;
|
|
|
|
if (PaintBuffer.SetSize(source->PITCH, source->SY))
|
|
{
|
|
prevPt.x = prevPt.y = 0;
|
|
}
|
|
|
|
if (prevPt.x == 0 && prevPt.y == 0)
|
|
{
|
|
memset(PaintBuffer.GetBase(), 0, source->SX*source->SY*sizeof(s32));
|
|
DrawPoint(source, &PaintBuffer, pt.x, pt.y, RGB, Opacity, Diam);
|
|
} else {
|
|
Brensenham(prevPt.x, prevPt.y, pt.x, pt.y, source, &PaintBuffer, RGB, Opacity, Diam);
|
|
}
|
|
}
|
|
|
|
void WORLD::PaintCursor(MAP *source, POINT pt, int radius)
|
|
{
|
|
if (pt.x < 0)
|
|
circleMidpoint(source, -pt.x, -pt.y, radius);
|
|
else
|
|
circleMidpoint(source, pt.x, pt.y, radius);
|
|
}
|
|
|
|
void WORLD::DrawSquareInLine(MAP *source, POINT pt, POINT prevPt, int sx, int sy, u32 RGB, int Opacity, int Diam, int Filled, float Angle, float previousAngle)
|
|
{
|
|
int x,y,dx,dy,incrmX,incrmY,dp,NE,SE,maxDiff;
|
|
float currentAngle, temp;
|
|
|
|
dx = prevPt.x-pt.x;
|
|
dy = prevPt.y-pt.y;
|
|
|
|
if (dx>0) incrmX = 1;
|
|
else {
|
|
incrmX = -1;
|
|
dx *= -1;
|
|
}
|
|
if (dy>0) incrmY = 1;
|
|
else {
|
|
incrmY = -1;
|
|
dy *= -1;
|
|
}
|
|
if (dx>=dy) {
|
|
dp=2*dy-dx;
|
|
SE=2*dy;
|
|
NE=2*(dy-dx);
|
|
|
|
y=pt.y;
|
|
|
|
for(x=pt.x;x!=prevPt.x;x+=incrmX) {
|
|
|
|
temp = abs(x - prevPt.x)/abs(pt.x - prevPt.x);
|
|
currentAngle = (prevAngle*temp+Angle*(1-temp)) ;
|
|
DrawSquare(source, x, y, sx, sy, RGB, Opacity, Diam, Filled, currentAngle);
|
|
|
|
if (dp<=0) /* on choisit le pixel E */
|
|
dp += SE;
|
|
else {
|
|
dp += NE;
|
|
y+=incrmY;
|
|
}
|
|
}
|
|
}
|
|
else if (dx<dy) {
|
|
dp=2*dx-dy;
|
|
SE=2*dx;
|
|
NE=2*(dx-dy);
|
|
|
|
x=pt.x;
|
|
for(y=pt.y;y!=prevPt.y;y+=incrmY) {
|
|
temp = abs(y - prevPt.y)/abs(pt.y - prevPt.y);
|
|
currentAngle = (prevAngle*temp+Angle*(1-temp)) ;
|
|
DrawSquare(source, x, y, sx, sy, RGB, Opacity, Diam, Filled, currentAngle);
|
|
|
|
if (dp<=0) /* on choisit le pixel E */
|
|
dp += SE;
|
|
else {
|
|
dp += NE;
|
|
x+=incrmX;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void WORLD::DrawSquare(MAP *source, int x, int y, int sx, int sy, u32 RGB, int Opacity, int Diam, int Filled, float Angle)
|
|
{
|
|
|
|
if (PaintBuffer.SetSize(source->PITCH, source->SY)
|
|
|| (prevMousePoint.x == 0 && prevMousePoint.y == 0))
|
|
{
|
|
memset(PaintBuffer.GetBase(), 0, source->SX*source->SY*sizeof(s32));
|
|
}
|
|
|
|
// x' = cos(theta)*(x-xc) - sin(theta)*(y-yc) + xc
|
|
// y' = sin(theta)*(x-xc) + cos(theta)*(y-yc) + yc
|
|
float cosAngle = cos(Angle);
|
|
float sinAngle = sin(Angle);
|
|
POINT rot;
|
|
rot.x = x+sx/2;
|
|
rot.y = y+sy/2;
|
|
|
|
if (Filled)
|
|
{
|
|
int xp, yp, yo, xo;
|
|
|
|
for (int i = 0; i <= sy; i += 1)
|
|
{
|
|
xp = cosAngle*( (x+sx) - rot.x ) - sinAngle*( (y+i) - rot.y ) + rot.x;
|
|
yp = sinAngle*( (x+sx) - rot.x ) + cosAngle*( (y+i) - rot.y ) + rot.y;
|
|
|
|
xo = cosAngle*( x - rot.x ) - sinAngle*( (y+i) - rot.y ) + rot.x;
|
|
yo = sinAngle*( x - rot.x ) + cosAngle*( (y+i) - rot.y ) + rot.y;
|
|
|
|
Brensenham(xo, yo, xp, yp, source, &PaintBuffer, RGB, Opacity, Diam);
|
|
}
|
|
|
|
} else
|
|
{
|
|
int xp, yp, yo, xo;
|
|
xo = cosAngle*( x - rot.x ) - sinAngle*( y - rot.y ) + rot.x;
|
|
yo = sinAngle*( x - rot.x ) + cosAngle*( y - rot.y ) + rot.y;
|
|
xp = cosAngle*( (x+sx) - rot.x ) - sinAngle*( y - rot.y ) + rot.x;
|
|
yp = sinAngle*( (x+sx) - rot.x ) + cosAngle*( y - rot.y ) + rot.y;
|
|
Brensenham(xo, yo, xp, yp, source, &PaintBuffer, RGB, Opacity, Diam);
|
|
|
|
xo = xp;
|
|
yo = yp;
|
|
xp = cosAngle*( (x+sx) - rot.x ) - sinAngle*( (y+sy) - rot.y ) + rot.x;
|
|
yp = sinAngle*( (x+sx) - rot.x ) + cosAngle*( (y+sy) - rot.y ) + rot.y;
|
|
Brensenham(xo, yo, xp, yp, source, &PaintBuffer, RGB, Opacity, Diam);
|
|
|
|
xo = xp;
|
|
yo = yp;
|
|
xp = cosAngle*( x - rot.x ) - sinAngle*( (y+sy) - rot.y ) + rot.x;
|
|
yp = sinAngle*( x - rot.x ) + cosAngle*( (y+sy) - rot.y ) + rot.y;
|
|
Brensenham(xo, yo, xp, yp, source, &PaintBuffer, RGB, Opacity, Diam);
|
|
|
|
xo = xp;
|
|
yo = yp;
|
|
xp = cosAngle*( x - rot.x ) - sinAngle*( y - rot.y ) + rot.x;
|
|
yp = sinAngle*( x - rot.x ) + cosAngle*( y - rot.y ) + rot.y;
|
|
Brensenham(xo, yo, xp, yp, source, &PaintBuffer, RGB, Opacity, Diam);
|
|
}
|
|
}
|
|
|
|
void WORLD::RenderText(unsigned char *Txt,float X, float Y, float FX, float FY , u32 ColorRGBA, char *font, int blendingMode)
|
|
{
|
|
int MediaIndex;
|
|
if (font == NULL)
|
|
{
|
|
DI->DrawText(Txt, X, Y, FX, FY , ColorRGBA);
|
|
return;
|
|
}
|
|
|
|
MediaIndex = MediaDico.IsExist(font);
|
|
if (MediaIndex == -1) return;
|
|
MediaIndex = MediaDico.mpst_Dico[MediaIndex].AssociatedValue;
|
|
if (MediaIndex == -1) return;
|
|
|
|
MAP *fontMap = &ID_MEDIA[MediaIndex]->Image;
|
|
SIZE *CharBounds = (SIZE *) ID_MEDIA[MediaIndex]->GetData(0);
|
|
SIZE *CharPos = (SIZE *) ID_MEDIA[MediaIndex]->GetData(1);
|
|
u32 FontMask = (u32) ID_MEDIA[MediaIndex]->GetData(2);
|
|
|
|
DI->RenderText(Txt, X, Y, FX, FY , ColorRGBA, fontMap, ID_MEDIA[MediaIndex]->ulAssociatedTextureIndex, CharPos, CharBounds, FontMask, blendingMode);
|
|
}
|
|
|
|
void WORLD::GetTextSize(unsigned char *Txt,POINT *OutSize, char *font)
|
|
{
|
|
int MediaIndex;
|
|
if (font == NULL)
|
|
{
|
|
DI->GetTextSize(Txt,(int *)&OutSize->x,(int *)&OutSize->y);
|
|
return;
|
|
}
|
|
MediaIndex = MediaDico.IsExist(font);
|
|
if (MediaIndex == -1) return;
|
|
MediaIndex = MediaDico.mpst_Dico[MediaIndex].AssociatedValue;
|
|
if (MediaIndex == -1) return;
|
|
SIZE *CharBounds = (SIZE *) ID_MEDIA[MediaIndex]->GetData(0);
|
|
DI->GetTextSize(Txt,(int *)&OutSize->x,(int *)&OutSize->y,CharBounds);
|
|
}
|
|
|
|
void WORLD::GetTextPoint(POINT *TC,POINT *OutPoint, char *font)
|
|
{
|
|
int MediaIndex;
|
|
if (font == NULL)
|
|
{
|
|
OutPoint->x = TC->x;
|
|
OutPoint->y = YSize - TC->y - 16;
|
|
return;
|
|
}
|
|
MediaIndex = MediaDico.IsExist(font);
|
|
if (MediaIndex == -1) return;
|
|
MediaIndex = MediaDico.mpst_Dico[MediaIndex].AssociatedValue;
|
|
if (MediaIndex == -1) return;
|
|
SIZE *CharBounds = (SIZE *) ID_MEDIA[MediaIndex]->GetData(0);
|
|
int lineHeight = 0;
|
|
for (int asc=0; asc<256; asc++) if (lineHeight < CharBounds[asc].cy) lineHeight = CharBounds[asc].cy;
|
|
OutPoint->x = TC->x;
|
|
OutPoint->y = YSize - TC->y - lineHeight;
|
|
}
|
|
|
|
|
|
|
|
SIZE GetTextBounds(u8 *Txt, INPUT_IO *fontMedia)
|
|
{
|
|
SIZE GlobalBounds = {0,0};
|
|
int LocalX = 0;
|
|
int lineHeight = 0;
|
|
SIZE *CharBounds = NULL;
|
|
|
|
|
|
|
|
if (fontMedia)
|
|
CharBounds = (SIZE *)fontMedia->GetData(0);
|
|
|
|
if (CharBounds)
|
|
{
|
|
for (int asc=0; asc<256; asc++)
|
|
if (lineHeight < CharBounds[asc].cy) lineHeight = CharBounds[asc].cy;
|
|
} else
|
|
lineHeight = 16;
|
|
|
|
GlobalBounds.cy = lineHeight;
|
|
for (;*Txt;Txt++)
|
|
{
|
|
if (*Txt == '\n')
|
|
{
|
|
LocalX = 0;
|
|
GlobalBounds.cy += lineHeight;
|
|
} else {
|
|
if (CharBounds)
|
|
LocalX += CharBounds[*Txt].cx;
|
|
else
|
|
LocalX += 8;
|
|
|
|
if (GlobalBounds.cx < LocalX)
|
|
GlobalBounds.cx = LocalX;
|
|
}
|
|
}
|
|
|
|
return GlobalBounds;
|
|
} |