void ArrangeByCell (CSymbolTable &Table, int cxDesiredWidth, CPaintMap &Map) { int i; // Compute the size of each image cell int cxCell = 32; int cyCell = 32; // Compute the number of rows & columns int iInitCols = (cxDesiredWidth / cxCell) + ((cxDesiredWidth % cxCell) ? 1 : 0); int iInitRows = AlignUp(20 * Table.GetCount(), iInitCols) / iInitCols; // Create an array that keeps track of which cells we've used up CCellMap CellMap(iInitCols, iInitRows); // Figure out where to place all the ships for (i = 0; i < Table.GetCount(); i++) { CShipClass *pClass = (CShipClass *)Table.GetValue(i); // Figure out how many cells we need int cxSize = RectWidth(pClass->GetImage().GetImageRect()); int iCellsNeeded = AlignUp(cxSize, cxCell) / cxCell; int cxAreaSize = iCellsNeeded * cxCell; // Position the ship int x, y; if (CellMap.GetSpace(iCellsNeeded, &x, &y)) Map.Place(i, x * cxCell + (cxAreaSize - cxSize) / 2, y * cyCell + (cxAreaSize - cxSize) / 2, cxSize, cxSize); } }
void CListSaveFilesTask::CreateFileEntry (CGameFile &GameFile, const CTimeDate &ModifiedTime, int yStart, IAnimatron **retpEntry, int *retcyHeight) // CreateFileEntry // // Creates a display entry for the save file { const CVisualPalette &VI = m_HI.GetVisuals(); const CG16bitFont &MediumFont = VI.GetFont(fontMedium); const CG16bitFont &SubTitleFont = VI.GetFont(fontSubTitle); int x = 0; int y = 0; int xText = x + ADVENTURE_ICON_WIDTH + ICON_SPACING_HORZ; int cxText = m_cxWidth - (ADVENTURE_ICON_WIDTH + 2 * ICON_SPACING_HORZ + SHIP_IMAGE_WIDTH); // Start with a sequencer CAniSequencer *pRoot = new CAniSequencer; pRoot->SetPropertyVector(PROP_POSITION, CVector(0, yStart)); // Add the character name and current star system CString sHeading = strPatternSubst(CONSTLIT("%s — %s"), GameFile.GetPlayerName(), GameFile.GetSystemName()); IAnimatron *pName = new CAniText; pName->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pName->SetPropertyVector(PROP_SCALE, CVector(10000, 1000)); pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput)); pName->SetPropertyFont(PROP_FONT, &SubTitleFont); pName->SetPropertyString(PROP_TEXT, sHeading); pRoot->AddTrack(pName, 0); y += SubTitleFont.GetHeight(); // Now add some additional information CShipClass *pClass = g_pUniverse->FindShipClass(GameFile.GetPlayerShip()); CString sShipClass = (pClass ? pClass->GetName() : NULL_STR); CString sGenome = strCapitalize(GetGenomeName(GameFile.GetPlayerGenome())); CString sState; if (GameFile.IsGameResurrect()) sState = strPatternSubst(CONSTLIT("Resurrect in the %s System"), GameFile.GetSystemName()); else sState = strPatternSubst(CONSTLIT("Continue in the %s System"), GameFile.GetSystemName()); CString sDesc; if (!sGenome.IsBlank() && !sShipClass.IsBlank()) sDesc = strPatternSubst(CONSTLIT("%s — %s — %s"), sGenome, sShipClass, sState); else sDesc = sState; IAnimatron *pDesc = new CAniText; pDesc->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000)); pDesc->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput)); pDesc->SetPropertyFont(PROP_FONT, &MediumFont); pDesc->SetPropertyString(PROP_TEXT, sDesc); RECT rcLine; pDesc->GetSpacingRect(&rcLine); pRoot->AddTrack(pDesc, 0); y += RectHeight(rcLine); // Adventure info CExtension *pAdventure = NULL; bool bHasAdventureIcon = false; if (g_pUniverse->FindExtension(GameFile.GetAdventure(), 0, &pAdventure)) { // Adventure icon CG16bitImage *pIcon; pAdventure->CreateIcon(ADVENTURE_ICON_WIDTH, ADVENTURE_ICON_HEIGHT, &pIcon); if (pIcon) { int xOffset = (ADVENTURE_ICON_WIDTH - pIcon->GetWidth()) / 2; IAnimatron *pIconAni = new CAniRect; pIconAni->SetPropertyVector(PROP_POSITION, CVector(x + xOffset, 0)); pIconAni->SetPropertyVector(PROP_SCALE, CVector(pIcon->GetWidth(), pIcon->GetHeight())); pIconAni->SetFillMethod(new CAniImageFill(pIcon, true)); pRoot->AddTrack(pIconAni, 0); bHasAdventureIcon = true; } // Adventure name pName = new CAniText; pName->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pName->SetPropertyVector(PROP_SCALE, CVector(10000, 1000)); pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel)); pName->SetPropertyFont(PROP_FONT, &MediumFont); pName->SetPropertyString(PROP_TEXT, pAdventure->GetName()); pRoot->AddTrack(pName, 0); y += MediumFont.GetHeight(); } // Create an image of the ship class if (pClass) { const CObjectImageArray &ObjImage = pClass->GetImage(); if (ObjImage.IsLoaded()) { RECT rcRect = ObjImage.GetImageRect(); CG16bitImage &Image = ObjImage.GetImage(NULL_STR); int cxImage = RectWidth(rcRect); int cyImage = RectHeight(rcRect); int cxNewWidth = Min(SHIP_IMAGE_WIDTH, cxImage); int cyNewHeight = cxNewWidth; CG16bitImage *pNewImage = new CG16bitImage; pNewImage->CreateFromImageTransformed(Image, rcRect.left, rcRect.top, cxImage, cyImage, (Metric)cxNewWidth / cxImage, (Metric)cyNewHeight / cyImage, 0.0); // Position int xImage = x + m_cxWidth - SHIP_IMAGE_WIDTH + (SHIP_IMAGE_WIDTH - cxNewWidth) / 2; int yImage = (SHIP_IMAGE_HEIGHT - cyNewHeight) / 2; // New image frame IAnimatron *pImageFrame = new CAniRect; pImageFrame->SetPropertyVector(PROP_POSITION, CVector(xImage, yImage)); pImageFrame->SetPropertyVector(PROP_SCALE, CVector(cxNewWidth, cyNewHeight)); pImageFrame->SetFillMethod(new CAniImageFill(pNewImage, true)); pRoot->AddTrack(pImageFrame, 0); } } // Extra information CString sEpitaph = GameFile.GetEpitaph(); int iScore = GameFile.GetScore(); CTimeDate LocalTime = ModifiedTime.ToLocalTime(); CString sModifiedTime = LocalTime.Format("%d %B %Y %I:%M %p"); CString sFilename = pathGetFilename(GameFile.GetFilespec()); CString sGameType; if (GameFile.IsRegistered()) sGameType = CONSTLIT("Registered"); else if (GameFile.IsDebug()) sGameType = CONSTLIT("Debug"); else sGameType = CONSTLIT("Unregistered"); CString sExtra; if (!sEpitaph.IsBlank()) sExtra = strPatternSubst(CONSTLIT("Score %d — %s\n%s — %s — %s"), iScore, sEpitaph, sGameType, sModifiedTime, sFilename); else if (iScore > 0) sExtra = strPatternSubst(CONSTLIT("Score %d\n%s — %s — %s"), iScore, sGameType, sModifiedTime, sFilename); else sExtra = strPatternSubst(CONSTLIT("%s — %s — %s"), sGameType, sModifiedTime, sFilename); pDesc = new CAniText; pDesc->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000)); pDesc->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel)); pDesc->SetPropertyFont(PROP_FONT, &MediumFont); pDesc->SetPropertyString(PROP_TEXT, sExtra); pDesc->GetSpacingRect(&rcLine); pRoot->AddTrack(pDesc, 0); y += RectHeight(rcLine); // Done *retpEntry = pRoot; if (retcyHeight) *retcyHeight = (bHasAdventureIcon ? Max(ADVENTURE_ICON_HEIGHT, y) : y); }
void GenerateImageChart (CUniverse &Universe, CXMLElement *pCmdLine) { int i; enum OrderTypes { orderSmallest = 1, orderLargest = 2, orderName = 3, orderLevel = 4, orderSovereign = 5, orderManufacturer = 6, }; // Item criteria bool bHasItemCriteria; CString sCriteria; CItemCriteria ItemCriteria; if (bHasItemCriteria = pCmdLine->FindAttribute(CONSTLIT("itemCriteria"), &sCriteria)) CItem::ParseCriteria(sCriteria, &ItemCriteria); else CItem::InitCriteriaAll(&ItemCriteria); // Get the criteria from the command line. CDesignTypeCriteria Criteria; if (pCmdLine->FindAttribute(CONSTLIT("criteria"), &sCriteria)) { if (CDesignTypeCriteria::ParseCriteria(sCriteria, &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } } else if (bHasItemCriteria) { if (CDesignTypeCriteria::ParseCriteria(CONSTLIT("i"), &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } } else { printf("ERROR: Expected criteria.\n"); return; } bool bAll = pCmdLine->GetAttributeBool(CONSTLIT("all")); // Options bool bTextBoxesOnly = pCmdLine->GetAttributeBool(CONSTLIT("textBoxesOnly")); bool bFieldUNID = pCmdLine->GetAttributeBool(CONSTLIT("unid")); // Figure out what order we want CString sOrder = pCmdLine->GetAttribute(CONSTLIT("sort")); int iOrder; if (strEquals(sOrder, CONSTLIT("smallest"))) iOrder = orderSmallest; else if (strEquals(sOrder, CONSTLIT("largest"))) iOrder = orderLargest; else if (strEquals(sOrder, CONSTLIT("level"))) iOrder = orderLevel; else if (strEquals(sOrder, CONSTLIT("sovereign"))) iOrder = orderSovereign; else if (strEquals(sOrder, CONSTLIT("manufacturer"))) iOrder = orderManufacturer; else iOrder = orderName; bool b3DGrid = pCmdLine->GetAttributeBool(CONSTLIT("3DGrid")); bool bDockingPorts = pCmdLine->GetAttributeBool(CONSTLIT("portPos")); bool bDevicePos = pCmdLine->GetAttributeBool(CONSTLIT("devicePos")); // Image size int cxDesiredWidth; if (pCmdLine->FindAttributeInteger(CONSTLIT("width"), &cxDesiredWidth)) cxDesiredWidth = Max(512, cxDesiredWidth); else cxDesiredWidth = 1280; // Spacing int cxSpacing = pCmdLine->GetAttributeInteger(CONSTLIT("xSpacing")); int cxExtraMargin = pCmdLine->GetAttributeInteger(CONSTLIT("xMargin")); int cxImageMargin = 2 * pCmdLine->GetAttributeInteger(CONSTLIT("xImageMargin")); // Font for text CString sTypeface; int iSize; bool bBold; bool bItalic; if (!CG16bitFont::ParseFontDesc(pCmdLine->GetAttribute(CONSTLIT("font")), &sTypeface, &iSize, &bBold, &bItalic)) { sTypeface = CONSTLIT("Arial"); iSize = 10; bBold = false; bItalic = false; } CG16bitFont NameFont; NameFont.Create(sTypeface, -PointsToPixels(iSize), bBold, bItalic); CG32bitPixel rgbNameColor = CG32bitPixel(255, 255, 255); // Rotation int iRotation = pCmdLine->GetAttributeInteger(CONSTLIT("rotation")); // Output file CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output")); if (!sFilespec.IsBlank()) sFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp")); // Generate a sorted table of types TSortMap<CString, SEntryDesc> Table; for (i = 0; i < Universe.GetDesignTypeCount(); i++) { CDesignType *pType = Universe.GetDesignType(i); SEntryDesc NewEntry; // Make sure we match the criteria if (!pType->MatchesCriteria(Criteria)) continue; // Figure stuff stuff out based on the specific design type switch (pType->GetType()) { case designItemType: { CItemType *pItemType = CItemType::AsType(pType); CItem Item(pItemType, 1); // Skip if not in item criteria if (!Item.MatchesCriteria(ItemCriteria)) continue; // Skip virtual classes if (pItemType->IsVirtual()) continue; // Initialize the entry NewEntry.pType = pType; NewEntry.sName = pItemType->GetNounPhrase(0); NewEntry.pImage = &pItemType->GetImage(); NewEntry.iSize = RectWidth(NewEntry.pImage->GetImageRect()); break; } case designShipClass: { CShipClass *pClass = CShipClass::AsType(pType); // Skip non-generic classess if (!bAll && !pClass->HasLiteralAttribute(CONSTLIT("genericClass"))) continue; // Initialize the entry NewEntry.pType = pType; NewEntry.sName = pClass->GetNounPhrase(0); NewEntry.iSize = RectWidth(pClass->GetImage().GetImageRect()); NewEntry.pImage = &pClass->GetImage(); NewEntry.iRotation = pClass->Angle2Direction(iRotation); NewEntry.sSovereignName = (pClass->GetDefaultSovereign() ? pClass->GetDefaultSovereign()->GetTypeNounPhrase() : NULL_STR); break; } case designStationType: { CStationType *pStationType = CStationType::AsType(pType); // Skip generic classes if (!bAll && !pStationType->HasLiteralAttribute(CONSTLIT("generic"))) continue; NewEntry.pType = pType; NewEntry.sName = pStationType->GetNounPhrase(0); NewEntry.iSize = pStationType->GetSize(); NewEntry.sSovereignName = (pStationType->GetSovereign() ? pStationType->GetSovereign()->GetTypeNounPhrase() : NULL_STR); InitStationTypeImage(NewEntry, pStationType); break; } default: // Don't know how to handle this type continue; break; } // Adjust name if (bFieldUNID) NewEntry.sName = strPatternSubst(CONSTLIT("%s (%x)"), NewEntry.sName, NewEntry.pType->GetUNID()); // Compute the sort key char szBuffer[1024]; switch (iOrder) { case orderLargest: wsprintf(szBuffer, "%09d%s%x", 1000000 - NewEntry.iSize, NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderLevel: wsprintf(szBuffer, "%09d%s%x", pType->GetLevel(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderSmallest: wsprintf(szBuffer, "%09d%s%x", NewEntry.iSize, NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderSovereign: wsprintf(szBuffer, "%s|%s|%x", NewEntry.sSovereignName.GetASCIIZPointer(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); NewEntry.sCategorize = NewEntry.sSovereignName; break; case orderManufacturer: { CString sManufacturer = NewEntry.pType->GetPropertyString(CONSTLIT("manufacturer")); wsprintf(szBuffer, "%s|%s|%x", sManufacturer.GetASCIIZPointer(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); NewEntry.sCategorize = sManufacturer; break; } default: wsprintf(szBuffer, "%s%x", NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; } // Add to list Table.Insert(CString(szBuffer), NewEntry); } // Allocate an arranger that tracks where to paint each world. CImageArranger Arranger; // Settings for the overall arrangement CImageArranger::SArrangeDesc Desc; Desc.cxDesiredWidth = Max(512, cxDesiredWidth - (2 * (cxSpacing + cxExtraMargin))); Desc.cxSpacing = cxSpacing; Desc.cxExtraMargin = cxExtraMargin; Desc.pHeader = &NameFont; // Generate a table of cells for the arranger TArray<CCompositeImageSelector> Selectors; Selectors.InsertEmpty(Table.GetCount()); CString sLastCategory; TArray<CImageArranger::SCellDesc> Cells; for (i = 0; i < Table.GetCount(); i++) { SEntryDesc &Entry = Table[i]; CImageArranger::SCellDesc *pNewCell = Cells.Insert(); pNewCell->cxWidth = (Entry.pImage ? RectWidth(Entry.pImage->GetImageRect()) : 0) + cxImageMargin; pNewCell->cyHeight = (Entry.pImage ? RectHeight(Entry.pImage->GetImageRect()) : 0) + cxImageMargin; pNewCell->sText = Entry.sName; if (!strEquals(sLastCategory, Entry.sCategorize)) { sLastCategory = Entry.sCategorize; pNewCell->bStartNewRow = true; } } // Arrange Arranger.ArrangeByRow(Desc, Cells); // Create a large image CG32bitImage Output; int cxWidth = Max(cxDesiredWidth, Arranger.GetWidth()); int cyHeight = Arranger.GetHeight(); Output.Create(cxWidth, cyHeight); printf("Creating %dx%d image.\n", cxWidth, cyHeight); // Paint the images for (i = 0; i < Table.GetCount(); i++) { SEntryDesc &Entry = Table[i]; int x = Arranger.GetX(i); int y = Arranger.GetY(i); // Paint if (x != -1) { int xCenter = x + (Arranger.GetWidth(i) / 2); int yCenter = y + (Arranger.GetHeight(i) / 2); int xOffset; int yOffset; Entry.pImage->GetImageOffset(0, Entry.iRotation, &xOffset, &yOffset); int cxImage = RectWidth(Entry.pImage->GetImageRect()); int cyImage = RectHeight(Entry.pImage->GetImageRect()); // Paint image if (!bTextBoxesOnly && Entry.pImage) { Entry.pImage->PaintImageUL(Output, x + (Arranger.GetWidth(i) - cxImage) / 2, y + (Arranger.GetHeight(i) - cyImage) / 2, 0, Entry.iRotation); } // Paint type specific stuff switch (Entry.pType->GetType()) { case designStationType: { CStationType *pStationType = CStationType::AsType(Entry.pType); int xStationCenter = xCenter - xOffset; int yStationCenter = yCenter - yOffset; if (bDockingPorts) pStationType->PaintDockPortPositions(Output, xStationCenter, yStationCenter); if (bDevicePos) pStationType->PaintDevicePositions(Output, xStationCenter, yStationCenter); // If we have docking or device positions, mark the center of the station if (bDockingPorts || bDevicePos) { const int LINE_HALF_LENGTH = 24; const CG32bitPixel RGB_CENTER_CROSS(255, 255, 0); Output.DrawLine(xStationCenter - LINE_HALF_LENGTH, yStationCenter, xStationCenter + LINE_HALF_LENGTH, yStationCenter, 1, RGB_CENTER_CROSS); Output.DrawLine(xStationCenter, yStationCenter - LINE_HALF_LENGTH, xStationCenter, yStationCenter + LINE_HALF_LENGTH, 1, RGB_CENTER_CROSS); } break; } } // Paint the 3D grid, if necessary if (b3DGrid) { int iScale = Entry.pImage->GetImageViewportSize(); Metric rMaxRadius = g_KlicksPerPixel * cxImage * 0.5; const Metric rGridSize = LIGHT_SECOND; Metric rRadius; for (rRadius = rGridSize; rRadius <= rMaxRadius; rRadius += rGridSize) { int iRadius = (int)((rRadius / g_KlicksPerPixel) + 0.5); const int iGridAngle = 8; int iPrevAngle = 0; int iAngle; for (iAngle = iGridAngle; iAngle <= 360; iAngle += iGridAngle) { int xFrom, yFrom; C3DConversion::CalcCoord(iScale, iPrevAngle, iRadius, 0, &xFrom, &yFrom); int xTo, yTo; C3DConversion::CalcCoord(iScale, iAngle, iRadius, 0, &xTo, &yTo); Output.DrawLine(xFrom + xCenter, yFrom + yCenter, xTo + xCenter, yTo + yCenter, 1, CG32bitPixel(255, 255, 0)); iPrevAngle = iAngle; } } } // Paint name int xText = Arranger.GetTextX(i); int yText = Arranger.GetTextY(i); if (xText != -1) { if (bTextBoxesOnly) Output.Fill(xText, yText, Arranger.GetTextWidth(i), Arranger.GetTextHeight(i), 0xffff); if (!bTextBoxesOnly) { Output.FillColumn(xCenter, y + Arranger.GetHeight(i), yText - (y + Arranger.GetHeight(i)), rgbNameColor); NameFont.DrawText(Output, xText, yText, rgbNameColor, Entry.sName); } } } } // Write to file or clipboard OutputImage(Output, sFilespec); }
void GenerateShipImageChart (CUniverse &Universe, CXMLElement *pCmdLine) { int i; enum OrderTypes { orderSmallest = 1, orderLargest = 2, orderName = 3, }; // Options bool bTextBoxesOnly = pCmdLine->GetAttributeBool(CONSTLIT("textBoxesOnly")); // Figure out what order we want CString sOrder = pCmdLine->GetAttribute(CONSTLIT("sort")); int iOrder; if (strEquals(sOrder, CONSTLIT("smallest"))) iOrder = orderSmallest; else if (strEquals(sOrder, CONSTLIT("largest"))) iOrder = orderLargest; else iOrder = orderName; // Image size int cxDesiredWidth; if (pCmdLine->FindAttributeInteger(CONSTLIT("width"), &cxDesiredWidth)) cxDesiredWidth = Max(512, cxDesiredWidth); else cxDesiredWidth = 1280; // Spacing int cxSpacing = pCmdLine->GetAttributeInteger(CONSTLIT("xSpacing")); int cxExtraMargin = pCmdLine->GetAttributeInteger(CONSTLIT("xMargin")); // Rotation int iRotation = pCmdLine->GetAttributeInteger(CONSTLIT("rotation")); // Font for text CString sTypeface; int iSize; bool bBold; bool bItalic; if (!CG16bitFont::ParseFontDesc(pCmdLine->GetAttribute(CONSTLIT("font")), &sTypeface, &iSize, &bBold, &bItalic)) { sTypeface = CONSTLIT("Arial"); iSize = 10; bBold = false; bItalic = false; } CG16bitFont NameFont; NameFont.Create(sTypeface, -PointsToPixels(iSize), bBold, bItalic); WORD wNameColor = CG16bitImage::RGBValue(255, 255, 255); // Output file CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output")); if (!sFilespec.IsBlank()) sFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp")); // Generate a table of ships CSymbolTable Table(FALSE, TRUE); for (i = 0; i < Universe.GetShipClassCount(); i++) { CShipClass *pClass = Universe.GetShipClass(i); // Skip player ship classes if (pClass->GetPlayerSettings()) continue; // Skip non-generic classes if (!pClass->HasAttribute(CONSTLIT("genericClass"))) continue; // Compute the sort key char szBuffer[1024]; switch (iOrder) { case orderLargest: wsprintf(szBuffer, "%04d%s%x", 2048 - RectWidth(pClass->GetImage().GetImageRect()), pClass->GetName().GetASCIIZPointer(), pClass); break; case orderSmallest: wsprintf(szBuffer, "%04d%s%x", RectWidth(pClass->GetImage().GetImageRect()), pClass->GetName().GetASCIIZPointer(), pClass); break; default: wsprintf(szBuffer, "%s%x", pClass->GetName().GetASCIIZPointer(), pClass); break; } // Add to list Table.AddEntry(CString(szBuffer), (CObject *)pClass); } // Allocate a map that tracks where to paint each ship CPaintMap Map(Table.GetCount()); // Arrange the ships SArrangeDesc Desc; Desc.cxDesiredWidth = Max(512, cxDesiredWidth - (2 * (cxSpacing + cxExtraMargin))); Desc.cxSpacing = cxSpacing; Desc.cxExtraMargin = cxExtraMargin; Desc.pHeader = &NameFont; ArrangeByRow(Table, Desc, Map); //ArrangeByCell(Table, cxDesiredWidth, Map); // Create a large image CG16bitImage Output; int cxWidth = Max(cxDesiredWidth, Map.GetWidth()); int cyHeight = Map.GetHeight(); Output.CreateBlank(cxWidth, cyHeight, false); printf("Creating %dx%d image.\n", cxWidth, cyHeight); // Paint the images for (i = 0; i < Table.GetCount(); i++) { CShipClass *pClass = (CShipClass *)Table.GetValue(i); int x = Map.GetX(i); int y = Map.GetY(i); if (x != -1) { if (!bTextBoxesOnly) pClass->GetImage().PaintImageUL(Output, x, y, 0, Angle2Direction(iRotation)); // Paint name int xText = Map.GetTextX(i); int yText = Map.GetTextY(i); if (xText != -1) { if (bTextBoxesOnly) Output.Fill(xText, yText, Map.GetTextWidth(i), Map.GetTextHeight(i), 0xffff); if (!bTextBoxesOnly) { Output.FillColumn(x + (Map.GetWidth(i) / 2), y + Map.GetHeight(i), yText - (y + Map.GetHeight(i)), wNameColor); NameFont.DrawText(Output, xText, yText, wNameColor, 255, pClass->GetNounPhrase(0)); } } } } // Write to file or clipboard OutputImage(Output, sFilespec); }
void ArrangeByRow (CSymbolTable &Table, SArrangeDesc &Desc, CPaintMap &Map) { int iNext = 0; int y = 0; int cyHeader = Desc.pHeader->GetHeight(); int cxInternalSpacing = 8; int cyInternalSpacing = 2 * Desc.pHeader->GetHeight(); int cyNameSpacing = Desc.pHeader->GetHeight() / 2; while (iNext < Table.GetCount()) { int i; int cxWidthLeft = Desc.cxDesiredWidth; int cyRowHeight = 0; int iStart = iNext; // First figure out how many ships will fit while (iNext < Table.GetCount()) { CShipClass *pClass = (CShipClass *)Table.GetValue(iNext); int cxSize = RectWidth(pClass->GetImage().GetImageRect()); if (cxSize > cxWidthLeft && iStart != iNext) break; int cxCell = Max(cxSize + cxInternalSpacing, Desc.cxSpacing); cxWidthLeft -= cxCell; if (cxSize > cyRowHeight) cyRowHeight = cxSize; iNext++; } // Compute the total width int cxRowWidth = Min(Desc.cxDesiredWidth - cxWidthLeft, Desc.cxDesiredWidth); int xOffset = (Desc.cxDesiredWidth - cxRowWidth) / 2; // See if any of the ships overlap the text from the previous ships // If so, we increase y a little bit int x = Desc.cxSpacing + Desc.cxExtraMargin; for (i = iStart; i < iNext; i++) { CShipClass *pClass = (CShipClass *)Table.GetValue(i); int cxSize = RectWidth(pClass->GetImage().GetImageRect()); int yOffset = (cyRowHeight - cxSize) / 2; int xPoint = x + xOffset + cxSize / 2; int yPoint = y + yOffset; for (int j = 0; j < iStart; j++) { int xText = Map.GetTextX(j); int yText = Map.GetTextY(j); int cxText = Map.GetTextWidth(j); int cyText = Map.GetTextHeight(j) + cyInternalSpacing; if (xPoint >= xText && xPoint < xText + cxText && yPoint < yText + cyText) y = yText + cyText + cyInternalSpacing; } int cxCell = Max(cxSize + cxInternalSpacing, Desc.cxSpacing); x += cxCell; } // Place the ships x = Desc.cxSpacing + Desc.cxExtraMargin; int yOverlapOffset = 0; for (i = iStart; i < iNext; i++) { CShipClass *pClass = (CShipClass *)Table.GetValue(i); int cxSize = RectWidth(pClass->GetImage().GetImageRect()); int cxCell = Max(cxSize + cxInternalSpacing, Desc.cxSpacing); // Center vertically int yOffset = (cyRowHeight - cxSize) / 2; // Place Map.Place(i, x + xOffset, y + yOffset, cxSize, cxSize); // Figure out the position of the text int cyName; int cxName = Desc.pHeader->MeasureText(pClass->GetNounPhrase(0), &cyName); if (cxName <= cxSize) { int yText = y + yOffset + cxSize + cyNameSpacing; Map.PlaceText(i, x + xOffset + (cxSize - cxName) / 2, yText, cxName, cyName); yOverlapOffset = yText + cyName + cyNameSpacing; } else { // See if the name fits above the previous name int yText; if (yOverlapOffset > 0 && i > iStart && (x + xOffset + cxSize - (Map.GetX(i - 1) + Map.GetWidth(i - 1) / 2)) > cxName + 8) { yText = y + yOffset + cxSize + cyNameSpacing; if (yText < Map.GetY(i - 1) + Map.GetHeight(i - 1)) yText = Map.GetY(i - 1) + Map.GetHeight(i - 1) + cyNameSpacing; if (yText > Map.GetTextY(i - 1) - (cyName + cyNameSpacing)) yText = yOverlapOffset; } // Otherwise, use the overlap, if it exits else if (yOverlapOffset == 0) yText = y + yOffset + cxSize + cyNameSpacing; else yText = yOverlapOffset; Map.PlaceText(i, x + xOffset + cxSize - cxName, yText, cxName, cyName); yOverlapOffset = yText + cyName + cyNameSpacing; } x += cxCell; } y += cyRowHeight; } // Add a margin to the right and bottom Map.AddMargin(Desc.cxSpacing + Desc.cxExtraMargin, cyInternalSpacing); }