mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 03:55:19 -04:00
Split up TexturePack into Animations and TexturePack (they end up being about equal lines of code anyways), remove a bit more of unused freetype code
This commit is contained in:
parent
f476eee0c1
commit
664428682c
400
src/Animations.c
Normal file
400
src/Animations.c
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
#include "TexturePack.h"
|
||||||
|
#include "Constants.h"
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Graphics.h"
|
||||||
|
#include "Event.h"
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Funcs.h"
|
||||||
|
#include "Errors.h"
|
||||||
|
#include "Chat.h"
|
||||||
|
#include "ExtMath.h"
|
||||||
|
#include "Options.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
#define LIQUID_ANIM_MAX 64
|
||||||
|
#define WATER_TEX_LOC 14
|
||||||
|
#define LAVA_TEX_LOC 30
|
||||||
|
|
||||||
|
#ifndef CC_BUILD_WEB
|
||||||
|
/* Based off the incredible work from https://dl.dropboxusercontent.com/u/12694594/lava.txt
|
||||||
|
mirrored at https://github.com/UnknownShadow200/ClassicalSharp/wiki/Minecraft-Classic-lava-animation-algorithm
|
||||||
|
Water animation originally written by cybertoon, big thanks!
|
||||||
|
*/
|
||||||
|
/*########################################################################################################################*
|
||||||
|
*-----------------------------------------------------Lava animation------------------------------------------------------*
|
||||||
|
*#########################################################################################################################*/
|
||||||
|
static float L_soupHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
||||||
|
static float L_potHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
||||||
|
static float L_flameHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
||||||
|
static RNGState L_rnd;
|
||||||
|
static cc_bool L_rndInited;
|
||||||
|
|
||||||
|
static void LavaAnimation_Tick(BitmapCol* ptr, int size) {
|
||||||
|
int mask = size - 1, shift = Math_Log2(size);
|
||||||
|
float soupHeat, potHeat, col;
|
||||||
|
int x, y, i = 0;
|
||||||
|
|
||||||
|
if (!L_rndInited) {
|
||||||
|
Random_SeedFromCurrentTime(&L_rnd);
|
||||||
|
L_rndInited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y = 0; y < size; y++) {
|
||||||
|
for (x = 0; x < size; x++) {
|
||||||
|
/* Calculate the colour at this coordinate in the heatmap */
|
||||||
|
|
||||||
|
/* Lookup table for (int)(1.2 * sin([ANGLE] * 22.5 * MATH_DEG2RAD)); */
|
||||||
|
/* [ANGLE] is integer x/y, so repeats every 16 intervals */
|
||||||
|
static cc_int8 sin_adj_table[16] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, -1, -1, -1, 0, 0 };
|
||||||
|
int xx = x + sin_adj_table[y & 0xF], yy = y + sin_adj_table[x & 0xF];
|
||||||
|
|
||||||
|
soupHeat =
|
||||||
|
L_soupHeat[((yy - 1) & mask) << shift | ((xx - 1) & mask)] +
|
||||||
|
L_soupHeat[((yy - 1) & mask) << shift | (xx & mask)] +
|
||||||
|
L_soupHeat[((yy - 1) & mask) << shift | ((xx + 1) & mask)] +
|
||||||
|
|
||||||
|
L_soupHeat[(yy & mask) << shift | ((xx - 1) & mask)] +
|
||||||
|
L_soupHeat[(yy & mask) << shift | (xx & mask)] +
|
||||||
|
L_soupHeat[(yy & mask) << shift | ((xx + 1) & mask)] +
|
||||||
|
|
||||||
|
L_soupHeat[((yy + 1) & mask) << shift | ((xx - 1) & mask)] +
|
||||||
|
L_soupHeat[((yy + 1) & mask) << shift | (xx & mask)] +
|
||||||
|
L_soupHeat[((yy + 1) & mask) << shift | ((xx + 1) & mask)];
|
||||||
|
|
||||||
|
potHeat =
|
||||||
|
L_potHeat[i] + /* x , y */
|
||||||
|
L_potHeat[y << shift | ((x + 1) & mask)] + /* x + 1, y */
|
||||||
|
L_potHeat[((y + 1) & mask) << shift | x] + /* x , y + 1 */
|
||||||
|
L_potHeat[((y + 1) & mask) << shift | ((x + 1) & mask)];/* x + 1, y + 1 */
|
||||||
|
|
||||||
|
L_soupHeat[i] = soupHeat * 0.1f + potHeat * 0.2f;
|
||||||
|
|
||||||
|
L_potHeat[i] += L_flameHeat[i];
|
||||||
|
if (L_potHeat[i] < 0.0f) L_potHeat[i] = 0.0f;
|
||||||
|
|
||||||
|
L_flameHeat[i] -= 0.06f * 0.01f;
|
||||||
|
if (Random_Float(&L_rnd) <= 0.005f) L_flameHeat[i] = 1.5f * 0.01f;
|
||||||
|
|
||||||
|
/* Output the pixel */
|
||||||
|
col = 2.0f * L_soupHeat[i];
|
||||||
|
Math_Clamp(col, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
*ptr = BitmapCol_Make(
|
||||||
|
col * 100.0f + 155.0f,
|
||||||
|
col * col * 255.0f,
|
||||||
|
col * col * col * col * 128.0f,
|
||||||
|
255);
|
||||||
|
|
||||||
|
ptr++; i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*########################################################################################################################*
|
||||||
|
*----------------------------------------------------Water animation------------------------------------------------------*
|
||||||
|
*#########################################################################################################################*/
|
||||||
|
static float W_soupHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
||||||
|
static float W_potHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
||||||
|
static float W_flameHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
||||||
|
static RNGState W_rnd;
|
||||||
|
static cc_bool W_rndInited;
|
||||||
|
|
||||||
|
static void WaterAnimation_Tick(BitmapCol* ptr, int size) {
|
||||||
|
int mask = size - 1, shift = Math_Log2(size);
|
||||||
|
float soupHeat, col;
|
||||||
|
int x, y, i = 0;
|
||||||
|
|
||||||
|
if (!W_rndInited) {
|
||||||
|
Random_SeedFromCurrentTime(&W_rnd);
|
||||||
|
W_rndInited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y = 0; y < size; y++) {
|
||||||
|
for (x = 0; x < size; x++) {
|
||||||
|
/* Calculate the colour at this coordinate in the heatmap */
|
||||||
|
soupHeat =
|
||||||
|
W_soupHeat[y << shift | ((x - 1) & mask)] +
|
||||||
|
W_soupHeat[y << shift | x ] +
|
||||||
|
W_soupHeat[y << shift | ((x + 1) & mask)];
|
||||||
|
|
||||||
|
W_soupHeat[i] = soupHeat / 3.3f + W_potHeat[i] * 0.8f;
|
||||||
|
|
||||||
|
W_potHeat[i] += W_flameHeat[i];
|
||||||
|
if (W_potHeat[i] < 0.0f) W_potHeat[i] = 0.0f;
|
||||||
|
|
||||||
|
W_flameHeat[i] -= 0.1f * 0.05f;
|
||||||
|
if (Random_Float(&W_rnd) <= 0.05f) W_flameHeat[i] = 0.5f * 0.05f;
|
||||||
|
|
||||||
|
/* Output the pixel */
|
||||||
|
col = W_soupHeat[i];
|
||||||
|
Math_Clamp(col, 0.0f, 1.0f);
|
||||||
|
col = col * col;
|
||||||
|
|
||||||
|
*ptr = BitmapCol_Make(
|
||||||
|
32.0f + col * 32.0f,
|
||||||
|
50.0f + col * 64.0f,
|
||||||
|
255,
|
||||||
|
146.0f + col * 50.0f);
|
||||||
|
|
||||||
|
ptr++; i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*########################################################################################################################*
|
||||||
|
*-------------------------------------------------------Animations--------------------------------------------------------*
|
||||||
|
*#########################################################################################################################*/
|
||||||
|
struct AnimationData {
|
||||||
|
TextureLoc texLoc; /* Tile (not pixel) coordinates in terrain.png */
|
||||||
|
cc_uint16 frameX, frameY; /* Top left pixel coordinates of start frame in animatons.png */
|
||||||
|
cc_uint16 frameSize; /* Size of each frame in pixel coordinates */
|
||||||
|
cc_uint16 state; /* Current animation frame index */
|
||||||
|
cc_uint16 statesCount; /* Total number of animation frames */
|
||||||
|
cc_uint16 delay; /* Delay in ticks until next frame is drawn */
|
||||||
|
cc_uint16 frameDelay; /* Delay between each frame */
|
||||||
|
};
|
||||||
|
|
||||||
|
static Bitmap anims_bmp;
|
||||||
|
static struct AnimationData anims_list[ATLAS1D_MAX_ATLASES];
|
||||||
|
static int anims_count;
|
||||||
|
static cc_bool anims_validated, useLavaAnim, useWaterAnim, alwaysLavaAnim, alwaysWaterAnim;
|
||||||
|
#define ANIM_MIN_ARGS 7
|
||||||
|
|
||||||
|
static void Animations_ReadDescription(struct Stream* stream, const String* path) {
|
||||||
|
String line; char lineBuffer[STRING_SIZE * 2];
|
||||||
|
String parts[ANIM_MIN_ARGS];
|
||||||
|
int count;
|
||||||
|
struct AnimationData data = { 0 };
|
||||||
|
cc_uint8 tileX, tileY;
|
||||||
|
|
||||||
|
cc_uint8 buffer[2048];
|
||||||
|
struct Stream buffered;
|
||||||
|
cc_result res;
|
||||||
|
|
||||||
|
String_InitArray(line, lineBuffer);
|
||||||
|
/* ReadLine reads single byte at a time */
|
||||||
|
Stream_ReadonlyBuffered(&buffered, stream, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
res = Stream_ReadLine(&buffered, &line);
|
||||||
|
if (res == ERR_END_OF_STREAM) break;
|
||||||
|
if (res) { Logger_Warn2(res, "reading from", path); break; }
|
||||||
|
|
||||||
|
if (!line.length || line.buffer[0] == '#') continue;
|
||||||
|
count = String_UNSAFE_Split(&line, ' ', parts, ANIM_MIN_ARGS);
|
||||||
|
if (count < ANIM_MIN_ARGS) {
|
||||||
|
Chat_Add1("&cNot enough arguments for anim: %s", &line); continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Convert_ParseUInt8(&parts[0], &tileX) || tileX >= ATLAS2D_TILES_PER_ROW) {
|
||||||
|
Chat_Add1("&cInvalid anim tile X coord: %s", &parts[0]); continue;
|
||||||
|
}
|
||||||
|
if (!Convert_ParseUInt8(&parts[1], &tileY) || tileY >= ATLAS2D_MAX_ROWS_COUNT) {
|
||||||
|
Chat_Add1("&cInvalid anim tile Y coord: %s", &parts[1]); continue;
|
||||||
|
}
|
||||||
|
if (!Convert_ParseUInt16(&parts[2], &data.frameX)) {
|
||||||
|
Chat_Add1("&cInvalid anim frame X coord: %s", &parts[2]); continue;
|
||||||
|
}
|
||||||
|
if (!Convert_ParseUInt16(&parts[3], &data.frameY)) {
|
||||||
|
Chat_Add1("&cInvalid anim frame Y coord: %s", &parts[3]); continue;
|
||||||
|
}
|
||||||
|
if (!Convert_ParseUInt16(&parts[4], &data.frameSize) || !data.frameSize) {
|
||||||
|
Chat_Add1("&cInvalid anim frame size: %s", &parts[4]); continue;
|
||||||
|
}
|
||||||
|
if (!Convert_ParseUInt16(&parts[5], &data.statesCount)) {
|
||||||
|
Chat_Add1("&cInvalid anim states count: %s", &parts[5]); continue;
|
||||||
|
}
|
||||||
|
if (!Convert_ParseUInt16(&parts[6], &data.frameDelay)) {
|
||||||
|
Chat_Add1("&cInvalid anim frame delay: %s", &parts[6]); continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anims_count == Array_Elems(anims_list)) {
|
||||||
|
Chat_AddRaw("&cCannot show over 512 animations"); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.texLoc = tileX + (tileY * ATLAS2D_TILES_PER_ROW);
|
||||||
|
anims_list[anims_count++] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ANIMS_FAST_SIZE 64
|
||||||
|
static void Animations_Draw(struct AnimationData* data, TextureLoc texLoc, int size) {
|
||||||
|
int dstX = Atlas1D_Index(texLoc), srcX;
|
||||||
|
int dstY = Atlas1D_RowId(texLoc) * Atlas2D.TileSize;
|
||||||
|
GfxResourceID tex;
|
||||||
|
|
||||||
|
cc_uint8 buffer[Bitmap_DataSize(ANIMS_FAST_SIZE, ANIMS_FAST_SIZE)];
|
||||||
|
cc_uint8* ptr = buffer;
|
||||||
|
Bitmap frame;
|
||||||
|
|
||||||
|
/* cannot allocate memory on the stack for very big animation.png frames */
|
||||||
|
if (size > ANIMS_FAST_SIZE) {
|
||||||
|
ptr = (cc_uint8*)Mem_Alloc(size * size, 4, "anim frame");
|
||||||
|
}
|
||||||
|
Bitmap_Init(frame, size, size, ptr);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
#ifndef CC_BUILD_WEB
|
||||||
|
if (texLoc == LAVA_TEX_LOC) {
|
||||||
|
LavaAnimation_Tick((BitmapCol*)frame.Scan0, size);
|
||||||
|
} else if (texLoc == WATER_TEX_LOC) {
|
||||||
|
WaterAnimation_Tick((BitmapCol*)frame.Scan0, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
srcX = data->frameX + data->state * size;
|
||||||
|
Bitmap_UNSAFE_CopyBlock(srcX, data->frameY, 0, 0, &anims_bmp, &frame, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
tex = Atlas1D.TexIds[dstX];
|
||||||
|
if (tex) { Gfx_UpdateTexturePart(tex, 0, dstY, &frame, Gfx.Mipmaps); }
|
||||||
|
if (size > ANIMS_FAST_SIZE) Mem_Free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Animations_Apply(struct AnimationData* data) {
|
||||||
|
TextureLoc loc;
|
||||||
|
if (data->delay) { data->delay--; return; }
|
||||||
|
|
||||||
|
data->state++;
|
||||||
|
data->state %= data->statesCount;
|
||||||
|
data->delay = data->frameDelay;
|
||||||
|
|
||||||
|
loc = data->texLoc;
|
||||||
|
#ifndef CC_BUILD_WEB
|
||||||
|
if (loc == LAVA_TEX_LOC && useLavaAnim) return;
|
||||||
|
if (loc == WATER_TEX_LOC && useWaterAnim) return;
|
||||||
|
#endif
|
||||||
|
Animations_Draw(data, loc, data->frameSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static cc_bool Animations_IsDefaultZip(void) {
|
||||||
|
String texPack;
|
||||||
|
cc_bool optExists;
|
||||||
|
if (World_TextureUrl.length) return false;
|
||||||
|
|
||||||
|
optExists = Options_UNSAFE_Get(OPT_DEFAULT_TEX_PACK, &texPack);
|
||||||
|
return !optExists || String_CaselessEqualsConst(&texPack, "default.zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Animations_Clear(void) {
|
||||||
|
Mem_Free(anims_bmp.Scan0);
|
||||||
|
anims_count = 0;
|
||||||
|
anims_bmp.Scan0 = NULL;
|
||||||
|
anims_validated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Animations_Validate(void) {
|
||||||
|
struct AnimationData data;
|
||||||
|
int maxX, maxY, tileX, tileY;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
anims_validated = true;
|
||||||
|
for (i = 0; i < anims_count; i++) {
|
||||||
|
data = anims_list[i];
|
||||||
|
|
||||||
|
maxX = data.frameX + data.frameSize * data.statesCount;
|
||||||
|
maxY = data.frameY + data.frameSize;
|
||||||
|
tileX = Atlas2D_TileX(data.texLoc);
|
||||||
|
tileY = Atlas2D_TileY(data.texLoc);
|
||||||
|
|
||||||
|
if (data.frameSize > Atlas2D.TileSize || tileY >= Atlas2D.RowsCount) {
|
||||||
|
Chat_Add2("&cAnimation frames for tile (%i, %i) are bigger than the size of a tile in terrain.png", &tileX, &tileY);
|
||||||
|
} else if (maxX > anims_bmp.Width || maxY > anims_bmp.Height) {
|
||||||
|
Chat_Add2("&cSome of the animation frames for tile (%i, %i) are at coordinates outside animations.png", &tileX, &tileY);
|
||||||
|
} else {
|
||||||
|
/* if user has water/lava animations in their default.zip, disable built-in */
|
||||||
|
/* However, 'usewateranim' and 'uselavaanim' files should always disable use */
|
||||||
|
/* of custom water/lava animations, even when they exist in animations.png */
|
||||||
|
if (data.texLoc == LAVA_TEX_LOC && !alwaysLavaAnim) useLavaAnim = false;
|
||||||
|
if (data.texLoc == WATER_TEX_LOC && !alwaysWaterAnim) useWaterAnim = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove this animation from the list */
|
||||||
|
for (j = i; j < anims_count - 1; j++) {
|
||||||
|
anims_list[j] = anims_list[j + 1];
|
||||||
|
}
|
||||||
|
i--; anims_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Animations_Tick(struct ScheduledTask* task) {
|
||||||
|
int i, size;
|
||||||
|
|
||||||
|
#ifndef CC_BUILD_WEB
|
||||||
|
if (useLavaAnim) {
|
||||||
|
size = min(Atlas2D.TileSize, 64);
|
||||||
|
Animations_Draw(NULL, LAVA_TEX_LOC, size);
|
||||||
|
}
|
||||||
|
if (useWaterAnim) {
|
||||||
|
size = min(Atlas2D.TileSize, 64);
|
||||||
|
Animations_Draw(NULL, WATER_TEX_LOC, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!anims_count) return;
|
||||||
|
if (!anims_bmp.Scan0) {
|
||||||
|
Chat_AddRaw("&cCurrent texture pack specifies it uses animations,");
|
||||||
|
Chat_AddRaw("&cbut is missing animations.png");
|
||||||
|
anims_count = 0; return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deferred, because when reading animations.txt, might not have read animations.png yet */
|
||||||
|
if (!anims_validated) Animations_Validate();
|
||||||
|
for (i = 0; i < anims_count; i++) {
|
||||||
|
Animations_Apply(&anims_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*########################################################################################################################*
|
||||||
|
*--------------------------------------------------Animations component---------------------------------------------------*
|
||||||
|
*#########################################################################################################################*/
|
||||||
|
static void OnPackChanged(void* obj) {
|
||||||
|
Animations_Clear();
|
||||||
|
useLavaAnim = Animations_IsDefaultZip();
|
||||||
|
useWaterAnim = useLavaAnim;
|
||||||
|
alwaysLavaAnim = false;
|
||||||
|
alwaysWaterAnim = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnFileChanged(void* obj, struct Stream* stream, const String* name) {
|
||||||
|
cc_result res;
|
||||||
|
if (String_CaselessEqualsConst(name, "animations.png")) {
|
||||||
|
res = Png_Decode(&anims_bmp, stream);
|
||||||
|
if (!res) return;
|
||||||
|
|
||||||
|
Logger_Warn2(res, "decoding", name);
|
||||||
|
Mem_Free(anims_bmp.Scan0);
|
||||||
|
anims_bmp.Scan0 = NULL;
|
||||||
|
} else if (String_CaselessEqualsConst(name, "animations.txt")) {
|
||||||
|
Animations_ReadDescription(stream, name);
|
||||||
|
} else if (String_CaselessEqualsConst(name, "uselavaanim")) {
|
||||||
|
useLavaAnim = true;
|
||||||
|
alwaysLavaAnim = true;
|
||||||
|
} else if (String_CaselessEqualsConst(name, "usewateranim")) {
|
||||||
|
useWaterAnim = true;
|
||||||
|
alwaysWaterAnim = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Animations_Init(void) {
|
||||||
|
ScheduledTask_Add(GAME_DEF_TICKS, Animations_Tick);
|
||||||
|
Event_RegisterVoid(&TextureEvents.PackChanged, NULL, OnPackChanged);
|
||||||
|
Event_RegisterEntry(&TextureEvents.FileChanged, NULL, OnFileChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Animations_Free(void) {
|
||||||
|
Animations_Clear();
|
||||||
|
Event_UnregisterVoid(&TextureEvents.PackChanged, NULL, OnPackChanged);
|
||||||
|
Event_UnregisterEntry(&TextureEvents.FileChanged, NULL, OnFileChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IGameComponent Animations_Component = {
|
||||||
|
Animations_Init, /* Init */
|
||||||
|
Animations_Free /* Free */
|
||||||
|
};
|
9
src/Animations.h
Normal file
9
src/Animations.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CC_ANIMATIONS_H
|
||||||
|
#define CC_ANIMATIONS_H
|
||||||
|
/* Contains everything relating to texture animations (including default water/lava ones)
|
||||||
|
Copyright 2014-2020 ClassiCube | Licensed under BSD-3
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct IGameComponent;
|
||||||
|
extern struct IGameComponent Animations_Component;
|
||||||
|
#endif
|
@ -187,6 +187,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Animations.h" />
|
||||||
<ClInclude Include="Http.h" />
|
<ClInclude Include="Http.h" />
|
||||||
<ClInclude Include="Audio.h" />
|
<ClInclude Include="Audio.h" />
|
||||||
<ClInclude Include="AxisLinesRenderer.h" />
|
<ClInclude Include="AxisLinesRenderer.h" />
|
||||||
@ -250,6 +251,7 @@
|
|||||||
<ClInclude Include="World.h" />
|
<ClInclude Include="World.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Animations.c" />
|
||||||
<ClCompile Include="Http.c" />
|
<ClCompile Include="Http.c" />
|
||||||
<ClCompile Include="Audio.c" />
|
<ClCompile Include="Audio.c" />
|
||||||
<ClCompile Include="Camera.c" />
|
<ClCompile Include="Camera.c" />
|
||||||
|
@ -309,6 +309,9 @@
|
|||||||
<ClInclude Include="Graphics.h">
|
<ClInclude Include="Graphics.h">
|
||||||
<Filter>Header Files\Graphics</Filter>
|
<Filter>Header Files\Graphics</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Animations.h">
|
||||||
|
<Filter>Header Files\TexturePack</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="String.c">
|
<ClCompile Include="String.c">
|
||||||
@ -530,5 +533,8 @@
|
|||||||
<ClCompile Include="Graphics.c">
|
<ClCompile Include="Graphics.c">
|
||||||
<Filter>Source Files\Graphics</Filter>
|
<Filter>Source Files\Graphics</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Animations.c">
|
||||||
|
<Filter>Source Files\TexturePack</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -35,6 +35,7 @@
|
|||||||
#include "Builder.h"
|
#include "Builder.h"
|
||||||
#include "Protocol.h"
|
#include "Protocol.h"
|
||||||
#include "Picking.h"
|
#include "Picking.h"
|
||||||
|
#include "Animations.h"
|
||||||
|
|
||||||
struct _GameData Game;
|
struct _GameData Game;
|
||||||
int Game_Port;
|
int Game_Port;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "TexturePack.h"
|
#include "TexturePack.h"
|
||||||
#include "Constants.h"
|
#include "Constants.h"
|
||||||
#include "Platform.h"
|
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
@ -9,403 +8,11 @@
|
|||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Deflate.h"
|
#include "Deflate.h"
|
||||||
#include "Stream.h"
|
|
||||||
#include "Funcs.h"
|
#include "Funcs.h"
|
||||||
#include "Errors.h"
|
|
||||||
#include "Chat.h"
|
|
||||||
#include "ExtMath.h"
|
#include "ExtMath.h"
|
||||||
#include "Chat.h"
|
|
||||||
#include "Options.h"
|
#include "Options.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
|
||||||
#define LIQUID_ANIM_MAX 64
|
|
||||||
#define WATER_TEX_LOC 14
|
|
||||||
#define LAVA_TEX_LOC 30
|
|
||||||
|
|
||||||
#ifndef CC_BUILD_WEB
|
|
||||||
/* Based off the incredible work from https://dl.dropboxusercontent.com/u/12694594/lava.txt
|
|
||||||
mirrored at https://github.com/UnknownShadow200/ClassicalSharp/wiki/Minecraft-Classic-lava-animation-algorithm
|
|
||||||
Water animation originally written by cybertoon, big thanks!
|
|
||||||
*/
|
|
||||||
/*########################################################################################################################*
|
|
||||||
*-----------------------------------------------------Lava animation------------------------------------------------------*
|
|
||||||
*#########################################################################################################################*/
|
|
||||||
static float L_soupHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
|
||||||
static float L_potHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
|
||||||
static float L_flameHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
|
||||||
static RNGState L_rnd;
|
|
||||||
static cc_bool L_rndInited;
|
|
||||||
|
|
||||||
static void LavaAnimation_Tick(BitmapCol* ptr, int size) {
|
|
||||||
int mask = size - 1, shift = Math_Log2(size);
|
|
||||||
float soupHeat, potHeat, col;
|
|
||||||
int x, y, i = 0;
|
|
||||||
|
|
||||||
if (!L_rndInited) {
|
|
||||||
Random_SeedFromCurrentTime(&L_rnd);
|
|
||||||
L_rndInited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (y = 0; y < size; y++) {
|
|
||||||
for (x = 0; x < size; x++) {
|
|
||||||
/* Calculate the colour at this coordinate in the heatmap */
|
|
||||||
|
|
||||||
/* Lookup table for (int)(1.2 * sin([ANGLE] * 22.5 * MATH_DEG2RAD)); */
|
|
||||||
/* [ANGLE] is integer x/y, so repeats every 16 intervals */
|
|
||||||
static cc_int8 sin_adj_table[16] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, -1, -1, -1, 0, 0 };
|
|
||||||
int xx = x + sin_adj_table[y & 0xF], yy = y + sin_adj_table[x & 0xF];
|
|
||||||
|
|
||||||
soupHeat =
|
|
||||||
L_soupHeat[((yy - 1) & mask) << shift | ((xx - 1) & mask)] +
|
|
||||||
L_soupHeat[((yy - 1) & mask) << shift | (xx & mask)] +
|
|
||||||
L_soupHeat[((yy - 1) & mask) << shift | ((xx + 1) & mask)] +
|
|
||||||
|
|
||||||
L_soupHeat[(yy & mask) << shift | ((xx - 1) & mask)] +
|
|
||||||
L_soupHeat[(yy & mask) << shift | (xx & mask)] +
|
|
||||||
L_soupHeat[(yy & mask) << shift | ((xx + 1) & mask)] +
|
|
||||||
|
|
||||||
L_soupHeat[((yy + 1) & mask) << shift | ((xx - 1) & mask)] +
|
|
||||||
L_soupHeat[((yy + 1) & mask) << shift | (xx & mask)] +
|
|
||||||
L_soupHeat[((yy + 1) & mask) << shift | ((xx + 1) & mask)];
|
|
||||||
|
|
||||||
potHeat =
|
|
||||||
L_potHeat[i] + /* x , y */
|
|
||||||
L_potHeat[y << shift | ((x + 1) & mask)] + /* x + 1, y */
|
|
||||||
L_potHeat[((y + 1) & mask) << shift | x] + /* x , y + 1 */
|
|
||||||
L_potHeat[((y + 1) & mask) << shift | ((x + 1) & mask)];/* x + 1, y + 1 */
|
|
||||||
|
|
||||||
L_soupHeat[i] = soupHeat * 0.1f + potHeat * 0.2f;
|
|
||||||
|
|
||||||
L_potHeat[i] += L_flameHeat[i];
|
|
||||||
if (L_potHeat[i] < 0.0f) L_potHeat[i] = 0.0f;
|
|
||||||
|
|
||||||
L_flameHeat[i] -= 0.06f * 0.01f;
|
|
||||||
if (Random_Float(&L_rnd) <= 0.005f) L_flameHeat[i] = 1.5f * 0.01f;
|
|
||||||
|
|
||||||
/* Output the pixel */
|
|
||||||
col = 2.0f * L_soupHeat[i];
|
|
||||||
Math_Clamp(col, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
*ptr = BitmapCol_Make(
|
|
||||||
col * 100.0f + 155.0f,
|
|
||||||
col * col * 255.0f,
|
|
||||||
col * col * col * col * 128.0f,
|
|
||||||
255);
|
|
||||||
|
|
||||||
ptr++; i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*########################################################################################################################*
|
|
||||||
*----------------------------------------------------Water animation------------------------------------------------------*
|
|
||||||
*#########################################################################################################################*/
|
|
||||||
static float W_soupHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
|
||||||
static float W_potHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
|
||||||
static float W_flameHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX];
|
|
||||||
static RNGState W_rnd;
|
|
||||||
static cc_bool W_rndInited;
|
|
||||||
|
|
||||||
static void WaterAnimation_Tick(BitmapCol* ptr, int size) {
|
|
||||||
int mask = size - 1, shift = Math_Log2(size);
|
|
||||||
float soupHeat, col;
|
|
||||||
int x, y, i = 0;
|
|
||||||
|
|
||||||
if (!W_rndInited) {
|
|
||||||
Random_SeedFromCurrentTime(&W_rnd);
|
|
||||||
W_rndInited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (y = 0; y < size; y++) {
|
|
||||||
for (x = 0; x < size; x++) {
|
|
||||||
/* Calculate the colour at this coordinate in the heatmap */
|
|
||||||
soupHeat =
|
|
||||||
W_soupHeat[y << shift | ((x - 1) & mask)] +
|
|
||||||
W_soupHeat[y << shift | x ] +
|
|
||||||
W_soupHeat[y << shift | ((x + 1) & mask)];
|
|
||||||
|
|
||||||
W_soupHeat[i] = soupHeat / 3.3f + W_potHeat[i] * 0.8f;
|
|
||||||
|
|
||||||
W_potHeat[i] += W_flameHeat[i];
|
|
||||||
if (W_potHeat[i] < 0.0f) W_potHeat[i] = 0.0f;
|
|
||||||
|
|
||||||
W_flameHeat[i] -= 0.1f * 0.05f;
|
|
||||||
if (Random_Float(&W_rnd) <= 0.05f) W_flameHeat[i] = 0.5f * 0.05f;
|
|
||||||
|
|
||||||
/* Output the pixel */
|
|
||||||
col = W_soupHeat[i];
|
|
||||||
Math_Clamp(col, 0.0f, 1.0f);
|
|
||||||
col = col * col;
|
|
||||||
|
|
||||||
*ptr = BitmapCol_Make(
|
|
||||||
32.0f + col * 32.0f,
|
|
||||||
50.0f + col * 64.0f,
|
|
||||||
255,
|
|
||||||
146.0f + col * 50.0f);
|
|
||||||
|
|
||||||
ptr++; i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*########################################################################################################################*
|
|
||||||
*-------------------------------------------------------Animations--------------------------------------------------------*
|
|
||||||
*#########################################################################################################################*/
|
|
||||||
struct AnimationData {
|
|
||||||
TextureLoc texLoc; /* Tile (not pixel) coordinates in terrain.png */
|
|
||||||
cc_uint16 frameX, frameY; /* Top left pixel coordinates of start frame in animatons.png */
|
|
||||||
cc_uint16 frameSize; /* Size of each frame in pixel coordinates */
|
|
||||||
cc_uint16 state; /* Current animation frame index */
|
|
||||||
cc_uint16 statesCount; /* Total number of animation frames */
|
|
||||||
cc_uint16 delay; /* Delay in ticks until next frame is drawn */
|
|
||||||
cc_uint16 frameDelay; /* Delay between each frame */
|
|
||||||
};
|
|
||||||
|
|
||||||
static Bitmap anims_bmp;
|
|
||||||
static struct AnimationData anims_list[ATLAS1D_MAX_ATLASES];
|
|
||||||
static int anims_count;
|
|
||||||
static cc_bool anims_validated, useLavaAnim, useWaterAnim, alwaysLavaAnim, alwaysWaterAnim;
|
|
||||||
#define ANIM_MIN_ARGS 7
|
|
||||||
|
|
||||||
static void Animations_ReadDescription(struct Stream* stream, const String* path) {
|
|
||||||
String line; char lineBuffer[STRING_SIZE * 2];
|
|
||||||
String parts[ANIM_MIN_ARGS];
|
|
||||||
int count;
|
|
||||||
struct AnimationData data = { 0 };
|
|
||||||
cc_uint8 tileX, tileY;
|
|
||||||
|
|
||||||
cc_uint8 buffer[2048];
|
|
||||||
struct Stream buffered;
|
|
||||||
cc_result res;
|
|
||||||
|
|
||||||
String_InitArray(line, lineBuffer);
|
|
||||||
/* ReadLine reads single byte at a time */
|
|
||||||
Stream_ReadonlyBuffered(&buffered, stream, buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
res = Stream_ReadLine(&buffered, &line);
|
|
||||||
if (res == ERR_END_OF_STREAM) break;
|
|
||||||
if (res) { Logger_Warn2(res, "reading from", path); break; }
|
|
||||||
|
|
||||||
if (!line.length || line.buffer[0] == '#') continue;
|
|
||||||
count = String_UNSAFE_Split(&line, ' ', parts, ANIM_MIN_ARGS);
|
|
||||||
if (count < ANIM_MIN_ARGS) {
|
|
||||||
Chat_Add1("&cNot enough arguments for anim: %s", &line); continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Convert_ParseUInt8(&parts[0], &tileX) || tileX >= ATLAS2D_TILES_PER_ROW) {
|
|
||||||
Chat_Add1("&cInvalid anim tile X coord: %s", &parts[0]); continue;
|
|
||||||
}
|
|
||||||
if (!Convert_ParseUInt8(&parts[1], &tileY) || tileY >= ATLAS2D_MAX_ROWS_COUNT) {
|
|
||||||
Chat_Add1("&cInvalid anim tile Y coord: %s", &parts[1]); continue;
|
|
||||||
}
|
|
||||||
if (!Convert_ParseUInt16(&parts[2], &data.frameX)) {
|
|
||||||
Chat_Add1("&cInvalid anim frame X coord: %s", &parts[2]); continue;
|
|
||||||
}
|
|
||||||
if (!Convert_ParseUInt16(&parts[3], &data.frameY)) {
|
|
||||||
Chat_Add1("&cInvalid anim frame Y coord: %s", &parts[3]); continue;
|
|
||||||
}
|
|
||||||
if (!Convert_ParseUInt16(&parts[4], &data.frameSize) || !data.frameSize) {
|
|
||||||
Chat_Add1("&cInvalid anim frame size: %s", &parts[4]); continue;
|
|
||||||
}
|
|
||||||
if (!Convert_ParseUInt16(&parts[5], &data.statesCount)) {
|
|
||||||
Chat_Add1("&cInvalid anim states count: %s", &parts[5]); continue;
|
|
||||||
}
|
|
||||||
if (!Convert_ParseUInt16(&parts[6], &data.frameDelay)) {
|
|
||||||
Chat_Add1("&cInvalid anim frame delay: %s", &parts[6]); continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anims_count == Array_Elems(anims_list)) {
|
|
||||||
Chat_AddRaw("&cCannot show over 512 animations"); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.texLoc = tileX + (tileY * ATLAS2D_TILES_PER_ROW);
|
|
||||||
anims_list[anims_count++] = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ANIMS_FAST_SIZE 64
|
|
||||||
static void Animations_Draw(struct AnimationData* data, TextureLoc texLoc, int size) {
|
|
||||||
int dstX = Atlas1D_Index(texLoc), srcX;
|
|
||||||
int dstY = Atlas1D_RowId(texLoc) * Atlas2D.TileSize;
|
|
||||||
GfxResourceID tex;
|
|
||||||
|
|
||||||
cc_uint8 buffer[Bitmap_DataSize(ANIMS_FAST_SIZE, ANIMS_FAST_SIZE)];
|
|
||||||
cc_uint8* ptr = buffer;
|
|
||||||
Bitmap frame;
|
|
||||||
|
|
||||||
/* cannot allocate memory on the stack for very big animation.png frames */
|
|
||||||
if (size > ANIMS_FAST_SIZE) {
|
|
||||||
ptr = (cc_uint8*)Mem_Alloc(size * size, 4, "anim frame");
|
|
||||||
}
|
|
||||||
Bitmap_Init(frame, size, size, ptr);
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
#ifndef CC_BUILD_WEB
|
|
||||||
if (texLoc == LAVA_TEX_LOC) {
|
|
||||||
LavaAnimation_Tick((BitmapCol*)frame.Scan0, size);
|
|
||||||
} else if (texLoc == WATER_TEX_LOC) {
|
|
||||||
WaterAnimation_Tick((BitmapCol*)frame.Scan0, size);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
srcX = data->frameX + data->state * size;
|
|
||||||
Bitmap_UNSAFE_CopyBlock(srcX, data->frameY, 0, 0, &anims_bmp, &frame, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
tex = Atlas1D.TexIds[dstX];
|
|
||||||
if (tex) { Gfx_UpdateTexturePart(tex, 0, dstY, &frame, Gfx.Mipmaps); }
|
|
||||||
if (size > ANIMS_FAST_SIZE) Mem_Free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Animations_Apply(struct AnimationData* data) {
|
|
||||||
TextureLoc loc;
|
|
||||||
if (data->delay) { data->delay--; return; }
|
|
||||||
|
|
||||||
data->state++;
|
|
||||||
data->state %= data->statesCount;
|
|
||||||
data->delay = data->frameDelay;
|
|
||||||
|
|
||||||
loc = data->texLoc;
|
|
||||||
#ifndef CC_BUILD_WEB
|
|
||||||
if (loc == LAVA_TEX_LOC && useLavaAnim) return;
|
|
||||||
if (loc == WATER_TEX_LOC && useWaterAnim) return;
|
|
||||||
#endif
|
|
||||||
Animations_Draw(data, loc, data->frameSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cc_bool Animations_IsDefaultZip(void) {
|
|
||||||
String texPack;
|
|
||||||
cc_bool optExists;
|
|
||||||
if (World_TextureUrl.length) return false;
|
|
||||||
|
|
||||||
optExists = Options_UNSAFE_Get(OPT_DEFAULT_TEX_PACK, &texPack);
|
|
||||||
return !optExists || String_CaselessEqualsConst(&texPack, "default.zip");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Animations_Clear(void) {
|
|
||||||
Mem_Free(anims_bmp.Scan0);
|
|
||||||
anims_count = 0;
|
|
||||||
anims_bmp.Scan0 = NULL;
|
|
||||||
anims_validated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Animations_Validate(void) {
|
|
||||||
struct AnimationData data;
|
|
||||||
int maxX, maxY, tileX, tileY;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
anims_validated = true;
|
|
||||||
for (i = 0; i < anims_count; i++) {
|
|
||||||
data = anims_list[i];
|
|
||||||
|
|
||||||
maxX = data.frameX + data.frameSize * data.statesCount;
|
|
||||||
maxY = data.frameY + data.frameSize;
|
|
||||||
tileX = Atlas2D_TileX(data.texLoc);
|
|
||||||
tileY = Atlas2D_TileY(data.texLoc);
|
|
||||||
|
|
||||||
if (data.frameSize > Atlas2D.TileSize || tileY >= Atlas2D.RowsCount) {
|
|
||||||
Chat_Add2("&cAnimation frames for tile (%i, %i) are bigger than the size of a tile in terrain.png", &tileX, &tileY);
|
|
||||||
} else if (maxX > anims_bmp.Width || maxY > anims_bmp.Height) {
|
|
||||||
Chat_Add2("&cSome of the animation frames for tile (%i, %i) are at coordinates outside animations.png", &tileX, &tileY);
|
|
||||||
} else {
|
|
||||||
/* if user has water/lava animations in their default.zip, disable built-in */
|
|
||||||
/* However, 'usewateranim' and 'uselavaanim' files should always disable use */
|
|
||||||
/* of custom water/lava animations, even when they exist in animations.png */
|
|
||||||
if (data.texLoc == LAVA_TEX_LOC && !alwaysLavaAnim) useLavaAnim = false;
|
|
||||||
if (data.texLoc == WATER_TEX_LOC && !alwaysWaterAnim) useWaterAnim = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove this animation from the list */
|
|
||||||
for (j = i; j < anims_count - 1; j++) {
|
|
||||||
anims_list[j] = anims_list[j + 1];
|
|
||||||
}
|
|
||||||
i--; anims_count--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Animations_Tick(struct ScheduledTask* task) {
|
|
||||||
int i, size;
|
|
||||||
|
|
||||||
#ifndef CC_BUILD_WEB
|
|
||||||
if (useLavaAnim) {
|
|
||||||
size = min(Atlas2D.TileSize, 64);
|
|
||||||
Animations_Draw(NULL, LAVA_TEX_LOC, size);
|
|
||||||
}
|
|
||||||
if (useWaterAnim) {
|
|
||||||
size = min(Atlas2D.TileSize, 64);
|
|
||||||
Animations_Draw(NULL, WATER_TEX_LOC, size);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!anims_count) return;
|
|
||||||
if (!anims_bmp.Scan0) {
|
|
||||||
Chat_AddRaw("&cCurrent texture pack specifies it uses animations,");
|
|
||||||
Chat_AddRaw("&cbut is missing animations.png");
|
|
||||||
anims_count = 0; return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deferred, because when reading animations.txt, might not have read animations.png yet */
|
|
||||||
if (!anims_validated) Animations_Validate();
|
|
||||||
for (i = 0; i < anims_count; i++) {
|
|
||||||
Animations_Apply(&anims_list[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*########################################################################################################################*
|
|
||||||
*--------------------------------------------------Animations component---------------------------------------------------*
|
|
||||||
*#########################################################################################################################*/
|
|
||||||
static void OnPackChanged(void* obj) {
|
|
||||||
Animations_Clear();
|
|
||||||
useLavaAnim = Animations_IsDefaultZip();
|
|
||||||
useWaterAnim = useLavaAnim;
|
|
||||||
alwaysLavaAnim = false;
|
|
||||||
alwaysWaterAnim = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnFileChanged(void* obj, struct Stream* stream, const String* name) {
|
|
||||||
cc_result res;
|
|
||||||
if (String_CaselessEqualsConst(name, "animations.png")) {
|
|
||||||
res = Png_Decode(&anims_bmp, stream);
|
|
||||||
if (!res) return;
|
|
||||||
|
|
||||||
Logger_Warn2(res, "decoding", name);
|
|
||||||
Mem_Free(anims_bmp.Scan0);
|
|
||||||
anims_bmp.Scan0 = NULL;
|
|
||||||
} else if (String_CaselessEqualsConst(name, "animations.txt")) {
|
|
||||||
Animations_ReadDescription(stream, name);
|
|
||||||
} else if (String_CaselessEqualsConst(name, "uselavaanim")) {
|
|
||||||
useLavaAnim = true;
|
|
||||||
alwaysLavaAnim = true;
|
|
||||||
} else if (String_CaselessEqualsConst(name, "usewateranim")) {
|
|
||||||
useWaterAnim = true;
|
|
||||||
alwaysWaterAnim = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Animations_Init(void) {
|
|
||||||
ScheduledTask_Add(GAME_DEF_TICKS, Animations_Tick);
|
|
||||||
Event_RegisterVoid(&TextureEvents.PackChanged, NULL, OnPackChanged);
|
|
||||||
Event_RegisterEntry(&TextureEvents.FileChanged, NULL, OnFileChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Animations_Free(void) {
|
|
||||||
Animations_Clear();
|
|
||||||
Event_UnregisterVoid(&TextureEvents.PackChanged, NULL, OnPackChanged);
|
|
||||||
Event_UnregisterEntry(&TextureEvents.FileChanged, NULL, OnFileChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IGameComponent Animations_Component = {
|
|
||||||
Animations_Init, /* Init */
|
|
||||||
Animations_Free /* Free */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*########################################################################################################################*
|
/*########################################################################################################################*
|
||||||
*------------------------------------------------------TerrainAtlas-------------------------------------------------------*
|
*------------------------------------------------------TerrainAtlas-------------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
|
@ -6,13 +6,11 @@
|
|||||||
- Extracting the textures from a .zip archive
|
- Extracting the textures from a .zip archive
|
||||||
- Caching terrain atlases and texture packs to avoid redundant downloads
|
- Caching terrain atlases and texture packs to avoid redundant downloads
|
||||||
- Terrain atlas (including breaking it down into multiple 1D atlases)
|
- Terrain atlas (including breaking it down into multiple 1D atlases)
|
||||||
- Texture animations (including default water/lava ones)
|
Copyright 2014-2020 ClassiCube | Licensed under BSD-3
|
||||||
Copyright 2014-2020 ClassiCube | Licensed under BSD-3 */
|
*/
|
||||||
|
|
||||||
struct Stream;
|
struct Stream;
|
||||||
struct HttpRequest;
|
struct HttpRequest;
|
||||||
struct IGameComponent;
|
|
||||||
extern struct IGameComponent Animations_Component;
|
|
||||||
|
|
||||||
/* Number of tiles in each row */
|
/* Number of tiles in each row */
|
||||||
#define ATLAS2D_TILES_PER_ROW 16
|
#define ATLAS2D_TILES_PER_ROW 16
|
||||||
|
@ -36,40 +36,6 @@
|
|||||||
#define FT_COMPONENT trace_afmodule
|
#define FT_COMPONENT trace_afmodule
|
||||||
|
|
||||||
|
|
||||||
static FT_Error
|
|
||||||
af_property_get_face_globals( FT_Face face,
|
|
||||||
AF_FaceGlobals* aglobals,
|
|
||||||
AF_Module module )
|
|
||||||
{
|
|
||||||
FT_Error error = FT_Err_Ok;
|
|
||||||
AF_FaceGlobals globals;
|
|
||||||
|
|
||||||
|
|
||||||
if ( !face )
|
|
||||||
return FT_THROW( Invalid_Face_Handle );
|
|
||||||
|
|
||||||
globals = (AF_FaceGlobals)face->autohint.data;
|
|
||||||
if ( !globals )
|
|
||||||
{
|
|
||||||
/* trigger computation of the global style data */
|
|
||||||
/* in case it hasn't been done yet */
|
|
||||||
error = af_face_globals_new( face, &globals, module );
|
|
||||||
if ( !error )
|
|
||||||
{
|
|
||||||
face->autohint.data =
|
|
||||||
(FT_Pointer)globals;
|
|
||||||
face->autohint.finalizer =
|
|
||||||
(FT_Generic_Finalizer)af_face_globals_free;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !error )
|
|
||||||
*aglobals = globals;
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const FT_ServiceDescRec af_services[] =
|
static const FT_ServiceDescRec af_services[] =
|
||||||
{
|
{
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
@ -374,24 +374,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FT_BASE_DEF( FT_ULong )
|
|
||||||
FT_Stream_GetUOffset( FT_Stream stream )
|
|
||||||
{
|
|
||||||
FT_Byte* p;
|
|
||||||
FT_ULong result;
|
|
||||||
|
|
||||||
|
|
||||||
FT_ASSERT( stream && stream->cursor );
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
p = stream->cursor;
|
|
||||||
if ( p + 2 < stream->limit )
|
|
||||||
result = FT_NEXT_UOFF3( p );
|
|
||||||
stream->cursor = p;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FT_BASE_DEF( FT_ULong )
|
FT_BASE_DEF( FT_ULong )
|
||||||
FT_Stream_GetULong( FT_Stream stream )
|
FT_Stream_GetULong( FT_Stream stream )
|
||||||
{
|
{
|
||||||
@ -410,24 +392,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FT_BASE_DEF( FT_ULong )
|
|
||||||
FT_Stream_GetULongLE( FT_Stream stream )
|
|
||||||
{
|
|
||||||
FT_Byte* p;
|
|
||||||
FT_ULong result;
|
|
||||||
|
|
||||||
|
|
||||||
FT_ASSERT( stream && stream->cursor );
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
p = stream->cursor;
|
|
||||||
if ( p + 3 < stream->limit )
|
|
||||||
result = FT_NEXT_ULONG_LE( p );
|
|
||||||
stream->cursor = p;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FT_BASE_DEF( FT_Char )
|
FT_BASE_DEF( FT_Char )
|
||||||
FT_Stream_ReadChar( FT_Stream stream,
|
FT_Stream_ReadChar( FT_Stream stream,
|
||||||
FT_Error* error )
|
FT_Error* error )
|
||||||
|
@ -205,10 +205,6 @@ FT_BEGIN_HEADER
|
|||||||
FT_BYTE_U32( p, 1, 8 ) | \
|
FT_BYTE_U32( p, 1, 8 ) | \
|
||||||
FT_BYTE_U32( p, 0, 0 ) )
|
FT_BYTE_U32( p, 0, 0 ) )
|
||||||
|
|
||||||
#define FT_PEEK_OFF3_LE( p ) FT_INT32( FT_BYTE_U32( p, 2, 16 ) | \
|
|
||||||
FT_BYTE_U32( p, 1, 8 ) | \
|
|
||||||
FT_BYTE_U32( p, 0, 0 ) )
|
|
||||||
|
|
||||||
#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \
|
#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \
|
||||||
FT_BYTE_U32( p, 1, 8 ) | \
|
FT_BYTE_U32( p, 1, 8 ) | \
|
||||||
FT_BYTE_U32( p, 0, 0 ) )
|
FT_BYTE_U32( p, 0, 0 ) )
|
||||||
@ -245,9 +241,6 @@ FT_BEGIN_HEADER
|
|||||||
#define FT_NEXT_USHORT_LE( buffer ) \
|
#define FT_NEXT_USHORT_LE( buffer ) \
|
||||||
( (unsigned short)( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) )
|
( (unsigned short)( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) )
|
||||||
|
|
||||||
#define FT_NEXT_OFF3_LE( buffer ) \
|
|
||||||
( (long)( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) )
|
|
||||||
|
|
||||||
#define FT_NEXT_UOFF3_LE( buffer ) \
|
#define FT_NEXT_UOFF3_LE( buffer ) \
|
||||||
( (unsigned long)( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) )
|
( (unsigned long)( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) )
|
||||||
|
|
||||||
@ -269,16 +262,12 @@ FT_BEGIN_HEADER
|
|||||||
#define FT_GET_BYTE() FT_GET_MACRO( BYTE )
|
#define FT_GET_BYTE() FT_GET_MACRO( BYTE )
|
||||||
#define FT_GET_SHORT() FT_GET_MACRO( SHORT )
|
#define FT_GET_SHORT() FT_GET_MACRO( SHORT )
|
||||||
#define FT_GET_USHORT() FT_GET_MACRO( USHORT )
|
#define FT_GET_USHORT() FT_GET_MACRO( USHORT )
|
||||||
#define FT_GET_OFF3() FT_GET_MACRO( OFF3 )
|
|
||||||
#define FT_GET_UOFF3() FT_GET_MACRO( UOFF3 )
|
|
||||||
#define FT_GET_LONG() FT_GET_MACRO( LONG )
|
#define FT_GET_LONG() FT_GET_MACRO( LONG )
|
||||||
#define FT_GET_ULONG() FT_GET_MACRO( ULONG )
|
#define FT_GET_ULONG() FT_GET_MACRO( ULONG )
|
||||||
#define FT_GET_TAG4() FT_GET_MACRO( ULONG )
|
#define FT_GET_TAG4() FT_GET_MACRO( ULONG )
|
||||||
|
|
||||||
#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE )
|
#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE )
|
||||||
#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE )
|
#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE )
|
||||||
#define FT_GET_LONG_LE() FT_GET_MACRO( LONG_LE )
|
|
||||||
#define FT_GET_ULONG_LE() FT_GET_MACRO( ULONG_LE )
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define FT_GET_MACRO( func, type ) ( (type)func( stream ) )
|
#define FT_GET_MACRO( func, type ) ( (type)func( stream ) )
|
||||||
@ -287,16 +276,12 @@ FT_BEGIN_HEADER
|
|||||||
#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte )
|
#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte )
|
||||||
#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Short )
|
#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Short )
|
||||||
#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UShort )
|
#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UShort )
|
||||||
#define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_Long )
|
|
||||||
#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_ULong )
|
|
||||||
#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Long )
|
#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Long )
|
||||||
#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong )
|
#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong )
|
||||||
#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong )
|
#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong )
|
||||||
|
|
||||||
#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Short )
|
#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Short )
|
||||||
#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UShort )
|
#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UShort )
|
||||||
#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Long )
|
|
||||||
#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_ULong )
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FT_READ_MACRO( func, type, var ) \
|
#define FT_READ_MACRO( func, type, var ) \
|
||||||
@ -418,10 +403,6 @@ FT_BEGIN_HEADER
|
|||||||
FT_BASE( FT_UShort )
|
FT_BASE( FT_UShort )
|
||||||
FT_Stream_GetUShort( FT_Stream stream );
|
FT_Stream_GetUShort( FT_Stream stream );
|
||||||
|
|
||||||
/* read a 24-bit big-endian unsigned integer from an entered frame */
|
|
||||||
FT_BASE( FT_ULong )
|
|
||||||
FT_Stream_GetUOffset( FT_Stream stream );
|
|
||||||
|
|
||||||
/* read a 32-bit big-endian unsigned integer from an entered frame */
|
/* read a 32-bit big-endian unsigned integer from an entered frame */
|
||||||
FT_BASE( FT_ULong )
|
FT_BASE( FT_ULong )
|
||||||
FT_Stream_GetULong( FT_Stream stream );
|
FT_Stream_GetULong( FT_Stream stream );
|
||||||
@ -430,10 +411,6 @@ FT_BEGIN_HEADER
|
|||||||
FT_BASE( FT_UShort )
|
FT_BASE( FT_UShort )
|
||||||
FT_Stream_GetUShortLE( FT_Stream stream );
|
FT_Stream_GetUShortLE( FT_Stream stream );
|
||||||
|
|
||||||
/* read a 32-bit little-endian unsigned integer from an entered frame */
|
|
||||||
FT_BASE( FT_ULong )
|
|
||||||
FT_Stream_GetULongLE( FT_Stream stream );
|
|
||||||
|
|
||||||
|
|
||||||
/* read a byte from a stream */
|
/* read a byte from a stream */
|
||||||
FT_BASE( FT_Char )
|
FT_BASE( FT_Char )
|
||||||
|
Loading…
x
Reference in New Issue
Block a user