diff --git a/src/gamedata/items/items.cpp b/src/gamedata/items/items.cpp index 988131d..47059d5 100644 --- a/src/gamedata/items/items.cpp +++ b/src/gamedata/items/items.cpp @@ -90,6 +90,23 @@ void showItemPopup(const std::pair &item) } } }; + static float windowWidth = 1.6f; + static float windowHeight = 2.0f; + static float windowDepth = 0.12f; + static float windowFrameWidth = 0.2f; + ImGui::Text("Windows tools..."); + char windowStyleName[32] = { 0 }; + ImGui::InputFloat("windowWidth", &windowWidth); + ImGui::InputFloat("windowHeight", &windowHeight); + ImGui::InputFloat("windowDepth", &windowDepth); + ImGui::InputFloat("windowFrameWidth", &windowFrameWidth); + if (ImGui::InputText("windowStyleAdd", windowStyleName, + sizeof(windowStyleName))) { + } + if (ImGui::SmallButton("Add")) { + } + + ImGui::Separator(); buttonGroup(buttons_large, sizeof(buttons_large) / sizeof(buttons_large[0])); buttonGroup(buttons_small, diff --git a/src/gamedata/items/items.h b/src/gamedata/items/items.h index ad65087..48654e3 100644 --- a/src/gamedata/items/items.h +++ b/src/gamedata/items/items.h @@ -72,6 +72,13 @@ static void to_json(nlohmann::json &j, const Ogre::Quaternion &orientation) j["y"] = orientation.y; j["z"] = orientation.z; } +static void to_json(nlohmann::json &j, const Ogre::ColourValue &colour) +{ + j["r"] = colour.r; + j["g"] = colour.g; + j["b"] = colour.b; + j["a"] = colour.a; +} static void from_json(const nlohmann::json &j, Ogre::Vector3 &position) { position.x = j["x"].get(); @@ -85,5 +92,12 @@ static void from_json(const nlohmann::json &j, Ogre::Quaternion &orientation) orientation.y = j["y"].get(); orientation.z = j["z"].get(); } +static void from_json(const nlohmann::json &j, Ogre::ColourValue &colour) +{ + colour.r = j["r"].get(); + colour.g = j["g"].get(); + colour.b = j["b"].get(); + colour.a = j["a"].get(); +} } #endif diff --git a/src/gamedata/items/town.cpp b/src/gamedata/items/town.cpp index a2517c3..faa0030 100644 --- a/src/gamedata/items/town.cpp +++ b/src/gamedata/items/town.cpp @@ -532,21 +532,51 @@ struct CellsScript { std::vector > roomEdge(int room) { std::vector > seg; + std::set > seen; int i; + if (rooms[room].sizeX <= 0 || rooms[room].sizeZ <= 0) + goto out; + else if (rooms[room].sizeX == 1 && rooms[room].sizeZ == 1) { + seg.push_back({ rooms[room].minX, rooms[room].minZ }); + goto out; + } else if (rooms[room].sizeZ == 1) { + for (i = 0; i < rooms[room].sizeX; i++) { + seg.push_back({ rooms[room].minX + i, + rooms[room].minZ }); + } + goto out; + } else if (rooms[room].sizeX == 1) { + for (i = 0; i < rooms[room].sizeZ; i++) { + seg.push_back({ rooms[room].minX, + rooms[room].minZ + i }); + } + goto out; + } + for (i = 0; i < rooms[room].sizeX; i++) { - seg.push_back( - { rooms[room].minX + i, rooms[room].minZ }); - seg.push_back( + // filling values for minZ == 0 + // starting with X = 0 + seen.insert({ rooms[room].minX + i, rooms[room].minZ }); + } + for (i = 0; i < rooms[room].sizeZ; i++) { + // zero part is laready filled + seen.insert({ rooms[room].minX, rooms[room].minZ + i }); + } + for (i = 0; i < rooms[room].sizeX; i++) { + seen.insert( { rooms[room].minX + i, rooms[room].minZ + rooms[room].sizeZ - 1 }); } for (i = 0; i < rooms[room].sizeZ; i++) { - seg.push_back( - { rooms[room].minX, rooms[room].minZ + i }); - seg.push_back( - { rooms[room].minX + rooms[room].sizeZ - 1, - rooms[room].minZ + i }); + seen.insert({ rooms[room].minX + rooms[room].sizeX - 1, + rooms[room].minZ + i }); } + for (auto &cell : seen) + seg.push_back(cell); +out: + dumpSeg(seg); + OgreAssert(seg.size() <= rooms[room].sizeX * rooms[room].sizeZ, + "bad edge returned"); return seg; } bool adjacent(std::pair c1, std::pair c2) @@ -555,6 +585,15 @@ struct CellsScript { int dz = std::abs(c1.second - c2.second); return (dx == 0 && dz == 1) || (dx == 1 && dz == 0); } + void dumpSeg(const std::vector > &seg) + { + int count = 0; + for (auto &cell : seg) { + std::cout << count << " " << cell.first << " " + << cell.second << std::endl; + count++; + } + } void adjacentCells(int room, int other, std::vector > &ret1, std::vector > &ret2) @@ -562,6 +601,10 @@ struct CellsScript { std::vector > room_seg = roomEdge(room); std::vector > other_seg = roomEdge(other); std::vector > ret; + std::cout << "main: " << std::endl; + dumpSeg(room_seg); + std::cout << "other: " << std::endl; + dumpSeg(other_seg); for (auto &cell : room_seg) for (auto &ocell : other_seg) { if (adjacent(cell, ocell)) { @@ -804,7 +847,11 @@ struct CellsScript { void connectRooms(int r1, int r2) { std::vector > seg1, seg2; + int index = 0; adjacentCells(r1, r2, seg1, seg2); + OgreAssert(seg1.size() == seg2.size(), "bad edges"); + if (seg1.size() == 0 || seg2.size() == 0) + return; for (auto &cell : seg1) { std::cout << "seg1: " << cell.first << " " << cell.second << std::endl; @@ -813,31 +860,36 @@ struct CellsScript { std::cout << "seg2: " << cell.first << " " << cell.second << std::endl; } - if (seg1.size() == 0 || seg2.size() == 0) - return; - int sumX = 0, sumZ = 0; - int count = 0; - for (count = 0; count < seg1.size(); count++) { - sumX += seg1[count].first; - sumZ += seg1[count].second; - } - sumX /= seg1.size(); - sumZ /= seg1.size(); - int distance = -1; - int index = -1; - for (count = 0; count < seg1.size(); count++) { - int mdx = seg1[count].first - sumX; - int mdz = seg1[count].second - sumZ; - if (count == 0) { - index = 0; - distance = mdx * mdx + mdz * mdz; - } else { - if (distance > mdx * mdx + mdz * mdz) { + if (seg1.size() > 1) { + int sumX = 0, sumZ = 0; + int count = 0; + // find average point of first room cells + for (count = 0; count < seg1.size(); count++) { + sumX += seg1[count].first; + sumZ += seg1[count].second; + } + sumX /= seg1.size(); + sumZ /= seg1.size(); + // find closest point to average; + int distance = -1; + for (count = 0; count < seg1.size(); count++) { + int mdx = seg1[count].first - sumX; + int mdz = seg1[count].second - sumZ; + if (count == 0) { + index = 0; distance = mdx * mdx + mdz * mdz; - index = count; + } else { + if (distance > mdx * mdx + mdz * mdz) { + distance = + mdx * mdx + mdz * mdz; + index = count; + } } } - } + } else + index = 0; + OgreAssert(adjacent(seg1[index], seg2[index]), + "connected points are not adjacent!"); int dx = seg1[index].first - seg2[index].first; int dz = seg1[index].second - seg2[index].second; std::cout << dx << " " << dz << std::endl; @@ -848,43 +900,55 @@ struct CellsScript { OgreAssert(std::abs(dx) == 1 && dz == 0 || dx == 0 && std::abs(dz) == 1, "shit happens"); + std::cout << "points: " << seg1[index].first << " " + << seg1[index].second << " "; + std::cout << seg2[index].first << " " << seg2[index].second + << std::endl; if (dz < 0) { currentX = seg1[index].first; currentZ = seg1[index].second; + OgreAssert(isBit("iwallz+"), "bad bit"); bitCmd("clear", "iwallz+"); bitCmd("set", "idoorz+"); currentX = seg2[index].first; currentZ = seg2[index].second; + OgreAssert(isBit("iwallz-"), "bad bit"); bitCmd("clear", "iwallz-"); bitCmd("set", "idoorz-"); } if (dz > 0) { currentX = seg1[index].first; currentZ = seg1[index].second; + OgreAssert(isBit("iwallz-"), "bad bit"); bitCmd("clear", "iwallz-"); bitCmd("set", "idoorz-"); currentX = seg2[index].first; currentZ = seg2[index].second; + OgreAssert(isBit("iwallz+"), "bad bit"); bitCmd("clear", "iwallz+"); bitCmd("set", "idoorz+"); } if (dx < 0) { currentX = seg1[index].first; currentZ = seg1[index].second; + OgreAssert(isBit("iwallx+"), "bad bit"); bitCmd("clear", "iwallx+"); bitCmd("set", "idoorx+"); currentX = seg2[index].first; currentZ = seg2[index].second; + OgreAssert(isBit("iwallx-"), "bad bit"); bitCmd("clear", "iwallx-"); bitCmd("set", "idoorx-"); } if (dx > 0) { currentX = seg1[index].first; currentZ = seg1[index].second; + OgreAssert(isBit("iwallx-"), "bad bit"); bitCmd("clear", "iwallx-"); bitCmd("set", "idoorx-"); currentX = seg2[index].first; currentZ = seg2[index].second; + OgreAssert(isBit("iwallx+"), "bad bit"); bitCmd("clear", "iwallx+"); bitCmd("set", "idoorx+"); } @@ -914,6 +978,141 @@ struct CellsScript { std::cout << "Running script OK" << std::endl; } }; +bool editRoofs(const Ogre::String &lotLabel, nlohmann::json &lot) +{ + bool changed = false; + static int roofPosition[3] = { 0, 0 }; + static int roofSize[2] = { 1, 1 }; + static float roofOffset[3] = { 0, 0, 0 }; + static float baseHeight = 0.5f; + static float maxHeight = 0.5f; + static int roofType = 0; + const char *items[] = { "Flat", "Normal", "Normal2", "Cone", + "Cylinder" }; + nlohmann::json roofs = nlohmann::json::array(); + if (lot.find("roofs") != lot.end()) + roofs = lot["roofs"]; + Ogre::String addNewLabel = lotLabel + "_AddNewRoof"; + ImGui::Text("Roofs"); + ImGui::Separator(); + ImGui::SeparatorText("in cell sizes"); + int roofCount = 0; + for (auto &roof : roofs) { + Ogre::String roofLabel = + lotLabel + "_" + + Ogre::StringConverter::toString(roofCount); + ImGui::Text("roof - %d", roofCount); + int mroofType = roof["type"].get(); + int mroofPosition[3]; + int mroofSize[2]; + float mroofOffset[3]; + float mbaseHeight, mmaxHeight; + mroofPosition[0] = roof["position_x"].get(); + mroofPosition[1] = roof["position_y"].get(); + mroofPosition[2] = roof["position_z"].get(); + mroofSize[0] = roof["size_x"].get(); + mroofSize[1] = roof["size_z"].get(); + mroofOffset[0] = roof["offset_x"].get(); + mroofOffset[1] = roof["offset_y"].get(); + mroofOffset[2] = roof["offset_z"].get(); + mbaseHeight = roof["base_height"].get(); + mmaxHeight = roof["max_height"].get(); + if (ImGui::Combo(("Roof Type##" + lotLabel).c_str(), &mroofType, + items, IM_ARRAYSIZE(items))) + changed = true; + if (ImGui::SliderInt(("Roof Position X##" + lotLabel).c_str(), + &mroofPosition[0], -100, 100)) + changed = true; + if (ImGui::SliderInt(("Roof Position Y##" + lotLabel).c_str(), + &mroofPosition[1], -100, 100)) + changed = true; + if (ImGui::SliderInt(("Roof Position Z##" + lotLabel).c_str(), + &mroofPosition[2], -100, 100)) + changed = true; + if (ImGui::SliderInt(("Roof Size X##" + lotLabel).c_str(), + &mroofSize[0], 1, 50)) + changed = true; + if (ImGui::SliderInt(("Roof Size Z##" + lotLabel).c_str(), + &mroofSize[1], 1, 50)) + changed = true; + if (ImGui::SliderFloat(("Roof Offset X##" + lotLabel).c_str(), + &mroofOffset[0], -10.0f, 10.0f)) + changed = true; + if (ImGui::SliderFloat(("Roof Offset Y##" + lotLabel).c_str(), + &mroofOffset[1], -10.0f, 10.0f)) + changed = true; + if (ImGui::SliderFloat(("Roof Offset Z##" + lotLabel).c_str(), + &mroofOffset[2], -10.0f, 10.0f)) + changed = true; + if (ImGui::SliderFloat(("Roof Base Height##" + lotLabel).c_str(), + &mbaseHeight, 0.1f, 100.0f)) + changed = true; + mmaxHeight = Ogre::Math::Clamp(mmaxHeight, mbaseHeight, 100.0f); + if (ImGui::SliderFloat(("Roof Max Height##" + lotLabel).c_str(), + &mmaxHeight, 0.1f, 100.0f)) + changed = true; + if (changed) { + roof["type"] = mroofType; + roof["position_x"] = mroofPosition[0]; + roof["position_y"] = mroofPosition[1]; + roof["position_z"] = mroofPosition[2]; + roof["size_x"] = mroofSize[0]; + roof["size_z"] = mroofSize[1]; + roof["offset_x"] = mroofOffset[0]; + roof["offset_y"] = mroofOffset[1]; + roof["offset_z"] = mroofOffset[2]; + roof["base_height"] = mbaseHeight; + roof["max_height"] = mmaxHeight; + } + if (ImGui::SmallButton(("Delete##" + roofLabel).c_str())) { + roofs.erase(roofCount); + changed = true; + break; + } + roofCount++; + } + ImGui::Combo(("Roof Type##" + addNewLabel).c_str(), &roofType, items, + IM_ARRAYSIZE(items)); + ImGui::SliderInt(("Roof Position X##" + addNewLabel).c_str(), + &roofPosition[0], -100, 100); + ImGui::SliderInt(("Roof Position Y##" + addNewLabel).c_str(), + &roofPosition[1], 0, 100); + ImGui::SliderInt(("Roof Position Z##" + addNewLabel).c_str(), + &roofPosition[2], -100, 100); + ImGui::SliderInt(("Roof Size X##" + addNewLabel).c_str(), &roofSize[0], + 1, 50); + ImGui::SliderInt(("Roof Size Z##" + addNewLabel).c_str(), &roofSize[1], + 1, 50); + ImGui::SliderFloat(("Roof Offset X##" + addNewLabel).c_str(), + &roofOffset[0], -10.0f, 10.0f); + ImGui::SliderFloat(("Roof Offset Y##" + addNewLabel).c_str(), + &roofOffset[1], -10.0f, 10.0f); + ImGui::SliderFloat(("Roof Offset Z##" + addNewLabel).c_str(), + &roofOffset[2], -10.0f, 10.0f); + ImGui::SliderFloat(("Roof Base Height##" + addNewLabel).c_str(), + &baseHeight, 0.1f, 100.0f); + ImGui::SliderFloat(("Roof Max Height##" + addNewLabel).c_str(), + &maxHeight, 0.1f, 100.0f); + if (ImGui::SmallButton(("Add##" + addNewLabel).c_str())) { + nlohmann::json roof; + roof["type"] = roofType; + roof["position_x"] = roofPosition[0]; + roof["position_y"] = roofPosition[1]; + roof["position_z"] = roofPosition[2]; + roof["size_x"] = roofSize[0]; + roof["size_z"] = roofSize[1]; + roof["offset_x"] = roofOffset[0]; + roof["offset_y"] = roofOffset[1]; + roof["offset_z"] = roofOffset[2]; + roof["base_height"] = baseHeight; + roof["max_height"] = maxHeight; + roofs.push_back(roof); + changed = true; + } + if (changed) + lot["roofs"] = roofs; + return changed; +} bool editLot(const Ogre::String &lotLabel, nlohmann::json &lot) { bool changed = false; @@ -964,96 +1163,118 @@ bool editLot(const Ogre::String &lotLabel, nlohmann::json &lot) } for (const auto &cell : lot["cells"]) cells.push_back(cell); - if (cells.size() == 0) { - Ogre::String createCellsLabel = "Create cells...##" + lotLabel; - if (ImGui::SmallButton(createCellsLabel.c_str())) { - nlohmann::json cell; - cell["x"] = 0; - cell["y"] = 0; - cell["z"] = 0; - cell["flags"] = 0U; - cell["id"] = makeCellKey(cell); - lot["cells"].push_back(cell); - changed = true; - } - } else { - int cellCount = 0; - for (auto &cell : cells) { - Ogre::String cellLabel = - lotLabel + "cell" + - Ogre::StringConverter::toString(cellCount); - ImGui::Text("x = %d", cell["x"].get()); - ImGui::Text("y = %d", cell["y"].get()); - ImGui::Text("z = %d", cell["z"].get()); - ImGui::Text("flags = %016lx", - cell["flags"].get()); - changed = changed || editCell(cellLabel, cell); - ImGui::Separator(); - auto makeCreateButton = [&](const Ogre::String &label, - int offsetX, int offsetY, - int offsetZ) { - if (ImGui::SmallButton(label.c_str())) { - int currentX = cell["x"].get(); - int currentY = cell["y"].get(); - int currentZ = cell["z"].get(); - nlohmann::json newcell; - newcell["x"] = currentX + offsetX; - newcell["y"] = currentY + offsetY; - newcell["z"] = currentZ + offsetZ; - newcell["flags"] = 0U; - bool ok = true; - for (const auto &chk : cells) { - int64_t main_key = - makeCellKey(newcell); - int64_t chk_key = - makeCellKey(chk); - if (main_key == chk_key) { - ok = false; - break; - } - } - if (ok) { - newcell["id"] = - makeCellKey(newcell); - cells.push_back(newcell); - changed = true; - } - } - }; - struct CreateButtons { - Ogre::String label; - int x, y, z; - }; - struct CreateButtons cbuttons[] = { - { "NewX+##" + cellLabel, 1, 0, 0 }, - { "NewX-##" + cellLabel, -1, 0, 0 }, - { "NewY+##" + cellLabel, 0, 1, 0 }, - { "NewY-##" + cellLabel, 0, -1, 0 }, - { "NewZ+##" + cellLabel, 0, 0, 1 }, - { "NewZ-##" + cellLabel, 0, 0, -1 }, - }; - int i; - for (i = 0; i < sizeof(cbuttons) / sizeof(cbuttons[0]); - i++) { - if (i > 0) - ImGui::SameLine(); - makeCreateButton(cbuttons[i].label, - cbuttons[i].x, cbuttons[i].y, - cbuttons[i].z); - } - Ogre::String cellDeleteLabel = "Delete##" + cellLabel; - - if (ImGui::SmallButton(cellDeleteLabel.c_str())) { - cells.erase(cellCount); + if (ImGui::CollapsingHeader(("Cells...##" + lotLabel).c_str())) { + if (cells.size() == 0) { + Ogre::String createCellsLabel = + "Create cells...##" + lotLabel; + if (ImGui::SmallButton(createCellsLabel.c_str())) { + nlohmann::json cell; + cell["x"] = 0; + cell["y"] = 0; + cell["z"] = 0; + cell["flags"] = 0U; + cell["id"] = makeCellKey(cell); + lot["cells"].push_back(cell); changed = true; } - if (changed) { - lot["cells"] = cells; - break; + } else { + int cellCount = 0; + for (auto &cell : cells) { + Ogre::String cellLabel = + lotLabel + "cell" + + Ogre::StringConverter::toString( + cellCount); + ImGui::Text("x = %d", cell["x"].get()); + ImGui::Text("y = %d", cell["y"].get()); + ImGui::Text("z = %d", cell["z"].get()); + ImGui::Text("flags = %016lx", + cell["flags"].get()); + changed = changed || editCell(cellLabel, cell); + ImGui::Separator(); + auto makeCreateButton = [&](const Ogre::String + &label, + int offsetX, + int offsetY, + int offsetZ) { + if (ImGui::SmallButton(label.c_str())) { + int currentX = + cell["x"].get(); + int currentY = + cell["y"].get(); + int currentZ = + cell["z"].get(); + nlohmann::json newcell; + newcell["x"] = + currentX + offsetX; + newcell["y"] = + currentY + offsetY; + newcell["z"] = + currentZ + offsetZ; + newcell["flags"] = 0U; + bool ok = true; + for (const auto &chk : cells) { + int64_t main_key = + makeCellKey( + newcell); + int64_t chk_key = + makeCellKey( + chk); + if (main_key == + chk_key) { + ok = false; + break; + } + } + if (ok) { + newcell["id"] = + makeCellKey( + newcell); + cells.push_back( + newcell); + changed = true; + } + } + }; + struct CreateButtons { + Ogre::String label; + int x, y, z; + }; + struct CreateButtons cbuttons[] = { + { "NewX+##" + cellLabel, 1, 0, 0 }, + { "NewX-##" + cellLabel, -1, 0, 0 }, + { "NewY+##" + cellLabel, 0, 1, 0 }, + { "NewY-##" + cellLabel, 0, -1, 0 }, + { "NewZ+##" + cellLabel, 0, 0, 1 }, + { "NewZ-##" + cellLabel, 0, 0, -1 }, + }; + int i; + for (i = 0; + i < sizeof(cbuttons) / sizeof(cbuttons[0]); + i++) { + if (i > 0) + ImGui::SameLine(); + makeCreateButton(cbuttons[i].label, + cbuttons[i].x, + cbuttons[i].y, + cbuttons[i].z); + } + Ogre::String cellDeleteLabel = + "Delete##" + cellLabel; + + if (ImGui::SmallButton( + cellDeleteLabel.c_str())) { + cells.erase(cellCount); + changed = true; + } + if (changed) { + lot["cells"] = cells; + break; + } + cellCount++; } - cellCount++; } } + changed = changed || editRoofs(lotLabel, lot); return changed; } bool editDistrict(const Ogre::String &districtLabel, nlohmann::json &district) @@ -1110,6 +1331,105 @@ bool editDistrict(const Ogre::String &districtLabel, nlohmann::json &district) } return changed; } +bool editColorRects(nlohmann::json &rects) +{ + bool changed = false; + ImGui::Text("Color Rects"); + for (auto it = rects.begin(); it != rects.end(); it++) { + Ogre::String key = it.key(); + ImGui::Text("%s", key.c_str()); + float left = 0.0f, top = 0.0f, right = 0.1f, bottom = 0.1f; + nlohmann::json nrect = it.value(); + left = nrect["left"].get(); + top = nrect["top"].get(); + right = nrect["right"].get(); + bottom = nrect["bottom"].get(); + float ccolor[4] = { 0, 0, 0, 1 }; + Ogre::ColourValue colour; + from_json(nrect["color"], colour); + ccolor[0] = colour.r; + ccolor[1] = colour.g; + ccolor[2] = colour.b; + ccolor[3] = colour.a; + if (ImGui::InputFloat(("left##" + key).c_str(), &left)) + changed = true; + if (ImGui::InputFloat(("top##" + key).c_str(), &top)) + changed = true; + if (ImGui::InputFloat(("right##" + key).c_str(), &right)) + changed = true; + if (ImGui::InputFloat(("bottom##" + key).c_str(), &bottom)) + changed = true; + if (ImGui::ColorPicker4(("Color##" + key).c_str(), ccolor)) + changed = true; + if (changed) { + left = Ogre::Math::Clamp(left, 0.0f, 1.0f); + top = Ogre::Math::Clamp(top, 0.0f, 1.0f); + right = Ogre::Math::Clamp(right, left, 1.0f); + bottom = Ogre::Math::Clamp(bottom, top, 1.0f); + nrect["left"] = left; + nrect["top"] = top; + nrect["right"] = right; + nrect["bottom"] = bottom; + colour.r = ccolor[0]; + colour.g = ccolor[1]; + colour.b = ccolor[2]; + colour.a = ccolor[3]; + to_json(nrect["color"], colour); + rects[key] = nrect; + } + } + if (rects.size() > 0) + ImGui::Separator(); + { + static char colorName[64] = { 0 }; + static float left = 0.0f, top = 0.0f, right = 0.1f, + bottom = 0.1f; + ImGui::InputText("New color rect", colorName, + sizeof(colorName)); + ImGui::InputFloat("left##New_Color_Rect", &left); + ImGui::InputFloat("top##New_Color_Rect", &top); + ImGui::InputFloat("right##New_Color_Rect", &right); + ImGui::InputFloat("bottom##New_Color_Rect", &bottom); + left = Ogre::Math::Clamp(left, 0.0f, 1.0f); + top = Ogre::Math::Clamp(top, 0.0f, 1.0f); + right = Ogre::Math::Clamp(right, left, 1.0f); + bottom = Ogre::Math::Clamp(bottom, top, 1.0f); + static float ccolor[4] = { 0, 0, 0, 1 }; + ImGui::ColorPicker4("Color##New_Color_Rect", ccolor); + ImGui::Text("%f %f %f %f", ccolor[0], ccolor[1], ccolor[2], + ccolor[3]); + bool valid = true; + if (right - left <= 0.0f || bottom - top <= 0.0f) + valid = false; + if (strlen(colorName) == 0) + valid = false; + + if (ImGui::SmallButton("Create##New_Color_Rect")) { + Ogre::ColourValue newColour; + newColour.r = ccolor[0]; + newColour.g = ccolor[1]; + newColour.b = ccolor[2]; + newColour.a = ccolor[3]; + Ogre::String sColorName(colorName); + if (valid) { + nlohmann::json nrect; + nrect["left"] = left; + nrect["top"] = top; + nrect["right"] = right; + nrect["bottom"] = bottom; + to_json(nrect["color"], newColour); + rects[sColorName] = nrect; + changed = true; + } + ccolor[0] = 0; + ccolor[1] = 0; + ccolor[2] = 0; + ccolor[3] = 1; + strcpy(colorName, ""); + } + } + return changed; +} void createTownPopup(const std::pair item) { Ogre::String prop = StaticGeometryModule::getItemProperties(item.first); @@ -1121,6 +1441,11 @@ void createTownPopup(const std::pair item) bool changed = false; int count = 0; ImGui::Text("Town"); + nlohmann::json colorRects = nlohmann::json::object(); + if (j.find("colorRects") != j.end()) + colorRects = j["colorRects"]; + changed = changed || editColorRects(colorRects); + ImGui::Separator(); nlohmann::json districts = nlohmann::json::array(); for (auto &district : j["districts"]) districts.push_back(district); @@ -1163,42 +1488,73 @@ void createTownPopup(const std::pair item) ImGui::Text("%s", j.dump(4).c_str()); if (changed) { j["districts"] = districts; + j["colorRects"] = colorRects; StaticGeometryModule::setItemProperties(item.first, j.dump()); StaticGeometryModule::saveItems(); StaticGeometryModule::destroyItemGeometry(item.first); - StaticGeometryModule::createItemGeometry(item.first); + Geometry::createTownMaterial(item.first, true); + StaticGeometryModule::createItemGeometry(item.first); } } } namespace Geometry { -void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, - Ogre::StaticGeometry *geo) +void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb, + const Ogre::String &rectKey) { - std::cout << "createTown " << e.id() << std::endl; - Ogre::MaterialPtr townMaterial; - townMaterial = Ogre::MaterialManager::getSingleton().getByName( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id())); - if (!townMaterial) { - Procedural::TextureBuffer colorAtlas(1024); - Procedural::RectangleTexture drawAtlas(&colorAtlas); - Ogre::ColourValue normalYellow(0.8f, 0.6f, 0, 1); - Ogre::ColourValue roadBrown(0.4f, 0.3f, 0.3f, 1); - Ogre::ColourValue bollardGrey(0.2f, 0.2f, 0.2f, 1); + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + nlohmann::json colorRects = nlohmann::json::object(); + if (jp.find("colorRects") != jp.end()) + colorRects = jp["colorRects"]; + if (colorRects.find(rectKey) == colorRects.end()) + return; + float left = colorRects[rectKey]["left"].get(); + float right = colorRects[rectKey]["right"].get(); + float top = colorRects[rectKey]["top"].get(); + float bottom = colorRects[rectKey]["bottom"].get(); + float umul = (right - left) * 0.8f; + float vmul = (bottom - top) * 0.8f; + for (auto &v : tb.getVertices()) { + v.mUV.x *= umul; + v.mUV.y *= vmul; + v.mUV.x += left + 0.01f; + v.mUV.y += top + 0.01f; + v.mUV.x = Ogre::Math::Clamp(v.mUV.x, left, right); + v.mUV.y = Ogre::Math::Clamp(v.mUV.y, top, bottom); + } +} +Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force) +{ + Ogre::MaterialPtr townMaterial; + Ogre::String props = e.get().properties; + nlohmann::json jp = nlohmann::json::parse(props); + nlohmann::json colorRects = nlohmann::json::object(); + if (jp.find("colorRects") != jp.end()) + colorRects = jp["colorRects"]; + Ogre::String materialName = "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id()); + townMaterial = + Ogre::MaterialManager::getSingleton().getByName(materialName); + if (!townMaterial || force) { + Procedural::TextureBuffer colorAtlas(1024); + Procedural::RectangleTexture drawAtlas(&colorAtlas); + Ogre::ColourValue normalYellow(0.8f, 0.6f, 0, 1); + Ogre::ColourValue roadBrown(0.4f, 0.3f, 0.3f, 1); + Ogre::ColourValue bollardGrey(0.2f, 0.2f, 0.2f, 1); Ogre::ColourValue floorRed(0.5f, 0.2f, 0.2f, 1); Ogre::ColourValue ceilingWhite(0.8f, 0.8f, 0.85f, 1); Ogre::ColourValue wallYellow(0.8f, 0.6f, 0, 1); Ogre::ColourValue intwallBlue(0.6f, 0.6f, 0.8f, 1); drawAtlas.setRectangle(Ogre::RealRect(0.0f, 0.0f, 0.4f, 1.0f)) - .setColour(normalYellow) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.2f, 0.0f, 0.3f, 1.0f)) - .setColour(bollardGrey) - .process(); - drawAtlas.setRectangle(Ogre::RealRect(0.4f, 0.0f, 1.0f, 1.0f)) - .setColour(roadBrown) - .process(); + .setColour(normalYellow) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.2f, 0.0f, 0.3f, 1.0f)) + .setColour(bollardGrey) + .process(); + drawAtlas.setRectangle(Ogre::RealRect(0.4f, 0.0f, 1.0f, 1.0f)) + .setColour(roadBrown) + .process(); drawAtlas.setRectangle(Ogre::RealRect(0.5f, 0.0f, 0.6f, 0.1f)) .setColour(floorRed) .process(); @@ -1211,41 +1567,90 @@ void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, drawAtlas.setRectangle(Ogre::RealRect(0.8f, 0.0f, 0.9f, 0.1f)) .setColour(intwallBlue) .process(); - Ogre::TexturePtr pierTexture = colorAtlas.createTexture( - "proceduralTextureTown" + - Ogre::StringConverter::toString(e.id())); - colorAtlas.saveImage("tmp4.png"); - townMaterial = Ogre::MaterialManager::getSingletonPtr()->create( - "proceduralMaterialTown" + - Ogre::StringConverter::toString(e.id()), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - townMaterial->getTechnique(0)->getPass(0)->setShininess(0); - townMaterial->getTechnique(0)->getPass(0)->setDiffuse( - Ogre::ColourValue::White); - townMaterial->getTechnique(0)->getPass(0)->setSpecular( - Ogre::ColourValue(1.0f, 1.0f, 0.9f)); - townMaterial->getTechnique(0) - ->getPass(0) - ->createTextureUnitState( - "proceduralTextureTown" + - Ogre::StringConverter::toString(e.id())); - if (Ogre::RTShader::ShaderGenerator::initialize()) { - townMaterial->prepare(); - Ogre::RTShader::ShaderGenerator *mShaderGenerator = - Ogre::RTShader::ShaderGenerator:: - getSingletonPtr(); - mShaderGenerator->createShaderBasedTechnique( - *townMaterial, - Ogre::MaterialManager::DEFAULT_SCHEME_NAME, - Ogre::RTShader::ShaderGenerator:: - DEFAULT_SCHEME_NAME); - Ogre::RTShader::RenderState *pMainRenderState = - mShaderGenerator->getRenderState( - Ogre::RTShader::ShaderGenerator:: - DEFAULT_SCHEME_NAME, - *townMaterial); - } - } + for (auto it = colorRects.begin(); it != colorRects.end(); + it++) { + std::cout << it.key() << std::endl; + nlohmann::json rect = it.value(); + float left = rect["left"].get(); + float top = rect["top"].get(); + float right = rect["right"].get(); + float bottom = rect["bottom"].get(); + Ogre::ColourValue colour; + from_json(rect["color"], colour); + drawAtlas + .setRectangle(Ogre::RealRect(left, top, right, + bottom)) + .setColour(colour) + .process(); + } + Ogre::String textureName = + "proceduralTextureTown" + + Ogre::StringConverter::toString(e.id()); + Ogre::TexturePtr townTexture = + Ogre::TextureManager::getSingleton().getByName( + textureName); + if (townTexture) { + Ogre::TexturePtr newTownTexture = + colorAtlas.createTexture(textureName + "_copy"); + newTownTexture->copyToTexture(townTexture); + Ogre::TextureManager::getSingleton().remove( + newTownTexture); + } else + Ogre::TexturePtr townTexture = + colorAtlas.createTexture(textureName); + + colorAtlas.saveImage("tmp4.png"); + if (!townMaterial) { + townMaterial = + Ogre::MaterialManager::getSingletonPtr()->create( + "proceduralMaterialTown" + + Ogre::StringConverter::toString( + e.id()), + Ogre::ResourceGroupManager:: + DEFAULT_RESOURCE_GROUP_NAME); + townMaterial->getTechnique(0)->getPass(0)->setShininess( + 0); + townMaterial->getTechnique(0)->getPass(0)->setDiffuse( + Ogre::ColourValue::White); + townMaterial->getTechnique(0)->getPass(0)->setSpecular( + Ogre::ColourValue(1.0f, 1.0f, 0.9f)); + townMaterial->getTechnique(0) + ->getPass(0) + ->createTextureUnitState(textureName); + if (Ogre::RTShader::ShaderGenerator::initialize()) { + townMaterial->prepare(); + Ogre::RTShader::ShaderGenerator + *mShaderGenerator = + Ogre::RTShader::ShaderGenerator:: + getSingletonPtr(); + mShaderGenerator->createShaderBasedTechnique( + *townMaterial, + Ogre::MaterialManager::DEFAULT_SCHEME_NAME, + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME); + Ogre::RTShader::RenderState *pMainRenderState = + mShaderGenerator->getRenderState( + Ogre::RTShader::ShaderGenerator:: + DEFAULT_SCHEME_NAME, + *townMaterial); + } + } else { +#if 0 + Ogre::TextureUnitState *state = + townMaterial->getTechnique(0) + ->getPass(0) + ->getTextureUnitState(textureName); + state-> +#endif + } + } + return townMaterial; +} +void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + std::cout << "createTown " << e.id() << std::endl; + Ogre::MaterialPtr townMaterial = createTownMaterial(e); { Ogre::String props = e.get().properties; nlohmann::json jp = nlohmann::json::parse(props); @@ -1257,6 +1662,7 @@ void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, createTownPlazza(e, jdistrict, index, sceneNode, geo); createTownLots(e, jdistrict, index, sceneNode, geo); createCells(e, jdistrict, index, sceneNode, geo); + createTownRoofs(e, jdistrict, index, sceneNode, geo); index++; } } @@ -1850,8 +2256,8 @@ struct ProcessCells { } } } - void process(const Ogre::Vector3 &cellOffset, uint64_t flags, - Procedural::TriangleBuffer &cellTb, + void process(flecs::entity e, const Ogre::Vector3 &cellOffset, + uint64_t flags, Procedural::TriangleBuffer &cellTb, Procedural::TriangleBuffer &intwinTb, Procedural::TriangleBuffer &exteriorTb) { @@ -1859,14 +2265,14 @@ struct ProcessCells { const Ogre::Vector3 &normal, const Ogre::Vector3 offset, Procedural::TriangleBuffer &tb) { - int nsegY = 8; + int nsegY = 1; if (sizeY < 1.0f) - nsegY = 4; + nsegY = 1; Procedural::PlaneGenerator() .setNormal(normal) .setSizeX(sizeX) .setSizeY(sizeY) - .setNumSegX(8) + .setNumSegX(1) .setNumSegY(nsegY) .setEnableNormals(true) .setPosition(cellOffset + offset) @@ -1958,20 +2364,8 @@ struct ProcessCells { v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.7f, 0.8f); v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); } - for (auto &v : intwalltb.getVertices()) { - // light blue int wall color - v.mUV *= 0.08f; - v.mUV.x += 0.81f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.8f, 0.9f); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); - } - for (auto &v : intwindowstb.getVertices()) { - // light blue int wall color - v.mUV *= 0.08f; - v.mUV.x += 0.81f; - v.mUV.x = Ogre::Math::Clamp(v.mUV.x, 0.8f, 0.9f); - v.mUV.y = Ogre::Math::Clamp(v.mUV.y, 0.0f, 0.1f); - } + clampUV(e, intwalltb, "internalWalls"); + clampUV(e, intwindowstb, "internalWalls"); for (auto &tb : std::vector( { &floortb, &ceilingtb, &intwalltb })) { if ((*tb).getVertices().size() > 0) @@ -2068,7 +2462,7 @@ void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index, cellTb.append(pcells.floortb); } else - pcells.process(cellOffset, flags, + pcells.process(e, cellOffset, flags, cellTb, intwinTb, exteriorTb); } @@ -2280,5 +2674,659 @@ void createTownLots(flecs::entity e, const nlohmann::json &jdistrict, int index, count++; } } +void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo) +{ + Ogre::MaterialPtr townMaterial; + townMaterial = Ogre::MaterialManager::getSingleton().getByName( + "proceduralMaterialTown" + + Ogre::StringConverter::toString(e.id())); + nlohmann::json jlots = nlohmann::json::array(); + if (jdistrict.find("lots") != jdistrict.end()) + jlots = jdistrict["lots"]; + Ogre::Vector3 centerPosition = sceneNode->_getDerivedPosition(); + Ogre::Quaternion centerOrientation = + sceneNode->_getDerivedOrientation(); + int count = 0; + const nlohmann::json &jp = jdistrict; + Ogre::Vector3 localPosition(0, 0, 0); + Ogre::Quaternion localRotation = Ogre::Quaternion::IDENTITY; + float delevation = 0.0f; + float radius = 50.0f; + if (jp.find("elevation") != jp.end()) + delevation = jp["elevation"].get(); + if (jp.find("radius") != jp.end()) + radius = jp["radius"].get(); + from_json(jp["position"], localPosition); + from_json(jp["rotation"], localRotation); + centerPosition = centerPosition + localPosition + + Ogre::Vector3(0, delevation, 0); + centerOrientation = centerOrientation * localRotation; + for (const auto &jb : jlots) { + Procedural::TriangleBuffer tb; + Procedural::TriangleBuffer tbTop; + Procedural::TriangleBuffer tbSide; + float angle = 0.0f; + int depth = 10; + int width = 10; + float distance = radius; + float elevation = 0.0f; + std::cout << jb.dump() << std::endl; + if (jb.find("angle") != jb.end()) + angle = jb["angle"].get(); + if (jb.find("depth") != jb.end()) + depth = jb["depth"].get(); + if (jb.find("width") != jb.end()) + width = jb["width"].get(); + if (jb.find("elevation") != jb.end()) + elevation = jb["elevation"].get(); + + Ogre::Quaternion rotation = Ogre::Quaternion( + Ogre::Degree(angle), Ogre::Vector3::UNIT_Y); + Ogre::Vector3 offset = centerOrientation * rotation * + (Ogre::Vector3::UNIT_Z * distance); + Ogre::Vector3 worldCenterPosition = + centerPosition + offset + + Ogre::Vector3(0, elevation, 0); + Ogre::Quaternion worldCenterOrientation = + centerOrientation * rotation; + if (jb.find("roofs") != jb.end()) { + for (auto &jroof : jb["roofs"]) { + int roofType = jroof["type"].get(); + int position_x = jroof["position_x"].get(); + int position_y = jroof["position_y"].get(); + int position_z = jroof["position_z"].get(); + int width = jroof["size_x"].get(); + int depth = jroof["size_z"].get(); + float baseHeight = + jroof["base_height"].get(); + float maxHeight = + jroof["max_height"].get(); + float extend = 0.24f; + if (roofType == 0) { + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width) + .setSizeY(baseHeight) + .setSizeZ(2.0f * (float)depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbTop); + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width) + .setSizeY(baseHeight + + extend * 2.0f) + .setSizeZ(extend) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + extend, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f + + (float)depth * + 2.0f / + 2.0f + + extend / 2.0f)) + .addToTriangleBuffer(tbSide); + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width) + .setSizeY(baseHeight + + extend * 2.0f) + .setSizeZ(extend) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + extend, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f - + (float)depth * + 2.0f / + 2.0f - + extend / 2.0f)) + .addToTriangleBuffer(tbSide); + Procedural::BoxGenerator() + .setSizeX(extend) + .setSizeY(baseHeight + + extend * 2.0f) + .setSizeZ(2.0f * (float)depth + + extend * 2.0f) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f + + (float)width * + 2.0f / + 2.0f + + extend / 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + extend, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbSide); + Procedural::BoxGenerator() + .setSizeX(extend) + .setSizeY(baseHeight + + extend * 2.0f) + .setSizeZ(2.0f * (float)depth + + extend * 2.0f) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f - + (float)width * + 2.0f / + 2.0f - + extend / 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + extend, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbSide); + OgreAssert(tbTop.getVertices().size() > + 8, + "bad box"); + clampUV(e, tbTop, "roofTop"); + clampUV(e, tbSide, "roofSide"); + } else if (roofType == 1) { + float q = 2.0f * (float)width / 2.0f; + float m = 1.0f; + float d = 1.4142f * (q + m); +#if 0 + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width) + .setSizeY(baseHeight) + .setSizeZ(2.0f * (float)depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbTop); +#endif + Procedural::BoxGenerator() + .setSizeX(d) + .setSizeY(baseHeight / 2.0f) + .setSizeZ(2.0f * (float)depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(45), + Ogre::Vector3:: + NEGATIVE_UNIT_Z)) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)q + + q / 2.0f + + m / 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + q / 2.0f - + m / 2.0f + + baseHeight / + 4.0f, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbTop); + Procedural::BoxGenerator() + .setSizeX(d) + .setSizeY(baseHeight / 2.0f) + .setSizeZ(2.0f * (float)depth) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(-45), + Ogre::Vector3:: + NEGATIVE_UNIT_Z)) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + q / 2.0f - + m / 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + q / 2.0f - + m / 2.0f + + baseHeight / + 4.0f, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbTop); + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width + + extend * 2.0f) + .setSizeY(q + baseHeight * 2.5f) + .setSizeZ(extend) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + q, + (float)position_y * + 4.0f + + elevation + + q / 2.0f, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f + + (float)depth * + 2.0f / + 2.0f + + extend / 2.0f)) + .addToTriangleBuffer(tbSide); + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width + + extend * 2.0f) + .setSizeY(q + baseHeight * 2.5f) + .setSizeZ(extend) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + q, + (float)position_y * + 4.0f + + elevation + + q / 2.0f, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f - + (float)depth * + 2.0f / + 2.0f - + extend / 2.0f)) + .addToTriangleBuffer(tbSide); + float minY = 0.0f; + float maxY = 0.0f; + for (auto &v : tbSide.getVertices()) { + if (v.mPosition.y > maxY) + maxY = v.mPosition.y; + if (v.mPosition.y < minY) + minY = v.mPosition.y; + } + for (auto &v : tbSide.getVertices()) { + if (v.mPosition.x > 0) + v.mPosition.x += + maxY - + v.mPosition.y - + q; + else if (v.mPosition.x < 0) + v.mPosition.x -= + maxY - + v.mPosition.y - + q; + } + clampUV(e, tbTop, "roofTop"); + clampUV(e, tbSide, "roofSide"); + } else if (roofType == 2) { + float q = 2.0f * (float)depth / 2.0f; + float m = 1.0f; + float d = 1.4142f * (q + m); + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width) + .setSizeY(baseHeight / 2.0f) + .setSizeZ(d) + .setNumSegY(1) + .setNumSegX(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(45), + Ogre::Vector3:: + NEGATIVE_UNIT_X)) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + q / 2.0f - + m / 2.0f + + baseHeight / + 4.0f, + (float)position_z * + 2.0f - + 1.0f + + q / 2.0f - + m / 2.0f)) + .addToTriangleBuffer(tbTop); + Procedural::BoxGenerator() + .setSizeX(2.0f * (float)width) + .setSizeY(baseHeight / 2.0f) + .setSizeZ(d) + .setNumSegX(1) + .setNumSegY(1) + .setNumSegZ(1) + .setEnableNormals(true) + .setOrientation(Ogre::Quaternion( + Ogre::Degree(-45), + Ogre::Vector3:: + NEGATIVE_UNIT_X)) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f, + (float)position_y * + 4.0f + + baseHeight / + 2.0f + + elevation + + q / 2.0f - + m / 2.0f + + baseHeight / + 4.0f, + (float)position_z * + 2.0f - + 1.0f + q + + q / 2.0f + + m / 2.0f)) + .addToTriangleBuffer(tbTop); + Procedural::BoxGenerator() + .setSizeX(extend) + .setSizeY(q + baseHeight * 2.5f) + .setSizeZ(2.0f * (float)depth + + 2.0f * baseHeight * + 3.0f) + .setNumSegX(2) + .setNumSegY(2) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f + + (float)width * + 2.0f / + 2.0f + + extend / 2.0f, + (float)position_y * + 4.0f + + elevation + + q / 2.0f, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbSide); + Procedural::BoxGenerator() + .setSizeX(extend) + .setSizeY(q + baseHeight * 2.5f) + .setSizeZ(2.0f * (float)depth + + 2.0f * baseHeight * + 3.0f) + .setNumSegX(2) + .setNumSegY(2) + .setNumSegZ(1) + .setEnableNormals(true) + .setPosition(Ogre::Vector3( + (float)position_x * + 2.0f - + 1.0f + + (float)width * + 2.0f / + 2.0f - + (float)width * + 2.0f / + 2.0f - + extend / 2.0f, + (float)position_y * + 4.0f + + elevation + + q / 2.0f, + (float)position_z * + 2.0f - + 1.0f + + (float)depth * + 2.0f / + 2.0f)) + .addToTriangleBuffer(tbSide); + float minY = 0.0f; + float maxY = 0.0f; + float maxZ = 0.0f; + float minZ = 0.0f; + int count = 0; + for (auto &v : tbSide.getVertices()) { + if (count == 0) { + minY = v.mPosition.y; + maxY = v.mPosition.y; + minZ = v.mPosition.z; + maxZ = v.mPosition.z; + } else { + if (v.mPosition.y > + maxY) + maxY = v.mPosition + .y; + if (v.mPosition.y < + minY) + minY = v.mPosition + .y; + if (v.mPosition.z > + maxZ) + maxZ = v.mPosition + .z; + if (v.mPosition.z < + minZ) + minZ = v.mPosition + .z; + } + count++; + } + float midZ = + minZ + (maxZ - minZ) / 2.0f; + for (auto &v : tbSide.getVertices()) { + float md = maxY - v.mPosition.y; + float hm = v.mPosition.z - midZ; + float he = + (hm / ((maxZ - minZ) / + 2.0f)) * + md; + v.mPosition.z = he + midZ; +#if 0 + if (v.mPosition.z >= midZ) + v.mPosition.z = + midZ + + (maxY - + v.mPosition.y); + else if (v.mPosition.z < midZ) + v.mPosition.z = + midZ - + (maxY - + v.mPosition.y); +#endif + } + clampUV(e, tbTop, "roofTop"); + clampUV(e, tbSide, "roofSide"); + } + } + { + Ogre::String meshName = + "roofbase" + + Ogre::StringConverter::toString(count) + + "_" + + Ogre::StringConverter::toString( + e.id()) + + "_" + + Ogre::StringConverter::toString(index); + Ogre::MeshPtr mesh = + Ogre::MeshManager::getSingleton() + .getByName(meshName); + if (mesh) + Ogre::MeshManager::getSingleton().remove( + mesh); + if (tbTop.getVertices().size() > 0) + tb.append(tbTop); + if (tbSide.getVertices().size() > 0) + tb.append(tbSide); + if (tb.getVertices().size() > 0) { + mesh = tb.transformToMesh(meshName); + Ogre::LodConfig config(mesh); + setupLods(config); + Ogre::Entity *ent = + ECS::get() + .mScnMgr->createEntity( + "Ent" + meshName, + mesh); + ent->setMaterial(townMaterial); + geo->addEntity( + ent, centerPosition + offset, + centerOrientation * rotation, + Ogre::Vector3::UNIT_SCALE); + ECS::get() + .mScnMgr->destroyEntity( + + ent); + } + } + count++; + } + } +} } } diff --git a/src/gamedata/items/town.h b/src/gamedata/items/town.h index 754c9f9..9813a97 100644 --- a/src/gamedata/items/town.h +++ b/src/gamedata/items/town.h @@ -2,6 +2,9 @@ #define __TOWN_H__ #include #include +namespace Procedural { +class TriangleBuffer; +} namespace ECS { namespace Items @@ -12,6 +15,9 @@ void createTownPopup(const std::pair item); } namespace Geometry { +void clampUV(flecs::entity e, Procedural::TriangleBuffer &tb, + const Ogre::String &rectKey); +Ogre::MaterialPtr createTownMaterial(flecs::entity e, bool force = false); void createCells(flecs::entity e, const nlohmann::json &jdistrict, int index, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); void createTown(flecs::entity e, Ogre::SceneNode *sceneNode, @@ -22,6 +28,9 @@ void createTownPlazza(flecs::entity e, const nlohmann::json &jdistrict, void createTownLots(flecs::entity e, const nlohmann::json &jdistrict, int index, Ogre::SceneNode *sceneNode, Ogre::StaticGeometry *geo); +void createTownRoofs(flecs::entity e, const nlohmann::json &jdistrict, + int index, Ogre::SceneNode *sceneNode, + Ogre::StaticGeometry *geo); } } #endif