#include "SCENE.h" #define MaximumSearchDepth 1024 #define MinimumToAcceptForPoint 5 #define MinimumToAcceptForEnterVEC 10 u32 MinimumToAcceptForVEC = 150; u32 MinimumLenght = 5; float LinearityCoef = 3.0f; float LinearityCoef_OL = 0.15f; float LinearityCoef_SURF =1.0f; float OptimizeErrorCoef = 50.f; float OptimizeErrorCoef_PASS1 = 50.f; float OptimizeErrorCoef_PASS2 = 20.f; u32 ModeSurf = 0; u32 DrawDot = 0; u32 DrawDotZC = 0; u32 Optimize = 0; typedef struct LineVec_ { s32 XBase; s32 YBase; s32 XEnd; s32 YEnd; s32 *CurrentPtr; s32 Pitch; MAP *CheckMap; u32 TAG; float Lenght; float DevLenght; u32 Strenght; u32 Number; } LineVec; typedef struct ScreenDot_ { float X,Y; float Error; s16 LinkIndex; s16 EdgeNumb; s16 Edge1; s16 Edge2; } ScreenDot; typedef struct ScreenLine_ { s16 Index1; s16 Index2; s16 Valid; u16 Angle; } ScreenLine; LineVec LineStack[MaximumSearchDepth+1]; #define MODE_SURFACE int REC_VEC(LineVec *CurrentLine,u32 Depth) { if (Depth > MaximumSearchDepth) return 0; LineStack[Depth] = *CurrentLine; if (Depth) { if (ModeSurf) { CurrentLine->Lenght = CurrentLine->XEnd * CurrentLine->YEnd / 2.0f; if (abs(CurrentLine->DevLenght - CurrentLine->Lenght) > LinearityCoef_SURF) return 1; } else { if (Depth > MinimumLenght) { float DX,DY,DEV; DX = CurrentLine->XEnd - LineStack[Depth - MinimumLenght].XEnd; DY = CurrentLine->YEnd - LineStack[Depth - MinimumLenght].YEnd; CurrentLine->Lenght = DX * DX + DY*DY; DEV =CurrentLine->DevLenght - LineStack[Depth - MinimumLenght].DevLenght; CurrentLine->Lenght = sqrt(CurrentLine->Lenght); if (DEV > CurrentLine->Lenght + LinearityCoef) { return 1; } } else { float DX,DY,DEV; CurrentLine->Lenght = CurrentLine->XEnd * CurrentLine->XEnd + CurrentLine->YEnd*CurrentLine->YEnd; CurrentLine->Lenght = sqrt(CurrentLine->Lenght); DEV = CurrentLine->DevLenght; if (DEV > CurrentLine->Lenght + LinearityCoef) return 0; } } } else CurrentLine->Lenght = 0.0f; *CurrentLine->CurrentPtr &= ~0x40000; *CurrentLine->CurrentPtr |= 0x80000; CurrentLine->Strenght += *CurrentLine->CurrentPtr & 0xffff ; CurrentLine->Number++; for (int PCounter = 0 ; PCounter < 8 ; PCounter++) { s32 X,Y; X = (((PCounter & 1) << 1)&3) - 1; Y = (((PCounter+1) & 2)&3) - 1; if (PCounter > 3) { s32 K; K = X; X = (X - Y)/2; Y = (K + Y)/2; } s32 *NewPtr,*OldPtr; OldPtr = CurrentLine->CurrentPtr; NewPtr = CurrentLine->CurrentPtr + X + Y * CurrentLine->Pitch; if(*NewPtr & 0x40000) { float DevLe; if (ModeSurf) DevLe = X * (CurrentLine->YEnd * 2 + Y) / 2.0f; else DevLe = sqrt((float)(X * X + Y * Y)); CurrentLine->CurrentPtr = NewPtr; CurrentLine->XEnd += X; CurrentLine->YEnd += Y; CurrentLine->DevLenght += DevLe; if (REC_VEC(CurrentLine,Depth+1)) return 1; CurrentLine->DevLenght -= DevLe; CurrentLine->CurrentPtr = OldPtr; CurrentLine->XEnd -= X; CurrentLine->YEnd -= Y; } } return 1; } int SET_VEC(LineVec *CurrentLine,u32 Value) { *CurrentLine->CurrentPtr = Value; for (int X = -1 ; X < 2 ; X ++) for (int Y = -1 ; Y < 2 ; Y ++) { CurrentLine->CurrentPtr += X + Y * CurrentLine->Pitch; if (*CurrentLine->CurrentPtr & 0x80000) SET_VEC(CurrentLine,Value); CurrentLine->CurrentPtr -= X + Y * CurrentLine->Pitch; } return 0; } int RESET_VEC(LineVec *CurrentLine) { *CurrentLine->CurrentPtr &= ~0x80000; *CurrentLine->CurrentPtr |= 0x40000; for (int X = -1 ; X < 2 ; X ++) for (int Y = -1 ; Y < 2 ; Y ++) { CurrentLine->CurrentPtr += X + Y * CurrentLine->Pitch; if (*CurrentLine->CurrentPtr & 0x80000) RESET_VEC(CurrentLine); CurrentLine->CurrentPtr -= X + Y * CurrentLine->Pitch; } return 0; } ScreenDot AllScreenDot[16384]; u32 AllScreenDotNP[16384]; u32 AllScreenDotNumber; ScreenLine AllScreenLines[16384]; u32 AllScreenLinesNumber; int Line_compare( const void *arg1, const void *arg2 ) { ScreenLine *L1, *L2; L1 = (ScreenLine *)arg1; L2 = (ScreenLine *)arg2; if (L1->Index1 < L2->Index1) return -1; else if (L1->Index1 > L2->Index1) return 1; else if (L1->Index2 < L2->Index2) return -1; if (L1->Index2 > L2->Index2) return 1; else return 0; } void COMPRESS_LINES() { if (!AllScreenLinesNumber) return; for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { if (AllScreenLines[Counter].Index1 > AllScreenLines[Counter].Index2) { u32 SWAP; SWAP = AllScreenLines[Counter].Index1; AllScreenLines[Counter].Index1 = AllScreenLines[Counter].Index2; AllScreenLines[Counter].Index2 = SWAP; } } qsort(AllScreenLines,AllScreenLinesNumber,sizeof(ScreenLine),Line_compare); ScreenLine*NewSL; NewSL = AllScreenLines; int Counter; for (Counter = 0 ; Counter < AllScreenLinesNumber-1 ; Counter++) { if (AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex != AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex) { if (!((AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex == AllScreenDot[AllScreenLines[Counter+1].Index1].LinkIndex) && (AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex == AllScreenDot[AllScreenLines[Counter+1].Index2].LinkIndex))) { *(NewSL++) = AllScreenLines[Counter]; } } } *(NewSL++) = AllScreenLines[Counter]; AllScreenLinesNumber = (u32)(NewSL - AllScreenLines); } float GET_LENGHT(ScreenDot *P1,ScreenDot *P2) { float Dx,Dy; Dx = P1->X - P2->X; Dy = P1->Y - P2->Y; return (Dx * Dx + Dy * Dy); } void EVALUATE_ERROR() { for (int Counter = 0 ; Counter < AllScreenDotNumber ; Counter++) { ScreenDot *P1,*P2,*P3; P2 = AllScreenDot + Counter; if (AllScreenDot[Counter].EdgeNumb == 2) { if (AllScreenLines[P2->Edge1].Index1 == Counter) P1 = AllScreenDot + AllScreenLines[P2->Edge1].Index2; else P1 = AllScreenDot + AllScreenLines[P2->Edge1].Index1; if (AllScreenLines[P2->Edge2].Index1 == Counter) P3 = AllScreenDot + AllScreenLines[P2->Edge2].Index2; else P3 = AllScreenDot + AllScreenLines[P2->Edge2].Index1; float LEr1,LEr2,LEr3; LEr1 = sqrt(GET_LENGHT(P1,P2)); LEr2 = sqrt(GET_LENGHT(P2,P3)); LEr3 = sqrt(GET_LENGHT(P1,P3)); LEr1 = abs(LEr1 + LEr2 - LEr3); /* P2->Error = LEr1 + LEr2 - LEr3 + 0.001f; P2->Error *= P2->Error;*/ LEr1 = (P2->X - P1->X) * (P2->Y + P1->Y) / 2.0f; LEr1 += (P3->X - P2->X) * (P3->Y + P2->Y) / 2.0f; LEr1 += (P1->X - P3->X) * (P1->Y + P3->Y) / 2.0f; P2->Error = OptimizeErrorCoef * abs(LEr1)/sqrt(GET_LENGHT(P1,P3)) + 0.000001f; P2->Error *= P2->Error ;//*/ /* P2->Error = OptimizeErrorCoef * LEr1 + 0.00001f; P2->Error *= P2->Error ;*/ } else P2->Error = 1000.0f; } } void LINE_MERGE() { EVALUATE_ERROR(); //return; for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { if (AllScreenLines[Counter].Index1 > AllScreenLines[Counter].Index2) { u32 SWAP; SWAP = AllScreenLines[Counter].Index1; AllScreenLines[Counter].Index1 = AllScreenLines[Counter].Index2; AllScreenLines[Counter].Index2 = SWAP; } } for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { float Dist; ScreenDot *P1,*P2,*Swp; if ((AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex == AllScreenLines[Counter].Index1) && (AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex == AllScreenLines[Counter].Index2)) { P1 = AllScreenDot + AllScreenLines[Counter].Index1; P2 = AllScreenDot + AllScreenLines[Counter].Index2; if (P1 > P2) { Swp = P1;P1 = P2; P2 = Swp; } if (P1 != P2) { Dist = GET_LENGHT(P1,P2); if ((Dist < 64) && (P2->EdgeNumb == 1) && (P1->EdgeNumb == 1)) { AllScreenLines[Counter].Index2 = AllScreenLines[Counter].Index1; AllScreenLines[Counter].Valid = 0; } else//*/ if ( (P2->Error < 1000.0f) && (P1->Error < 1000.0f) //|| //(Dist < 5) ) { float Div; //if ((P1 != P2) && ((P2->EdgeNumb == 2) || (P1->EdgeNumb == 2)/*&& (P1->EdgeNumb == 2)*/)) { Div = 1.0f / (P1->Error + P2->Error); P1->X = (P1->X * P1->Error + P2->X * P2->Error) * Div; P1->Y = (P1->Y * P1->Error + P2->Y * P2->Error) * Div; P1->Error = P1->Error + P2->Error + 100000.0f; P2->Error = P1->Error + P2->Error + 100000.0f; P2->LinkIndex = P1 - AllScreenDot; P2->EdgeNumb = 0; AllScreenLines[Counter].Index2 = AllScreenLines[Counter].Index1; AllScreenLines[Counter].Valid = 0;//*/ } } } } } } void VEC_COMPRESS() { ScreenDot *NewSD; ScreenLine*NewSL; if (!AllScreenLinesNumber) return; if (!AllScreenDotNumber) return; NewSD = AllScreenDot; for (int Counter = 0 ; Counter < AllScreenDotNumber ; Counter++) { u32 K; K = Counter; while (AllScreenDot[K].LinkIndex != K ) {K = AllScreenDot[K].LinkIndex;}; AllScreenDot[Counter].LinkIndex = K; AllScreenDot[Counter].EdgeNumb = 0; } for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { AllScreenLines[Counter].Index1 = AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex; AllScreenLines[Counter].Index2 = AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex; AllScreenDot[AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex].EdgeNumb++; AllScreenDot[AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex].EdgeNumb++; } for (int Counter = 0 ; Counter < AllScreenDotNumber ; Counter++) { ScreenDot *P1,*P2; P1 = &AllScreenDot[Counter]; P2 = &AllScreenDot[AllScreenDot[Counter].LinkIndex]; AllScreenDotNP[Counter] = (u32)(NewSD - AllScreenDot); if ((P1 == P2) && P1->EdgeNumb) { /* Create New Entry */ *NewSD = *P1; NewSD ->LinkIndex = (u32)(NewSD - AllScreenDot); NewSD -> EdgeNumb = 0; NewSD++; } } AllScreenDotNumber = (u32)(NewSD - AllScreenDot); for (int Counter = 0 ; Counter < AllScreenDotNumber ; Counter++) { AllScreenDot[Counter].LinkIndex = Counter; } COMPRESS_LINES(); NewSL = AllScreenLines; for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { NewSL->Index1 = AllScreenDotNP[AllScreenLines[Counter].Index1]; NewSL->Index2 = AllScreenDotNP[AllScreenLines[Counter].Index2]; if ((NewSL->Index1 != NewSL->Index2) && AllScreenLines[Counter].Valid) { NewSL->Valid = AllScreenLines[Counter].Valid; if (AllScreenDot[NewSL->Index1].EdgeNumb==0) AllScreenDot[NewSL->Index1].Edge1 = (u32)(NewSL - AllScreenLines); else if (AllScreenDot[NewSL->Index1].EdgeNumb==1) AllScreenDot[NewSL->Index1].Edge2 = (u32)(NewSL - AllScreenLines); if (AllScreenDot[NewSL->Index2].EdgeNumb==0) AllScreenDot[NewSL->Index2].Edge1 = (u32)(NewSL - AllScreenLines); else if (AllScreenDot[NewSL->Index2].EdgeNumb==1) AllScreenDot[NewSL->Index2].Edge2 = (u32)(NewSL - AllScreenLines); AllScreenDot[NewSL->Index1].EdgeNumb ++; AllScreenDot[NewSL->Index2].EdgeNumb ++; NewSL++; } } AllScreenLinesNumber = (u32)(NewSL - AllScreenLines); } void VECTORIZE_MAP(MAP *MapSRC,MAP *MapDST) { u32 TAG = 1; START_RASTER(Vectorization); SET_BORDER(MapSRC,10,0); for (int X = 1 ; X < MapSRC->SX-1 ; X++) for (int Y = 1 ; Y < MapSRC->SY-1 ; Y++) { s32 *LV; LV = (MapSRC->GetBase() + X + MapSRC->PITCH * Y); if ((*LV & 0xffff) < MinimumToAcceptForPoint) *LV = 0; if ((DrawDotZC) && (*LV & 0x40000)) { LV = (MapDST->GetBase() + X + MapDST->PITCH * Y); *LV = 0xff00; }//*/ } AllScreenDotNumber = 0; AllScreenLinesNumber = 0; for (int X = 1 ; X < MapSRC->SX-1 ; X++) { for (int Y = 1 ; Y < MapSRC->SY-1 ; Y++) { LineVec LV; LV.CurrentPtr = MapSRC->GetBase() + X + MapSRC->PITCH * Y; if ((*LV.CurrentPtr & 0x40000) && ((*LV.CurrentPtr & 0xffff)> MinimumToAcceptForEnterVEC) ) { LV.Pitch = MapSRC->PITCH; LV.XEnd = LV.XBase = X; LV.YEnd = LV.YBase = Y; LV.XEnd = 0; LV.YEnd = 0; LV.TAG = TAG++; LV.CheckMap = MapSRC; LV.Strenght = 0; LV.Number = 0; LV.Lenght = 0.0f; LV.DevLenght = 0.0f; REC_VEC(&LV,0); LV.XEnd += X; LV.YEnd += Y; LV.Strenght <<= 2; if ((LV.Strenght < MinimumToAcceptForVEC<<2) || (LV.NumberGetBase() + LV.XEnd + MapSRC->PITCH * LV.YEnd)& 0xffff; AllScreenDot[AllScreenDotNumber].LinkIndex = AllScreenDotNumber; AllScreenDot[AllScreenDotNumber].EdgeNumb = 1; if (AllScreenDotNumber < 16383) AllScreenDotNumber++; } } } *LV.CurrentPtr &= ~0x40000; } } for (int X = 1 ; X < MapSRC->SX-1 ; X++) for (int Y = 1 ; Y < MapSRC->SY-1 ; Y++) { s32 *LV; LV = (MapSRC->GetBase() + X + MapSRC->PITCH * Y); if (*LV & 0x1000000) { *LV &= ~(0x80000+0x40000); *LV |= 0x40000; }//*/ } STOP_RASTER(Vectorization); return; /* Add line from lenght 0 */ SET(MapSRC,0); /* PLOT w/ dot number */ for (int C = 0 ; C < AllScreenDotNumber ; C++) { s32 *Ptr; Ptr = MapSRC->GetBase() + (s32)AllScreenDot[C].X + MapSRC->PITCH * (s32)AllScreenDot[C].Y; *Ptr = C + 1; } for (int C = 0 ; C < AllScreenDotNumber ; C++) { s32 *Ptr; u32 Counter; for (int PCounter = 0 ; PCounter < 8 ; PCounter++) { s32 X,Y; X = (((PCounter & 1) << 1)&3) - 1; Y = (((PCounter+1) & 2)&3) - 1; if (PCounter > 3) { s32 K; K = X; X = (X - Y)/2; Y = (K + Y)/2; } Ptr = MapSRC->GetBase() + (s32)AllScreenDot[C].X + X + MapSRC->PITCH * ((s32)AllScreenDot[C].Y + Y); if (*Ptr) { AllScreenLines[AllScreenLinesNumber].Index1 = C; AllScreenLines[AllScreenLinesNumber].Index2 = *Ptr - 1; AllScreenLines[AllScreenLinesNumber].Valid = 1; if (AllScreenLinesNumber < 16383) AllScreenLinesNumber++; } } } if (!AllScreenLinesNumber) return; if (!AllScreenDotNumber) return; /* Optimize */ VEC_COMPRESS(); for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { ScreenDot *P1,*P2; P1 = &AllScreenDot[AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex]; P2 = &AllScreenDot[AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex]; DrawLine(MapDST,P1->X,P1->Y,P2->X,P2->Y,0x8000); } u32 AllScreenLinesNumberSave,AllScreenDotNumberSave; AllScreenLinesNumberSave = AllScreenDotNumberSave = 0; if (Optimize) { OptimizeErrorCoef = OptimizeErrorCoef_PASS1; while ( (AllScreenLinesNumberSave != AllScreenLinesNumber) && (AllScreenDotNumberSave != AllScreenDotNumber)) { AllScreenLinesNumberSave = AllScreenLinesNumber; AllScreenDotNumberSave = AllScreenDotNumber; LINE_MERGE(); VEC_COMPRESS(); };//*/ AllScreenLinesNumberSave = AllScreenDotNumberSave = 0; OptimizeErrorCoef = OptimizeErrorCoef_PASS2; while ( (AllScreenLinesNumberSave != AllScreenLinesNumber) && (AllScreenDotNumberSave != AllScreenDotNumber)) { AllScreenLinesNumberSave = AllScreenLinesNumber; AllScreenDotNumberSave = AllScreenDotNumber; LINE_MERGE(); VEC_COMPRESS(); };//*/ } //VEC_COMPRESS(); /* Render */ EVALUATE_ERROR(); /* for (int Counter = 0 ; Counter < AllScreenDotNumber ; Counter++) { AllScreenDot[Counter].X += (u32)(rand()% 4); AllScreenDot[Counter].Y += (u32)(rand()% 4); } //*/ SET(MapDST,0xffffff); for (int Counter = 0 ; Counter < AllScreenLinesNumber ; Counter++) { ScreenDot *P1,*P2; P1 = &AllScreenDot[AllScreenDot[AllScreenLines[Counter].Index1].LinkIndex]; P2 = &AllScreenDot[AllScreenDot[AllScreenLines[Counter].Index2].LinkIndex]; u32 Color = 0; if (Counter & 1) Color |= 0x80; if (Counter & 2) Color |= 0x80<<8; if (Counter & 4) Color |= 0x80<<16; if (Counter & 8) Color |= 0x40; if (Counter & 16) Color |= 0x40<<8; if (Counter & 32) Color |= 0x40<<16; Color = 0; if (AllScreenLines[Counter].Valid == 1) DrawLine(MapDST,P1->X,P1->Y,P2->X,P2->Y,Color); else DrawLine(MapDST,P1->X,P1->Y,P2->X,P2->Y,Color);//*/ } void DrawCross(MAP *image, POINT p, u32 color, int len, char orient = 3); for (int Counter = 0 ; Counter < AllScreenDotNumber ; Counter++) { if (DrawDot) { /* if (AllScreenDot[Counter].EdgeNumb != 2) { POINT p; p.x = AllScreenDot[Counter].X; p.y = AllScreenDot[Counter].Y; u32 Color; Color = AllScreenDot[Counter].Error * 10; if (Color > 255) Color = 255; Color |= Color<<8; Color |= Color<<8; DrawQuad( MapDST,p.x-2,p.y-2,p.x+2,p.y+2,Color,1); // DrawCross(MapDST,p,Color, 1); } //*/ if (AllScreenDot[Counter].EdgeNumb == 2) { POINT p; p.x = AllScreenDot[Counter].X; p.y = AllScreenDot[Counter].Y; u32 Color; Color = AllScreenDot[Counter].Error * 10; if (Color > 255) Color = 255; Color |= Color<<8; Color |= Color<<8; //DrawQuad( MapDST,p.x-2,p.y-2,p.x+2,p.y+2,Color,1); DrawCross(MapDST,p,Color, 1); } if (AllScreenDot[Counter].EdgeNumb == 0) { POINT p; p.x = AllScreenDot[Counter].X; p.y = AllScreenDot[Counter].Y; u32 Color; Color = AllScreenDot[Counter].Error * 10; Color = 255; Color |= Color<<8; Color |= Color<<8; //DrawQuad( MapDST,p.x-2,p.y-2,p.x+2,p.y+2,Color,1); DrawCross(MapDST,p,Color, 1); } /*else if (AllScreenDot[Counter].EdgeNumb > 2) { POINT p; p.x = AllScreenDot[Counter].X; p.y = AllScreenDot[Counter].Y; DrawCross(MapDST,p,0xff0000, 1); } /*else if (AllScreenDot[Counter].EdgeNumb) { POINT p; p.x = AllScreenDot[Counter].X; p.y = AllScreenDot[Counter].Y; DrawCross(MapDST,p, 0xffffff , 1); } //*/ } }//*/ char DEG[1024]; sprintf(DEG,"NPE:%d NLE:%d",AllScreenDotNumber,AllScreenLinesNumber); DRawTEXT_Soft_B((u8*)DEG,(u32*)MapDST->GetBase(),0,40,MapDST->SX, MapDST->SY, 0xff0000); STOP_RASTER(Vectorization); }