// -- Creates a JB2Image with the remaining components GP<JB2Image> CCImage::get_jb2image() const { GP<JB2Image> jimg = JB2Image::create(); jimg->set_dimension(width, height); if (runs.hbound() < 0) return jimg; if (ccs.hbound() < 0) G_THROW("Must first perform a cc analysis"); // Iterate over CCs for (int ccid=0; ccid<=ccs.hbound(); ccid++) { JB2Shape shape; JB2Blit blit; shape.parent = -1; shape.bits = get_bitmap_for_cc(ccid); shape.userdata = 0; if (ccid >= nregularccs) shape.userdata |= JB2SHAPE_SPECIAL; blit.shapeno = jimg->add_shape(shape); blit.left = ccs[ccid].bb.xmin; blit.bottom = ccs[ccid].bb.ymin; jimg->add_blit(blit); shape.bits->compress(); } // Return return jimg; }
//************************************ // Method: ShowWinline // FullName: BSSlotsContainer::ShowWinline // Access: protected // Returns: bool // Qualifier: show winline // Parameter: const int id : winlinID //************************************ bool BSSlotsContainer::SetupWinline(const int winlineID, const int timeToShowPerWinline) { if(m_pTicketGenerator == NULL) return false; //show winline slot animations; if(!m_winlineReelSlotsDict.KeyExists(winlineID)) { GTLogManager::SLogFormatWarning("Warning! Can not find winline%d!", winlineID); return false; } GTArray<GTVector2>* pWinSlotsInReel = NULL; m_winlineReelSlotsDict.GetValueByKey(winlineID, pWinSlotsInReel); if(pWinSlotsInReel != NULL) { for(int i=0; i < pWinSlotsInReel->Length(); i++) { GTVector2 value = (*pWinSlotsInReel)[i]; int reelID = value.x; int slotPos = value.y; m_reelColumns[reelID]->ShowWinline(winlineID, slotPos, timeToShowPerWinline); //GTLogManager::SLogFormatComment("----- show winline %d ------- reel %d : status = %d --> slot[%d] win!!!", // it->first, reelID, m_reelColumns[reelID]->GetStatus(), slotPos); } return true; } return false; }
//check all reels status; GTArray<BSReelColumn::ColumnStatus> BSSlotsContainer::CheckAllReelsStatus() { GTArray<BSReelColumn::ColumnStatus> reelColumnsStatus; for(int i = 0; i < m_reelColumnCount; i++) { BSReelColumn::ColumnStatus status = m_reelColumns[i]->GetStatus(); reelColumnsStatus.Add(status); } return reelColumnsStatus; }
// -- Adds a run to the CCImage inline void CCImage::add_single_run(int y, int x1, int x2, int ccid) { int index = runs.hbound(); runs.touch(++index); Run& run = runs[index]; run.y = y; run.x1 = x1; run.x2 = x2; run.ccid = ccid; }
void CCImage::init(int w, int h, int dpi) { runs.empty(); ccs.empty(); height = h; width = w; nregularccs = 0; dpi = MAX(200, MIN(900, dpi)); largesize = MIN( 500, MAX(64, dpi)); smallsize = MAX(2, dpi/150); tinysize = MAX(0, dpi*dpi/20000 - 1); }
//************************************ // Method: CreateTicket // FullName: BSSlotsContainer::BuildTicket // Access: public // Returns: void // Qualifier: based on real slot symbols to build fake tickets to all reels; Fake reels(top & bottom invisible) // Parameter: GTArray<int> slotSymbols : //************************************ void BSSlotsContainer::BuildTicket(GTArray<int> slotSymbols) { #ifdef GT_DEBUG GTLogManager::SLogFormatComment("<------------- slot symbols (visible part current 3X5 reels)----------->"); GTLogManager::SLogFormatComment(slotSymbols.ToString()); #endif //based on real slot symbols to create fake tickets to all reels; //make Fake reels(top & bottom invisible) //for exmaple: // 2, 3, 5, 6, 5, // 5, 5, 5, 8, 1, // 4, 3, 3, 3, 3 // make 5 reels // reel1: 0, 2, 5, 4, 0 // reel2: 0, 3, 5, 3, 0 // and so on GTDictionary<int, GTArray<int>* > reeltickets; //initialize for(int reelIndex = 0; reelIndex < m_reelColumns.Count(); reelIndex++) { GTArray<int>* pTickets = new GTArray<int>(); pTickets->AddToTail(0); //make fake symbols for top invisible symbols reeltickets.Add(reelIndex, pTickets); } //add reel symbols; for(int i = 0; i < slotSymbols.Length(); i++) { int reelID = i % m_reelColumns.Count(); int slotSymbolValue = slotSymbols[i]; GTArray<int>* pTickets = NULL; reeltickets.GetValueByKey(reelID, pTickets); pTickets->AddToTail(slotSymbolValue); } //make fake symbols for top and bottom invisible symbols; for(int reelIndex = 0; reelIndex < m_reelColumns.Count(); reelIndex++) { GTArray<int>* pTickets; reeltickets.GetValueByKey(reelIndex, pTickets); pTickets->AddToTail(0); //make fake symbols for bottom invisible symbols m_reelColumns[reelIndex]->SetTicket(*pTickets); //send it to every reel; delete pTickets; } m_slotsSymbols = slotSymbols; }
//************************************ // Method: GetReelWinSlotsForWinlines // FullName: BSSlotsContainer::GetReelWinSlotsForWinlines // Access: protected // Returns: GTDictionary<int, GTArray<GTVector2>* > key = winlineID, value = (reelID, slotID) // Qualifier: based on finalWinlineRes and winline define, match to every win slot position in every reel; and get (reel and win slots in this reel) for all winline // Parameter: GTDictionary<int, WinlineValue> finalWinlineRes : key = winlineID, value = winlineValue; //************************************ void BSSlotsContainer::GetReelWinSlotsForWinlines(GTDictionary<int, WinlineValue>* pFinalWinlineRes) { //get winline define; GTDictionary<int, GTArray<int> >* pSourceWinlines = WinlineAlgorithm::GetWinlines(); // based on finalWinlineRes and winline define, match to every win slot position in every slot; for(GTDictionary<int,WinlineValue>::ObjectTypeIterator it= pFinalWinlineRes->Begin(); it != pFinalWinlineRes->End(); it++) { int winlineID = it->first; WinlineValue value = it->second; int winCount = value.WinCount; GTArray<int> winline; pSourceWinlines->GetValueByKey(winlineID, winline); //get winline; for(int i = 0; i < winCount; i++) { int winSlot = winline[i]; int reelID = winSlot % m_reelColumnCount; //get reelID; int realSlotPosInReel = winSlot / m_reelColumnCount; //realSlotPostion int slotPosInReel = realSlotPosInReel + 1; // because we had one fake slot (invisible) GTVector2 reelWinSlotValue(reelID, slotPosInReel); //value = (reelID, slotPosInReel) in reel; GTArray<GTVector2>* winReelSlots = NULL; //add winline slot into reelWinSlotsDict; if(m_winlineReelSlotsDict.KeyExists(winlineID)) { m_winlineReelSlotsDict.GetValueByKey(winlineID, winReelSlots); } else { winReelSlots = new GTArray<GTVector2>(); } winReelSlots->AddToTail(reelWinSlotValue); m_winlineReelSlotsDict.Add(winlineID, winReelSlots); //save winlineid as key, value is reel slot value to dict } } }
// Removes ccs which are too small. void CCImage::erase_tiny_ccs() { // ISSUE: HALFTONE DETECTION // We should not remove tiny ccs if they are part of a halftone pattern... for (int i=0; i<ccs.size(); i++) { CC& cc = ccs[i]; if (cc.npix <= tinysize) { // Mark cc to be erased Run *r = &runs[cc.frun]; int nr = cc.nrun; cc.nrun = 0; cc.npix = 0; while (--nr >= 0) (r++)->ccid = -1; } } }
int DjVuPalette::compute_palette(int maxcolors, int minboxsize) { if (!hist) G_THROW( ERR_MSG("DjVuPalette.no_color") ); if (maxcolors<1 || maxcolors>MAXPALETTESIZE) G_THROW( ERR_MSG("DjVuPalette.many_colors") ); // Paul Heckbert: "Color Image Quantization for Frame Buffer Display", // SIGGRAPH '82 Proceedings, page 297. (also in ppmquant) // Collect histogram colors int sum = 0; int ncolors = 0; GTArray<PData> pdata; { // extra nesting for windows for (GPosition p = *hist; p; ++p) { pdata.touch(ncolors); PData &data = pdata[ncolors++]; int k = hist->key(p); data.p[0] = (k>>16) & 0xff; data.p[1] = (k>>8) & 0xff; data.p[2] = (k) & 0xff; data.w = (*hist)[p]; sum += data.w; } } // Create first box GList<PBox> boxes; PBox newbox; newbox.data = pdata; newbox.colors = ncolors; newbox.boxsize = 256; newbox.sum = sum; boxes.append(newbox); // Repeat spliting boxes while (boxes.size() < maxcolors) { // Find suitable box GPosition p; for (p=boxes; p; ++p) if (boxes[p].colors>=2 && boxes[p].boxsize>minboxsize) break; if (! p) break; // Find box boundaries PBox &splitbox = boxes[p]; unsigned char pmax[3]; unsigned char pmin[3]; pmax[0] = pmin[0] = splitbox.data->p[0]; pmax[1] = pmin[1] = splitbox.data->p[1]; pmax[2] = pmin[2] = splitbox.data->p[2]; { // extra nesting for windows for (int j=1; j<splitbox.colors; j++) { pmax[0] = umax(pmax[0], splitbox.data[j].p[0]); pmax[1] = umax(pmax[1], splitbox.data[j].p[1]); pmax[2] = umax(pmax[2], splitbox.data[j].p[2]); pmin[0] = umin(pmin[0], splitbox.data[j].p[0]); pmin[1] = umin(pmin[1], splitbox.data[j].p[1]); pmin[2] = umin(pmin[2], splitbox.data[j].p[2]); } } // Determine split direction and sort int bl = pmax[0]-pmin[0]; int gl = pmax[1]-pmin[1]; int rl = pmax[2]-pmin[2]; splitbox.boxsize = (bl>gl ? (rl>bl ? rl : bl) : (rl>gl ? rl : gl)); if (splitbox.boxsize <= minboxsize) continue; if (gl == splitbox.boxsize) qsort(splitbox.data, splitbox.colors, sizeof(PData), gcomp); else if (rl == splitbox.boxsize) qsort(splitbox.data, splitbox.colors, sizeof(PData), rcomp); else qsort(splitbox.data, splitbox.colors, sizeof(PData), bcomp); // Find median int lowercolors = 0; int lowersum = 0; while (lowercolors<splitbox.colors-1 && lowersum+lowersum<splitbox.sum) lowersum += splitbox.data[lowercolors++].w; // Compute new boxes newbox.data = splitbox.data + lowercolors; newbox.colors = splitbox.colors - lowercolors; newbox.sum = splitbox.sum - lowersum; splitbox.colors = lowercolors; splitbox.sum = lowersum; // Insert boxes at proper location GPosition q; for (q=p; q; ++q) if (boxes[q].sum < newbox.sum) break; boxes.insert_before(q, newbox); for (q=p; q; ++q) if (boxes[q].sum < splitbox.sum) break; boxes.insert_before(q, boxes, p); } // Fill palette array ncolors = 0; palette.empty(); palette.resize(0,boxes.size()-1); { // extra nesting for windows for (GPosition p=boxes; p; ++p) { PBox &box = boxes[p]; // Compute box representative color float bsum = 0; float gsum = 0; float rsum = 0; for (int j=0; j<box.colors; j++) { float w = (float)box.data[j].w; bsum += box.data[j].p[0] * w; gsum += box.data[j].p[1] * w; rsum += box.data[j].p[2] * w; } PColor &color = palette[ncolors++]; color.p[0] = (unsigned char) fmin(255, bsum/box.sum); color.p[1] = (unsigned char) fmin(255, gsum/box.sum); color.p[2] = (unsigned char) fmin(255, rsum/box.sum); color.p[3] = ( color.p[0]*BMUL + color.p[1]*GMUL + color.p[2]*RMUL) / SMUL; } } // Save dominant color PColor dcolor = palette[0]; // Sort palette colors in luminance order qsort((PColor*)palette, ncolors, sizeof(PColor), lcomp); // Clear invalid data colordata.empty(); delete pmap; pmap = 0; // Return dominant color return color_to_index_slow(dcolor.p); }
// Create the sprite from the property tree node bool BSWinlineLoader::CreateFromPropertyTreeNode(GTTreeNode *pTreeNode) { if(NULL == pTreeNode) { return false; } bool res = false; GTString errorCode(""); //load all winlines; Note: from winline 1 -> n int winlineID = 1; do { //set reel name GTString winlineTag = PROPERTY_TAG_WINLINE; winlineTag.Append(GTString::From(winlineID));// + GTString::FormatFrom(id); GTTreeNode* pWinline = pTreeNode->GetChild(winlineTag.ToCharString()); if(pWinline == NULL) break; GTArray<int> winlineSlotArray; //winline slot define; pWinline->ValueToArrayInt(winlineSlotArray); if(m_winlineDict.KeyExists(winlineID)) { m_winlineDict.Remove(winlineID); GTLogManager::SLogFormatWarning("Warning! new winline[%d] will replace old one!!", winlineID); } m_winlineDict.Add(winlineID, winlineSlotArray); winlineID++; } while (true); //load paytable; from 1 -> n int wintableID = 1; do { //set reel name GTString PayTableTag = PROPERTY_TAG_PAYTABLE; PayTableTag.Append(GTString::From(wintableID));// + GTString::FormatFrom(id); GTTreeNode* pPaytable = pTreeNode->GetChild(PayTableTag.ToCharString()); if(pPaytable == NULL) break; GTArray<int> payTableValue; //winline slot define; pPaytable->ValueToArrayInt(payTableValue); if(payTableValue.Length() < 2) { GTLogManager::SLogFormatError("Error! Paytable[%d] does not have 2 values!", wintableID); } else { int paytableID = payTableValue[0]; int ptValue = payTableValue[1]; if(m_paytableDict.KeyExists(paytableID)) { m_paytableDict.Remove(paytableID); GTLogManager::SLogFormatWarning("Warning! new paytable[%d] will replace old one!!", wintableID); } m_paytableDict.Add(paytableID, ptValue); } wintableID++; } while (true); return res; }
// -- Merges small ccs of similar color and splits large ccs void CCImage::merge_and_split_ccs(int smallsize, int largesize) { int ncc = ccs.size(); int nruns = runs.size(); int splitsize = largesize; if (ncc <= 0) return; // Associative map for storing merged ccids GMap<Grid_x_Color,int> map; nregularccs = ncc; // Set the correct ccids for the runs for (int ccid=0; ccid<ccs.size(); ccid++) { CC* cc = &ccs[ccid]; if (cc->nrun <= 0) continue; Grid_x_Color key; key.color = cc->color; int ccheight = cc->bb.height(); int ccwidth = cc->bb.width(); if (ccheight<=smallsize && ccwidth<=smallsize) { key.gridi = (cc->bb.ymin+cc->bb.ymax)/splitsize/2; key.gridj = (cc->bb.xmin+cc->bb.xmax)/splitsize/2; int newccid = makeccid(key, map, ncc); for(int runid=cc->frun; runid<cc->frun+cc->nrun; runid++) runs[runid].ccid = newccid; } else if (ccheight>=largesize || ccwidth>=largesize) { for(int runid=cc->frun; runid<cc->frun+cc->nrun; runid++) { Run *r = & runs[runid]; key.gridi = r->y/splitsize; key.gridj = r->x1/splitsize; int gridj_end = r->x2/splitsize; int gridj_span = gridj_end - key.gridj; r->ccid = makeccid(key, map, ncc); if (gridj_span>0) { // truncate current run runs.touch(nruns+gridj_span-1); r = &runs[runid]; int x = key.gridj*splitsize + splitsize; int x_end = r->x2; r->x2 = x-1; // append additional runs to the runs array while (++key.gridj < gridj_end) { Run& newrun = runs[nruns++]; newrun.y = r->y; newrun.x1 = x; x += splitsize; newrun.x2 = x-1; newrun.color = key.color; newrun.ccid = makeccid(key, map, ncc); } // append last run to the run array Run& newrun = runs[nruns++]; newrun.y = r->y; newrun.x1 = x; newrun.x2 = x_end; newrun.color = key.color; newrun.ccid = makeccid(key, map, ncc); } } } } // Recompute cc descriptors make_ccs_from_ccids(); }
// -- Constructs the ``ccs'' array from run's ccids. void CCImage::make_ccs_from_ccids() { int n; Run *pruns = runs; // Find maximal ccid int maxccid = -1; for (n=0; n<=runs.hbound(); n++) if (pruns[n].ccid > maxccid) maxccid = runs[n].ccid; GTArray<int> armap(0,maxccid); int *rmap = armap; // Renumber ccs for (n=0; n<=maxccid; n++) armap[n] = -1; for (n=0; n<=runs.hbound(); n++) if (pruns[n].ccid >= 0) rmap[ pruns[n].ccid ] = 1; int nid = 0; for (n=0; n<=maxccid; n++) if (rmap[n] > 0) rmap[n] = nid++; // Adjust nregularccs (since ccs are renumbered) while (nregularccs>0 && rmap[nregularccs-1]<0) nregularccs -= 1; if (nregularccs>0) nregularccs = 1 + rmap[nregularccs-1]; // Prepare cc descriptors ccs.resize(0,nid-1); for (n=0; n<nid; n++) ccs[n].nrun = 0; // Relabel runs for (n=0; n<=runs.hbound(); n++) { Run &run = pruns[n]; if (run.ccid < 0) continue; // runs with negative ccids are destroyed int oldccid = run.ccid; int newccid = rmap[oldccid]; CC &cc = ccs[newccid]; run.ccid = newccid; cc.nrun += 1; } // Compute positions for runs of cc int frun = 0; for (n=0; n<nid; n++) { ccs[n].frun = rmap[n] = frun; frun += ccs[n].nrun; } // Copy runs GTArray<Run> rtmp; rtmp.steal(runs); Run *ptmp = rtmp; runs.resize(0,frun-1); pruns = runs; for (n=0; n<=rtmp.hbound(); n++) { int id = ptmp[n].ccid; if (id < 0) continue; int pos = rmap[id]++; pruns[pos] = ptmp[n]; } // Finalize ccs for (n=0; n<nid; n++) { CC &cc = ccs[n]; int npix = 0; runs.sort(cc.frun, cc.frun+cc.nrun-1); Run *run = &runs[cc.frun]; int xmin = run->x1; int xmax = run->x2; int ymin = run->y; int ymax = run->y; cc.color = run->color; for (int i=0; i<cc.nrun; i++, run++) { if (run->x1 < xmin) xmin = run->x1; if (run->x2 > xmax) xmax = run->x2; if (run->y < ymin) ymin = run->y; if (run->y > ymax) ymax = run->y; npix += run->x2 - run->x1 + 1; } cc.npix = npix; cc.bb.xmin = xmin; cc.bb.ymin = ymin; cc.bb.xmax = xmax + 1; cc.bb.ymax = ymax + 1; } }
// -- Performs color connected component analysis void CCImage::make_ccids_by_analysis() { // Sort runs runs.sort(); // Single Pass Connected Component Analysis (with unodes) int n; int p=0; GTArray<int> umap; for (n=0; n<=runs.hbound(); n++) { int y = runs[n].y; int x1 = runs[n].x1 - 1; int x2 = runs[n].x2 + 1; int color = runs[n].color; int id = (umap.hbound() + 1); // iterate over previous line runs if (p>0) p--; for(;runs[p].y < y-1;p++); for(;(runs[p].y < y) && (runs[p].x1 <= x2);p++ ) { if ( runs[p].x2 >= x1 ) { if (runs[p].color == color) { // previous run touches current run and has same color int oid = runs[p].ccid; while (umap[oid] < oid) oid = umap[oid]; if ((int)id > umap.hbound()) { id = oid; } else if (id < oid) { umap[oid] = id; } else { umap[id] = oid; id = oid; } // freshen previous run id runs[p].ccid = id; } // stop if previous run goes past current run if (runs[p].x2 >= x2) break; } } // create new entry in umap runs[n].ccid = id; if (id > umap.hbound()) { umap.touch(id); umap[id] = id; } } // Update umap and ccid for (n=0; n<=runs.hbound(); n++) { Run &run = runs[n]; int ccid = run.ccid; while (umap[ccid] < ccid) ccid = umap[ccid]; umap[run.ccid] = ccid; run.ccid = ccid; } }
//************************************ // Method: CheckBonusAndLock // FullName: BSSlotsContainer::CheckBonusAndLock // Access: protected // Returns: bool // Qualifier: depends on locked(2rd round) or not lock(1st round), to check bonus symbols and play respin or freespin // Parameter: bool haveReelsLocked : //************************************ bool BSSlotsContainer::CheckBonusSymbolsAndLock(bool haveReelsLocked) { int bonusMiniCount = 0; if(haveReelsLocked) { //means to get final locked reels, this is 2rd round, which some reels had been locked //in this round, even 1 reel should be lock and play; bonusMiniCount = 0; } else { //this is 1st round, only bonus count larger than bonusMiniCount, //then lock and play respin; bonusMiniCount = 2; } bool haveNewLockReel = false; GTArray<int> newLockReelIDs; //store all new lock reels //check bonus symbol; int bonusSymbolID = m_pTicketGenerator->GetBonusSymbolID(); //GTArray<int> slotSymbols = m_pTicketGenerator->GetSlotSymbols(); for(int i = 0; i < m_slotsSymbols.Length(); i++) { int reelID = i % m_reelColumnCount; int slotSymbolValue = m_slotsSymbols[i]; //find bonus symbol, then add this reelID into dictionary for later lock; if(slotSymbolValue == bonusSymbolID) { if(!m_lockReelsDict.KeyExists(reelID)) { newLockReelIDs.Add(reelID); } } } if(newLockReelIDs.Length() < bonusMiniCount) return false; //initialize all new lock reels for(int i = 0; i < newLockReelIDs.Length(); i++) { m_lockReelsDict.Add(newLockReelIDs[i], NULL); } //build new respin for every one new lock reels for(int i = 0; i < newLockReelIDs.Length(); i++) { int reelID = newLockReelIDs[i]; GTGameObject* pGameObject = GTGameObjectManager::Inst()->CreateGameObject(NULL, CTEXT("respin1"), CTEXT("SlotGame/Respin.property")); if(pGameObject) { //add new lock reel into dictionary; m_lockReelsDict.Remove(reelID); m_lockReelsDict.Add(reelID, pGameObject); //get every reel position BSReelColumn* reelColum = m_reelColumns[reelID]; GTPoint2 reelPos = reelColum->GetGameObjectPosition(); //set respin to there and play animation BSRespin* pRespin = (BSRespin*)(pGameObject->GetBehaviour(CTEXT("BSRespin"))); if(pRespin) { pRespin->SetGameObjectPosition(reelPos); GTLogManager::SLogFormatTrace("repsin lock: (%f, %f) -> playing lock animtion", reelPos.x, reelPos.y); pRespin->PlayLockAnimation(); haveNewLockReel = true; } } } return haveNewLockReel; }
// -- Merges small ccs and split large ccs void CCImage::merge_and_split_ccs() { int ncc = ccs.size(); int nruns = runs.size(); int splitsize = largesize; if (ncc <= 0) return; // Grid of special components int gridwidth = (width+splitsize-1)/splitsize; nregularccs = ncc; // Set the correct ccids for the runs for (int ccid=0; ccid<ncc; ccid++) { CC* cc = &ccs[ccid]; if (cc->nrun <= 0) continue; int ccheight = cc->bb.height(); int ccwidth = cc->bb.width(); if (ccheight<=smallsize && ccwidth<=smallsize) { int gridi = (cc->bb.ymin+cc->bb.ymax)/splitsize/2; int gridj = (cc->bb.xmin+cc->bb.xmax)/splitsize/2; int newccid = ncc + gridi*gridwidth + gridj; for(int runid=cc->frun; runid<cc->frun+cc->nrun; runid++) runs[runid].ccid = newccid; } else if (ccheight>=largesize || ccwidth>=largesize) { for(int runid=cc->frun; runid<cc->frun+cc->nrun; runid++) { Run& r = runs[runid]; int y = r.y; int x_start = r.x1; int x_end = r.x2; int gridi = y/splitsize; int gridj_start = x_start/splitsize; int gridj_end = x_end/splitsize; int gridj_span = gridj_end-gridj_start; int newccid = ncc + gridi*gridwidth + gridj_start; if (! gridj_span) { r.ccid = newccid; } else // gridj_span>0 { // truncate the current run r.ccid = newccid++; int x = (gridj_start+1)*splitsize; r.x2 = x-1; runs.touch(nruns+gridj_span-1); // append additional runs to the runs array for(int gridj=gridj_start+1; gridj<gridj_end; gridj++) { Run& newrun = runs[nruns++]; newrun.y = y; newrun.x1 = x; x += splitsize; newrun.x2 = x-1; newrun.ccid = newccid++; } // append last run to the run array Run& newrun = runs[nruns++]; newrun.y = y; newrun.x1 = x; newrun.x2 = x_end; newrun.ccid = newccid++; } } } } // Recompute cc descriptors make_ccs_from_ccids(); }