<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="https://zanidrak.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://zanidrak.com/" rel="alternate" type="text/html" /><updated>2025-06-05T08:52:23+00:00</updated><id>https://zanidrak.com/feed.xml</id><title type="html">Stuff</title><subtitle>Posts on programming and art</subtitle><entry><title type="html">CPU failure</title><link href="https://zanidrak.com/hardware/2025/03/02/cpu-failure.html" rel="alternate" type="text/html" title="CPU failure" /><published>2025-03-02T08:00:00+00:00</published><updated>2025-03-02T08:00:00+00:00</updated><id>https://zanidrak.com/hardware/2025/03/02/cpu-failure</id><content type="html" xml:base="https://zanidrak.com/hardware/2025/03/02/cpu-failure.html"><![CDATA[<h1 id="how-my-motherboard-killed-my-cpu">How my motherboard killed my CPU</h1>

<p>My computer stopped working recently after two years of use at stock settings with no overclocking. Normally a restart with a reset of the UEFI settings fixes things but not in this particular case.
After a restart and a reset of the firmware using a motherboard switch, I was presented with a hanging POST. Thankfully my motherboard has a useful feature called “Q-CODE” which displays where it’s at in the POST process.</p>

<blockquote>
  <p>Asus Q-CODE is a two-character alphanumeric diagnostic display found on many ASUS motherboards, especially mid to high-end models (like those in the ROG or TUF series). 
It shows POST (Power-On Self-Test) codes during boot to help identify the current status of the system or diagnose issues if something goes wrong.</p>
</blockquote>

<p>For my particular issue it’s at <code class="language-plaintext highlighter-rouge">00</code>. 
<img src="/assets/hardware/cpu_fail.png" alt="motherboard stuck on POST" /></p>

<p>After a quick glance at my motherboard’s manual to see what Asus’s <code class="language-plaintext highlighter-rouge">Q_CODE 00</code> refers to…
<img src="/assets/hardware/q_code_table.png" alt="q code table" /></p>

<p>…00 is not used. It’s the code shown initially when booting. Time to search the web for clues.</p>

<p>A few posts on the Asus forums indicate CPU, motherboard or PSU. Experience tells me it’s either the PSU or motherboard. CPU issues are rare especially after only two years of use.
At this point I’m two hours into my investigation and I’ve removed all the components from my PC except for the CPU, PSU and motherboard.</p>

<p>I decided to try one last fix before switching out the PSU. I went to Asus’s support site and checked for firmware updates to apply the latest version. That’s when I found out about these updates…
<img src="/assets/hardware/bios_updates.png" alt="bios updates on asus website" /></p>

<p>Nice. I suspect Asus’s faulty firmware had been setting the CPU SOC voltage beyond the maximum 1.3v even with EXPO (overclocking) disabled. The CPU is now dead.</p>

<p>After further testing and contacting support, I now have a new CPU and my PC once again works.</p>]]></content><author><name>raffclar</name></author><category term="hardware" /><summary type="html"><![CDATA[How my motherboard killed my CPU]]></summary></entry><entry><title type="html">Adding temple interiors to OpenBlack</title><link href="https://zanidrak.com/cpp/games/2024/02/06/black-white-temple.html" rel="alternate" type="text/html" title="Adding temple interiors to OpenBlack" /><published>2024-02-06T00:00:00+00:00</published><updated>2024-02-06T00:00:00+00:00</updated><id>https://zanidrak.com/cpp/games/2024/02/06/black-white-temple</id><content type="html" xml:base="https://zanidrak.com/cpp/games/2024/02/06/black-white-temple.html"><![CDATA[<h1 id="temple-geometry-is-now-loaded-in">Temple geometry is now loaded in</h1>
<p>The vanilla game compresses the larger temple models using Deflate and need to be inflated/decompressed.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/aECrwOJlC_8?si=UzKtwN1wj4RiAv3h" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

<h1 id="interior-lighting-sprites">Interior lighting sprites</h1>
<p>Black &amp; White uses two billboards for most “glow” effects. Light effects are stored in *.glw files which I have started reverse engineering.
Nvidia Nsight is very useful for this sort of stuff; in this picture I have disabled the sprite rendering in the fragment shaders in the vanilla game
to confirm sprite positions and to help match the depth and draw buffer flags.
<img src="/assets/b_and_w/black_and_white_glow_sprites.png" alt="vanilla under nsight" /></p>

<h2 id="original-lights">Original lights</h2>
<p><img src="/assets/b_and_w/vanilla_temple_lights.png" alt="vanilla lights" /></p>
<h2 id="openblack-lights">Openblack lights</h2>
<p><img src="/assets/b_and_w/openblack_temple_lights.png" alt="openblack_temple_lights" />
<img src="/assets/b_and_w/openblack_creature_cave.png" alt="openblack_creature_cave" /></p>]]></content><author><name>raffclar</name></author><category term="cpp" /><category term="games" /><summary type="html"><![CDATA[Temple geometry is now loaded in The vanilla game compresses the larger temple models using Deflate and need to be inflated/decompressed. Interior lighting sprites Black &amp; White uses two billboards for most “glow” effects. Light effects are stored in *.glw files which I have started reverse engineering. Nvidia Nsight is very useful for this sort of stuff; in this picture I have disabled the sprite rendering in the fragment shaders in the vanilla game to confirm sprite positions and to help match the depth and draw buffer flags. Original lights Openblack lights]]></summary></entry><entry><title type="html">Unity web assembly test</title><link href="https://zanidrak.com/jekyll/update/2021/08/17/unity-wasm.html" rel="alternate" type="text/html" title="Unity web assembly test" /><published>2021-08-17T17:34:18+00:00</published><updated>2021-08-17T17:34:18+00:00</updated><id>https://zanidrak.com/jekyll/update/2021/08/17/unity-wasm</id><content type="html" xml:base="https://zanidrak.com/jekyll/update/2021/08/17/unity-wasm.html"><![CDATA[<p>Unity web support is pretty good</p>

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas"></canvas>
  <div id="unity-loading-bar">
	<div id="unity-logo"></div>
	<div id="unity-progress-bar-empty">
	  <div id="unity-progress-bar-full"></div>
	</div>
  </div>
</div>
<script>
  var buildUrl = "/assets/unity/creature_sim/build";
  var loaderUrl = buildUrl + "/build.loader.js";
  var config = {
	dataUrl: buildUrl + "/build.data",
	frameworkUrl: buildUrl + "/build.framework.js",
	codeUrl: buildUrl + "/build.wasm",
	streamingAssetsUrl: "StreamingAssets",
	companyName: "AAB",
	productName: "Creature Sim",
	productVersion: "0.1",
  };

  var container = document.querySelector("#unity-container");
  var canvas = document.querySelector("#unity-canvas");
  var loadingBar = document.querySelector("#unity-loading-bar");
  var progressBarFull = document.querySelector("#unity-progress-bar-full");
  var fullscreenButton = document.querySelector("#unity-fullscreen-button");
  var mobileWarning = document.querySelector("#unity-mobile-warning");

  // By default Unity keeps WebGL canvas render target size matched with
  // the DOM size of the canvas element (scaled by window.devicePixelRatio)
  // Set this to false if you want to decouple this synchronization from
  // happening inside the engine, and you would instead like to size up
  // the canvas DOM size and WebGL render target sizes yourself.
  // config.matchWebGLToCanvasSize = false;

  canvas.style.width = "960px";
  canvas.style.height = "600px";
  var script = document.createElement("script");
  script.src = loaderUrl;
  script.onload = () => {
	createUnityInstance(canvas, config, (progress) => {
	  progressBarFull.style.width = 100 * progress + "%";
	}).then((unityInstance) => {
	  loadingBar.style.display = "none";
	}).catch((message) => {
	  alert(message);
	});
  };
  document.body.appendChild(script);
