yet more c90 rewrite

This commit is contained in:
UnknownShadow200 2018-11-04 13:23:40 +11:00
parent 514174f2bf
commit feaf213fa2
15 changed files with 273 additions and 215 deletions

View File

@ -23,7 +23,8 @@ void GZipHeader_Init(struct GZipHeader* header) {
} }
ReturnCode GZipHeader_Read(struct Stream* s, struct GZipHeader* header) { ReturnCode GZipHeader_Read(struct Stream* s, struct GZipHeader* header) {
ReturnCode res; uint8_t tmp; uint8_t tmp;
ReturnCode res;
switch (header->State) { switch (header->State) {
case GZIP_STATE_HEADER1: case GZIP_STATE_HEADER1:
@ -104,7 +105,8 @@ void ZLibHeader_Init(struct ZLibHeader* header) {
} }
ReturnCode ZLibHeader_Read(struct Stream* s, struct ZLibHeader* header) { ReturnCode ZLibHeader_Read(struct Stream* s, struct ZLibHeader* header) {
ReturnCode res; uint8_t tmp; uint8_t tmp;
ReturnCode res;
switch (header->State) { switch (header->State) {
case ZLIB_STATE_COMPRESSIONMETHOD: case ZLIB_STATE_COMPRESSIONMETHOD:
@ -196,7 +198,8 @@ static void Huffman_Build(struct HuffmanTable* table, uint8_t* bitLens, int coun
offset += bl_count[i]; offset += bl_count[i];
/* Last codeword is actually: code + (bl_count[i] - 1) */ /* Last codeword is actually: code + (bl_count[i] - 1) */
/* When decoding we peform < against this value though, so we need to add 1 here */ /* When decoding we peform < against this value though, so need to add 1 here */
/* This way, don't need to special case bit lengths with 0 codewords when decoding */
if (bl_count[i]) { if (bl_count[i]) {
table->EndCodewords[i] = code + bl_count[i]; table->EndCodewords[i] = code + bl_count[i];
} else { } else {
@ -306,7 +309,7 @@ void Inflate_Init(struct InflateState* state, struct Stream* source) {
state->LastBlock = false; state->LastBlock = false;
state->Bits = 0; state->Bits = 0;
state->NumBits = 0; state->NumBits = 0;
state->NextIn = state->Input; state->NextIn = state->Input;
state->AvailIn = 0; state->AvailIn = 0;
state->Output = NULL; state->Output = NULL;
state->AvailOut = 0; state->AvailOut = 0;
@ -420,7 +423,7 @@ void Inflate_Process(struct InflateState* state) {
} break; } break;
case 1: { /* Fixed/static huffman compressed */ case 1: { /* Fixed/static huffman compressed */
Huffman_Build(&state->Table.Lits, fixed_lits, INFLATE_MAX_LITS); Huffman_Build(&state->Table.Lits, fixed_lits, INFLATE_MAX_LITS);
Huffman_Build(&state->TableDists, fixed_dists, INFLATE_MAX_DISTS); Huffman_Build(&state->TableDists, fixed_dists, INFLATE_MAX_DISTS);
state->State = Inflate_NextCompressState(state); state->State = Inflate_NextCompressState(state);
} break; } break;

View File

@ -75,8 +75,8 @@ NOINLINE_ void Inflate_MakeStream(struct Stream* stream, struct InflateState* st
#define DEFLATE_HASH_SIZE 0x1000UL #define DEFLATE_HASH_SIZE 0x1000UL
#define DEFLATE_HASH_MASK 0x0FFFUL #define DEFLATE_HASH_MASK 0x0FFFUL
struct DeflateState { struct DeflateState {
uint32_t Bits; /* Holds bits across byte boundaries*/ uint32_t Bits; /* Holds bits across byte boundaries */
uint32_t NumBits; /* Number of bits in Bits buffer*/ uint32_t NumBits; /* Number of bits in Bits buffer */
uint32_t InputPosition; uint32_t InputPosition;
uint8_t* NextOut; /* Pointer within Output buffer to next byte that can be written */ uint8_t* NextOut; /* Pointer within Output buffer to next byte that can be written */

View File

@ -40,8 +40,9 @@ void Drawer2D_Make2DTexture(struct Texture* tex, Bitmap* bmp, Size2D used, int X
bool Drawer2D_ValidColCodeAt(const String* text, int i); bool Drawer2D_ValidColCodeAt(const String* text, int i);
bool Drawer2D_ValidColCode(char c); bool Drawer2D_ValidColCode(char c);
/* Whether text is empty or consists purely of valid colour codes. */
bool Drawer2D_IsEmptyText(const String* text); bool Drawer2D_IsEmptyText(const String* text);
/* Returns the last valid colour code in the given input, or \0 if no valid colour code was found. */ /* Returns the last valid colour code in the given input, or \0 if not found. */
char Drawer2D_LastCol(const String* text, int start); char Drawer2D_LastCol(const String* text, int start);
bool Drawer2D_IsWhiteCol(char c); bool Drawer2D_IsWhiteCol(char c);

View File

@ -528,6 +528,7 @@ static void Player_DrawName(struct Player* player) {
struct Model* model = e->Model; struct Model* model = e->Model;
Vector3 pos; Vector3 pos;
float scale; float scale;
VertexP3fT2fC4b vertices[4];
if (player->NameTex.X == PLAYER_NAME_EMPTY_TEX) return; if (player->NameTex.X == PLAYER_NAME_EMPTY_TEX) return;
if (!player->NameTex.ID) Player_MakeNameTexture(player); if (!player->NameTex.ID) Player_MakeNameTexture(player);
@ -548,7 +549,6 @@ static void Player_DrawName(struct Player* player) {
size.X *= tempW * 0.2f; size.Y *= tempW * 0.2f; size.X *= tempW * 0.2f; size.Y *= tempW * 0.2f;
} }
VertexP3fT2fC4b vertices[4];
TextureRec rec = { 0.0f, 0.0f, player->NameTex.U2, player->NameTex.V2 }; TextureRec rec = { 0.0f, 0.0f, player->NameTex.U2, player->NameTex.V2 };
PackedCol col = PACKEDCOL_WHITE; PackedCol col = PACKEDCOL_WHITE;
Particle_DoRender(&size, &pos, &rec, col, vertices); Particle_DoRender(&size, &pos, &rec, col, vertices);
@ -664,26 +664,27 @@ static void Player_ClearHat(Bitmap* bmp, uint8_t skinType) {
} }
} }
static void Player_EnsurePow2(struct Player* player, Bitmap* bmp) { static void Player_EnsurePow2(struct Player* p, Bitmap* bmp) {
int width = Math_NextPowOf2(bmp->Width); uint32_t stride;
int height = Math_NextPowOf2(bmp->Height); int width, height;
Bitmap scaled; Bitmap scaled;
int y;
width = Math_NextPowOf2(bmp->Width);
height = Math_NextPowOf2(bmp->Height);
if (width == bmp->Width && height == bmp->Height) return; if (width == bmp->Width && height == bmp->Height) return;
Bitmap_Allocate(&scaled, width, height); Bitmap_Allocate(&scaled, width, height);
int y; p->Base.uScale = (float)bmp->Width / width;
uint32_t stride = (uint32_t)(bmp->Width) * BITMAP_SIZEOF_PIXEL; p->Base.vScale = (float)bmp->Height / height;
stride = bmp->Width * BITMAP_SIZEOF_PIXEL;
for (y = 0; y < bmp->Height; y++) { for (y = 0; y < bmp->Height; y++) {
uint32_t* src = Bitmap_GetRow(bmp, y); uint32_t* src = Bitmap_GetRow(bmp, y);
uint32_t* dst = Bitmap_GetRow(&scaled, y); uint32_t* dst = Bitmap_GetRow(&scaled, y);
Mem_Copy(dst, src, stride); Mem_Copy(dst, src, stride);
} }
struct Entity* entity = &player->Base;
entity->uScale = (float)bmp->Width / width;
entity->vScale = (float)bmp->Height / height;
Mem_Free(bmp->Scan0); Mem_Free(bmp->Scan0);
*bmp = scaled; *bmp = scaled;
} }
@ -831,16 +832,18 @@ static void LocalPlayer_SetLocation(struct Entity* e, struct LocationUpdate* upd
} }
void LocalPlayer_Tick(struct Entity* e, double delta) { void LocalPlayer_Tick(struct Entity* e, double delta) {
if (!World_Blocks) return;
struct LocalPlayer* p = (struct LocalPlayer*)e; struct LocalPlayer* p = (struct LocalPlayer*)e;
struct HacksComp* hacks = &p->Hacks; struct HacksComp* hacks = &p->Hacks;
e->StepSize = hacks->FullBlockStep && hacks->Enabled && hacks->CanAnyHacks && hacks->CanSpeed ? 1.0f : 0.5f;
p->OldVelocity = e->Velocity;
float xMoving = 0, zMoving = 0; float xMoving = 0, zMoving = 0;
LocalInterpComp_AdvanceState(&p->Interp); bool wasOnGround;
bool wasOnGround = e->OnGround; Vector3 headingVelocity;
if (!World_Blocks) return;
e->StepSize = hacks->FullBlockStep && hacks->Enabled && hacks->CanAnyHacks && hacks->CanSpeed ? 1.0f : 0.5f;
p->OldVelocity = e->Velocity;
wasOnGround = e->OnGround;
LocalInterpComp_AdvanceState(&p->Interp);
LocalPlayer_HandleInput(&xMoving, &zMoving); LocalPlayer_HandleInput(&xMoving, &zMoving);
hacks->Floating = hacks->Noclip || hacks->Flying; hacks->Floating = hacks->Noclip || hacks->Flying;
if (!hacks->Floating && hacks->CanBePushed) PhysicsComp_DoEntityPush(e); if (!hacks->Floating && hacks->CanBePushed) PhysicsComp_DoEntityPush(e);
@ -851,7 +854,7 @@ void LocalPlayer_Tick(struct Entity* e, double delta) {
} }
PhysicsComp_UpdateVelocityState(&p->Physics); PhysicsComp_UpdateVelocityState(&p->Physics);
Vector3 headingVelocity = Vector3_RotateY3(xMoving, 0, zMoving, e->HeadY * MATH_DEG2RAD); headingVelocity = Vector3_RotateY3(xMoving, 0, zMoving, e->HeadY * MATH_DEG2RAD);
PhysicsComp_PhysicsTick(&p->Physics, headingVelocity); PhysicsComp_PhysicsTick(&p->Physics, headingVelocity);
/* Fixes high jump, when holding down a movement key, jump, fly, then let go of fly key */ /* Fixes high jump, when holding down a movement key, jump, fly, then let go of fly key */
@ -861,7 +864,7 @@ void LocalPlayer_Tick(struct Entity* e, double delta) {
AnimatedComp_Update(e, p->Interp.Prev.Pos, p->Interp.Next.Pos, delta); AnimatedComp_Update(e, p->Interp.Prev.Pos, p->Interp.Next.Pos, delta);
TiltComp_Update(&p->Tilt, delta); TiltComp_Update(&p->Tilt, delta);
Player_CheckSkin((struct Player*)p); Player_CheckSkin(&p->Base);
SoundComp_Tick(wasOnGround); SoundComp_Tick(wasOnGround);
} }
@ -928,7 +931,7 @@ struct EntityVTABLE localPlayer_VTABLE = {
void LocalPlayer_Init(void) { void LocalPlayer_Init(void) {
struct LocalPlayer* p = &LocalPlayer_Instance; struct LocalPlayer* p = &LocalPlayer_Instance;
Player_Init(&p->Base); Player_Init(&p->Base);
Player_SetName((struct Player*)p, &Game_Username, &Game_Username); Player_SetName(&p->Base, &Game_Username, &Game_Username);
p->Collisions.Entity = &p->Base; p->Collisions.Entity = &p->Base;
HacksComp_Init(&p->Hacks); HacksComp_Init(&p->Hacks);
@ -944,22 +947,26 @@ void LocalPlayer_Init(void) {
static bool LocalPlayer_IsSolidCollide(BlockID b) { return Block_Collide[b] == COLLIDE_SOLID; } static bool LocalPlayer_IsSolidCollide(BlockID b) { return Block_Collide[b] == COLLIDE_SOLID; }
static void LocalPlayer_DoRespawn(void) { static void LocalPlayer_DoRespawn(void) {
struct LocalPlayer* p = &LocalPlayer_Instance; struct LocalPlayer* p = &LocalPlayer_Instance;
Vector3 spawn = p->Spawn; struct LocationUpdate update;
Vector3I P;
struct AABB bb; struct AABB bb;
Vector3 spawn = p->Spawn;
Vector3I pos;
BlockID block;
float height, spawnY;
int y;
if (!World_Blocks) return; if (!World_Blocks) return;
Vector3I_Floor(&P, &spawn); Vector3I_Floor(&pos, &spawn);
/* Spawn player at highest valid position */ /* Spawn player at highest valid position */
if (World_IsValidPos_3I(P)) { if (World_IsValidPos_3I(pos)) {
AABB_Make(&bb, &spawn, &p->Base.Size); AABB_Make(&bb, &spawn, &p->Base.Size);
int y; for (y = pos.Y; y <= World_Height; y++) {
for (y = P.Y; y <= World_Height; y++) { spawnY = Respawn_HighestFreeY(&bb);
float spawnY = Respawn_HighestFreeY(&bb);
if (spawnY == RESPAWN_NOT_FOUND) { if (spawnY == RESPAWN_NOT_FOUND) {
BlockID block = World_GetPhysicsBlock(P.X, y, P.Z); block = World_GetPhysicsBlock(pos.X, y, pos.Z);
float height = Block_Collide[block] == COLLIDE_SOLID ? Block_MaxBB[block].Y : 0.0f; height = Block_Collide[block] == COLLIDE_SOLID ? Block_MaxBB[block].Y : 0.0f;
spawn.Y = y + height + ENTITY_ADJUSTMENT; spawn.Y = y + height + ENTITY_ADJUSTMENT;
break; break;
} }
@ -967,8 +974,8 @@ static void LocalPlayer_DoRespawn(void) {
} }
} }
spawn.Y += 2.0f / 16.0f; spawn.Y += 2.0f/16.0f;
struct LocationUpdate update; LocationUpdate_MakePosAndOri(&update, spawn, p->SpawnRotY, p->SpawnHeadX, false); LocationUpdate_MakePosAndOri(&update, spawn, p->SpawnRotY, p->SpawnHeadX, false);
p->Base.VTABLE->SetLocation(&p->Base, &update, false); p->Base.VTABLE->SetLocation(&p->Base, &update, false);
p->Base.Velocity = Vector3_Zero; p->Base.Velocity = Vector3_Zero;
@ -1063,7 +1070,7 @@ static void NetPlayer_SetLocation(struct Entity* e, struct LocationUpdate* updat
static void NetPlayer_Tick(struct Entity* e, double delta) { static void NetPlayer_Tick(struct Entity* e, double delta) {
struct NetPlayer* p = (struct NetPlayer*)e; struct NetPlayer* p = (struct NetPlayer*)e;
Player_CheckSkin((struct Player*)p); Player_CheckSkin(&p->Base);
NetInterpComp_AdvanceState(&p->Interp); NetInterpComp_AdvanceState(&p->Interp);
AnimatedComp_Update(e, p->Interp.Prev.Pos, p->Interp.Next.Pos, delta); AnimatedComp_Update(e, p->Interp.Prev.Pos, p->Interp.Next.Pos, delta);
} }
@ -1086,16 +1093,16 @@ static void NetPlayer_RenderName(struct Entity* e) {
distance = Model_RenderDistance(e); distance = Model_RenderDistance(e);
threshold = Entities_NameMode == NAME_MODE_ALL_UNSCALED ? 8192 * 8192 : 32 * 32; threshold = Entities_NameMode == NAME_MODE_ALL_UNSCALED ? 8192 * 8192 : 32 * 32;
if (distance <= (float)threshold) Player_DrawName((struct Player*)p); if (distance <= (float)threshold) Player_DrawName(&p->Base);
} }
struct EntityVTABLE netPlayer_VTABLE = { struct EntityVTABLE netPlayer_VTABLE = {
NetPlayer_Tick, Player_Despawn, NetPlayer_SetLocation, Entity_GetCol, NetPlayer_Tick, Player_Despawn, NetPlayer_SetLocation, Entity_GetCol,
NetPlayer_RenderModel, NetPlayer_RenderName, Player_ContextLost, Player_ContextRecreated, NetPlayer_RenderModel, NetPlayer_RenderName, Player_ContextLost, Player_ContextRecreated,
}; };
void NetPlayer_Init(struct NetPlayer* player, const String* displayName, const String* skinName) { void NetPlayer_Init(struct NetPlayer* p, const String* displayName, const String* skinName) {
Mem_Set(player, 0, sizeof(struct NetPlayer)); Mem_Set(p, 0, sizeof(struct NetPlayer));
Player_Init(&player->Base); Player_Init(&p->Base);
Player_SetName((struct Player*)player, displayName, skinName); Player_SetName(&p->Base, displayName, skinName);
player->Base.VTABLE = &netPlayer_VTABLE; p->Base.VTABLE = &netPlayer_VTABLE;
} }

View File

@ -166,8 +166,7 @@ void HacksComp_Init(struct HacksComp* hacks) {
hacks->NoclipSlide = true; hacks->NoclipSlide = true;
hacks->CanBePushed = true; hacks->CanBePushed = true;
String str = String_FromArray(hacks->__HacksFlagsBuffer); String_InitArray(hacks->HacksFlags, hacks->__HacksFlagsBuffer);
hacks->HacksFlags = str;
} }
bool HacksComp_CanJumpHigher(struct HacksComp* hacks) { bool HacksComp_CanJumpHigher(struct HacksComp* hacks) {

View File

@ -485,14 +485,21 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
X11Button ok = { 0 }; X11Button ok = { 0 };
X11Textbox body = { 0 }; X11Textbox body = { 0 };
XFontStruct* font;
Atom wmDelete;
int x, y, width, height;
XSizeHints hints = { 0 };
int mouseX = -1, mouseY = -1, over;
XEvent e;
X11Window_Init(w); X11Window_Init(w);
XMapWindow(dpy, w->win); XMapWindow(dpy, w->win);
XStoreName(dpy, w->win, title); XStoreName(dpy, w->win, title);
Atom wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmDelete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, w->win, &wmDelete, 1); XSetWMProtocols(dpy, w->win, &wmDelete, 1);
XFontStruct* font = XQueryFont(dpy, XGContextFromGC(w->gc)); font = XQueryFont(dpy, XGContextFromGC(w->gc));
if (!font) return; if (!font) return;
/* Compute size of widgets */ /* Compute size of widgets */
@ -504,10 +511,10 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
ok.Height = ok.Text.Height + 10; ok.Height = ok.Text.Height + 10;
/* Compute size and position of window */ /* Compute size and position of window */
int width = body.Width + 20; width = body.Width + 20;
int height = body.Height + 20 + ok.Height + 20; height = body.Height + 20 + ok.Height + 20;
int x = DisplayWidth (dpy, DefaultScreen(dpy))/2 - width/2; x = DisplayWidth (dpy, DefaultScreen(dpy))/2 - width/2;
int y = DisplayHeight(dpy, DefaultScreen(dpy))/2 - height/2; y = DisplayHeight(dpy, DefaultScreen(dpy))/2 - height/2;
XMoveResizeWindow(dpy, w->win, x, y, width, height); XMoveResizeWindow(dpy, w->win, x, y, width, height);
/* Adjust bounds of widgets */ /* Adjust bounds of widgets */
@ -518,7 +525,6 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
XFreeFontInfo(NULL, font, 1); XFreeFontInfo(NULL, font, 1);
XUnmapWindow(dpy, w->win); /* Make window non resizeable */ XUnmapWindow(dpy, w->win); /* Make window non resizeable */
XSizeHints hints = { 0 };
hints.flags = PSize | PMinSize | PMaxSize; hints.flags = PSize | PMinSize | PMaxSize;
hints.min_width = hints.max_width = hints.base_width = width; hints.min_width = hints.max_width = hints.base_width = width;
hints.min_height = hints.max_height = hints.base_height = height; hints.min_height = hints.max_height = hints.base_height = height;
@ -527,9 +533,6 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
XMapRaised(dpy, w->win); XMapRaised(dpy, w->win);
XFlush(dpy); XFlush(dpy);
XEvent e;
int mouseX = -1, mouseY = -1;
for (;;) { for (;;) {
XNextEvent(dpy, &e); XNextEvent(dpy, &e);
@ -538,7 +541,7 @@ static void X11_MessageBox(const char* title, const char* text, X11Window* w) {
case ButtonPress: case ButtonPress:
case ButtonRelease: case ButtonRelease:
if (e.xbutton.button != Button1) break; if (e.xbutton.button != Button1) break;
int over = X11Button_Contains(&ok, mouseX, mouseY); over = X11Button_Contains(&ok, mouseX, mouseY);
if (ok.Clicked && e.type == ButtonRelease) { if (ok.Clicked && e.type == ButtonRelease) {
if (over) return; if (over) return;

View File

@ -305,9 +305,10 @@ static ReturnCode Nbt_ReadTag(uint8_t typeId, bool readTagName, struct Stream* s
uint32_t i, count; uint32_t i, count;
if (typeId == NBT_END) return 0; if (typeId == NBT_END) return 0;
tag.TagID = typeId; tag.Parent = parent; tag.TagID = typeId;
tag.Name = String_Init(tag.NameBuffer, 0, NBT_STRING_SIZE); tag.Parent = parent;
tag.DataSize = 0; tag.DataSize = 0;
String_InitArray(tag.Name, tag.NameBuffer);
if (readTagName) { if (readTagName) {
res = Nbt_ReadString(stream, &tag.Name); res = Nbt_ReadString(stream, &tag.Name);
@ -343,7 +344,7 @@ static ReturnCode Nbt_ReadTag(uint8_t typeId, bool readTagName, struct Stream* s
} }
break; break;
case NBT_STR: case NBT_STR:
tag.Value.Str.Text = String_Init(tag.Value.Str.Buffer, 0, NBT_STRING_SIZE); String_InitArray(tag.Value.Str.Text, tag.Value.Str.Buffer);
res = Nbt_ReadString(stream, &tag.Value.Str.Text); res = Nbt_ReadString(stream, &tag.Value.Str.Text);
break; break;

View File

@ -1267,9 +1267,7 @@ static void SaveLevelScreen_Schematic(void* a, void* b) { SaveLevelScreen_Save(a
static void SaveLevelScreen_Init(void* screen) { static void SaveLevelScreen_Init(void* screen) {
struct SaveLevelScreen* s = screen; struct SaveLevelScreen* s = screen;
String str = String_FromArray(s->__TextPathBuffer); String_InitArray(s->TextPath, s->__TextPathBuffer);
s->TextPath = str;
Key_KeyRepeat = true; Key_KeyRepeat = true;
MenuScreen_Init(s); MenuScreen_Init(s);
} }
@ -3158,9 +3156,8 @@ struct Screen* UrlWarningOverlay_MakeInstance(const String* url) {
s->Widgets = widgets; s->Widgets = widgets;
s->WidgetsCount = Array_Elems(widgets); s->WidgetsCount = Array_Elems(widgets);
String dstUrl = String_FromArray(s->__UrlBuffer); String_InitArray(s->Url, s->__UrlBuffer);
String_Copy(&dstUrl, url); String_Copy(&s->Url, url);
s->Url = dstUrl;
s->VTABLE = &UrlWarningOverlay_VTABLE; s->VTABLE = &UrlWarningOverlay_VTABLE;
return (struct Screen*)s; return (struct Screen*)s;
@ -3225,9 +3222,8 @@ struct Screen* ConfirmDenyOverlay_MakeInstance(const String* url, bool alwaysDen
s->Widgets = widgets; s->Widgets = widgets;
s->WidgetsCount = Array_Elems(widgets); s->WidgetsCount = Array_Elems(widgets);
String dstUrl = String_FromArray(s->__UrlBuffer); String_InitArray(s->Url, s->__UrlBuffer);
String_Copy(&dstUrl, url); String_Copy(&s->Url, url);
s->Url = dstUrl;
s->AlwaysDeny = alwaysDeny; s->AlwaysDeny = alwaysDeny;
s->VTABLE = &ConfirmDenyOverlay_VTABLE; s->VTABLE = &ConfirmDenyOverlay_VTABLE;
@ -3337,12 +3333,11 @@ struct Screen* TexPackOverlay_MakeInstance(const String* url) {
s->Widgets = widgets; s->Widgets = widgets;
s->WidgetsCount = Array_Elems(widgets); s->WidgetsCount = Array_Elems(widgets);
String identifier = String_FromArray(s->__IdentifierBuffer); String_InitArray(s->Identifier, s->__IdentifierBuffer);
String_Format1(&identifier, "CL_%s", url); String_Format1(&s->Identifier, "CL_%s", url);
s->Identifier = identifier;
s->ContentLength = 0; s->ContentLength = 0;
AsyncDownloader_GetContentLength(url, true, &identifier); AsyncDownloader_GetContentLength(url, true, &s->Identifier);
s->VTABLE = &TexPackOverlay_VTABLE; s->VTABLE = &TexPackOverlay_VTABLE;
return (struct Screen*)s; return (struct Screen*)s;
} }

View File

@ -113,10 +113,14 @@ void Model_Render(struct Model* model, struct Entity* entity) {
} }
void Model_SetupState(struct Model* model, struct Entity* entity) { void Model_SetupState(struct Model* model, struct Entity* entity) {
model->index = 0; PackedCol col;
PackedCol col = entity->VTABLE->GetCol(entity); bool _64x64;
float yawDelta;
bool _64x64 = entity->SkinType != SKIN_64x32; model->index = 0;
col = entity->VTABLE->GetCol(entity);
_64x64 = entity->SkinType != SKIN_64x32;
/* only apply when using humanoid skins */ /* only apply when using humanoid skins */
_64x64 &= model->UsesHumanSkin || entity->MobTextureId; _64x64 &= model->UsesHumanSkin || entity->MobTextureId;
@ -131,10 +135,11 @@ void Model_SetupState(struct Model* model, struct Entity* entity) {
} else { } else {
Model_Cols[1] = col; Model_Cols[2] = col; Model_Cols[4] = col; Model_Cols[1] = col; Model_Cols[2] = col; Model_Cols[4] = col;
} }
Model_Cols[3] = Model_Cols[2]; Model_Cols[3] = Model_Cols[2];
Model_Cols[5] = Model_Cols[4]; Model_Cols[5] = Model_Cols[4];
yawDelta = entity->HeadY - entity->RotY;
float yawDelta = entity->HeadY - entity->RotY;
Model_cosHead = (float)Math_Cos(yawDelta * MATH_DEG2RAD); Model_cosHead = (float)Math_Cos(yawDelta * MATH_DEG2RAD);
Model_sinHead = (float)Math_Sin(yawDelta * MATH_DEG2RAD); Model_sinHead = (float)Math_Sin(yawDelta * MATH_DEG2RAD);
Model_ActiveModel = model; Model_ActiveModel = model;
@ -148,9 +153,11 @@ void Model_UpdateVB(void) {
void Model_ApplyTexture(struct Entity* entity) { void Model_ApplyTexture(struct Entity* entity) {
struct Model* model = Model_ActiveModel; struct Model* model = Model_ActiveModel;
GfxResourceID tex = model->UsesHumanSkin ? entity->TextureId : entity->MobTextureId;
struct CachedTexture* data; struct CachedTexture* data;
GfxResourceID tex;
bool _64x64;
tex = model->UsesHumanSkin ? entity->TextureId : entity->MobTextureId;
if (tex) { if (tex) {
Model_skinType = entity->SkinType; Model_skinType = entity->SkinType;
} else { } else {
@ -160,7 +167,8 @@ void Model_ApplyTexture(struct Entity* entity) {
} }
Gfx_BindTexture(tex); Gfx_BindTexture(tex);
bool _64x64 = Model_skinType != SKIN_64x32; _64x64 = Model_skinType != SKIN_64x32;
Model_uScale = entity->uScale * 0.015625f; Model_uScale = entity->uScale * 0.015625f;
Model_vScale = entity->vScale * (_64x64 ? 0.015625f : 0.03125f); Model_vScale = entity->vScale * (_64x64 ? 0.015625f : 0.03125f);
} }

View File

@ -597,13 +597,10 @@ struct Screen* LoadingScreen_MakeInstance(const String* title, const String* mes
s->VTABLE = &LoadingScreen_VTABLE; s->VTABLE = &LoadingScreen_VTABLE;
s->Progress = 0.0f; s->Progress = 0.0f;
String title_copy = String_FromArray(s->__TitleBuffer); String_InitArray(s->TitleStr, s->__TitleBuffer);
String_AppendString(&title_copy, title); String_AppendString(&s->TitleStr, title);
s->TitleStr = title_copy; String_InitArray(s->MessageStr, s->__MessageBuffer);
String_AppendString(&s->MessageStr, message);
String message_copy = String_FromArray(s->__MessageBuffer);
String_AppendString(&message_copy, message);
s->MessageStr = message_copy;
s->HandlesAllInput = true; s->HandlesAllInput = true;
s->BlocksWorld = true; s->BlocksWorld = true;
@ -1540,13 +1537,10 @@ struct Screen* DisconnectScreen_MakeInstance(const String* title, const String*
s->BlocksWorld = true; s->BlocksWorld = true;
s->HidesHUD = true; s->HidesHUD = true;
String title_copy = String_FromArray(s->__TitleBuffer); String_InitArray(s->TitleStr, s->__TitleBuffer);
String_AppendString(&title_copy, title); String_AppendString(&s->TitleStr, title);
s->TitleStr = title_copy; String_InitArray(s->MessageStr, s->__MessageBuffer);
String_AppendString(&s->MessageStr, message);
String message_copy = String_FromArray(s->__MessageBuffer);
String_AppendString(&message_copy, message);
s->MessageStr = message_copy;
char whyBuffer[STRING_SIZE]; char whyBuffer[STRING_SIZE];
String why = String_FromArray(whyBuffer); String why = String_FromArray(whyBuffer);

View File

@ -45,6 +45,8 @@ NOINLINE_ String String_FromReadonly(STRING_REF const char* buffer);
#define String_FromRawArray(buffer) String_FromRaw(buffer, sizeof(buffer)) #define String_FromRawArray(buffer) String_FromRaw(buffer, sizeof(buffer))
/* Constructs a string from a compile time array (leaving 1 byte of room for null terminator) */ /* Constructs a string from a compile time array (leaving 1 byte of room for null terminator) */
#define String_NT_Array(buffer) { buffer, 0, (sizeof(buffer) - 1)} #define String_NT_Array(buffer) { buffer, 0, (sizeof(buffer) - 1)}
/* Initialises a string from a compile time array. */
#define String_InitArray(str, buffr) str.buffer = buffr; str.length = 0; str.capacity = sizeof(buffr);
/* Removes all colour codes from the given string. */ /* Removes all colour codes from the given string. */
NOINLINE_ void String_StripCols(String* str); NOINLINE_ void String_StripCols(String* str);

View File

@ -204,7 +204,8 @@ static void EntryList_Load(struct EntryList* list) {
char lineBuffer[FILENAME_SIZE]; char lineBuffer[FILENAME_SIZE];
String line = String_FromArray(lineBuffer); String line = String_FromArray(lineBuffer);
struct Stream stream; uint8_t buffer[2048];
struct Stream stream, buffered;
ReturnCode res; ReturnCode res;
String_Format3(&path, "%c%r%c", list->Folder, &Directory_Separator, list->Filename); String_Format3(&path, "%c%r%c", list->Folder, &Directory_Separator, list->Filename);
@ -213,7 +214,6 @@ static void EntryList_Load(struct EntryList* list) {
if (res) { Chat_LogError2(res, "opening", &path); return; } if (res) { Chat_LogError2(res, "opening", &path); return; }
/* ReadLine reads single byte at a time */ /* ReadLine reads single byte at a time */
uint8_t buffer[2048]; struct Stream buffered;
Stream_ReadonlyBuffered(&buffered, &stream, buffer, sizeof(buffer)); Stream_ReadonlyBuffered(&buffered, &stream, buffer, sizeof(buffer));
for (;;) { for (;;) {

View File

@ -52,7 +52,7 @@ bool TextureCache_Has(const String* url);
/* Attempts to get the cached data stream for the given url. */ /* Attempts to get the cached data stream for the given url. */
bool TextureCache_Get(const String* url, struct Stream* stream); bool TextureCache_Get(const String* url, struct Stream* stream);
/* Attempts to get the Last-Modified header cached for the given URL. */ /* Attempts to get the Last-Modified header cached for the given URL. */
/* If header is not found, returns last time the cached datastream was modified. */ /* If header is not found, returns last time the cached data was modified. */
void TextureCache_GetLastModified(const String* url, TimeMS* time); void TextureCache_GetLastModified(const String* url, TimeMS* time);
/* Attempts to get the ETag header cached for the given URL. */ /* Attempts to get the ETag header cached for the given URL. */
void TextureCache_GetETag(const String* url, String* etag); void TextureCache_GetETag(const String* url, String* etag);

View File

@ -117,7 +117,10 @@ static void ButtonWidget_Reposition(void* widget) {
static void ButtonWidget_Render(void* widget, double delta) { static void ButtonWidget_Render(void* widget, double delta) {
struct ButtonWidget* w = widget; struct ButtonWidget* w = widget;
struct Texture back = w->Active ? Button_SelectedTex : Button_ShadowTex; struct Texture back;
PackedCol col;
back = w->Active ? Button_SelectedTex : Button_ShadowTex;
if (w->Disabled) back = Button_DisabledTex; if (w->Disabled) back = Button_DisabledTex;
back.ID = Game_UseClassicGui ? Gui_GuiClassicTex : Gui_GuiTex; back.ID = Game_UseClassicGui ? Gui_GuiClassicTex : Gui_GuiTex;
@ -147,7 +150,7 @@ static void ButtonWidget_Render(void* widget, double delta) {
PackedCol disabledCol = PACKEDCOL_CONST(160, 160, 160, 255); PackedCol disabledCol = PACKEDCOL_CONST(160, 160, 160, 255);
if (!w->Texture.ID) return; if (!w->Texture.ID) return;
PackedCol col = w->Disabled ? disabledCol : (w->Active ? activeCol : normCol); col = w->Disabled ? disabledCol : (w->Active ? activeCol : normCol);
Texture_RenderShaded(&w->Texture, col); Texture_RenderShaded(&w->Texture, col);
} }
@ -503,13 +506,13 @@ static int Table_Height(struct TableWidget* w) {
#define TABLE_MAX_VERTICES (8 * 10 * ISOMETRICDRAWER_MAXVERTICES) #define TABLE_MAX_VERTICES (8 * 10 * ISOMETRICDRAWER_MAXVERTICES)
static bool TableWidget_GetCoords(struct TableWidget* w, int i, int* winX, int* winY) { static bool TableWidget_GetCoords(struct TableWidget* w, int i, int* cellX, int* cellY) {
int x = i % w->ElementsPerRow, y = i / w->ElementsPerRow; int x, y;
*winX = w->X + w->BlockSize * x; x = i % w->ElementsPerRow;
*winY = w->Y + w->BlockSize * y + 3; y = i / w->ElementsPerRow - w->Scroll.ScrollY;
*winY -= w->Scroll.ScrollY * w->BlockSize; *cellX = w->X + w->BlockSize * x;
y -= w->Scroll.ScrollY; *cellY = w->Y + w->BlockSize * y + 3;
return y >= 0 && y < TABLE_MAX_ROWS_DISPLAYED; return y >= 0 && y < TABLE_MAX_ROWS_DISPLAYED;
} }
@ -536,8 +539,10 @@ static void TableWidget_MoveCursorToSelected(struct TableWidget* w) {
} }
static void TableWidget_MakeBlockDesc(String* desc, BlockID block) { static void TableWidget_MakeBlockDesc(String* desc, BlockID block) {
String name;
if (Game_PureClassic) { String_AppendConst(desc, "Select block"); return; } if (Game_PureClassic) { String_AppendConst(desc, "Select block"); return; }
String name = Block_UNSAFE_GetName(block);
name = Block_UNSAFE_GetName(block);
String_AppendString(desc, &name); String_AppendString(desc, &name);
if (Game_ClassicMode) return; if (Game_ClassicMode) return;
@ -574,9 +579,9 @@ static void TableWidget_RecreateDescTex(struct TableWidget* w) {
} }
void TableWidget_MakeDescTex(struct TableWidget* w, BlockID block) { void TableWidget_MakeDescTex(struct TableWidget* w, BlockID block) {
struct DrawTextArgs args;
char descBuffer[STRING_SIZE * 2]; char descBuffer[STRING_SIZE * 2];
String desc = String_FromArray(descBuffer); String desc = String_FromArray(descBuffer);
struct DrawTextArgs args;
Gfx_DeleteTexture(&w->DescTex.ID); Gfx_DeleteTexture(&w->DescTex.ID);
if (block == BLOCK_AIR) return; if (block == BLOCK_AIR) return;
@ -627,6 +632,9 @@ static void TableWidget_Init(void* widget) {
static void TableWidget_Render(void* widget, double delta) { static void TableWidget_Render(void* widget, double delta) {
struct TableWidget* w = widget; struct TableWidget* w = widget;
VertexP3fT2fC4b vertices[TABLE_MAX_VERTICES];
int i, x, y;
/* These were sourced by taking a screenshot of vanilla /* These were sourced by taking a screenshot of vanilla
Then using paint to extract the colour components Then using paint to extract the colour components
Then using wolfram alpha to solve the glblendfunc equation */ Then using wolfram alpha to solve the glblendfunc equation */
@ -644,8 +652,8 @@ static void TableWidget_Render(void* widget, double delta) {
int blockSize = w->BlockSize; int blockSize = w->BlockSize;
if (w->SelectedIndex != -1 && Game_ClassicMode) { if (w->SelectedIndex != -1 && Game_ClassicMode) {
int x, y;
TableWidget_GetCoords(w, w->SelectedIndex, &x, &y); TableWidget_GetCoords(w, w->SelectedIndex, &x, &y);
float off = blockSize * 0.1f; float off = blockSize * 0.1f;
int size = (int)(blockSize + off * 2); int size = (int)(blockSize + off * 2);
GfxCommon_Draw2DGradient((int)(x - off), (int)(y - off), GfxCommon_Draw2DGradient((int)(x - off), (int)(y - off),
@ -654,11 +662,8 @@ static void TableWidget_Render(void* widget, double delta) {
Gfx_SetTexturing(true); Gfx_SetTexturing(true);
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B); Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
VertexP3fT2fC4b vertices[TABLE_MAX_VERTICES];
IsometricDrawer_BeginBatch(vertices, w->VB); IsometricDrawer_BeginBatch(vertices, w->VB);
int i;
for (i = 0; i < w->ElementsCount; i++) { for (i = 0; i < w->ElementsCount; i++) {
int x, y;
if (!TableWidget_GetCoords(w, i, &x, &y)) continue; if (!TableWidget_GetCoords(w, i, &x, &y)) continue;
/* We want to always draw the selected block on top of others */ /* We want to always draw the selected block on top of others */
@ -669,8 +674,8 @@ static void TableWidget_Render(void* widget, double delta) {
i = w->SelectedIndex; i = w->SelectedIndex;
if (i != -1) { if (i != -1) {
int x, y;
TableWidget_GetCoords(w, i, &x, &y); TableWidget_GetCoords(w, i, &x, &y);
IsometricDrawer_DrawBatch(w->Elements[i], IsometricDrawer_DrawBatch(w->Elements[i],
(blockSize + w->SelBlockExpand) * 0.7f / 2.0f, (blockSize + w->SelBlockExpand) * 0.7f / 2.0f,
x + blockSize / 2, y + blockSize / 2); x + blockSize / 2, y + blockSize / 2);
@ -872,13 +877,13 @@ static void InputWidget_FormatLine(struct InputWidget* w, int i, String* line) {
} }
static void InputWidget_CalculateLineSizes(struct InputWidget* w) { static void InputWidget_CalculateLineSizes(struct InputWidget* w) {
char lineBuffer[STRING_SIZE];
String line = String_FromArray(lineBuffer);
struct DrawTextArgs args; struct DrawTextArgs args;
Size2D size; Size2D size;
int y; int y;
char lineBuffer[STRING_SIZE];
String line = String_FromArray(lineBuffer);
for (y = 0; y < INPUTWIDGET_MAX_LINES; y++) { for (y = 0; y < INPUTWIDGET_MAX_LINES; y++) {
w->LineSizes[y] = Size2D_Empty; w->LineSizes[y] = Size2D_Empty;
} }
@ -1042,14 +1047,16 @@ static bool InputWidget_CheckCol(struct InputWidget* w, int index) {
} }
static void InputWidget_BackspaceKey(struct InputWidget* w) { static void InputWidget_BackspaceKey(struct InputWidget* w) {
int i, len;
if (InputWidget_ControlDown()) { if (InputWidget_ControlDown()) {
if (w->CaretPos == -1) { w->CaretPos = w->Text.length - 1; } if (w->CaretPos == -1) { w->CaretPos = w->Text.length - 1; }
int len = WordWrap_GetBackLength(&w->Text, w->CaretPos); len = WordWrap_GetBackLength(&w->Text, w->CaretPos);
if (!len) return; if (!len) return;
w->CaretPos -= len; w->CaretPos -= len;
if (w->CaretPos < 0) { w->CaretPos = 0; } if (w->CaretPos < 0) { w->CaretPos = 0; }
int i;
for (i = 0; i <= len; i++) { for (i = 0; i <= len; i++) {
String_DeleteAt(&w->Text, w->CaretPos); String_DeleteAt(&w->Text, w->CaretPos);
} }
@ -1214,10 +1221,12 @@ static bool InputWidget_KeyPress(void* widget, char keyChar) {
static bool InputWidget_MouseDown(void* widget, int x, int y, MouseButton button) { static bool InputWidget_MouseDown(void* widget, int x, int y, MouseButton button) {
struct InputWidget* w = widget; struct InputWidget* w = widget;
struct DrawTextArgs args;
if (button != MouseButton_Left) return true; if (button != MouseButton_Left) return true;
x -= w->InputTex.X; y -= w->InputTex.Y; x -= w->InputTex.X; y -= w->InputTex.Y;
struct DrawTextArgs args; DrawTextArgs_MakeEmpty(&args, &w->Font, true); DrawTextArgs_MakeEmpty(&args, &w->Font, true);
int offset = 0, charHeight = w->CaretTex.Height; int offset = 0, charHeight = w->CaretTex.Height;
char lineBuffer[STRING_SIZE]; char lineBuffer[STRING_SIZE];
@ -1399,7 +1408,7 @@ struct MenuInputValidator MenuInputValidator_Path(void) {
struct MenuInputValidator MenuInputValidator_Enum(const char** names, int namesCount) { struct MenuInputValidator MenuInputValidator_Enum(const char** names, int namesCount) {
struct MenuInputValidator v; struct MenuInputValidator v;
v.VTABLE = NULL; v.VTABLE = NULL;
v.Meta._Enum.Names = names; v.Meta._Enum.Names = names;
v.Meta._Enum.Count = namesCount; v.Meta._Enum.Count = namesCount;
return v; return v;
@ -1444,14 +1453,18 @@ static void MenuInputWidget_Render(void* widget, double delta) {
static void MenuInputWidget_RemakeTexture(void* widget) { static void MenuInputWidget_RemakeTexture(void* widget) {
struct MenuInputWidget* w = widget; struct MenuInputWidget* w = widget;
struct MenuInputValidator* v;
struct DrawTextArgs args; struct DrawTextArgs args;
Size2D size;
Bitmap bmp;
DrawTextArgs_Make(&args, &w->Base.Lines[0], &w->Base.Font, false); DrawTextArgs_Make(&args, &w->Base.Lines[0], &w->Base.Font, false);
Size2D size = Drawer2D_MeasureText(&args); size = Drawer2D_MeasureText(&args);
w->Base.CaretAccumulator = 0.0; w->Base.CaretAccumulator = 0.0;
char rangeBuffer[STRING_SIZE]; char rangeBuffer[STRING_SIZE];
String range = String_FromArray(rangeBuffer); String range = String_FromArray(rangeBuffer);
struct MenuInputValidator* v = &w->Validator; v = &w->Validator;
v->VTABLE->GetRange(v, &range); v->VTABLE->GetRange(v, &range);
/* Ensure we don't have 0 text height */ /* Ensure we don't have 0 text height */
@ -1465,7 +1478,7 @@ static void MenuInputWidget_RemakeTexture(void* widget) {
w->Base.Height = max(size.Height, w->MinHeight); w->Base.Height = max(size.Height, w->MinHeight);
Size2D adjSize = size; adjSize.Width = w->Base.Width; Size2D adjSize = size; adjSize.Width = w->Base.Width;
Bitmap bmp; Bitmap_AllocateClearedPow2(&bmp, adjSize.Width, adjSize.Height); Bitmap_AllocateClearedPow2(&bmp, adjSize.Width, adjSize.Height);
{ {
Drawer2D_DrawText(&bmp, &args, w->Base.Padding, 0); Drawer2D_DrawText(&bmp, &args, w->Base.Padding, 0);
@ -1491,13 +1504,14 @@ static void MenuInputWidget_RemakeTexture(void* widget) {
static bool MenuInputWidget_AllowedChar(void* widget, char c) { static bool MenuInputWidget_AllowedChar(void* widget, char c) {
struct InputWidget* w = widget; struct InputWidget* w = widget;
struct MenuInputValidator* v; struct MenuInputValidator* v;
int maxChars;
bool valid; bool valid;
if (c == '&') return false; if (c == '&') return false;
v = &((struct MenuInputWidget*)w)->Validator; v = &((struct MenuInputWidget*)w)->Validator;
if (!v->VTABLE->IsValidChar(v, c)) return false; if (!v->VTABLE->IsValidChar(v, c)) return false;
int maxChars = w->GetMaxLines() * INPUTWIDGET_LEN; maxChars = w->GetMaxLines() * INPUTWIDGET_LEN;
if (w->Text.length == maxChars) return false; if (w->Text.length == maxChars) return false;
/* See if the new string is in valid format */ /* See if the new string is in valid format */
@ -1524,8 +1538,7 @@ void MenuInputWidget_Create(struct MenuInputWidget* w, int width, int height, co
w->Base.ConvertPercents = false; w->Base.ConvertPercents = false;
w->Base.Padding = 3; w->Base.Padding = 3;
String inputStr = String_FromArray(w->__TextBuffer); String_InitArray(w->Base.Text, w->__TextBuffer);
w->Base.Text = inputStr;
w->Base.GetMaxLines = MenuInputWidget_GetMaxLines; w->Base.GetMaxLines = MenuInputWidget_GetMaxLines;
w->Base.RemakeTexture = MenuInputWidget_RemakeTexture; w->Base.RemakeTexture = MenuInputWidget_RemakeTexture;
@ -1541,19 +1554,21 @@ void MenuInputWidget_Create(struct MenuInputWidget* w, int width, int height, co
*#########################################################################################################################*/ *#########################################################################################################################*/
static void ChatInputWidget_RemakeTexture(void* widget) { static void ChatInputWidget_RemakeTexture(void* widget) {
struct InputWidget* w = widget; struct InputWidget* w = widget;
int totalHeight = 0, maxWidth = 0, i; struct DrawTextArgs args;
Size2D size = { 0, 0 };
Bitmap bmp;
int i;
w->CaretAccumulator = 0; w->CaretAccumulator = 0;
for (i = 0; i < w->GetMaxLines(); i++) { for (i = 0; i < w->GetMaxLines(); i++) {
totalHeight += w->LineSizes[i].Height; size.Height += w->LineSizes[i].Height;
maxWidth = max(maxWidth, w->LineSizes[i].Width); size.Width = max(size.Width, w->LineSizes[i].Width);
} }
Size2D size = { maxWidth, totalHeight };
int realHeight = 0; int realHeight = 0;
Bitmap bmp; Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height); Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height);
struct DrawTextArgs args; DrawTextArgs_MakeEmpty(&args, &w->Font, true); DrawTextArgs_MakeEmpty(&args, &w->Font, true);
if (w->Prefix.length) { if (w->Prefix.length) {
args.Text = w->Prefix; args.Text = w->Prefix;
Drawer2D_DrawText(&bmp, &args, 0, 0); Drawer2D_DrawText(&bmp, &args, 0, 0);
@ -1566,7 +1581,7 @@ static void ChatInputWidget_RemakeTexture(void* widget) {
if (!w->Lines[i].length) break; if (!w->Lines[i].length) break;
line.length = 0; line.length = 0;
/* Colour code goes to next line */ /* Colour code continues in next line */
char lastCol = InputWidget_GetLastCol(w, 0, i); char lastCol = InputWidget_GetLastCol(w, 0, i);
if (!Drawer2D_IsWhiteCol(lastCol)) { if (!Drawer2D_IsWhiteCol(lastCol)) {
String_Append(&line, '&'); String_Append(&line, lastCol); String_Append(&line, '&'); String_Append(&line, lastCol);
@ -1632,8 +1647,11 @@ static void ChatInputWidget_OnPressedEnter(void* widget) {
static void ChatInputWidget_UpKey(struct InputWidget* w) { static void ChatInputWidget_UpKey(struct InputWidget* w) {
struct ChatInputWidget* W = (struct ChatInputWidget*)w; struct ChatInputWidget* W = (struct ChatInputWidget*)w;
String prevInput;
int pos;
if (InputWidget_ControlDown()) { if (InputWidget_ControlDown()) {
int pos = w->CaretPos == -1 ? w->Text.length : w->CaretPos; pos = w->CaretPos == -1 ? w->Text.length : w->CaretPos;
if (pos < INPUTWIDGET_LEN) return; if (pos < INPUTWIDGET_LEN) return;
w->CaretPos = pos - INPUTWIDGET_LEN; w->CaretPos = pos - INPUTWIDGET_LEN;
@ -1650,7 +1668,7 @@ static void ChatInputWidget_UpKey(struct InputWidget* w) {
w->Text.length = 0; w->Text.length = 0;
if (W->TypingLogPos < 0) W->TypingLogPos = 0; if (W->TypingLogPos < 0) W->TypingLogPos = 0;
String prevInput = StringsBuffer_UNSAFE_Get(&Chat_InputLog, W->TypingLogPos); prevInput = StringsBuffer_UNSAFE_Get(&Chat_InputLog, W->TypingLogPos);
String_AppendString(&w->Text, &prevInput); String_AppendString(&w->Text, &prevInput);
w->CaretPos = -1; w->CaretPos = -1;
@ -1659,8 +1677,11 @@ static void ChatInputWidget_UpKey(struct InputWidget* w) {
static void ChatInputWidget_DownKey(struct InputWidget* w) { static void ChatInputWidget_DownKey(struct InputWidget* w) {
struct ChatInputWidget* W = (struct ChatInputWidget*)w; struct ChatInputWidget* W = (struct ChatInputWidget*)w;
String prevInput;
int lines;
if (InputWidget_ControlDown()) { if (InputWidget_ControlDown()) {
int lines = w->GetMaxLines(); lines = w->GetMaxLines();
if (w->CaretPos == -1 || w->CaretPos >= (lines - 1) * INPUTWIDGET_LEN) return; if (w->CaretPos == -1 || w->CaretPos >= (lines - 1) * INPUTWIDGET_LEN) return;
w->CaretPos += INPUTWIDGET_LEN; w->CaretPos += INPUTWIDGET_LEN;
@ -1676,7 +1697,7 @@ static void ChatInputWidget_DownKey(struct InputWidget* w) {
W->TypingLogPos = Chat_InputLog.Count; W->TypingLogPos = Chat_InputLog.Count;
String_AppendString(&w->Text, &W->OrigStr); String_AppendString(&w->Text, &W->OrigStr);
} else { } else {
String prevInput = StringsBuffer_UNSAFE_Get(&Chat_InputLog, W->TypingLogPos); prevInput = StringsBuffer_UNSAFE_Get(&Chat_InputLog, W->TypingLogPos);
String_AppendString(&w->Text, &prevInput); String_AppendString(&w->Text, &prevInput);
} }
@ -1690,18 +1711,18 @@ static bool ChatInputWidget_IsNameChar(char c) {
} }
static void ChatInputWidget_TabKey(struct InputWidget* w) { static void ChatInputWidget_TabKey(struct InputWidget* w) {
EntityID matches[TABLIST_MAX_NAMES];
String part, match;
int end = w->CaretPos == -1 ? w->Text.length - 1 : w->CaretPos; int end = w->CaretPos == -1 ? w->Text.length - 1 : w->CaretPos;
int start = end; int beg = end;
char* buffer = w->Text.buffer; char* buffer = w->Text.buffer;
while (start >= 0 && ChatInputWidget_IsNameChar(buffer[start])) { start--; } while (beg >= 0 && ChatInputWidget_IsNameChar(buffer[beg])) { beg--; }
start++; beg++;
if (end < 0 || start > end) return; if (end < 0 || beg > end) return;
String part = String_UNSAFE_Substring(&w->Text, start, (end + 1) - start); part = String_UNSAFE_Substring(&w->Text, beg, (end + 1) - beg);
Chat_AddOf(&String_Empty, MSG_TYPE_CLIENTSTATUS_3); Chat_AddOf(&String_Empty, MSG_TYPE_CLIENTSTATUS_3);
EntityID matches[TABLIST_MAX_NAMES];
int i, matchesCount = 0; int i, matchesCount = 0;
for (i = 0; i < TABLIST_MAX_NAMES; i++) { for (i = 0; i < TABLIST_MAX_NAMES; i++) {
@ -1715,13 +1736,13 @@ static void ChatInputWidget_TabKey(struct InputWidget* w) {
if (matchesCount == 1) { if (matchesCount == 1) {
if (w->CaretPos == -1) end++; if (w->CaretPos == -1) end++;
int len = end - start, j; int len = end - beg, j;
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
String_DeleteAt(&w->Text, start); String_DeleteAt(&w->Text, beg);
} }
if (w->CaretPos != -1) w->CaretPos -= len; if (w->CaretPos != -1) w->CaretPos -= len;
String match = TabList_UNSAFE_GetPlayer(matches[0]); match = TabList_UNSAFE_GetPlayer(matches[0]);
InputWidget_AppendString(w, &match); InputWidget_AppendString(w, &match);
} else if (matchesCount > 1) { } else if (matchesCount > 1) {
char strBuffer[STRING_SIZE]; char strBuffer[STRING_SIZE];
@ -1729,7 +1750,7 @@ static void ChatInputWidget_TabKey(struct InputWidget* w) {
String_Format1(&str, "&e%i matching names: ", &matchesCount); String_Format1(&str, "&e%i matching names: ", &matchesCount);
for (i = 0; i < matchesCount; i++) { for (i = 0; i < matchesCount; i++) {
String match = TabList_UNSAFE_GetPlayer(matches[i]); match = TabList_UNSAFE_GetPlayer(matches[i]);
if ((str.length + match.length + 1) > STRING_SIZE) break; if ((str.length + match.length + 1) > STRING_SIZE) break;
String_AppendString(&str, &match); String_AppendString(&str, &match);
@ -1771,10 +1792,8 @@ void ChatInputWidget_Create(struct ChatInputWidget* w, const FontDesc* font) {
w->Base.RemakeTexture = ChatInputWidget_RemakeTexture; w->Base.RemakeTexture = ChatInputWidget_RemakeTexture;
w->Base.OnPressedEnter = ChatInputWidget_OnPressedEnter; w->Base.OnPressedEnter = ChatInputWidget_OnPressedEnter;
String inputStr = String_FromArray(w->__TextBuffer); String_InitArray(w->Base.Text, w->__TextBuffer);
w->Base.Text = inputStr; String_InitArray(w->OrigStr, w->__OrigBuffer);
String origStr = String_FromArray(w->__OrigBuffer);
w->OrigStr = origStr;
} }
@ -1827,40 +1846,41 @@ void PlayerListWidget_GetNameUnder(struct PlayerListWidget* w, int x, int y, Str
static void PlayerListWidget_UpdateTableDimensions(struct PlayerListWidget* w) { static void PlayerListWidget_UpdateTableDimensions(struct PlayerListWidget* w) {
int width = w->XMax - w->XMin, height = w->YHeight; int width = w->XMax - w->XMin, height = w->YHeight;
w->X = (w->XMin ) - LIST_BOUNDS_SIZE; w->X = (w->XMin ) - LIST_BOUNDS_SIZE;
w->Y = (Game_Height / 2 - height / 2) - LIST_BOUNDS_SIZE; w->Y = (Game_Height / 2 - height / 2) - LIST_BOUNDS_SIZE;
w->Width = width + LIST_BOUNDS_SIZE * 2; w->Width = width + LIST_BOUNDS_SIZE * 2;
w->Height = height + LIST_BOUNDS_SIZE * 2; w->Height = height + LIST_BOUNDS_SIZE * 2;
} }
static int PlayerListWidget_GetColumnWidth(struct PlayerListWidget* w, int column) { static int PlayerListWidget_GetColumnWidth(struct PlayerListWidget* w, int column) {
int i = column * LIST_NAMES_PER_COLUMN; int i = column * LIST_NAMES_PER_COLUMN;
int end = min(w->NamesCount, i + LIST_NAMES_PER_COLUMN);
int maxWidth = 0; int maxWidth = 0;
int maxIndex = min(w->NamesCount, i + LIST_NAMES_PER_COLUMN);
for (; i < maxIndex; i++) { for (; i < end; i++) {
maxWidth = max(maxWidth, w->Textures[i].Width); maxWidth = max(maxWidth, w->Textures[i].Width);
} }
return maxWidth + LIST_COLUMN_PADDING + w->ElementOffset; return maxWidth + LIST_COLUMN_PADDING + w->ElementOffset;
} }
static int PlayerListWidget_GetColumnHeight(struct PlayerListWidget* w, int column) { static int PlayerListWidget_GetColumnHeight(struct PlayerListWidget* w, int column) {
int i = column * LIST_NAMES_PER_COLUMN; int i = column * LIST_NAMES_PER_COLUMN;
int total = 0; int end = min(w->NamesCount, i + LIST_NAMES_PER_COLUMN);
int maxIndex = min(w->NamesCount, i + LIST_NAMES_PER_COLUMN); int height = 0;
for (; i < maxIndex; i++) { for (; i < end; i++) {
total += w->Textures[i].Height + 1; height += w->Textures[i].Height + 1;
} }
return total; return height;
} }
static void PlayerListWidget_SetColumnPos(struct PlayerListWidget* w, int column, int x, int y) { static void PlayerListWidget_SetColumnPos(struct PlayerListWidget* w, int column, int x, int y) {
int i = column * LIST_NAMES_PER_COLUMN; struct Texture tex;
int maxIndex = min(w->NamesCount, i + LIST_NAMES_PER_COLUMN); int i = column * LIST_NAMES_PER_COLUMN;
int end = min(w->NamesCount, i + LIST_NAMES_PER_COLUMN);
for (; i < maxIndex; i++) { for (; i < end; i++) {
struct Texture tex = w->Textures[i]; tex = w->Textures[i];
tex.X = x; tex.Y = y - 10; tex.X = x; tex.Y = y - 10;
y += tex.Height + 1; y += tex.Height + 1;
@ -1909,11 +1929,12 @@ static void PlayerListWidget_Reposition(void* widget) {
} }
static void PlayerListWidget_AddName(struct PlayerListWidget* w, EntityID id, int index) { static void PlayerListWidget_AddName(struct PlayerListWidget* w, EntityID id, int index) {
String name;
/* insert at end of list */ /* insert at end of list */
if (index == -1) { index = w->NamesCount; w->NamesCount++; } if (index == -1) { index = w->NamesCount; w->NamesCount++; }
String name = TabList_UNSAFE_GetList(id); name = TabList_UNSAFE_GetList(id);
w->IDs[index] = id; w->IDs[index] = id;
PlayerListWidget_DrawName(&w->Textures[index], w, &name); PlayerListWidget_DrawName(&w->Textures[index], w, &name);
} }
@ -1950,11 +1971,12 @@ static void PlayerListWidget_AddGroup(struct PlayerListWidget* w, int id, int* i
static int PlayerListWidget_GetGroupCount(struct PlayerListWidget* w, int id, int i) { static int PlayerListWidget_GetGroupCount(struct PlayerListWidget* w, int id, int i) {
String group = TabList_UNSAFE_GetGroup(id); String group = TabList_UNSAFE_GetGroup(id);
String curGroup;
int count = 0; int count = 0;
for (; i < w->NamesCount; i++, count++) { for (; i < w->NamesCount; i++, count++) {
String curGroup = TabList_UNSAFE_GetGroup(w->IDs[i]); curGroup = TabList_UNSAFE_GetGroup(w->IDs[i]);
if (!String_CaselessEquals(&group, &curGroup)) return count; if (!String_CaselessEquals(&group, &curGroup)) break;
} }
return count; return count;
} }
@ -2089,8 +2111,8 @@ static void PlayerListWidget_Init(void* widget) {
} }
PlayerListWidget_SortAndReposition(w); PlayerListWidget_SortAndReposition(w);
TextWidget_Create(&w->Overview, &title, &w->Font); TextWidget_Create(&w->Title, &title, &w->Font);
Widget_SetLocation(&w->Overview, ANCHOR_CENTRE, ANCHOR_MIN, 0, 0); Widget_SetLocation(&w->Title, ANCHOR_CENTRE, ANCHOR_MIN, 0, 0);
Event_RegisterInt(&TabListEvents_Added, w, PlayerListWidget_TabEntryAdded); Event_RegisterInt(&TabListEvents_Added, w, PlayerListWidget_TabEntryAdded);
Event_RegisterInt(&TabListEvents_Changed, w, PlayerListWidget_TabEntryChanged); Event_RegisterInt(&TabListEvents_Changed, w, PlayerListWidget_TabEntryChanged);
@ -2099,26 +2121,29 @@ static void PlayerListWidget_Init(void* widget) {
static void PlayerListWidget_Render(void* widget, double delta) { static void PlayerListWidget_Render(void* widget, double delta) {
struct PlayerListWidget* w = widget; struct PlayerListWidget* w = widget;
struct TextWidget* overview = &w->Overview; struct TextWidget* title = &w->Title;
PackedCol topCol = PACKEDCOL_CONST(0, 0, 0, 180); struct Texture tex;
int offset, height;
int i, selectedI;
PackedCol topCol = PACKEDCOL_CONST( 0, 0, 0, 180);
PackedCol bottomCol = PACKEDCOL_CONST(50, 50, 50, 205); PackedCol bottomCol = PACKEDCOL_CONST(50, 50, 50, 205);
Gfx_SetTexturing(false); Gfx_SetTexturing(false);
int offset = overview->Height + 10; offset = title->Height + 10;
int height = max(300, w->Height + overview->Height); height = max(300, w->Height + title->Height);
GfxCommon_Draw2DGradient(w->X, w->Y - offset, w->Width, height, topCol, bottomCol); GfxCommon_Draw2DGradient(w->X, w->Y - offset, w->Width, height, topCol, bottomCol);
Gfx_SetTexturing(true); Gfx_SetTexturing(true);
overview->YOffset = w->Y - offset + 5; title->YOffset = w->Y - offset + 5;
Widget_Reposition(overview); Widget_Reposition(title);
Elem_Render(overview, delta); Elem_Render(title, delta);
int i, highlightedI = PlayerListWidget_HighlightedName(w, Mouse_X, Mouse_Y); selectedI = PlayerListWidget_HighlightedName(w, Mouse_X, Mouse_Y);
for (i = 0; i < w->NamesCount; i++) { for (i = 0; i < w->NamesCount; i++) {
if (!w->Textures[i].ID) continue; if (!w->Textures[i].ID) continue;
struct Texture tex = w->Textures[i]; tex = w->Textures[i];
if (i == highlightedI) tex.X += 4; if (i == selectedI) tex.X += 4;
Texture_Render(&tex); Texture_Render(&tex);
} }
} }
@ -2130,7 +2155,7 @@ static void PlayerListWidget_Free(void* widget) {
Gfx_DeleteTexture(&w->Textures[i].ID); Gfx_DeleteTexture(&w->Textures[i].ID);
} }
Elem_TryFree(&w->Overview); Elem_TryFree(&w->Title);
Event_UnregisterInt(&TabListEvents_Added, w, PlayerListWidget_TabEntryAdded); Event_UnregisterInt(&TabListEvents_Added, w, PlayerListWidget_TabEntryAdded);
Event_UnregisterInt(&TabListEvents_Changed, w, PlayerListWidget_TabEntryChanged); Event_UnregisterInt(&TabListEvents_Changed, w, PlayerListWidget_TabEntryChanged);
Event_UnregisterInt(&TabListEvents_Removed, w, PlayerListWidget_TabEntryRemoved); Event_UnregisterInt(&TabListEvents_Removed, w, PlayerListWidget_TabEntryRemoved);
@ -2160,8 +2185,8 @@ void PlayerListWidget_Create(struct PlayerListWidget* w, const FontDesc* font, b
*#########################################################################################################################*/ *#########################################################################################################################*/
#define TextGroupWidget_LineBuffer(w, i) ((w)->Buffer + (i) * TEXTGROUPWIDGET_LEN) #define TextGroupWidget_LineBuffer(w, i) ((w)->Buffer + (i) * TEXTGROUPWIDGET_LEN)
String TextGroupWidget_UNSAFE_Get(struct TextGroupWidget* w, int i) { String TextGroupWidget_UNSAFE_Get(struct TextGroupWidget* w, int i) {
int length = w->LineLengths[i]; int len = w->LineLengths[i];
return String_Init(TextGroupWidget_LineBuffer(w, i), length, length); return String_Init(TextGroupWidget_LineBuffer(w, i), len, len);
} }
void TextGroupWidget_GetText(struct TextGroupWidget* w, int index, String* text) { void TextGroupWidget_GetText(struct TextGroupWidget* w, int index, String* text) {
@ -2170,9 +2195,11 @@ void TextGroupWidget_GetText(struct TextGroupWidget* w, int index, String* text)
} }
void TextGroupWidget_PushUpAndReplaceLast(struct TextGroupWidget* w, const String* text) { void TextGroupWidget_PushUpAndReplaceLast(struct TextGroupWidget* w, const String* text) {
int y = w->Y; int max_index;
int i, y = w->Y;
Gfx_DeleteTexture(&w->Textures[0].ID); Gfx_DeleteTexture(&w->Textures[0].ID);
int i, max_index = w->LinesCount - 1; max_index = w->LinesCount - 1;
/* Move contents of X line to X - 1 line */ /* Move contents of X line to X - 1 line */
for (i = 0; i < max_index; i++) { for (i = 0; i < max_index; i++) {
@ -2276,13 +2303,15 @@ struct Portion { int16_t Beg, Len, LineBeg, LineLen; };
#define TEXTGROUPWIDGET_PACKED_LEN 0x7FFF #define TEXTGROUPWIDGET_PACKED_LEN 0x7FFF
static int TextGroupWidget_NextUrl(char* chars, int charsLen, int i) { static int TextGroupWidget_NextUrl(char* chars, int charsLen, int i) {
int start, left;
for (; i < charsLen; i++) { for (; i < charsLen; i++) {
if (!(chars[i] == 'h' || chars[i] == '&')) continue; if (!(chars[i] == 'h' || chars[i] == '&')) continue;
int left = charsLen - i; left = charsLen - i;
if (left < TEXTGROUPWIDGET_HTTP_LEN) return charsLen; if (left < TEXTGROUPWIDGET_HTTP_LEN) return charsLen;
/* colour codes at start of URL */ /* colour codes at start of URL */
int start = i; start = i;
while (left >= 2 && chars[i] == '&') { left -= 2; i += 2; } while (left >= 2 && chars[i] == '&') { left -= 2; i += 2; }
if (left < TEXTGROUPWIDGET_HTTP_LEN) continue; if (left < TEXTGROUPWIDGET_HTTP_LEN) continue;
@ -2299,9 +2328,12 @@ static int TextGroupWidget_NextUrl(char* chars, int charsLen, int i) {
static int TextGroupWidget_UrlEnd(char* chars, int charsLen, int32_t* begs, int begsLen, int i) { static int TextGroupWidget_UrlEnd(char* chars, int charsLen, int32_t* begs, int begsLen, int i) {
int start = i, j; int start = i, j;
int next, left;
bool isBeg;
for (; i < charsLen && chars[i] != ' '; i++) { for (; i < charsLen && chars[i] != ' '; i++) {
/* Is this character the start of a line */ /* Is this character the start of a line */
bool isBeg = false; isBeg = false;
for (j = 0; j < begsLen; j++) { for (j = 0; j < begsLen; j++) {
if (i == begs[j]) { isBeg = true; break; } if (i == begs[j]) { isBeg = true; break; }
} }
@ -2311,7 +2343,7 @@ static int TextGroupWidget_UrlEnd(char* chars, int charsLen, int32_t* begs, int
if (chars[i] != '>') break; if (chars[i] != '>') break;
/* Does this line start with "> ", making it a multiline */ /* Does this line start with "> ", making it a multiline */
int next = i + 1, left = charsLen - next; next = i + 1; left = charsLen - next;
while (left >= 2 && chars[next] == '&') { left -= 2; next += 2; } while (left >= 2 && chars[next] == '&') { left -= 2; next += 2; }
if (left == 0 || chars[next] != ' ') break; if (left == 0 || chars[next] != ' ') break;
@ -2321,7 +2353,10 @@ static int TextGroupWidget_UrlEnd(char* chars, int charsLen, int32_t* begs, int
} }
static void TextGroupWidget_Output(struct Portion bit, int lineBeg, int lineEnd, struct Portion** portions) { static void TextGroupWidget_Output(struct Portion bit, int lineBeg, int lineEnd, struct Portion** portions) {
struct Portion* cur;
int overBy, underBy;
if (bit.Beg >= lineEnd || !bit.Len) return; if (bit.Beg >= lineEnd || !bit.Len) return;
bit.LineBeg = bit.Beg; bit.LineBeg = bit.Beg;
bit.LineLen = bit.Len & TEXTGROUPWIDGET_PACKED_LEN; bit.LineLen = bit.Len & TEXTGROUPWIDGET_PACKED_LEN;
@ -2329,18 +2364,18 @@ static void TextGroupWidget_Output(struct Portion bit, int lineBeg, int lineEnd,
if (bit.Beg >= lineBeg) { if (bit.Beg >= lineBeg) {
} else if (bit.Beg + bit.LineLen > lineBeg) { } else if (bit.Beg + bit.LineLen > lineBeg) {
/* Adjust start of portion to be within this line */ /* Adjust start of portion to be within this line */
int underBy = lineBeg - bit.Beg; underBy = lineBeg - bit.Beg;
bit.LineBeg += underBy; bit.LineLen -= underBy; bit.LineBeg += underBy; bit.LineLen -= underBy;
} else { return; } } else { return; }
/* Limit length of portion to be within this line */ /* Limit length of portion to be within this line */
int overBy = (bit.LineBeg + bit.LineLen) - lineEnd; overBy = (bit.LineBeg + bit.LineLen) - lineEnd;
if (overBy > 0) bit.LineLen -= overBy; if (overBy > 0) bit.LineLen -= overBy;
bit.LineBeg -= lineBeg; bit.LineBeg -= lineBeg;
if (!bit.LineLen) return; if (!bit.LineLen) return;
struct Portion* cur = *portions; *cur++ = bit; *portions = cur; cur = *portions; *cur++ = bit; *portions = cur;
} }
static int TextGroupWidget_Reduce(struct TextGroupWidget* w, char* chars, int target, struct Portion* portions) { static int TextGroupWidget_Reduce(struct TextGroupWidget* w, char* chars, int target, struct Portion* portions) {
@ -2348,20 +2383,22 @@ static int TextGroupWidget_Reduce(struct TextGroupWidget* w, char* chars, int ta
int32_t begs[TEXTGROUPWIDGET_MAX_LINES]; int32_t begs[TEXTGROUPWIDGET_MAX_LINES];
int32_t ends[TEXTGROUPWIDGET_MAX_LINES]; int32_t ends[TEXTGROUPWIDGET_MAX_LINES];
struct Portion bit; struct Portion bit;
int i, total = 0, end = 0; int len, nextStart;
int i, total = 0, end;
for (i = 0; i < w->LinesCount; i++) { for (i = 0; i < w->LinesCount; i++) {
int lineLen = w->LineLengths[i]; len = w->LineLengths[i];
begs[i] = -1; ends[i] = -1; begs[i] = -1; ends[i] = -1;
if (!lineLen) continue; if (!len) continue;
begs[i] = total; begs[i] = total;
Mem_Copy(&chars[total], TextGroupWidget_LineBuffer(w, i), lineLen); Mem_Copy(&chars[total], TextGroupWidget_LineBuffer(w, i), len);
total += lineLen; ends[i] = total; total += len; ends[i] = total;
} }
end = 0;
for (;;) { for (;;) {
int nextStart = TextGroupWidget_NextUrl(chars, total, end); nextStart = TextGroupWidget_NextUrl(chars, total, end);
/* add normal portion between urls */ /* add normal portion between urls */
bit.Beg = end; bit.Beg = end;
@ -2397,25 +2434,28 @@ static void TextGroupWidget_FormatUrl(String* text, const String* url) {
static bool TextGroupWidget_GetUrl(struct TextGroupWidget* w, String* text, int index, int mouseX) { static bool TextGroupWidget_GetUrl(struct TextGroupWidget* w, String* text, int index, int mouseX) {
char chars[TEXTGROUPWIDGET_MAX_LINES * TEXTGROUPWIDGET_LEN]; char chars[TEXTGROUPWIDGET_MAX_LINES * TEXTGROUPWIDGET_LEN];
struct Portion portions[2 * (TEXTGROUPWIDGET_LEN / TEXTGROUPWIDGET_HTTP_LEN)]; struct Portion portions[2 * (TEXTGROUPWIDGET_LEN / TEXTGROUPWIDGET_HTTP_LEN)];
struct Portion bit;
struct DrawTextArgs args = { 0 }; struct DrawTextArgs args = { 0 };
String line; String line, url;
int portionsCount;
int i, x, width;
mouseX -= w->Textures[index].X; mouseX -= w->Textures[index].X;
args.UseShadow = true; args.UseShadow = true;
line = TextGroupWidget_UNSAFE_Get(w, index); line = TextGroupWidget_UNSAFE_Get(w, index);
if (Game_ClassicMode) return false; if (Game_ClassicMode) return false;
int i, x, portionsCount = TextGroupWidget_Reduce(w, chars, index, portions); portionsCount = TextGroupWidget_Reduce(w, chars, index, portions);
for (i = 0, x = 0; i < portionsCount; i++) { for (i = 0, x = 0; i < portionsCount; i++) {
struct Portion bit = portions[i]; bit = portions[i];
args.Text = String_UNSAFE_Substring(&line, bit.LineBeg, bit.LineLen); args.Text = String_UNSAFE_Substring(&line, bit.LineBeg, bit.LineLen);
args.Font = (bit.Len & TEXTGROUPWIDGET_URL) ? w->UnderlineFont : w->Font; args.Font = (bit.Len & TEXTGROUPWIDGET_URL) ? w->UnderlineFont : w->Font;
int width = Drawer2D_MeasureText(&args).Width; width = Drawer2D_MeasureText(&args).Width;
if ((bit.Len & TEXTGROUPWIDGET_URL) && mouseX >= x && mouseX < x + width) { if ((bit.Len & TEXTGROUPWIDGET_URL) && mouseX >= x && mouseX < x + width) {
bit.Len &= TEXTGROUPWIDGET_PACKED_LEN; bit.Len &= TEXTGROUPWIDGET_PACKED_LEN;
String url = String_Init(&chars[bit.Beg], bit.Len, bit.Len); url = String_Init(&chars[bit.Beg], bit.Len, bit.Len);
TextGroupWidget_FormatUrl(text, &url); TextGroupWidget_FormatUrl(text, &url);
return true; return true;
@ -2460,33 +2500,38 @@ static bool TextGroupWidget_MightHaveUrls(struct TextGroupWidget* w) {
static void TextGroupWidget_DrawAdvanced(struct TextGroupWidget* w, struct Texture* tex, struct DrawTextArgs* args, int index, const String* text) { static void TextGroupWidget_DrawAdvanced(struct TextGroupWidget* w, struct Texture* tex, struct DrawTextArgs* args, int index, const String* text) {
char chars[TEXTGROUPWIDGET_MAX_LINES * TEXTGROUPWIDGET_LEN]; char chars[TEXTGROUPWIDGET_MAX_LINES * TEXTGROUPWIDGET_LEN];
struct Portion portions[2 * (TEXTGROUPWIDGET_LEN / TEXTGROUPWIDGET_HTTP_LEN)]; struct Portion portions[2 * (TEXTGROUPWIDGET_LEN / TEXTGROUPWIDGET_HTTP_LEN)];
int i, x, portionsCount = TextGroupWidget_Reduce(w, chars, index, portions); struct Portion bit;
Size2D size = { 0, 0 };
Size2D total = { 0, 0 };
Size2D partSizes[Array_Elems(portions)]; Size2D partSizes[Array_Elems(portions)];
Bitmap bmp; Bitmap bmp;
int portionsCount;
int i, x;
portionsCount = TextGroupWidget_Reduce(w, chars, index, portions);
for (i = 0; i < portionsCount; i++) { for (i = 0; i < portionsCount; i++) {
struct Portion bit = portions[i]; bit = portions[i];
args->Text = String_UNSAFE_Substring(text, bit.LineBeg, bit.LineLen); args->Text = String_UNSAFE_Substring(text, bit.LineBeg, bit.LineLen);
args->Font = (bit.Len & TEXTGROUPWIDGET_URL) ? w->UnderlineFont : w->Font; args->Font = (bit.Len & TEXTGROUPWIDGET_URL) ? w->UnderlineFont : w->Font;
partSizes[i] = Drawer2D_MeasureText(args); partSizes[i] = Drawer2D_MeasureText(args);
total.Height = max(partSizes[i].Height, total.Height); size.Height = max(partSizes[i].Height, size.Height);
total.Width += partSizes[i].Width; size.Width += partSizes[i].Width;
} }
Bitmap_AllocateClearedPow2(&bmp, total.Width, total.Height); Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height);
{ {
for (i = 0, x = 0; i < portionsCount; i++) { x = 0;
struct Portion bit = portions[i]; for (i = 0; i < portionsCount; i++) {
bit = portions[i];
args->Text = String_UNSAFE_Substring(text, bit.LineBeg, bit.LineLen); args->Text = String_UNSAFE_Substring(text, bit.LineBeg, bit.LineLen);
args->Font = (bit.Len & TEXTGROUPWIDGET_URL) ? w->UnderlineFont : w->Font; args->Font = (bit.Len & TEXTGROUPWIDGET_URL) ? w->UnderlineFont : w->Font;
Drawer2D_DrawText(&bmp, args, x, 0); Drawer2D_DrawText(&bmp, args, x, 0);
x += partSizes[i].Width; x += partSizes[i].Width;
} }
Drawer2D_Make2DTexture(tex, &bmp, total, 0, 0); Drawer2D_Make2DTexture(tex, &bmp, size, 0, 0);
} }
Mem_Free(bmp.Scan0); Mem_Free(bmp.Scan0);
} }

View File

@ -183,7 +183,7 @@ struct PlayerListWidget {
int NamesCount, ElementOffset; int NamesCount, ElementOffset;
int XMin, XMax, YHeight; int XMin, XMax, YHeight;
bool Classic; bool Classic;
struct TextWidget Overview; struct TextWidget Title;
uint16_t IDs[TABLIST_MAX_NAMES * 2]; uint16_t IDs[TABLIST_MAX_NAMES * 2];
struct Texture Textures[TABLIST_MAX_NAMES * 2]; struct Texture Textures[TABLIST_MAX_NAMES * 2];
}; };