JD2022-TU1/main/extern/Camcam/LIBS/Mixer/SCENE_Paint.cpp

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;
}