</script>]]></content><author><name>raffclar</name></author><category term="jekyll" /><category term="update" /><summary type="html"><![CDATA[Unity web support is pretty good]]></summary></entry><entry><title type="html">Adding audio to OpenBlack</title><link href="https://zanidrak.com/cpp/games/2021/01/03/black-white-audio.html" rel="alternate" type="text/html" title="Adding audio to OpenBlack" /><published>2021-01-03T01:00:00+00:00</published><updated>2021-01-03T01:00:00+00:00</updated><id>https://zanidrak.com/cpp/games/2021/01/03/black-white-audio</id><content type="html" xml:base="https://zanidrak.com/cpp/games/2021/01/03/black-white-audio.html"><![CDATA[<h1 id="first-version">First version</h1>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Ff8oOGxpXik" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<h1 id="second-version">Second version</h1>
<iframe width="560" height="315" src="https://www.youtube.com/embed/g76iscJPbno" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>]]></content><author><name>raffclar</name></author><category term="cpp" /><category term="games" /><summary type="html"><![CDATA[First version Second version]]></summary></entry><entry><title type="html">Black &amp;amp; White PC Mesh NamedData struct</title><link href="https://zanidrak.com/cpp/games/2021/01/03/black-white-mesh-headers.html" rel="alternate" type="text/html" title="Black &amp;amp; White PC Mesh NamedData struct" /><published>2021-01-03T01:00:00+00:00</published><updated>2021-01-03T01:00:00+00:00</updated><id>https://zanidrak.com/cpp/games/2021/01/03/black-white-mesh-headers</id><content type="html" xml:base="https://zanidrak.com/cpp/games/2021/01/03/black-white-mesh-headers.html"><![CDATA[<p>LH NameData, UV2Data, FootprintData size function.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ulonglong</span> <span class="p">.</span><span class="n">GetSizeNameData__8LH3DMeshFv</span><span class="p">(</span><span class="kt">int</span> <span class="n">param_1</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">int</span> <span class="n">iVar2</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">iVar3</span><span class="p">;</span>
  <span class="n">ulonglong</span> <span class="n">uVar1</span><span class="p">;</span>
  
  <span class="c1">// mesh-&gt;flags.ContainsNameData == 0</span>
  <span class="k">if</span> <span class="p">((</span><span class="o">*</span><span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_1</span> <span class="o">+</span> <span class="mi">4</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x80000</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uVar1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="c1">// mesh-&gt;flags.ContainsNameData == 0</span>
    <span class="n">iVar2</span> <span class="o">=</span> <span class="p">.</span><span class="n">IsContainsNameData__8LH3DMeshFv</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">iVar2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">uVar1</span><span class="p">.</span><span class="n">_4_4_</span> <span class="o">=</span> <span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">;</span> <span class="c1">// No data, return 0</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="p">{</span>
      <span class="c1">// UV2Size + FootprintSize + 72 bytes</span>
      <span class="n">iVar2</span> <span class="o">=</span> <span class="p">.</span><span class="n">GetSizeUV2Data__8LH3DMeshFv</span><span class="p">(</span><span class="n">param_1</span><span class="p">);</span>
      <span class="n">iVar3</span> <span class="o">=</span> <span class="p">.</span><span class="n">GetSizeFootprintData__8LH3DMeshFv</span><span class="p">(</span><span class="n">param_1</span><span class="p">);</span>
      <span class="n">uVar1</span><span class="p">.</span><span class="n">_4_4_</span> <span class="o">=</span> <span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)(</span><span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_1</span> <span class="o">+</span> <span class="mh">0x48</span><span class="p">)</span> <span class="o">+</span> <span class="n">iVar3</span> <span class="o">+</span> <span class="n">iVar2</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">uVar1</span> <span class="o">=</span> <span class="p">(</span><span class="n">ulonglong</span><span class="p">)</span><span class="o">*</span><span class="n">uVar1</span><span class="p">.</span><span class="n">_4_4_</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">uVar1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now for <code class="language-plaintext highlighter-rouge">.GetSizeUV2Data__8LH3DMeshFv</code>. Very similar to the above</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="n">ulonglong</span> <span class="p">.</span><span class="n">GetSizeUV2Data__8LH3DMeshFv</span><span class="p">(</span><span class="kt">int</span> <span class="n">param_1</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">int</span> <span class="n">iVar2</span><span class="p">;</span>
  <span class="n">ulonglong</span> <span class="n">uVar1</span><span class="p">;</span>
  
  <span class="c1">// mesh-&gt;flags.ContainsUV2 == 0</span>
  <span class="k">if</span> <span class="p">((</span><span class="o">*</span><span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_1</span> <span class="o">+</span> <span class="mi">4</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x40000</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uVar1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">iVar2</span> <span class="o">=</span> <span class="p">.</span><span class="n">IsContainsUV2__8LH3DMeshFv</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">iVar2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">uVar1</span><span class="p">.</span><span class="n">_4_4_</span> <span class="o">=</span> <span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">;</span> <span class="c1">// No data, return 0</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="p">{</span>
	  <span class="c1">// FootprintSize + 72 bytes</span>
      <span class="n">iVar2</span> <span class="o">=</span> <span class="p">.</span><span class="n">GetSizeFootprintData__8LH3DMeshFv</span><span class="p">(</span><span class="n">param_1</span><span class="p">);</span>
      <span class="n">uVar1</span><span class="p">.</span><span class="n">_4_4_</span> <span class="o">=</span> <span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)(</span><span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_1</span> <span class="o">+</span> <span class="mh">0x48</span><span class="p">)</span> <span class="o">+</span> <span class="n">iVar2</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">uVar1</span> <span class="o">=</span> <span class="p">(</span><span class="n">ulonglong</span><span class="p">)</span><span class="o">*</span><span class="n">uVar1</span><span class="p">.</span><span class="n">_4_4_</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">uVar1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now for <code class="language-plaintext highlighter-rouge">.GetSizeFootprintData__8LH3DMeshFv</code>. Also very similar</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ulonglong</span> <span class="p">.</span><span class="n">GetSizeFootprintData__8LH3DMeshFv</span><span class="p">(</span><span class="kt">int</span> <span class="n">param_1</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">int</span> <span class="n">iVar2</span><span class="p">;</span>
  <span class="n">ulonglong</span> <span class="n">uVar1</span><span class="p">;</span>
  
  <span class="c1">// mesh-&gt;flags.ContainsLandscapeFeature</span>
  <span class="k">if</span> <span class="p">((</span><span class="o">*</span><span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_1</span> <span class="o">+</span> <span class="mi">4</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x8000</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uVar1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>  <span class="c1">// No data, return 0</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">iVar2</span> <span class="o">=</span> <span class="p">.</span><span class="n">IsContainsLandscapeFeature__8LH3DMeshFv</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">iVar2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">iVar2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// Dead code. Branch never taken</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="p">{</span>
      <span class="n">iVar2</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)(</span><span class="n">param_1</span> <span class="o">+</span> <span class="mh">0x48</span><span class="p">);</span>
    <span class="p">}</span>
	<span class="c1">// If mesh has a landscape feature then go to offset 72 + 8</span>
	<span class="c1">// otherwise offset 8</span>
    <span class="n">uVar1</span> <span class="o">=</span> <span class="p">(</span><span class="n">ulonglong</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">uint</span> <span class="o">*</span><span class="p">)(</span><span class="n">iVar2</span> <span class="o">+</span> <span class="mi">8</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">uVar1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>0x48/72 bytes skipped when the <code class="language-plaintext highlighter-rouge">ContainsLandscapeFeature</code> flag is present. Add another 8 bytes to get 80. This makes us skip 20 DWORDs.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void .DrawNameScrolls__10TempleRoomFiiiPPwPA3_Ulff(undefined8 param_1,double param_2,undefined8 param_3,int param_4,int param_5,int param_6,longlong param_7)
{
  int *piVar1;
  undefined4 *puVar2;
  undefined *puVar3;
  undefined **ppuVar4;
  int iVar6;
  int iVar7;
  int iVar8;
  undefined8 uVar5;
  int iVar9;
  undefined8 unaff_r14;
  undefined8 unaff_r15;
  undefined8 unaff_r16;
  undefined8 unaff_r17;
  undefined8 unaff_r18;
  undefined8 unaff_r19;
  undefined8 unaff_r20;
  undefined8 unaff_r21;
  undefined8 unaff_r22;
  undefined8 unaff_r23;
  undefined8 unaff_r24;
  undefined8 unaff_r25;
  undefined8 unaff_r26;
  int iVar10;
  undefined8 unaff_r27;
  ulonglong uVar11;
  undefined8 unaff_r28;
  undefined8 unaff_r29;
  undefined8 unaff_r30;
  undefined8 unaff_r31;
  ulonglong uVar12;
  double extraout_f1;
  double dVar13;
  double dVar14;
  double dVar15;
  double dVar16;
  double dVar17;
  int local_11c;
  undefined auStack208 [12];
  float local_c4;
  float local_c0;
  float local_bc;
  float local_b8;
  float local_b4;
  float local_b0;
  float local_ac;
  float local_a8;
  float local_a4;
  float local_a0;
  float local_9c;
  float local_98;
  float local_94;
  float local_90;
  float local_8c;
  longlong local_88;
  undefined4 local_80;
  uint uStack124;
  undefined4 local_78;
  undefined4 uStack116;
  undefined4 uStack112;
  undefined4 uStack108;
  undefined4 uStack104;
  undefined4 uStack100;
  undefined4 uStack96;
  undefined4 uStack92;
  undefined4 uStack88;
  undefined4 uStack84;
  undefined4 uStack80;
  undefined4 uStack76;
  undefined4 uStack72;
  undefined4 uStack68;
  undefined4 uStack64;
  undefined4 uStack60;
  undefined4 uStack56;
  undefined4 uStack52;
  
  ppuVar4 = &amp;toc;
  iVar6 = FUN_1061a870();
  local_78 = (undefined4)((ulonglong)unaff_r14 &gt;&gt; 0x20);
  uStack116 = (undefined4)((ulonglong)unaff_r15 &gt;&gt; 0x20);
  uStack112 = (undefined4)((ulonglong)unaff_r16 &gt;&gt; 0x20);
  uStack108 = (undefined4)((ulonglong)unaff_r17 &gt;&gt; 0x20);
  uStack104 = (undefined4)((ulonglong)unaff_r18 &gt;&gt; 0x20);
  uStack100 = (undefined4)((ulonglong)unaff_r19 &gt;&gt; 0x20);
  uStack96 = (undefined4)((ulonglong)unaff_r20 &gt;&gt; 0x20);
  uStack92 = (undefined4)((ulonglong)unaff_r21 &gt;&gt; 0x20);
  uStack88 = (undefined4)((ulonglong)unaff_r22 &gt;&gt; 0x20);
  uStack84 = (undefined4)((ulonglong)unaff_r23 &gt;&gt; 0x20);
  uStack80 = (undefined4)((ulonglong)unaff_r24 &gt;&gt; 0x20);
  uStack76 = (undefined4)((ulonglong)unaff_r25 &gt;&gt; 0x20);
  uStack72 = (undefined4)((ulonglong)unaff_r26 &gt;&gt; 0x20);
  uStack68 = (undefined4)((ulonglong)unaff_r27 &gt;&gt; 0x20);
  uStack64 = (undefined4)((ulonglong)unaff_r28 &gt;&gt; 0x20);
  uStack60 = (undefined4)((ulonglong)unaff_r29 &gt;&gt; 0x20);
  uStack56 = (undefined4)((ulonglong)unaff_r30 &gt;&gt; 0x20);
  uStack52 = (undefined4)((ulonglong)unaff_r31 &gt;&gt; 0x20);
  piVar1 = (int *)ppuVar4[-0x1619];
  puVar2 = (undefined4 *)ppuVar4[-0x1ae8];
  puVar3 = ppuVar4[0x3e6];
  uVar11 = (ulonglong)*(uint *)ppuVar4[-0x1af2];
  iVar10 = *(int *)(*(int *)(iVar6 + 0xc0) + 0x14);
  dVar14 = extraout_f1;
  iVar7 = .IsContainsNameData__8LH3DMeshFv(iVar10);
  if (iVar7 == 0) {
    iVar10 = 0;
  }
  else {
    iVar7 = .GetSizeUV2Data__8LH3DMeshFv(iVar10);
    iVar8 = .GetSizeFootprintData__8LH3DMeshFv(iVar10);
    iVar10 = *(int *)(iVar10 + 0x48) + iVar8 + iVar7;
  }
  *(undefined **)puVar2 = ppuVar4[-0x1b0f];
  uStack124 = GetTickCount__7MacDozeFv();
  uStack124 = uStack124 &amp; 0x3ff;
  local_80 = 0x43300000;
  dVar13 = (double)sin((double)(*(float *)(puVar3 + 0x44) *
                                (float)((double)CONCAT44(0x43300000,uStack124) -
                                       *(double *)(*(int *)(local_11c + 0xf90) + 0x10)) *
                               *(float *)(puVar3 + 0x48)));
  local_88 = (longlong)(int)(*(float *)(puVar3 + 0x40) * (float)dVar13 + *(float *)(puVar3 + 0x3c));
  if (param_5 != 0) {
    iVar8 = 0;
    iVar7 = 0;
    while (iVar7 &lt; param_4) {
      iVar9 = *(int *)(iVar6 + iVar8 + 0x7c);
      countLeadingZeros(iVar7 - param_6);
      if (-1 &lt; iVar9) {
        uVar12 = (ulonglong)*(uint *)param_7;
        iVar9 = *(int *)(iVar10 + 8) + iVar9 * 0xe0;
        local_b8 = *(float *)(iVar9 + 0x68);
        local_b4 = *(float *)(iVar9 + 0x6c);
        local_b0 = *(float *)(iVar9 + 0x70);
        local_ac = *(float *)(iVar9 + 0x74);
        local_a8 = *(float *)(iVar9 + 0x78);
        local_a4 = *(float *)(iVar9 + 0x7c);
        local_a0 = *(float *)(iVar9 + 0x80);
        local_9c = *(float *)(iVar9 + 0x84);
        local_98 = *(float *)(iVar9 + 0x88);
        local_94 = *(float *)(iVar9 + 0x8c);
        local_90 = *(float *)(iVar9 + 0x90);
        local_8c = *(float *)(iVar9 + 0x94);
        .__pl__7LHPointCFRC7LHPoint(auStack208,iVar9 + 0xd4,iVar9 + 200);
        .__ml__7LHPointCFf((double)*(float *)(puVar3 + 0x14),&amp;local_c4,auStack208);
        dVar15 = (double)(local_bc * local_a0 + local_c0 * local_ac + local_c4 * local_b8 + local_94
                         );
        dVar16 = (double)(local_bc * local_9c + local_c0 * local_a8 + local_c4 * local_b4 + local_90
                         );
        dVar13 = (double)(local_bc * local_98 + local_c0 * local_a4 + local_c4 * local_b0 + local_8c
                         );
        NormaliseMatrixOnly__8LHMatrixFv(&amp;local_b8);
        local_ac = -local_ac;
        local_a8 = -local_a8;
        local_94 = (float)dVar15;
        local_a4 = -local_a4;
        local_90 = (float)dVar16;
        local_8c = (float)dVar13;
        uVar5 = wcslen(uVar12);
        dVar17 = (double)(float)((double)*(float *)(puVar3 + 0x50) * dVar14);
        dVar13 = (double)GetStringWidth__13GatheringTextFPwif(dVar17,uVar11,uVar12,uVar5);
        iVar9 = *piVar1;
        dVar16 = (double)(float)((double)*(float *)(puVar3 + 0x4c) * param_2);
        dVar13 = (double)(float)(dVar16 * dVar13);
        uVar5 = wcslen(uVar12);
        dVar13 = (double)(float)(-dVar13 * (double)*(float *)(puVar3 + 0x14));
        dVar15 = (double)(float)(-dVar17 * (double)*(float *)(puVar3 + 0x14));
        DrawTextRawOriented__13GatheringTextFR8LHMatrixiiPwifffffP9LH3DColoriP9LH3DColor
                  (dVar13,(double)(float)(dVar15 - (double)(float)(dVar17 / (double)*(float *)(
                                                  puVar3 + 0x54))),(double)*(float *)(puVar3 + 0x58)
                   ,dVar17,dVar16,uVar11,&amp;local_b8,(ulonglong)(iVar9 == 0),2,uVar12,uVar5);
        uVar5 = wcslen(uVar12);
        DrawTextRawOriented__13GatheringTextFR8LHMatrixiiPwifffffP9LH3DColoriP9LH3DColor
                  (dVar13,dVar15,(double)*(float *)(puVar3 + 0x5c),dVar17,dVar16,uVar11,&amp;local_b8,
                   (ulonglong)(iVar9 == 0),2,uVar12,uVar5);
      }
      iVar8 = iVar8 + 4;
      param_7 = param_7 + 4;
      iVar7 = iVar7 + 1;
    }
  }
  *puVar2 = *(undefined4 *)(local_11c + -0x6c54);
  FUN_1061a8c0();
  return;
}

</code></pre></div></div>]]></content><author><name>raffclar</name></author><category term="cpp" /><category term="games" /><summary type="html"><![CDATA[LH NameData, UV2Data, FootprintData size function.]]></summary></entry><entry><title type="html">Black &amp;amp; White audio explained</title><link href="https://zanidrak.com/cpp/games/2021/01/03/black-and-white-audio-explained.html" rel="alternate" type="text/html" title="Black &amp;amp; White audio explained" /><published>2021-01-03T01:00:00+00:00</published><updated>2021-01-03T01:00:00+00:00</updated><id>https://zanidrak.com/cpp/games/2021/01/03/black-and-white-audio-explained</id><content type="html" xml:base="https://zanidrak.com/cpp/games/2021/01/03/black-and-white-audio-explained.html"><![CDATA[<h1 id="summary">Summary</h1>
<p>Sound in black &amp; white 1 is bit of mess. The game’s music and dialogue was considered too large for hard-drives back then so they decided to use various techniques to reduce the amount of MBs taken up. These techniques worked and they were able to ship the game.</p>

<h2 id="music">Music</h2>
<ul>
  <li>Compressed as MP2</li>
  <li>Stored on the game CD</li>
  <li>Split up into “sectors”. This is for performance reasons. Reading an entire song from the CD and decoding it would have taken a couple of seconds</li>
  <li>Always stereo</li>
  <li>Sailor’s song on Land 1 is treated as music</li>
</ul>

<h2 id="dialogue">Dialogue</h2>
<ul>
  <li>More than 90% of the dialogue is compressed as MP2 however there are a few that are raw</li>
  <li>Stored in the game directory</li>
  <li>Always mono for 3D and to save space</li>
</ul>

<h2 id="fx">FX</h2>
<ul>
  <li>More than 90% is uncompressed. A couple of FX sounds are compressed, namely the logo sound (which is also stereo) and the volcano ambience on the last campaign island.</li>
  <li>Compression is either MP2 or MS-ADPCM (Microsoft’s Adaptive Delta Pulse Code Modulation)</li>
  <li>For MS-ADPCM it’s worth looking into doing this ourselves as it’s not too hard to decode ADPCM into PCM.</li>
  <li>3D sounds have to be in mono which is why more than 99% of FX are in mono. Exclusions include looped ambience which are stereo (and heard from all directions)</li>
</ul>

<h2 id="sound-variants-found-so-far">Sound variants found so far</h2>

<table>
  <thead>
    <tr>
      <th>sound type</th>
      <th>sound format</th>
      <th>container</th>
      <th>layout</th>
      <th>channels</th>
      <th>sample rate</th>
      <th>bit rate</th>
      <th>possible ffmpeg alternative</th>
      <th>license</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Music</td>
      <td>MPEG-1 Audio Layer II</td>
      <td>mpg</td>
      <td>stereo</td>
      <td>2</td>
      <td> </td>
      <td> </td>
      <td><a href="https://en.wikipedia.org/wiki/Mpg123">mpg123</a></td>
      <td>LGPLv2.1</td>
    </tr>
    <tr>
      <td>Dialogue</td>
      <td>MPEG-1 Audio Layer II</td>
      <td>wav</td>
      <td>mono</td>
      <td>1</td>
      <td>22050</td>
      <td>64</td>
      <td><a href="https://en.wikipedia.org/wiki/Mpg123">mpg123</a></td>
      <td>LGPLv2.1</td>
    </tr>
    <tr>
      <td>Dialogue</td>
      <td>PCM 16-bit</td>
      <td>wav</td>
      <td>mono</td>
      <td>1</td>
      <td>22050</td>
      <td>43Ko/s</td>
      <td><a href="https://mackron.github.io/dr_wav">dr_wav</a></td>
      <td>Public domain</td>
    </tr>
    <tr>
      <td>FX</td>
      <td>PCM 16-bit</td>
      <td>wav</td>
      <td>mono</td>
      <td>1</td>
      <td>22050</td>
      <td>43Ko/s</td>
      <td><a href="https://mackron.github.io/dr_wav">dr_wav</a></td>
      <td>Public domain</td>
    </tr>
    <tr>
      <td>FX</td>
      <td>MPEG-1 Audio Layer II</td>
      <td>wav</td>
      <td>mono/stereo</td>
      <td>1/2</td>
      <td>22050</td>
      <td>64</td>
      <td><a href="https://en.wikipedia.org/wiki/Mpg123">mpg123</a></td>
      <td>LGPLv2.1</td>
    </tr>
    <tr>
      <td>FX looped atmos</td>
      <td>PCM 16-bit</td>
      <td>wav</td>
      <td>stereo</td>
      <td>2</td>
      <td>22050</td>
      <td>86Ko/s</td>
      <td><a href="https://mackron.github.io/dr_wav">dr_wav</a></td>
      <td>Public domain</td>
    </tr>
    <tr>
      <td>FX</td>
      <td>ADPCM 4-bit</td>
      <td>wav</td>
      <td>mono</td>
      <td>1</td>
      <td>22050</td>
      <td>86Ko/s</td>
      <td>None that I could find</td>
      <td> </td>
    </tr>
  </tbody>
</table>

<h2 id="sounds-pulled-from-the-game">Sounds pulled from the game</h2>
<ol>
  <li><a href="/assets/b_and_w/sounds/dialogue_pcm_mono_HELP_TEXT_TUTORIAL_LAND_26.wav">dialog_pcm_mono</a></li>
  <li><a href="/assets/b_and_w/sounds/dialogue_mp2_mono_HELP_TEXT_CITADEL_GUIDE_03.wav">dialog_mp2_mono</a></li>
  <li><a href="/assets/b_and_w/sounds/fx_pcm_mono_wind01.wav">fx_pcm_mono</a></li>
  <li><a href="/assets/b_and_w/sounds/fx_pcm_stereo_jungleloop4.wav">fx_pcm_stereo</a></li>
  <li><a href="/assets/b_and_w/sounds/fx_mp2_mono_G_Volcano_02.wav">fx_mp2_mono</a></li>
  <li><a href="/assets/b_and_w/sounds/fx_mp2_stereo_Logo.wav">fx_mp2_stereo</a></li>
  <li><a href="/assets/b_and_w/sounds/fx_msadpcm_mono_S_FireworkExplosion_01.wav">fx_adpcm_mono</a></li>
</ol>

<p>Further reading:</p>
<ol>
  <li><a href="https://wiki.multimedia.cx/index.php/Microsoft_ADPCM">MS-ADPCM explained</a></li>
  <li><a href="https://github.com/mackron/dr_libs/blob/master/dr_wav.h">dr_wav library</a></li>
  <li><a href="https://www.mpg123.de/">mpg123 library</a></li>
  <li><a href="https://github.com/microsoft/vcpkg/tree/master/ports/mpg123">vcpkg supports mpg123</a></li>
</ol>]]></content><author><name>raffclar</name></author><category term="cpp" /><category term="games" /><summary type="html"><![CDATA[Summary Sound in black &amp; white 1 is bit of mess. The game’s music and dialogue was considered too large for hard-drives back then so they decided to use various techniques to reduce the amount of MBs taken up. These techniques worked and they were able to ship the game.]]></summary></entry><entry><title type="html">Doorbell receiver source code</title><link href="https://zanidrak.com/doorbell/c/2019/10/04/doorbell-code.html" rel="alternate" type="text/html" title="Doorbell receiver source code" /><published>2019-10-04T10:00:00+00:00</published><updated>2019-10-04T10:00:00+00:00</updated><id>https://zanidrak.com/doorbell/c/2019/10/04/doorbell-code</id><content type="html" xml:base="https://zanidrak.com/doorbell/c/2019/10/04/doorbell-code.html"><![CDATA[<p>This wasn’t possible without <a href="https://osmocom.org/projects/rtl-sdr/wiki/Rtl-sdr">rtl-sdr</a></p>

<p>SDR is a NESDR SMArTee v2 (RTL2832U, R820T2)</p>

<p>I wrote this to test out the library, to capture signals to a file and to see how easy it is to write code using my SDR device.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;errno.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;getopt.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;assert.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;complex.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;math.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdbool.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;inttypes.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;sys/time.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;limits.h&gt;</span><span class="cp">
</span>
<span class="cp">#include</span> <span class="cpf">"rtl-sdr.h"</span><span class="cp">
</span>
<span class="n">rtlsdr_dev_t</span> <span class="o">*</span><span class="n">device</span><span class="p">;</span>
<span class="kt">FILE</span> <span class="o">*</span><span class="n">record_file</span><span class="p">;</span>

<span class="cp">#define SAMPLE_RATE 250000
#define FREQUENCY 433920000
#define USE_RAW_DATA_FILE 0
</span>
<span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
    <span class="n">short_pulse</span><span class="p">,</span>
    <span class="n">short_gap</span><span class="p">,</span>
    <span class="n">sync_gap</span><span class="p">,</span>
    <span class="n">long_pulse</span><span class="p">,</span>
    <span class="n">long_gap</span>
<span class="p">}</span> <span class="n">ook_modulation</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">uint32_t</span> <span class="n">short_width</span> <span class="o">=</span> <span class="mi">360</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">uint32_t</span> <span class="n">long_width</span> <span class="o">=</span> <span class="mi">1070</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">uint32_t</span> <span class="n">gap_limit</span> <span class="o">=</span> <span class="mi">1200</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">get_sample_file</span><span class="p">(</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">buffer_length</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">len</span><span class="p">;</span>
    <span class="n">len</span> <span class="o">=</span> <span class="n">fread</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">),</span> <span class="n">buffer_length</span><span class="p">,</span> <span class="n">record_file</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">len</span> <span class="o">==</span> <span class="n">buffer_length</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">get_samples_rtl_sdr</span><span class="p">(</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">buffer_length</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">length</span><span class="p">;</span>
    <span class="c1">//length = fread(buffer, sizeof(uint8_t), buffer_length, record_file);</span>
    <span class="n">rtlsdr_read_sync</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">buffer_length</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">length</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">length</span> <span class="o">==</span> <span class="n">buffer_length</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int32_t</span> <span class="nf">remove_dc_bias</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">sample</span><span class="p">,</span> <span class="kt">double</span> <span class="n">weight</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="o">*</span><span class="n">previous_average</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">previous_average</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int32_t</span><span class="p">)</span> <span class="n">round</span><span class="p">(</span><span class="n">weight</span> <span class="o">*</span> <span class="n">sample</span> <span class="o">+</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">weight</span><span class="p">)</span> <span class="o">*</span> <span class="o">*</span><span class="n">previous_average</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">sample</span> <span class="o">-</span> <span class="o">*</span><span class="n">previous_average</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int32_t</span> <span class="nf">get_envelope</span><span class="p">(</span><span class="kt">int32_t</span> <span class="n">sample</span><span class="p">,</span> <span class="kt">double</span> <span class="n">weight</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">previous_average</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="kt">int32_t</span><span class="p">)</span> <span class="n">round</span><span class="p">(</span><span class="n">weight</span> <span class="o">*</span> <span class="n">sample</span> <span class="o">+</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">weight</span><span class="p">)</span> <span class="o">*</span> <span class="n">previous_average</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int32_t</span> <span class="nf">is_pulse</span><span class="p">(</span><span class="kt">uint32_t</span> <span class="n">envelope</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="n">threshold</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">envelope</span> <span class="o">&gt;</span> <span class="n">threshold</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">printf</span><span class="p">(</span><span class="s">"Using file.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">record_file</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"good_sample_3"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">record_file</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="mi">3</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">rtlsdr_get_device_count</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">rtlsdr_open</span><span class="p">(</span><span class="o">&amp;</span><span class="n">device</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">false</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">// Disable automatic gain control on the RTL2832U chip</span>
	    <span class="n">printf</span><span class="p">(</span><span class="s">"Setting AGC mode.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">rtlsdr_set_agc_mode</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="c1">// Auto gain</span>
	    <span class="n">printf</span><span class="p">(</span><span class="s">"Setting gain mode.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">rtlsdr_set_tuner_gain_mode</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
	
	    <span class="n">printf</span><span class="p">(</span><span class="s">"Setting frequency and sample rate.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">rtlsdr_set_center_freq</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="n">FREQUENCY</span><span class="p">);</span>
        <span class="n">rtlsdr_set_sample_rate</span><span class="p">(</span><span class="n">device</span><span class="p">,</span> <span class="n">SAMPLE_RATE</span><span class="p">);</span>
	
	    <span class="n">printf</span><span class="p">(</span><span class="s">"Flushing buffer.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="c1">// Flush the device buffer</span>
        <span class="n">rtlsdr_reset_buffer</span><span class="p">(</span><span class="n">device</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">size_t</span> <span class="n">buffer_length</span> <span class="o">=</span> <span class="mi">2048</span><span class="p">;</span>
    <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">2048</span><span class="p">);</span>

    <span class="c1">// Signal is as follows:</span>
    <span class="c1">// |¯|________|¯¯|__|¯|_|¯|_|¯¯|_|¯¯|_|¯¯|_|¯¯|_|¯¯|__|¯|_|¯|_|¯¯|__|¯|__|¯|__|¯|_|¯¯|_|¯¯|_|¯¯|_|¯¯|</span>
    <span class="n">ook_modulation</span> <span class="n">protocol</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">sync_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">long_gap</span><span class="p">,</span>
            <span class="n">short_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span><span class="p">,</span>
            <span class="n">short_gap</span><span class="p">,</span>
            <span class="n">long_pulse</span>
    <span class="p">};</span>

    <span class="kt">int</span> <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">protocol_length</span> <span class="o">=</span> <span class="mi">37</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">get_sample_file</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">buffer_length</span><span class="p">)</span> <span class="o">==</span> <span class="nb">false</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="mi">5</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">int32_t</span> <span class="n">dc_avg</span> <span class="o">=</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="kt">int32_t</span> <span class="n">env_avg</span> <span class="o">=</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="c1">// Keep track of the duration of the current protocol step; pulse or the absence of a pulse</span>
    <span class="kt">uint32_t</span> <span class="n">duration</span>  <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="c1">// We will allow this amount of variance in the envelope signal when stepping through a pulse</span>
    <span class="kt">uint32_t</span> <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="c1">// Threshold</span>
    <span class="kt">uint32_t</span> <span class="n">threshold</span> <span class="o">=</span> <span class="mi">50</span><span class="p">;</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"Loop begin.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="kt">FILE</span> <span class="o">*</span><span class="n">test</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"test"</span><span class="p">,</span> <span class="s">"w+"</span><span class="p">);</span>

    <span class="k">do</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">protocol_index</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">==</span> <span class="n">protocol_length</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">fprintf</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="s">"OOK protocol match.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
            <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">start</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">buffer_length</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">int32_t</span> <span class="n">sample</span> <span class="o">=</span> <span class="n">buffer</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
            <span class="kt">int32_t</span> <span class="n">dc_sample</span> <span class="o">=</span> <span class="n">abs</span><span class="p">(</span><span class="n">remove_dc_bias</span><span class="p">(</span><span class="n">sample</span><span class="p">,</span> <span class="mi">0</span><span class="p">.</span><span class="mo">03</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">dc_avg</span><span class="p">));</span>
            <span class="n">env_avg</span> <span class="o">=</span> <span class="n">abs</span><span class="p">(</span><span class="n">get_envelope</span><span class="p">(</span><span class="n">dc_sample</span><span class="p">,</span> <span class="mi">0</span><span class="p">.</span><span class="mi">10</span><span class="p">,</span> <span class="n">env_avg</span><span class="p">));</span>
            <span class="kt">uint8_t</span> <span class="n">v</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span> <span class="n">env_avg</span><span class="p">;</span>

            <span class="n">ook_modulation</span> <span class="n">part</span> <span class="o">=</span> <span class="n">protocol</span><span class="p">[</span><span class="n">protocol_index</span><span class="p">];</span>
    	    <span class="n">fwrite</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sample</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">v</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="n">test</span><span class="p">);</span>

            <span class="k">switch</span> <span class="p">(</span><span class="n">part</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">case</span> <span class="n">short_pulse</span><span class="p">:</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">is_pulse</span><span class="p">(</span><span class="n">env_avg</span><span class="p">,</span> <span class="n">threshold</span> <span class="o">-</span> <span class="n">tolerance</span><span class="p">))</span> <span class="p">{</span>
                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
                        <span class="n">duration</span><span class="o">++</span><span class="p">;</span>
                    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="k">if</span> <span class="p">(</span><span class="n">duration</span> <span class="o">&gt;</span> <span class="mi">130</span><span class="p">)</span> <span class="p">{</span>
                            <span class="n">protocol_index</span><span class="o">++</span><span class="p">;</span>
                        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                            <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="p">}</span>

                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                    <span class="p">}</span>
                    <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="k">case</span> <span class="n">short_gap</span><span class="p">:</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">is_pulse</span><span class="p">(</span><span class="n">env_avg</span><span class="p">,</span> <span class="n">threshold</span> <span class="o">-</span> <span class="n">tolerance</span><span class="p">))</span> <span class="p">{</span>
                        <span class="n">duration</span><span class="o">++</span><span class="p">;</span>
                    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="k">if</span> <span class="p">(</span><span class="n">duration</span> <span class="o">&gt;</span> <span class="mi">130</span><span class="p">)</span> <span class="p">{</span>
                            <span class="n">protocol_index</span><span class="o">++</span><span class="p">;</span>
                        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                            <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="p">}</span>

                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                    <span class="p">}</span>

                    <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="k">case</span> <span class="n">long_pulse</span><span class="p">:</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">is_pulse</span><span class="p">(</span><span class="n">env_avg</span><span class="p">,</span> <span class="n">threshold</span> <span class="o">-</span> <span class="n">tolerance</span><span class="p">))</span> <span class="p">{</span>
                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
                        <span class="n">duration</span><span class="o">++</span><span class="p">;</span>
                    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="k">if</span> <span class="p">(</span><span class="n">duration</span> <span class="o">&gt;</span> <span class="mi">270</span><span class="p">)</span> <span class="p">{</span>
                            <span class="n">protocol_index</span><span class="o">++</span><span class="p">;</span>
                        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                            <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="p">}</span>

                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                    <span class="p">}</span>

                    <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="k">case</span> <span class="n">sync_gap</span><span class="p">:</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">is_pulse</span><span class="p">(</span><span class="n">env_avg</span><span class="p">,</span> <span class="n">threshold</span> <span class="o">-</span> <span class="n">tolerance</span><span class="p">))</span> <span class="p">{</span>
                        <span class="n">duration</span><span class="o">++</span><span class="p">;</span>
                    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="k">if</span> <span class="p">(</span><span class="n">duration</span> <span class="o">&gt;</span> <span class="mi">2850</span><span class="p">)</span> <span class="p">{</span>
                            <span class="n">protocol_index</span><span class="o">++</span><span class="p">;</span>
                        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                            <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="p">}</span>

                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                    <span class="p">}</span>

                    <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="k">case</span> <span class="n">long_gap</span><span class="p">:</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">is_pulse</span><span class="p">(</span><span class="n">env_avg</span><span class="p">,</span> <span class="n">threshold</span> <span class="o">-</span> <span class="n">tolerance</span><span class="p">))</span> <span class="p">{</span>
                        <span class="n">duration</span><span class="o">++</span><span class="p">;</span>
                    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="k">if</span> <span class="p">(</span><span class="n">duration</span> <span class="o">&gt;</span> <span class="mi">270</span><span class="p">)</span> <span class="p">{</span>
                            <span class="n">protocol_index</span><span class="o">++</span><span class="p">;</span>
                        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                            <span class="n">protocol_index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="p">}</span>

                        <span class="n">tolerance</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                        <span class="n">duration</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                    <span class="p">}</span>

                    <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="nl">default:</span> <span class="p">{</span>
                    <span class="n">printf</span><span class="p">(</span><span class="s">"Finished reading file!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
                    <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="n">start</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">get_samples_rtl_sdr</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">buffer_length</span><span class="p">)</span> <span class="o">==</span> <span class="nb">true</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>raffclar</name></author><category term="doorbell" /><category term="c" /><summary type="html"><![CDATA[This wasn’t possible without rtl-sdr SDR is a NESDR SMArTee v2 (RTL2832U, R820T2) I wrote this to test out the library, to capture signals to a file and to see how easy it is to write code using my SDR device. #include &lt;stdlib.h&gt; #include &lt;stdio.h&gt; #include &lt;errno.h&gt; #include &lt;getopt.h&gt; #include &lt;unistd.h&gt; #include &lt;string.h&gt; #include &lt;assert.h&gt; #include &lt;complex.h&gt; #include &lt;math.h&gt; #include &lt;stdbool.h&gt; #include &lt;inttypes.h&gt; #include &lt;sys/time.h&gt; #include &lt;limits.h&gt; #include "rtl-sdr.h" rtlsdr_dev_t *device; FILE *record_file; #define SAMPLE_RATE 250000 #define FREQUENCY 433920000 #define USE_RAW_DATA_FILE 0 typedef enum { short_pulse, short_gap, sync_gap, long_pulse, long_gap } ook_modulation; const uint32_t short_width = 360; const uint32_t long_width = 1070; const uint32_t gap_limit = 1200; int get_sample_file(uint8_t *buffer, int buffer_length) { int len; len = fread(buffer, sizeof(uint8_t), buffer_length, record_file); return len == buffer_length; } int get_samples_rtl_sdr(uint8_t *buffer, int buffer_length) { int length; //length = fread(buffer, sizeof(uint8_t), buffer_length, record_file); rtlsdr_read_sync(device, buffer, buffer_length, &amp;length); return length == buffer_length; } int32_t remove_dc_bias(int32_t sample, double weight, int32_t *previous_average) { *previous_average = (int32_t) round(weight * sample + (1 - weight) * *previous_average); return sample - *previous_average; } int32_t get_envelope(int32_t sample, double weight, int32_t previous_average) { return (int32_t) round(weight * sample + (1 - weight) * previous_average); } int32_t is_pulse(uint32_t envelope, uint32_t threshold) { if (envelope &gt; threshold) { return true; } return false; } int main() { if (1) { printf("Using file.\n"); record_file = fopen("good_sample_3", "r"); if (!record_file) { return 3; } } else { if (!rtlsdr_get_device_count()) { return 1; } if (rtlsdr_open(&amp;device, 0) != false) { return 2; } // Disable automatic gain control on the RTL2832U chip printf("Setting AGC mode.\n"); rtlsdr_set_agc_mode(device, 0); // Auto gain printf("Setting gain mode.\n"); rtlsdr_set_tuner_gain_mode(device, 0); printf("Setting frequency and sample rate.\n"); rtlsdr_set_center_freq(device, FREQUENCY); rtlsdr_set_sample_rate(device, SAMPLE_RATE); printf("Flushing buffer.\n"); // Flush the device buffer rtlsdr_reset_buffer(device); } size_t buffer_length = 2048; uint8_t *buffer = malloc(2048); // Signal is as follows: // |¯|________|¯¯|__|¯|_|¯|_|¯¯|_|¯¯|_|¯¯|_|¯¯|_|¯¯|__|¯|_|¯|_|¯¯|__|¯|__|¯|__|¯|_|¯¯|_|¯¯|_|¯¯|_|¯¯| ook_modulation protocol[] = { short_pulse, sync_gap, long_pulse, long_gap, short_pulse, long_gap, short_pulse, short_gap, long_pulse, short_gap, long_pulse, short_gap, long_pulse, short_gap, long_pulse, short_gap, long_pulse, long_gap, short_pulse, long_gap, short_pulse, short_gap, long_pulse, long_gap, short_pulse, long_gap, short_pulse, long_gap, short_pulse, short_gap, long_pulse, short_gap, long_pulse, short_gap, long_pulse, short_gap, long_pulse }; int protocol_index = 0; int protocol_length = 37; if (get_sample_file(buffer, buffer_length) == false) { return 5; } int32_t dc_avg = buffer[0]; int32_t env_avg = buffer[0]; int start = 1; // Keep track of the duration of the current protocol step; pulse or the absence of a pulse uint32_t duration = 0; // We will allow this amount of variance in the envelope signal when stepping through a pulse uint32_t tolerance = 0; // Threshold uint32_t threshold = 50; printf("Loop begin.\n"); FILE *test = fopen("test", "w+"); do { if (protocol_index + 1 == protocol_length) { fprintf(stdout, "OOK protocol match.\n"); protocol_index = 0; tolerance = 0; } for (int i = start; i &lt; buffer_length; i++) { int32_t sample = buffer[i]; int32_t dc_sample = abs(remove_dc_bias(sample, 0.03, &amp;dc_avg)); env_avg = abs(get_envelope(dc_sample, 0.10, env_avg)); uint8_t v = (uint8_t) env_avg; ook_modulation part = protocol[protocol_index]; fwrite(&amp;sample, sizeof(v), 1, test); switch (part) { case short_pulse: { if (is_pulse(env_avg, threshold - tolerance)) { tolerance = 10; duration++; } else { if (duration &gt; 130) { protocol_index++; } else { protocol_index = 0; } tolerance = 0; duration = 0; } break; } case short_gap: { if (!is_pulse(env_avg, threshold - tolerance)) { duration++; } else { if (duration &gt; 130) { protocol_index++; } else { protocol_index = 0; } tolerance = 0; duration = 0; } break; } case long_pulse: { if (is_pulse(env_avg, threshold - tolerance)) { tolerance = 10; duration++; } else { if (duration &gt; 270) { protocol_index++; } else { protocol_index = 0; } tolerance = 0; duration = 0; } break; } case sync_gap: { if (!is_pulse(env_avg, threshold - tolerance)) { duration++; } else { if (duration &gt; 2850) { protocol_index++; } else { protocol_index = 0; } tolerance = 0; duration = 0; } break; } case long_gap: { if (!is_pulse(env_avg, threshold - tolerance)) { duration++; } else { if (duration &gt; 270) { protocol_index++; } else { protocol_index = 0; } tolerance = 0; duration = 0; } break; } default: { printf("Finished reading file!\n"); exit(1); } } } start = 0; } while (get_samples_rtl_sdr(buffer, buffer_length) == true); return 0; }]]></summary></entry><entry><title type="html">Working on a doorbell receiver in C</title><link href="https://zanidrak.com/doorbell/c/2019/10/03/doorbell.html" rel="alternate" type="text/html" title="Working on a doorbell receiver in C" /><published>2019-10-03T10:00:00+00:00</published><updated>2019-10-03T10:00:00+00:00</updated><id>https://zanidrak.com/doorbell/c/2019/10/03/doorbell</id><content type="html" xml:base="https://zanidrak.com/doorbell/c/2019/10/03/doorbell.html"><![CDATA[<p>I want to receive an email whenever someone rings the doorbell. To do this, I’m using an RTL-SDR USB dongle from Nooelec hooked up a to Pi.</p>

<p>My doorbell sends a signal 3 times in pulse width modulation on every press. The signal doesn’t change and it’s unique. Good start!</p>

<h2 id="carrier-signal">Carrier signal:</h2>
<p><img src="/assets/signals/doorbell_raw.png" alt="raw signal graph" /></p>

<h3 id="steps">Steps</h3>

<ol>
  <li>Balance the signal by removing the DC bias. Use averaging.</li>
  <li><code class="language-plaintext highlighter-rouge">Abs()</code> all values in the signal. I want everything on one side of the X-axis for later on.</li>
  <li>Smooth out the amplitude ripples. Use even more averaging for this.</li>
</ol>

<h2 id="demodulated">Demodulated:</h2>
<p><img src="/assets/signals/doorbell_demodulated.png" alt="demodulated graph" /></p>

<h2 id="output-using-a-test-file">Output using a test file:</h2>
<p><img src="/assets/signals/example_cmd.png" alt="example output from console" /></p>

<p>The C program is straightforward. Each pulse/gap has a duration. Just keep track of the current duration of the pulse/gap and progress or reset if the duration is wrong. To do this I iterate through the below array where each element is the next bit of the doorbell signal.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ook_modulation protocol[] = {
    short_pulse,
    sync_gap,
    long_pulse,
    long_gap,
    short_pulse,
    long_gap,
    short_pulse,
    short_gap,
    long_pulse,
    short_gap,
    long_pulse,
    short_gap,
    long_pulse,
    short_gap,
    long_pulse,
    short_gap,
    long_pulse,
    long_gap,
    ...
}
</code></pre></div></div>]]></content><author><name>raffclar</name></author><category term="doorbell" /><category term="c" /><summary type="html"><![CDATA[I want to receive an email whenever someone rings the doorbell. To do this, I’m using an RTL-SDR USB dongle from Nooelec hooked up a to Pi. My doorbell sends a signal 3 times in pulse width modulation on every press. The signal doesn’t change and it’s unique. Good start!]]></summary></entry><entry><title type="html">Reimplementing Black and White (PC game) scripting functions</title><link href="https://zanidrak.com/cpp/games/2019/10/03/black-and-white-scripts.html" rel="alternate" type="text/html" title="Reimplementing Black and White (PC game) scripting functions" /><published>2019-10-03T01:37:18+00:00</published><updated>2019-10-03T01:37:18+00:00</updated><id>https://zanidrak.com/cpp/games/2019/10/03/black-and-white-scripts</id><content type="html" xml:base="https://zanidrak.com/cpp/games/2019/10/03/black-and-white-scripts.html"><![CDATA[<p>Black and White uses a proprietary language “LHScript”. It’s extremely simple but it has many inconsistencies.</p>

<p>Every tree, rock, bush, building, light, animal and more is created through a function call. My work so far has been on spawning the objects
into the game world by creating the appropriate components within the entity component system (ECS) and assigning them to new entities.</p>

<p>Here is a line used to create a large immobile rock:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE_NEW_FEATURE("1445.55,2136.40", "Pilar2 Lime", 0, 1000, 0)
</code></pre></div></div>

<p>Here is a line used to create an interactable rock:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE_MOBILE_STATIC("2030.81,2325.50", 25, 10.184691, 0.214573, 0.825486, 0.000783, 1.6)
</code></pre></div></div>

<p>Here is a simple example of an inconsistency. Both specify the rotation of their rocks as radians. The first uses an int (<code class="language-plaintext highlighter-rouge">1000</code>) and the second uses a float (<code class="language-plaintext highlighter-rouge">0.825486</code>). I have to divide the int value to get something useful. 
This is a very common issue across a number of different LHScript functions.</p>

<p>Left side is the original game from 2001.
<img src="/assets/b_and_w/black_and_white_1_diff.png" alt="First comparison" />
<img src="/assets/b_and_w/black_and_white_1_diff_2.png" alt="Second comparison" /></p>

<p>For our ECS we decided to use <a href="https://github.com/skypjack/entt">enTT</a>. It’s a superb library.</p>]]></content><author><name>raffclar</name></author><category term="cpp" /><category term="games" /><summary type="html"><![CDATA[Black and White uses a proprietary language “LHScript”. It’s extremely simple but it has many inconsistencies.]]></summary></entry><entry><title type="html">Emscripten (C/C++ to JS) File Upload Example</title><link href="https://zanidrak.com/jekyll/update/2019/10/02/test.html" rel="alternate" type="text/html" title="Emscripten (C/C++ to JS) File Upload Example" /><published>2019-10-02T22:37:18+00:00</published><updated>2019-10-02T22:37:18+00:00</updated><id>https://zanidrak.com/jekyll/update/2019/10/02/test</id><content type="html" xml:base="https://zanidrak.com/jekyll/update/2019/10/02/test.html"><![CDATA[<p>Emscripten is a compiler backend that generates web assembly (.wasm) files from LLVM’s intermediate representation. This representation can be generated through Clang.</p>

<p><a href="https://github.com/raffclar/pe_appended">I have compiled one of my tools written in C++ using Emscripten</a>. This can be run by selecting a Windows executable. Large executables might fail due to memory allocation limits.</p>

<p><label style="display:block;font: 2rem 'Fira Sans', sans-serif;" for="emscripten-file-input">Select a Windows Executable (exe) file:</label>
<input id="emscripten-file-input" type="file" /></p>
<textarea id="emscripten-output" rows="16" cols="60"></textarea>

<script type="text/javascript">
    var exeInput = document.getElementById('emscripten-file-input');

    exeInput.onchange = function(event) {
        var reader = new FileReader();
        var files = event.target.files;

        reader.onloadend = function () {
            var fileName = "file";
            var base64result = reader.result.split(',')[1];
            run_pe_appended(fileName, base64result);
        };

        reader.readAsDataURL(files[0]);
    };

    var Module;

    function run_pe_appended(fileName, fileData) {
        Module = {
            preRun: [],
            postRun: [],
            print: (function () {
                var element = document.getElementById('emscripten-output');
                if (element) element.value = ''; // clear browser cache
                return function (text) {
                    if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
                    console.log(text);
                    if (element) {
                        element.value += text + "\n";
                        element.scrollTop = element.scrollHeight; // focus on bottom
                    }
                };
            })(),
            printErr: function (text) {
                if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
                console.error(text);
            },
            preRun: function () {
                FS.createDataFile(".", fileName, atob(fileData), true, true);
            },
            totalDependencies: 0,
            arguments: [fileName]
        };

        var emscripten = document.getElementById('emscripten-runner');

        if (emscripten) {
            emscripten.remove();
        }

        emscripten = document.createElement('script');
        emscripten.setAttribute('src','/assets/cpp/pe_appended_loader.js');
        emscripten.setAttribute('id', 'emscripten-runner');

        document.head.appendChild(emscripten);
    }
</script>

<p>This might have issues with older browsers.</p>]]></content><author><name>raffclar</name></author><category term="jekyll" /><category term="update" /><summary type="html"><![CDATA[Emscripten is a compiler backend that generates web assembly (.wasm) files from LLVM’s intermediate representation. This representation can be generated through Clang.]]></summary></entry></feed>