summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2012-10-25 04:59:11 +0200
committerTreeki <treeki@gmail.com>2012-10-25 04:59:11 +0200
commit0bee9e3ae3bd5a9f4a9f0ea8a4d04955a90798fa (patch)
tree999ea89b9eb357fbd4a0b7d8acd6c71f2a82c8f6
parent47795a5f0eee896df557e4e3481068e510fe51fb (diff)
downloadkamek-0bee9e3ae3bd5a9f4a9f0ea8a4d04955a90798fa.tar.gz
kamek-0bee9e3ae3bd5a9f4a9f0ea8a4d04955a90798fa.zip
refactoring, API fixes and shop mostly finished
Diffstat (limited to '')
-rw-r--r--include/g3dhax.h4
-rwxr-xr-xinclude/game.h5
-rw-r--r--kamek_pal.x4
-rw-r--r--koopatlas.yaml1
-rw-r--r--src/koopatlas/core.cpp2
-rw-r--r--src/koopatlas/hud.cpp139
-rw-r--r--src/koopatlas/hud.h18
-rw-r--r--src/koopatlas/pathmanager.cpp4
-rw-r--r--src/koopatlas/shop.cpp117
-rw-r--r--src/koopatlas/shop.h11
-rw-r--r--src/texmapcolouriser.cpp142
-rw-r--r--src/texmapcolouriser.h22
12 files changed, 292 insertions, 177 deletions
diff --git a/include/g3dhax.h b/include/g3dhax.h
index 8a2063a..85dc922 100644
--- a/include/g3dhax.h
+++ b/include/g3dhax.h
@@ -322,7 +322,7 @@ namespace m3d {
bool setup(nw4r::g3d::ResMdl modelRes, nw4r::g3d::ResAnmChr anmRes,
mAllocator_c *allocator, u32 *sizeOutPtr);
- void bind(/*b*/mdl_c *model, nw4r::g3d::ResAnmChr anmRes, int unk);
+ void bind(/*b*/mdl_c *model, nw4r::g3d::ResAnmChr anmRes, bool playsOnce);
};
class anmVis_c : public fanm_c {
@@ -333,7 +333,7 @@ namespace m3d {
bool setup(nw4r::g3d::ResMdl modelRes, nw4r::g3d::ResAnmVis anmRes,
mAllocator_c *allocator, u32 *sizeOutPtr);
- void bind(/*b*/mdl_c *model, nw4r::g3d::ResAnmVis anmRes, int unk);
+ void bind(/*b*/mdl_c *model, nw4r::g3d::ResAnmVis anmRes, bool playsOnce);
};
class anmClr_c : public fanm_c {
diff --git a/include/game.h b/include/game.h
index 48c7f65..c4a9238 100755
--- a/include/game.h
+++ b/include/game.h
@@ -132,6 +132,11 @@ class GameMgr {
u8 _AFC, _AFD, _AFE[88];
u8 _B56[4];
u8 _B5A, _B5B;
+
+ void giveOneStockPowerup(int type); // 800BB330
+ void takeOneStockPowerup(int type); // 800BB380
+ int getStockPowerupCount(int type); // 800BB3D0
+ void resetStockPowerupCount(int type); // 800BB410
};
extern GameMgr *GameMgrP;
diff --git a/kamek_pal.x b/kamek_pal.x
index 7cfd502..0332692 100644
--- a/kamek_pal.x
+++ b/kamek_pal.x
@@ -1343,7 +1343,7 @@ SECTIONS {
__dt__Q23m3d8anmChr_cFv = 0x800260c0;
vf0C__Q23m3d8anmChr_cFv = 0x8002a210;
setup__Q23m3d8anmChr_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmChrP12mAllocator_cPUi = 0x80165210;
- bind__Q23m3d8anmChr_cFPQ23m3d5mdl_cQ34nw4r3g3d9ResAnmChri = 0x80165330;
+ bind__Q23m3d8anmChr_cFPQ23m3d5mdl_cQ34nw4r3g3d9ResAnmChrb = 0x80165330;
internalBind__Q23m3d8anmChr_cFv = 0x801653c0;
/* m3d::anmVis_c */
@@ -1351,7 +1351,7 @@ SECTIONS {
__dt__Q23m3d8anmVis_cFv = 0x809b2090;
vf0C__Q23m3d8anmVis_cFv = 0x809b3c20;
setup__Q23m3d8anmVis_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmVisP12mAllocator_cPUi = 0x80167d80;
- bind__Q23m3d8anmVis_cFPQ23m3d5mdl_cQ34nw4r3g3d9ResAnmVisi = 0x80167ea0;
+ bind__Q23m3d8anmVis_cFPQ23m3d5mdl_cQ34nw4r3g3d9ResAnmVisb = 0x80167ea0;
internalBind__Q23m3d8anmVis_cFv = 0x80167f90;
/* m3d::anmClr_c */
diff --git a/koopatlas.yaml b/koopatlas.yaml
index eea87e6..3556996 100644
--- a/koopatlas.yaml
+++ b/koopatlas.yaml
@@ -13,6 +13,7 @@ source_files:
- ../src/koopatlas/pathmanager.cpp
- ../src/koopatlas/shop.cpp
- ../src/koopatlas/starcoin.cpp
+ - ../src/texmapcolouriser.cpp
hooks:
- name: BuildWorldMap # WORLD_MAP
diff --git a/src/koopatlas/core.cpp b/src/koopatlas/core.cpp
index 6fb030a..249861f 100644
--- a/src/koopatlas/core.cpp
+++ b/src/koopatlas/core.cpp
@@ -265,7 +265,7 @@ bool WMInit_SetupExtra(void *ptr) {
// it is created in dScKoopatlas_c::onCreate
SpammyReport("creating SHOP\n");
- wm->shop = (dWMShop_c*)CreateParentedObject(WM_SHOP, wm, 0, 0);
+ wm->shop = (dWMShop_c*)CreateParentedObject(WM_SHOP, wm, 0, 2);
SpammyReport("creating Star Coin Menu\n");
wm->coins = (dWMStarCoin_c*)CreateParentedObject(WM_STARCOIN, wm, 0, 0);
diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp
index 2479133..ab093ef 100644
--- a/src/koopatlas/hud.cpp
+++ b/src/koopatlas/hud.cpp
@@ -2,145 +2,6 @@
#include <newer.h>
-dTexMapColouriser_c::dTexMapColouriser_c() {
- texmap = 0;
- original = 0;
- mine = 0;
-}
-
-void *EGG__Heap__alloc(unsigned long size, int unk, void *heap);
-void EGG__Heap__free(void *ptr, void *heap);
-
-dTexMapColouriser_c::~dTexMapColouriser_c() {
- resetAndClear();
-}
-
-void dTexMapColouriser_c::resetAndClear() {
- texmap = 0;
- if (mine) {
- EGG__Heap__free(mine, 0);
- mine = 0;
- }
-}
-
-void dTexMapColouriser_c::setTexMap(nw4r::lyt::TexMap *tm) {
- OSReport("Colourising TexMap: %p (w:%d h:%d)\n", tm, tm->width, tm->height);
- if (texmap)
- resetAndClear();
-
- if (tm->mBits.textureFormat != GX_TF_IA8) {
- OSReport("Warning: Trying to colourise image whose format is %d not GX_TF_IA8\n", tm->mBits.textureFormat);
- }
-
- texmap = tm;
- original = (u16*)tm->image;
- mine = (u16*)EGG__Heap__alloc(tm->width * tm->height * 4, 0x20, mHeap::gameHeaps[2]);
- tm->image = mine;
- tm->mBits.textureFormat = GX_TF_RGBA8;
-}
-
-void dTexMapColouriser_c::applyAlso(nw4r::lyt::TexMap *tm) {
- if (!texmap) {
- setTexMap(tm);
- } else {
- tm->image = mine;
- tm->mBits.textureFormat = GX_TF_RGBA8;
- }
-}
-
-inline static float hslValue(float n1, float n2, float hue) {
- if (hue > 6.0f)
- hue -= 6.0f;
- else if (hue < 0.0f)
- hue += 6.0f;
-
- if (hue < 1.0f)
- return n1 + (n2 - n1) * hue;
- else if (hue < 3.0f)
- return n2;
- else if (hue < 4.0f)
- return n1 + (n2 - n1) * (4.0f - hue);
- else
- return n1;
-}
-
-void dTexMapColouriser_c::colourise(int h, int s, int l) {
- if (!mine)
- return;
-
- int width = texmap->width, height = texmap->height;
- int texelW = width / 4, texelH = height / 4;
-
- u16 *source = original, *dest = mine;
-
- float hueParam = h / 360.0f;
- float satParam = s / 100.0f;
- float lumParam = l / 100.0f;
-
- for (int texelY = 0; texelY < texelH; texelY++) {
- for (int texelX = 0; texelX < texelW; texelX++) {
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
- u8 intensity = *source & 0xFF;
- u8 alpha = *source >> 8;
-
- u8 r, g, b;
-
- // This is a hack
- if (alpha < 250) {
- r = g = b = intensity;
- } else {
- // converting from GIMP's colourise code...
- // h and s are always the same
- // l is the only thing we need to touch:
- // we get the luminance from the source pixel
- // (which, conveniently, is the intensity)
- // manipulate it using the passed l and then
- // convert the whole thing to RGB
-
- float lum = intensity / 255.0f;
-
- // manipulate it
- if (l > 0) {
- lum = lum * (1.0f - lumParam);
- lum += (1.0f - (1.0f - lumParam));
- } else if (l < 0) {
- lum = lum * (lumParam + 1.0f);
- }
-
- // make it RGB
-
- if (s == 0) {
- r = g = b = lum*255.0f;
- } else {
- float m1, m2;
- if (lum <= 0.5f)
- m2 = lum * (1.0f + satParam);
- else
- m2 = lum + satParam - lum * satParam;
-
- m1 = 2.0f * lum - m2;
-
- r = hslValue(m1, m2, hueParam * 6.0f + 2.0) * 255.0f;
- g = hslValue(m1, m2, hueParam * 6.0f) * 255.0f;
- b = hslValue(m1, m2, hueParam * 6.0f - 2.0) * 255.0f;
- }
- }
-
- // now write it
- dest[0] = (alpha<<8)|r;
- dest[16] = (g<<8)|b;
-
- source++;
- dest++;
- }
- }
-
- dest += 16;
- }
- }
-}
-
dWMHud_c *dWMHud_c::instance = 0;
diff --git a/src/koopatlas/hud.h b/src/koopatlas/hud.h
index ee64133..32a09be 100644
--- a/src/koopatlas/hud.h
+++ b/src/koopatlas/hud.h
@@ -2,23 +2,7 @@
#define __KOOPATLAS_HUD_H
#include "koopatlas/core.h"
-
-// Colourises an IA8 texture
-class dTexMapColouriser_c {
- public:
- dTexMapColouriser_c();
- ~dTexMapColouriser_c();
-
- void resetAndClear();
- void setTexMap(nw4r::lyt::TexMap *tm);
- void applyAlso(nw4r::lyt::TexMap *tm);
- void colourise(int h, int s, int l);
-
- private:
- nw4r::lyt::TexMap *texmap;
- u16 *original;
- u16 *mine;
-};
+#include "texmapcolouriser.h"
class dWMHud_c : public dBase_c {
public:
diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp
index fa2a862..5d301df 100644
--- a/src/koopatlas/pathmanager.cpp
+++ b/src/koopatlas/pathmanager.cpp
@@ -657,10 +657,10 @@ void dWMPathManager_c::moveThroughPath() {
OSReport("Activating world change %d\n", to->worldID);
const dKPWorldDef_s *world = dScKoopatlas_c::instance->mapData.findWorldDef(to->worldID);
if (world) {
- bool visiblyChange = false;
+ bool visiblyChange = true;
if (strncmp(save->newerWorldName, world->name, 32) == 0) {
OSReport("Already here, but setting BGM track\n");
- visiblyChange = true;
+ visiblyChange = false;
}
OSReport("Found!\n");
diff --git a/src/koopatlas/shop.cpp b/src/koopatlas/shop.cpp
index 9da5fc0..b42c58a 100644
--- a/src/koopatlas/shop.cpp
+++ b/src/koopatlas/shop.cpp
@@ -15,13 +15,14 @@ void dWMShop_c::ShopModel_c::setupItem(float x, float y, ItemTypes type) {
{ "I_propeller", "g3d/I_propeller.brres", "I_propeller_model", "wait2" },
{ "I_kinoko_bundle","g3d/I_mini_kinoko.brres", "I_mini_kinoko", "wait2" },
{ "I_star", "g3d/I_star.brres", "I_star", "wait2" },
- { "I_hammer", "g3d/I_hammer.brres", "I_hammer", "wait2" },
+ { "I_hammer", "g3d/I_fireflower.brres", "I_fireflower", "wait2" },
{ "I_kinoko_bundle","g3d/I_life_kinoko.brres", "I_life_kinoko", "wait2" },
{ "obj_coin", "g3d/obj_coin.brres", "obj_coin", "wait2" }
};
this->x = x;
this->y = y;
+ scaleFactor = 2.3f;
int id = (int)type;
@@ -29,8 +30,14 @@ void dWMShop_c::ShopModel_c::setupItem(float x, float y, ItemTypes type) {
res.data = getResource(Produce[id][0], Produce[id][1]);
nw4r::g3d::ResMdl mdlRes = res.GetResMdl(Produce[id][2]);
- model.setup(mdlRes, &allocator, ANM_VTX, 1, 0);
- SetupTextures_Item(&model, 1);
+ model.setup(mdlRes, &allocator, 0x224, 1, 0);
+
+ if (type == COINS) {
+ SetupTextures_MapObj(&model, 1);
+ this->y += 20.0f;
+ scaleFactor = 2.7f;
+ } else
+ SetupTextures_Item(&model, 1);
nw4r::g3d::ResAnmChr anmChr = res.GetResAnmChr(Produce[id][3]);
animation.setup(mdlRes, anmChr, &allocator, 0);
@@ -45,12 +52,14 @@ void dWMShop_c::ShopModel_c::setupLakitu(int id) {
"g3d/ghost.brres", "g3d/space.brres", "g3d/koopa.brres", "g3d/sewer.brres", "g3d/goldwood.brres"
};
+ scaleFactor = 1.0f;
+
allocator.link(-1, GameHeaps[0], 0, 0x20);
res.data = getResource("lakitu", models[id]);
nw4r::g3d::ResMdl mdlRes = res.GetResMdl("lakitu");
- model.setup(mdlRes, &allocator, ANM_VTX, 1, 0);
- SetupTextures_Item(&model, 1);
+ model.setup(mdlRes, &allocator, 0x224, 1, 0);
+ SetupTextures_Enemy(&model, 1);
nw4r::g3d::ResAnmChr anmChr = res.GetResAnmChr("idle");
animation.setup(mdlRes, anmChr, &allocator, 0);
@@ -62,7 +71,7 @@ void dWMShop_c::ShopModel_c::setupLakitu(int id) {
void dWMShop_c::ShopModel_c::playAnim(const char *name, float rate) {
nw4r::g3d::ResAnmChr anmChr = res.GetResAnmChr(name);
- animation.bind(&model, anmChr, 1);
+ animation.bind(&model, anmChr, 0);
model.bindAnim(&animation, 0.0f);
animation.setUpdateRate(rate);
}
@@ -73,12 +82,12 @@ void dWMShop_c::ShopModel_c::execute() {
void dWMShop_c::ShopModel_c::draw() {
mMtx mtx;
- Vec pos = {250.0f, 170.0f, 3000.0f};
- Vec scale = {1.0f, 1.0f, 1.0f};
- mtx.translation(pos.x, pos.y, pos.z);
-
+ mtx.translation(x, y, 1000.0f);
model.setDrawMatrix(mtx);
+
+ Vec scale = {scaleFactor, scaleFactor, scaleFactor};
model.setScale(&scale);
+
model.calcWorld(false);
model.scheduleForDrawing();
}
@@ -111,7 +120,6 @@ int dWMShop_c::onCreate() {
layout.build("shop.brlyt");
- layout.layout.rootPane->trans.x = -112.0f;
if (IsWideScreen()) {
layout.layout.rootPane->scale.x = 0.735f;
} else {
@@ -154,6 +162,36 @@ int dWMShop_c::onCreate() {
};
layout.getTextBoxes(tbNames, &Title, 6);
+ // Warning: weird code coming up
+ const char *crap = "000102031\0" "2\0";
+ char name[12];
+ for (int i = 0; i < 6; i++) {
+ strcpy(name, "BtnLeftXX");
+ name[7] = crap[i*2];
+ name[8] = crap[i*2+1];
+ BtnLeft[i] = layout.findPictureByName(name);
+
+ strcpy(name, "BtnMidXX");
+ name[6] = crap[i*2];
+ name[7] = crap[i*2+1];
+ BtnMid[i] = layout.findPictureByName(name);
+
+ strcpy(name, "BtnRightXX");
+ name[8] = crap[i*2];
+ name[9] = crap[i*2+1];
+ BtnRight[i] = layout.findPictureByName(name);
+ }
+
+ leftCol.setTexMap(BtnLeft[0]->material->texMaps);
+ midCol.setTexMap(BtnMid[0]->material->texMaps);
+ rightCol.setTexMap(BtnRight[0]->material->texMaps);
+
+ for (int i = 1; i < 6; i++) {
+ leftCol.applyAlso(BtnLeft[i]->material->texMaps);
+ midCol.applyAlso(BtnMid[i]->material->texMaps);
+ rightCol.applyAlso(BtnRight[i]->material->texMaps);
+ }
+
layoutLoaded = true;
}
@@ -226,6 +264,7 @@ void dWMShop_c::beginState_ShowWait() {
layout.enableNonLoopAnim(SHOW_ALL);
visible = true;
+ loadInfo();
loadModels();
}
void dWMShop_c::executeState_ShowWait() {
@@ -301,12 +340,14 @@ void dWMShop_c::endState_Wait() { }
void dWMShop_c::beginState_HideWait() {
MapSoundPlayer(SoundRelatedClass, SE_SYS_DIALOGUE_OUT_AUTO, 1);
layout.enableNonLoopAnim(HIDE_ALL);
+ layout.enableNonLoopAnim(DEACTIVATE_BUTTON+selected);
}
void dWMShop_c::executeState_HideWait() {
if (!layout.isAnimOn(HIDE_ALL))
state.setState(&StateID_Hidden);
}
void dWMShop_c::endState_HideWait() {
+ deleteModels();
visible = false;
}
@@ -384,10 +425,29 @@ const dWMShop_c::ItemTypes dWMShop_c::Inventory[10][12] = {
void dWMShop_c::loadModels() {
lakituModel = new ShopModel_c;
lakituModel->setupLakitu(shopKind);
+ lakituModel->x = 240.0f;
+ lakituModel->y = 220.0f;
+
+ static const float itemPos[ITEM_COUNT][2] = {
+ {357.0f, 276.0f},
+ {450.0f, 276.0f},
+ {543.0f, 276.0f},
+ {636.0f, 276.0f},
+
+ {380.0f, 190.0f},
+ {462.0f, 190.0f},
+ {544.0f, 190.0f},
+
+ {363.0f, 104.0f},
+ {413.0f, 104.0f},
+ {463.0f, 104.0f},
+ {513.0f, 104.0f},
+ {563.0f, 104.0f},
+ };
itemModels = new ShopModel_c[ITEM_COUNT];
for (int i = 0; i < ITEM_COUNT; i++)
- itemModels[i].setupItem(0.0f, 0.0f, Inventory[shopKind][i]);
+ itemModels[i].setupItem(itemPos[i][0], itemPos[i][1], Inventory[shopKind][i]);
}
void dWMShop_c::deleteModels() {
if (lakituModel)
@@ -400,6 +460,39 @@ void dWMShop_c::deleteModels() {
}
+void dWMShop_c::loadInfo() {
+ SaveBlock *save = GetSaveFile()->GetBlock(-1);
+
+ leftCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL);
+ midCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL);
+ rightCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL);
+
+ // find out the shop name
+ dLevelInfo_c::entry_s *shopNameEntry =
+ dLevelInfo_c::s_info.searchBySlot(shopKind, 98);
+
+ wchar_t shopName[100];
+ // TODO: refactor this a bit
+ const char *sourceName = dLevelInfo_c::s_info.getNameForLevel(shopNameEntry);
+ int charCount = 0;
+
+ while (*sourceName != 0 && charCount < 99) {
+ shopName[charCount] = *sourceName;
+ sourceName++;
+ charCount++;
+ }
+ shopName[charCount] = 0;
+
+ Title->SetString(shopName);
+ TitleShadow->SetString(shopName);
+
+ // load the coin count
+ int scCount = getStarCoinCount();
+ WriteNumberToTextBox(&scCount, CoinCount, false);
+ WriteNumberToTextBox(&scCount, CoinCountShadow, false);
+}
+
+
void dWMShop_c::buyItem(int item) {
static int itemDefs[6][3] = {
// Cost, Start Index, Count
diff --git a/src/koopatlas/shop.h b/src/koopatlas/shop.h
index 719a087..304154a 100644
--- a/src/koopatlas/shop.h
+++ b/src/koopatlas/shop.h
@@ -2,8 +2,9 @@
#define __KOOPATLAS_SHOP_H
#include "koopatlas/core.h"
+#include "texmapcolouriser.h"
-class dWMShop_c : public dBase_c {
+class dWMShop_c : public dActor_c {
public:
static dWMShop_c *build();
static dWMShop_c *instance;
@@ -56,6 +57,11 @@ class dWMShop_c : public dBase_c {
*CoinCount, *CoinCountShadow,
*BackText, *BuyText;
+ nw4r::lyt::Picture
+ *BtnLeft[6], *BtnMid[6], *BtnRight[6];
+
+ dTexMapColouriser_c leftCol, midCol, rightCol;
+
class ShopModel_c {
public:
mHeapAllocator_c allocator;
@@ -64,7 +70,7 @@ class dWMShop_c : public dBase_c {
m3d::mdl_c model;
m3d::anmChr_c animation;
- float x, y;
+ float x, y, scaleFactor;
void setupItem(float x, float y, ItemTypes type);
void setupLakitu(int id);
@@ -78,6 +84,7 @@ class dWMShop_c : public dBase_c {
void show(int shopNumber);
+ void loadInfo();
void loadModels();
void deleteModels();
diff --git a/src/texmapcolouriser.cpp b/src/texmapcolouriser.cpp
new file mode 100644
index 0000000..1aa2d7c
--- /dev/null
+++ b/src/texmapcolouriser.cpp
@@ -0,0 +1,142 @@
+#include "texmapcolouriser.h"
+
+dTexMapColouriser_c::dTexMapColouriser_c() {
+ texmap = 0;
+ original = 0;
+ mine = 0;
+}
+
+void *EGG__Heap__alloc(unsigned long size, int unk, void *heap);
+void EGG__Heap__free(void *ptr, void *heap);
+
+dTexMapColouriser_c::~dTexMapColouriser_c() {
+ resetAndClear();
+}
+
+void dTexMapColouriser_c::resetAndClear() {
+ texmap = 0;
+ if (mine) {
+ EGG__Heap__free(mine, 0);
+ mine = 0;
+ }
+}
+
+void dTexMapColouriser_c::setTexMap(nw4r::lyt::TexMap *tm) {
+ OSReport("Colourising TexMap: %p (w:%d h:%d)\n", tm, tm->width, tm->height);
+ if (texmap)
+ resetAndClear();
+
+ if (tm->mBits.textureFormat != GX_TF_IA8) {
+ OSReport("Warning: Trying to colourise image whose format is %d not GX_TF_IA8\n", tm->mBits.textureFormat);
+ }
+
+ texmap = tm;
+ original = (u16*)tm->image;
+ mine = (u16*)EGG__Heap__alloc(tm->width * tm->height * 4, 0x20, mHeap::gameHeaps[2]);
+ tm->image = mine;
+ tm->mBits.textureFormat = GX_TF_RGBA8;
+}
+
+void dTexMapColouriser_c::applyAlso(nw4r::lyt::TexMap *tm) {
+ if (!texmap) {
+ setTexMap(tm);
+ } else {
+ tm->image = mine;
+ tm->mBits.textureFormat = GX_TF_RGBA8;
+ }
+}
+
+inline static float hslValue(float n1, float n2, float hue) {
+ if (hue > 6.0f)
+ hue -= 6.0f;
+ else if (hue < 0.0f)
+ hue += 6.0f;
+
+ if (hue < 1.0f)
+ return n1 + (n2 - n1) * hue;
+ else if (hue < 3.0f)
+ return n2;
+ else if (hue < 4.0f)
+ return n1 + (n2 - n1) * (4.0f - hue);
+ else
+ return n1;
+}
+
+void dTexMapColouriser_c::colourise(int h, int s, int l) {
+ if (!mine)
+ return;
+
+ int width = texmap->width, height = texmap->height;
+ int texelW = width / 4, texelH = height / 4;
+
+ u16 *source = original, *dest = mine;
+
+ float hueParam = h / 360.0f;
+ float satParam = s / 100.0f;
+ float lumParam = l / 100.0f;
+
+ for (int texelY = 0; texelY < texelH; texelY++) {
+ for (int texelX = 0; texelX < texelW; texelX++) {
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ u8 intensity = *source & 0xFF;
+ u8 alpha = *source >> 8;
+
+ u8 r, g, b;
+
+ // This is a hack
+ if (alpha < 250) {
+ r = g = b = intensity;
+ } else {
+ // converting from GIMP's colourise code...
+ // h and s are always the same
+ // l is the only thing we need to touch:
+ // we get the luminance from the source pixel
+ // (which, conveniently, is the intensity)
+ // manipulate it using the passed l and then
+ // convert the whole thing to RGB
+
+ float lum = intensity / 255.0f;
+
+ // manipulate it
+ if (l > 0) {
+ lum = lum * (1.0f - lumParam);
+ lum += (1.0f - (1.0f - lumParam));
+ } else if (l < 0) {
+ lum = lum * (lumParam + 1.0f);
+ }
+
+ // make it RGB
+
+ if (s == 0) {
+ r = g = b = lum*255.0f;
+ } else {
+ float m1, m2;
+ if (lum <= 0.5f)
+ m2 = lum * (1.0f + satParam);
+ else
+ m2 = lum + satParam - lum * satParam;
+
+ m1 = 2.0f * lum - m2;
+
+ r = hslValue(m1, m2, hueParam * 6.0f + 2.0) * 255.0f;
+ g = hslValue(m1, m2, hueParam * 6.0f) * 255.0f;
+ b = hslValue(m1, m2, hueParam * 6.0f - 2.0) * 255.0f;
+ }
+ }
+
+ // now write it
+ dest[0] = (alpha<<8)|r;
+ dest[16] = (g<<8)|b;
+
+ source++;
+ dest++;
+ }
+ }
+
+ dest += 16;
+ }
+ }
+}
+
+
diff --git a/src/texmapcolouriser.h b/src/texmapcolouriser.h
new file mode 100644
index 0000000..22d5d25
--- /dev/null
+++ b/src/texmapcolouriser.h
@@ -0,0 +1,22 @@
+#ifndef TEXMAPCOLOURISER_H
+#define TEXMAPCOLOURISER_H
+#include <game.h>
+
+// Colourises an IA8 texture
+class dTexMapColouriser_c {
+ public:
+ dTexMapColouriser_c();
+ ~dTexMapColouriser_c();
+
+ void resetAndClear();
+ void setTexMap(nw4r::lyt::TexMap *tm);
+ void applyAlso(nw4r::lyt::TexMap *tm);
+ void colourise(int h, int s, int l);
+
+ private:
+ nw4r::lyt::TexMap *texmap;
+ u16 *original;
+ u16 *mine;
+};
+
+#endif /* TEXMAPCOLOURISER_H */