1
0
Fork 0
mirror of https://github.com/sbrl/Nibriboard.git synced 2018-01-10 21:33:49 +00:00

[server+client] Start working on the line-spanning-multiple-chunks issue, now that the last crisis has been averted :P

This commit is contained in:
Starbeamrainbowlabs 2017-09-22 22:35:56 +01:00
parent c4609ffd3a
commit c3952f0778
4 changed files with 159 additions and 10 deletions

View file

@ -19,6 +19,20 @@ class Chunk
this.lines = []; this.lines = [];
} }
/**
* Fetches the first line in this chunk by it's id.
* @param {string} lineId The target line id to search for.
* @return {object|null} The requested line, or null if it wasn't found.
*/
getLineById(lineId)
{
for (let line of this.lines) {
if(line.LineId == lineId)
return line;
}
return null;
}
/** /**
* Whether this chunk is located at the specified chunk reference. * Whether this chunk is located at the specified chunk reference.
* @param {ChunkReference} otherChunkRef The chunk reference to check * @param {ChunkReference} otherChunkRef The chunk reference to check
@ -33,12 +47,34 @@ class Chunk
return false; return false;
} }
/**
* Whether this chunk falls inside the specified rectangle.
* @param {Rectangle} area The rectangle to test against, in location-space
* @return {Boolean} Whether this chunk falls inside the specified rectangle.
*/
isVisible(area)
{
let chunkArea = new Rectangle(
this.chunkRef.x * this.size,
this.chunkRef.y * this.size,
this.size, this.size
);
return area.overlaps(area);
}
update(dt) update(dt)
{ {
} }
render(canvas, context) /**
* Renders this chunk to the given canvas with the given context.
* @param {HTMLCanvasElement} canvas The canvas to render to.
* @param {CanvasRenderingContext2D} context The context to render with.
* @param {ChunkCache} chunkCache The chunk cache to use to fetch data from surrounding chunks.
* @param {Rectangle} chunkArea The area in which chunks are being rendered.
*/
render(canvas, context, chunkCache, chunkArea)
{ {
var planeSpaceRef = this.chunkRef.inPlaneSpace(this.size); var planeSpaceRef = this.chunkRef.inPlaneSpace(this.size);
@ -47,16 +83,32 @@ class Chunk
for(let line of this.lines) for(let line of this.lines)
{ {
// Don't draw lines that are walked by other chunks
if(line.ContinuesFrom != null &&
chunkCache.fetchChunk(line.ContinuesFrom) != null)
continue;
let linePoints = line.Points;
// Fetch all the points on fragments of this line forwards from here
if(line.ContinuesIn != null) {
let nextLines = chunkCache.fetchLineFragments(line.ContinuesIn, line.LineId);
for (let nextLine of nextLines) {
linePoints = linePoints.concat(nextLine.Points);
}
}
context.beginPath(); context.beginPath();
context.moveTo( context.moveTo(
line.Points[0].x - planeSpaceRef.x, linePoints[0].x - planeSpaceRef.x,
line.Points[0].y - planeSpaceRef.y linePoints[0].y - planeSpaceRef.y
); );
for(let i = 1; i < line.Points.length; i++)
for(let i = 1; i < linePoints.length; i++)
{ {
context.lineTo( context.lineTo(
line.Points[i].x - planeSpaceRef.x, linePoints[i].x - planeSpaceRef.x,
line.Points[i].y - planeSpaceRef.y linePoints[i].y - planeSpaceRef.y
); );
} }

View file

@ -18,6 +18,48 @@ class ChunkCache
this.boardWindow.rippleLink.on("ChunkUpdate", this.handleChunkUpdate.bind(this)); this.boardWindow.rippleLink.on("ChunkUpdate", this.handleChunkUpdate.bind(this));
} }
/**
* Fetches the chunk with the specified chunk reference.
* @param {ChunkReference} chunkRef The chunk reference of the chunk to fetch.
* @return {Chunk|null} The requested chunk, or null if it isn't present in the cache.
*/
fetchChunk(chunkRef)
{
if(!this.cache.has(chunkRef.toString()))
return null;
return this.cache.get(chunkRef.toString());
}
/**
* Walk the currently cached chunks to find all the line fragments for the
* specified line id, starting at the specified chunk reference.
* @param {ChunkReference} startingChunkRef The reference of hte chunk we should start walking at.
* @param {string} lineId The id of the line we should fetch the fragments for.
* @return {object[]} A list of line fragments found.
*/
fetchLineFragments(startingChunkRef, lineId)
{
let lineFragments = [];
let currentChunk = this.fetchChunk(startingChunkRef);
while(currentChunk != null)
{
let nextLineFragment = currentChunk.getLineById(lineId);
if(nextLineFragment == null)
break;
lineFragments.push(nextLineFragment);
if(nextLineFragment.ContinuesIn == null)
break;
currentChunk = this.fetchChunk(nextLineFragment.ContinuesIn);
}
return lineFragments;
}
/** /**
* Adds the given chunk to the chunk cache. * Adds the given chunk to the chunk cache.
* @param {Chunk} chunkData The chunk to add to the cache. * @param {Chunk} chunkData The chunk to add to the cache.
@ -98,7 +140,7 @@ class ChunkCache
let chunk = this.cache.get(cChunk.toString()); let chunk = this.cache.get(cChunk.toString());
if(typeof chunk != "undefined" && !chunk.requestedFromServer) if(typeof chunk != "undefined" && !chunk.requestedFromServer)
chunk.render(canvas, context); chunk.render(canvas, context, this, chunkArea);
if(this.showRenderedChunks) { if(this.showRenderedChunks) {
context.beginPath(); context.beginPath();
@ -125,6 +167,18 @@ class ChunkCache
let newChunk = new Chunk(newChunkRef, chunkData.Size); let newChunk = new Chunk(newChunkRef, chunkData.Size);
let newLines = chunkData.lines.map((line) => { let newLines = chunkData.lines.map((line) => {
line.Points = line.Points.map((raw) => new Vector(raw.X, raw.Y)); line.Points = line.Points.map((raw) => new Vector(raw.X, raw.Y));
if(line.ContinuesIn != null) {
line.ContinuesIn = new ChunkReference(
this.boardWindow.currentPlaneName,
line.ContinuesIn.X, line.ContinuesIn.Y
);
}
if(line.ContinuesFrom != null) {
line.ContinuesFrom = new ChunkReference(
this.boardWindow.currentPlaneName,
line.ContinuesFrom.X, line.ContinuesFrom.Y
);
}
return line; return line;
}); });
newChunk.lines = newChunk.lines.concat(newLines); newChunk.lines = newChunk.lines.concat(newLines);

View file

@ -2,9 +2,9 @@
import Vector from './Vector'; import Vector from './Vector';
/// <summary> /**
/// Represents a rectangle in 2D space. * Represents a rectangle in 2D space.
/// </summary> */
class Rectangle class Rectangle
{ {
/** /**
@ -78,6 +78,22 @@ class Rectangle
this.height = height; this.height = height;
} }
/**
* Figures out whether this rectangle overlaps another rectangle.
* @param {Rectangle} otherRectangle The other rectangle to check the overlap of.
* @return {bool} Whether this rectangle overlaps another rectangle.
*/
overlaps(otherRectangle)
{
if(this.Top > otherRectangle.Bottom ||
this.Bottom < otherRectangle.Top ||
this.Left > otherRectangle.Right ||
this.Right < otherRectangle.Left)
return false;
return true;
}
/** /**
* Returns a copy of this rectangle that can be safely edited without affecting the original. * Returns a copy of this rectangle that can be safely edited without affecting the original.
* @returns {Rectangle} * @returns {Rectangle}

View file

@ -59,6 +59,20 @@ namespace Nibriboard.RippleSpace
} }
} }
/// <summary>
/// The chunk reference of the next chunk that this line continues in.
/// A value of null is present when this line doesn't continue into another chunk.
/// </summary>
[JsonProperty]
public ChunkReference ContinuesIn = null;
/// <summary>
/// The chunk reference of the previous chunk that contains the line fragment that
/// this line continues from. Is null when this line either doesn't continue from
/// another line fragment or doesn't span multiple chunks.
/// </summary>
[JsonProperty]
public ChunkReference ContinuesFrom = null;
/// <summary> /// <summary>
/// Gets a reference in chunk-space ot the chunk that this line starts in. /// Gets a reference in chunk-space ot the chunk that this line starts in.
/// </summary> /// </summary>
@ -120,6 +134,19 @@ namespace Nibriboard.RippleSpace
results.Add(nextLine); results.Add(nextLine);
} }
// Set the ContinuesIn and ContinuesFrom properties
// so that clients can find the next / previous chunk line fragmentss
for(int i = 0; i < results.Count - 1; i++)
{
// Set the ContinuesFrom reference, but not on the first fragment in the list
if(i > 0)
results[i].ContinuesFrom = results[i - 1].ContainingChunk;
// Set the ContinuesIn reference, but not on the last fragment in the list
if(i < results.Count - 1)
results[i].ContinuesIn = results[i + 1].ContainingChunk;
}
return results; return results;
} }
} }