littlejsengine 1.18.22 → 1.18.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,7 +35,7 @@ const engineName = 'LittleJS';
35
35
  * @type {string}
36
36
  * @default
37
37
  * @memberof Engine */
38
- const engineVersion = '1.18.22';
38
+ const engineVersion = '1.18.23';
39
39
 
40
40
  /** Frames per second to update
41
41
  * @type {number}
@@ -14307,13 +14307,19 @@ class TextureSheet
14307
14307
  * @param {Vector2} imageSize - Size of the source image in pixels
14308
14308
  * @param {Vector2} [frameSize] - Size of each frame, or the whole image if not passed
14309
14309
  * @param {number} [padding] - How many pixels padding around each frame
14310
+ * @param {number} [sourcePadding] - How many pixels padding around each frame in the source image
14310
14311
  * @return {TileInfo} Tile for the packed image, or undefined if the sheet is full */
14311
- tryAdd(imageSize, frameSize=imageSize, padding=textureSheetPadding)
14312
+ tryAdd(imageSize, frameSize=imageSize, padding=textureSheetPadding, sourcePadding=0)
14312
14313
  {
14313
14314
  ASSERT(isVector2(imageSize) && isVector2(frameSize), 'sizes must be vec2');
14314
14315
  ASSERT(frameSize.x > 0 && frameSize.y > 0, 'frame size must be positive');
14315
- ASSERT(imageSize.x % frameSize.x === 0 && imageSize.y % frameSize.y === 0,
14316
- 'image size must be a multiple of the frame size');
14316
+ ASSERT(isNumber(sourcePadding) && sourcePadding >= 0, 'sourcePadding must be a number >= 0');
14317
+
14318
+ // the source may have its own padding baked in around each frame
14319
+ const sourceCellWidth = frameSize.x + sourcePadding*2;
14320
+ const sourceCellHeight = frameSize.y + sourcePadding*2;
14321
+ ASSERT(imageSize.x % sourceCellWidth === 0 && imageSize.y % sourceCellHeight === 0,
14322
+ 'image size must be a multiple of the padded frame size');
14317
14323
 
14318
14324
  const cellWidth = frameSize.x + padding*2;
14319
14325
  const cellHeight = frameSize.y + padding*2;
@@ -14322,8 +14328,8 @@ class TextureSheet
14322
14328
 
14323
14329
  // keep the layout of the source image, but narrow it if a row is too wide
14324
14330
  // frames wrap down to the next row, which TileInfo.frame handles via columns
14325
- const sourceColumns = imageSize.x / frameSize.x;
14326
- const frameCount = sourceColumns * (imageSize.y / frameSize.y);
14331
+ const sourceColumns = imageSize.x / sourceCellWidth;
14332
+ const frameCount = sourceColumns * (imageSize.y / sourceCellHeight);
14327
14333
  const columns = min(sourceColumns, maxColumns);
14328
14334
  const blockWidth = columns * cellWidth;
14329
14335
  const blockHeight = ceil(frameCount / columns) * cellHeight;
@@ -14352,23 +14358,26 @@ class TextureSheet
14352
14358
  /** Draw an image into this sheet at a tile returned by tryAdd
14353
14359
  * @param {HTMLImageElement} image - Source image to copy from
14354
14360
  * @param {TileInfo} tileInfo - Where to put it, from tryAdd
14355
- * @param {boolean} [update] - Upload to webgl now, pass false when batching */
14356
- drawImage(image, tileInfo, update=true)
14361
+ * @param {boolean} [update] - Upload to webgl now, pass false when batching
14362
+ * @param {number} [sourcePadding] - How many pixels padding around each frame in the source image */
14363
+ drawImage(image, tileInfo, update=true, sourcePadding=0)
14357
14364
  {
14358
14365
  ASSERT(!!this.context, 'texture sheet has no canvas');
14359
14366
 
14360
14367
  // copy frames in order, reading the source left to right, top to bottom
14361
14368
  // the destination wraps at tileInfo.columns which may be narrower than the source
14362
14369
  const frameSize = tileInfo.size;
14363
- const sourceColumns = image.width / frameSize.x;
14364
- const frameCount = sourceColumns * (image.height / frameSize.y);
14370
+ const sourceCellWidth = frameSize.x + sourcePadding*2;
14371
+ const sourceCellHeight = frameSize.y + sourcePadding*2;
14372
+ const sourceColumns = image.width / sourceCellWidth;
14373
+ const frameCount = sourceColumns * (image.height / sourceCellHeight);
14365
14374
  const columns = tileInfo.columns || frameCount;
14366
14375
  const cellWidth = frameSize.x + tileInfo.padding*2;
14367
14376
  const cellHeight = frameSize.y + tileInfo.padding*2;
14368
14377
  for (let i = frameCount; i--;)
14369
14378
  {
14370
- const sourceX = (i % sourceColumns) * frameSize.x;
14371
- const sourceY = (i / sourceColumns | 0) * frameSize.y;
14379
+ const sourceX = (i % sourceColumns) * sourceCellWidth + sourcePadding;
14380
+ const sourceY = (i / sourceColumns | 0) * sourceCellHeight + sourcePadding;
14372
14381
  this.context.drawImage(image,
14373
14382
  sourceX, sourceY, frameSize.x, frameSize.y,
14374
14383
  tileInfo.pos.x + (i % columns) * cellWidth,
@@ -14398,15 +14407,17 @@ class TextureSheet
14398
14407
  * - Nothing is visible until it loads, use spritesReady to wait for it
14399
14408
  * - Pass frameSize for animations, then step through them with TileInfo.frame
14400
14409
  * - Grid images keep their layout and frames wrap down to the next row
14410
+ * - Pass sourcePadding if the source image has padding baked in around frames
14401
14411
  * @param {string} src - Image source path
14402
14412
  * @param {Vector2|number} [frameSize] - Size of each animation frame in pixels
14403
14413
  * @param {number} [padding] - How many pixels padding around each frame
14414
+ * @param {number} [sourcePadding] - How many pixels padding around each frame in the source image
14404
14415
  * @return {TileInfo}
14405
14416
  * @example
14406
14417
  * const playerTile = loadSprite('player.png'); // a single sprite
14407
14418
  * const runTile = loadSprite('run.png', vec2(16)); // a 16x16 frame animation
14408
14419
  * @memberof TextureSheets */
14409
- function loadSprite(src, frameSize, padding=textureSheetPadding)
14420
+ function loadSprite(src, frameSize, padding=textureSheetPadding, sourcePadding=0)
14410
14421
  {
14411
14422
  ASSERT(isStringLike(src), 'image src must be a string');
14412
14423
  ASSERT(!frameSize || isVector2(frameSize) || isNumber(frameSize), 'frameSize must be a vec2 or number');
@@ -14441,9 +14452,9 @@ function loadSprite(src, frameSize, padding=textureSheetPadding)
14441
14452
  // pack onto a sheet, then fill in the tile that was already handed out,
14442
14453
  // copying every field so nothing is missed if TileInfo gains more of them
14443
14454
  const imageSize = vec2(image.width, image.height);
14444
- const {sheet, tile} = textureSheetAdd(imageSize, frameSize, padding);
14455
+ const {sheet, tile} = textureSheetAdd(imageSize, frameSize, padding, sourcePadding);
14445
14456
  Object.assign(tileInfo, tile);
14446
- sheet.drawImage(image, tileInfo, false); // upload once per batch below
14457
+ sheet.drawImage(image, tileInfo, false, sourcePadding); // upload once per batch below
14447
14458
  }
14448
14459
  else
14449
14460
  {
@@ -14644,16 +14655,16 @@ function textureSheetCreate()
14644
14655
  }
14645
14656
 
14646
14657
  // use the first sheet with enough space, or make a new one
14647
- function textureSheetAdd(imageSize, frameSize, padding)
14658
+ function textureSheetAdd(imageSize, frameSize, padding, sourcePadding)
14648
14659
  {
14649
14660
  let sheet, tile;
14650
14661
  for (sheet of textureSheets)
14651
- if (tile = sheet.tryAdd(imageSize, frameSize, padding))
14662
+ if (tile = sheet.tryAdd(imageSize, frameSize, padding, sourcePadding))
14652
14663
  break;
14653
14664
  if (!tile)
14654
14665
  {
14655
14666
  sheet = textureSheetCreate();
14656
- tile = sheet.tryAdd(imageSize, frameSize, padding);
14667
+ tile = sheet.tryAdd(imageSize, frameSize, padding, sourcePadding);
14657
14668
  ASSERT(!!tile, 'image is too large to fit on a texture sheet');
14658
14669
  }
14659
14670
  return {sheet, tile};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.18.22",
3
+ "version": "1.18.23",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "dist/littlejs.esm.js",
6
6
  "types": "dist/littlejs.d.ts",
@@ -73,13 +73,19 @@ class TextureSheet
73
73
  * @param {Vector2} imageSize - Size of the source image in pixels
74
74
  * @param {Vector2} [frameSize] - Size of each frame, or the whole image if not passed
75
75
  * @param {number} [padding] - How many pixels padding around each frame
76
+ * @param {number} [sourcePadding] - How many pixels padding around each frame in the source image
76
77
  * @return {TileInfo} Tile for the packed image, or undefined if the sheet is full */
77
- tryAdd(imageSize, frameSize=imageSize, padding=textureSheetPadding)
78
+ tryAdd(imageSize, frameSize=imageSize, padding=textureSheetPadding, sourcePadding=0)
78
79
  {
79
80
  ASSERT(isVector2(imageSize) && isVector2(frameSize), 'sizes must be vec2');
80
81
  ASSERT(frameSize.x > 0 && frameSize.y > 0, 'frame size must be positive');
81
- ASSERT(imageSize.x % frameSize.x === 0 && imageSize.y % frameSize.y === 0,
82
- 'image size must be a multiple of the frame size');
82
+ ASSERT(isNumber(sourcePadding) && sourcePadding >= 0, 'sourcePadding must be a number >= 0');
83
+
84
+ // the source may have its own padding baked in around each frame
85
+ const sourceCellWidth = frameSize.x + sourcePadding*2;
86
+ const sourceCellHeight = frameSize.y + sourcePadding*2;
87
+ ASSERT(imageSize.x % sourceCellWidth === 0 && imageSize.y % sourceCellHeight === 0,
88
+ 'image size must be a multiple of the padded frame size');
83
89
 
84
90
  const cellWidth = frameSize.x + padding*2;
85
91
  const cellHeight = frameSize.y + padding*2;
@@ -88,8 +94,8 @@ class TextureSheet
88
94
 
89
95
  // keep the layout of the source image, but narrow it if a row is too wide
90
96
  // frames wrap down to the next row, which TileInfo.frame handles via columns
91
- const sourceColumns = imageSize.x / frameSize.x;
92
- const frameCount = sourceColumns * (imageSize.y / frameSize.y);
97
+ const sourceColumns = imageSize.x / sourceCellWidth;
98
+ const frameCount = sourceColumns * (imageSize.y / sourceCellHeight);
93
99
  const columns = min(sourceColumns, maxColumns);
94
100
  const blockWidth = columns * cellWidth;
95
101
  const blockHeight = ceil(frameCount / columns) * cellHeight;
@@ -118,23 +124,26 @@ class TextureSheet
118
124
  /** Draw an image into this sheet at a tile returned by tryAdd
119
125
  * @param {HTMLImageElement} image - Source image to copy from
120
126
  * @param {TileInfo} tileInfo - Where to put it, from tryAdd
121
- * @param {boolean} [update] - Upload to webgl now, pass false when batching */
122
- drawImage(image, tileInfo, update=true)
127
+ * @param {boolean} [update] - Upload to webgl now, pass false when batching
128
+ * @param {number} [sourcePadding] - How many pixels padding around each frame in the source image */
129
+ drawImage(image, tileInfo, update=true, sourcePadding=0)
123
130
  {
124
131
  ASSERT(!!this.context, 'texture sheet has no canvas');
125
132
 
126
133
  // copy frames in order, reading the source left to right, top to bottom
127
134
  // the destination wraps at tileInfo.columns which may be narrower than the source
128
135
  const frameSize = tileInfo.size;
129
- const sourceColumns = image.width / frameSize.x;
130
- const frameCount = sourceColumns * (image.height / frameSize.y);
136
+ const sourceCellWidth = frameSize.x + sourcePadding*2;
137
+ const sourceCellHeight = frameSize.y + sourcePadding*2;
138
+ const sourceColumns = image.width / sourceCellWidth;
139
+ const frameCount = sourceColumns * (image.height / sourceCellHeight);
131
140
  const columns = tileInfo.columns || frameCount;
132
141
  const cellWidth = frameSize.x + tileInfo.padding*2;
133
142
  const cellHeight = frameSize.y + tileInfo.padding*2;
134
143
  for (let i = frameCount; i--;)
135
144
  {
136
- const sourceX = (i % sourceColumns) * frameSize.x;
137
- const sourceY = (i / sourceColumns | 0) * frameSize.y;
145
+ const sourceX = (i % sourceColumns) * sourceCellWidth + sourcePadding;
146
+ const sourceY = (i / sourceColumns | 0) * sourceCellHeight + sourcePadding;
138
147
  this.context.drawImage(image,
139
148
  sourceX, sourceY, frameSize.x, frameSize.y,
140
149
  tileInfo.pos.x + (i % columns) * cellWidth,
@@ -164,15 +173,17 @@ class TextureSheet
164
173
  * - Nothing is visible until it loads, use spritesReady to wait for it
165
174
  * - Pass frameSize for animations, then step through them with TileInfo.frame
166
175
  * - Grid images keep their layout and frames wrap down to the next row
176
+ * - Pass sourcePadding if the source image has padding baked in around frames
167
177
  * @param {string} src - Image source path
168
178
  * @param {Vector2|number} [frameSize] - Size of each animation frame in pixels
169
179
  * @param {number} [padding] - How many pixels padding around each frame
180
+ * @param {number} [sourcePadding] - How many pixels padding around each frame in the source image
170
181
  * @return {TileInfo}
171
182
  * @example
172
183
  * const playerTile = loadSprite('player.png'); // a single sprite
173
184
  * const runTile = loadSprite('run.png', vec2(16)); // a 16x16 frame animation
174
185
  * @memberof TextureSheets */
175
- function loadSprite(src, frameSize, padding=textureSheetPadding)
186
+ function loadSprite(src, frameSize, padding=textureSheetPadding, sourcePadding=0)
176
187
  {
177
188
  ASSERT(isStringLike(src), 'image src must be a string');
178
189
  ASSERT(!frameSize || isVector2(frameSize) || isNumber(frameSize), 'frameSize must be a vec2 or number');
@@ -207,9 +218,9 @@ function loadSprite(src, frameSize, padding=textureSheetPadding)
207
218
  // pack onto a sheet, then fill in the tile that was already handed out,
208
219
  // copying every field so nothing is missed if TileInfo gains more of them
209
220
  const imageSize = vec2(image.width, image.height);
210
- const {sheet, tile} = textureSheetAdd(imageSize, frameSize, padding);
221
+ const {sheet, tile} = textureSheetAdd(imageSize, frameSize, padding, sourcePadding);
211
222
  Object.assign(tileInfo, tile);
212
- sheet.drawImage(image, tileInfo, false); // upload once per batch below
223
+ sheet.drawImage(image, tileInfo, false, sourcePadding); // upload once per batch below
213
224
  }
214
225
  else
215
226
  {
@@ -410,16 +421,16 @@ function textureSheetCreate()
410
421
  }
411
422
 
412
423
  // use the first sheet with enough space, or make a new one
413
- function textureSheetAdd(imageSize, frameSize, padding)
424
+ function textureSheetAdd(imageSize, frameSize, padding, sourcePadding)
414
425
  {
415
426
  let sheet, tile;
416
427
  for (sheet of textureSheets)
417
- if (tile = sheet.tryAdd(imageSize, frameSize, padding))
428
+ if (tile = sheet.tryAdd(imageSize, frameSize, padding, sourcePadding))
418
429
  break;
419
430
  if (!tile)
420
431
  {
421
432
  sheet = textureSheetCreate();
422
- tile = sheet.tryAdd(imageSize, frameSize, padding);
433
+ tile = sheet.tryAdd(imageSize, frameSize, padding, sourcePadding);
423
434
  ASSERT(!!tile, 'image is too large to fit on a texture sheet');
424
435
  }
425
436
  return {sheet, tile};
package/src/engine.js CHANGED
@@ -32,7 +32,7 @@ const engineName = 'LittleJS';
32
32
  * @type {string}
33
33
  * @default
34
34
  * @memberof Engine */
35
- const engineVersion = '1.18.22';
35
+ const engineVersion = '1.18.23';
36
36
 
37
37
  /** Frames per second to update
38
38
  * @type {number}