void base64(const size_t in_len, const u8* in, u8* out) { u32 pool = 0; // of bits from buffer ssize_t pool_bits = 0; // # bits currently in buffer static const u8 tbl[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; size_t in_bytes_left = in_len; // to avoid overrunning input buffer const size_t out_chars = (in_len*8 + 5) / 6; // = ceil(# 6-bit blocks) for(size_t i = 0; i < out_chars; i++) { if(pool_bits < 6 && in_bytes_left) { pool <<= 8; pool |= *in++; pool_bits += 8; in_bytes_left--; } pool_bits -= 6; size_t c; if (pool_bits < 0) c = (pool << -pool_bits) & 63; else c = (pool >> pool_bits) & 63; *out++ = tbl[c]; } if (out_chars % 4 >= 2) *out++ = '='; if (out_chars % 4 == 2) *out++ = '='; *out++ = '\0'; } #include "graphics/Terrain.h" #include "simulation2/components/ICmpTerrain.h" #include "simulation2/components/ICmpWaterManager.h" #include "simulation2/components/ICmpPosition.h" #include "simulation2/components/ICmpObstruction.h" #include "simulation2/components/ICmpVisual.h" #include "simulation2/components/ICmpTemplateManager.h" #include "simulation2/components/ICmpGuiInterface.h" #include "simulation2/system/ComponentManager.h" #include "simulation2/system/SimContext.h" #include "ps/Overlay.h" #include "lib/alignment.h" #include "lib/allocators/shared_ptr.h" #include "lib/base32.h" class CTextRenderer { private: struct Cell { wchar_t ch; CColor fg; CColor bg; }; public: CTextRenderer(CSimulation2& simulation) : m_Simulation(simulation) { } void Render() { CmpPtr cmpTerrain(m_Simulation, SYSTEM_ENTITY); CmpPtr cmpWaterManager(m_Simulation, SYSTEM_ENTITY); ssize_t tilesW = cmpTerrain->GetVerticesPerSide() - 1; ssize_t tilesH = cmpTerrain->GetVerticesPerSide() - 1; CTerrain* terrain = cmpTerrain->GetCTerrain(); const size_t w = (size_t)tilesW, h = (size_t)tilesH; const size_t bpp = 24; int flags = TEX_BOTTOM_UP; const size_t img_size = w * h * bpp/8; const size_t hdr_size = tex_hdr_size(L"example.png"); shared_ptr buf; AllocateAligned(buf, hdr_size+img_size, maxSectorSize); u8* img = buf.get() + hdr_size; Tex t; if (tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0) debug_warn(L"tex_wrap failed"); std::vector cells; for (ssize_t j = 0; j < tilesH; ++j) { for (ssize_t i = 0; i < tilesW; ++i) { float x = i*CELL_SIZE + CELL_SIZE/2; float z = j*CELL_SIZE + CELL_SIZE/2; float h = terrain->GetExactGroundLevel(x, z); bool underwater = (h < cmpWaterManager->GetExactWaterLevel(x, z)); fixed slope = terrain->GetSlopeFixed(i, j); Cell c; c.ch = ' '; c.fg = CColor(0, 0, 0, 1); float shade = 1 / (1 + slope.ToFloat()); shade = (int)(shade * 16.f) / 16.f; c.bg = underwater ? CColor(0.5, 0.5, shade, 1) : CColor(0.5, shade, 0.5, 1); cells.push_back(c); *img++ = (u8)(c.bg.r * 255.f); *img++ = (u8)(c.bg.g * 255.f); *img++ = (u8)(c.bg.b * 255.f); } } std::ostream& str = std::cerr; str << "\n"; str << "\n"; str << "\n"; str << "\n"; str << "\n"; str << "\n"; DynArray da; if (tex_encode(&t, ".png", &da) < 0) debug_warn(L"tex_encode failed"); char* imgBase64 = new char[(da.pos*8 + 5) / 6 + 3]; base64(da.pos, da.base, (u8*)imgBase64); str << "\n"; delete[] imgBase64; CmpPtr cmpTemplateManager(m_Simulation, SYSTEM_ENTITY); CmpPtr cmpGuiInterface(m_Simulation, SYSTEM_ENTITY); std::set usedTemplates; CComponentManager::InterfaceList ents = m_Simulation.GetSimContext().GetComponentManager().GetEntitiesWithInterface(IID_Visual); for (CComponentManager::InterfaceList::iterator it = ents.begin(); it != ents.end(); ++it) { wchar_t sym = static_cast(it->second)->GetSymbol(); if (!sym) continue; CmpPtr cmpPosition(m_Simulation, it->first); if (cmpPosition.null() || !cmpPosition->IsInWorld()) continue; CFixedVector2D pos = cmpPosition->GetPosition2D(); float obstrW = 4.f; float obstrH = 4.f; float obstrR = 0.f; CmpPtr cmpObstruction(m_Simulation, it->first); ICmpObstructionManager::ObstructionSquare obstr; if (!cmpObstruction.null() && cmpObstruction->GetObstructionSquare(obstr)) { obstrW = obstr.hw.ToFloat()*2; obstrH = obstr.hh.ToFloat()*2; obstrR = atan2(obstr.v.X.ToFloat(), obstr.v.Y.ToFloat()); } std::string templName = cmpTemplateManager->GetCurrentTemplateName(it->first); usedTemplates.insert(templName); CScriptVal entState = cmpGuiInterface->ScriptCall(1, L"GetEntityState", ScriptInterface::ToJSVal(m_Simulation.GetScriptInterface().GetContext(), it->first)); std::string entStateJson = m_Simulation.GetScriptInterface().StringifyJSON(entState.get(), false); float x = pos.X.ToFloat(); float y = (tilesH*CELL_SIZE - pos.Y.ToFloat()); str << "\n"; // ssize_t i = (pos.X / (int)CELL_SIZE).ToInt_RoundToNegInfinity(); // ssize_t j = (pos.Y / (int)CELL_SIZE).ToInt_RoundToNegInfinity(); // if (0 <= i && i < tilesW && 0 <= j && j < tilesH) // cells[i + j*tilesW].ch = sym; } str << "\n"; str << "\n"; str << "
\n"; // OutputHTML(tilesW, tilesH, cells, std::cout); } void OutputHTML(ssize_t w, ssize_t h, const std::vector& cells, std::ostream& str) { str << "\n"; str << "\n"; str << "
\n";
		for (ssize_t j = h-1; j >= 0; --j)
		{
			for (ssize_t i = 0; i < w; ++i)
			{
				Cell c = cells[i + j*w];
				if (i == 0 || c.bg != cells[i-1 + j*w].bg || c.fg != cells[i-1 + j*w].fg)
					str << "";
				str << EscapeHTML(c.ch);
				if (i == w-1 || c.bg != cells[i+1 + j*w].bg || c.fg != cells[i+1 + j*w].fg)
					str << "";
			}
			str << "\n";
		}
		str << "
"; } std::string ColourCSS(const CColor& c) { char out[8]; sprintf_s(out, ARRAY_SIZE(out), "#%02x%02x%02x", (int)(c.r*255), (int)(c.g*255), (int)(c.b*255)); return out; } std::string EscapeHTML(wchar_t c) { if (0x20 <= c && c <= 0x7f && c != '&' && c != '<' && c != '"') return std::string(1, (char)c); char out[8]; sprintf_s(out, ARRAY_SIZE(out), "&#%d;", c); return out; } std::string EscapeHTMLAttrSingleQuoted(const std::string& str) { std::string out; for (size_t i = 0; i < str.length(); ++i) { if (str[i] == '&') out += "&"; else if (str[i] == '\'') out += "'"; else out += str[i]; } return out; } private: CSimulation2& m_Simulation; };