<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.0">Jekyll</generator><link href="http://www.independent-software.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://www.independent-software.com/" rel="alternate" type="text/html" /><updated>2026-06-26T12:48:54+00:00</updated><id>http://www.independent-software.com/</id><title type="html">Independent Software</title><subtitle>Independent Software crafts beautiful, professional websites and database solutions.</subtitle><author><name>Alexander van Oostenrijk</name></author><entry><title type="html">Mercator: gridded earth data as map tiles</title><link href="http://www.independent-software.com/mercator-gridded-earth-data-as-tiles.html" rel="alternate" type="text/html" title="Mercator: gridded earth data as map tiles" /><published>2026-06-11T07:00:00+00:00</published><updated>2026-06-11T07:00:00+00:00</updated><id>http://www.independent-software.com/mercator-gridded-earth-data-as-tiles</id><content type="html" xml:base="http://www.independent-software.com/mercator-gridded-earth-data-as-tiles.html">&lt;p&gt;A few years ago I wrote here about &lt;a href=&quot;/fast-uniform-vector-grids-with-scattered-data-interpolation-in-csharp.html&quot;&gt;generating current-flow animations on map tiles from sparse vector data&lt;/a&gt;. That little tile-by-tile animation experiment never quite left me alone. I have spent the last while turning the idea into a real product, and it is now live: &lt;strong&gt;&lt;a href=&quot;https://mercator.blue&quot;&gt;mercator&lt;/a&gt;&lt;/strong&gt;, a gridded earth data API that serves weather, ocean, air quality and elevation as map tiles.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;&lt;img src=&quot;https://mercator.blue/og-default.png&quot; alt=&quot;mercator: gridded earth data as tiles&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;the-problem&quot;&gt;The problem&lt;/h1&gt;

&lt;p&gt;There is an enormous amount of earth-science data on the internet, and almost none of it is shaped for a map. Most commercial weather APIs answer one question well: &lt;em&gt;what is the value at this latitude and longitude?&lt;/em&gt; You send a coordinate, you get a number. That is perfect for a “weather in your city” widget and useless if you want to draw temperature as a continuous field across a continent, or animate wind as flowing particles over an ocean.&lt;/p&gt;

&lt;p&gt;If you want the continuous surface, a point API forces you to make thousands of requests and then interpolate between them yourself. You end up rebuilding a grid the provider already had and threw away at the API boundary. What you actually want is the grid. The raw model output (NOAA’s GFS, ocean state from HYCOM, air quality from Copernicus CAMS, elevation from GEBCO) is already a regular array of values over the globe. The real job is just getting that array into a browser efficiently enough to render it at 60fps.&lt;/p&gt;

&lt;h1 id=&quot;values-baked-into-pixels&quot;&gt;Values baked into pixels&lt;/h1&gt;

&lt;p&gt;Map tiles already solved “deliver a huge raster to a browser, lazily, at the zoom and region the user is actually looking at, cached hard at a CDN”. Every mapping library on earth speaks that protocol. The only twist mercator adds is that its tiles do not carry &lt;em&gt;colours&lt;/em&gt;. They carry &lt;em&gt;values&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The bytes in each pixel are the actual physical quantity, scaled and offset to fit the 8-bit channels of an ordinary PNG, and a fragment shader decodes them back to real units on the GPU at draw time. This is the same idea as Mapbox’s Terrain-RGB, which packs elevation into RGB, generalised to scalars like temperature and to vector fields like wind and currents.&lt;/p&gt;

&lt;p&gt;The payoff is that the developer controls the visualisation entirely on the client. Swap the colour ramp, switch from a filled raster to streamlines to contours, change the value range, all without refetching a single byte, because the bytes are the data and not a picture of it. The current-flow animation from that old article is now just one of the things you can render, except the heavy lifting happens in a shader instead of being baked into a GIF.&lt;/p&gt;

&lt;h1 id=&quot;what-it-does&quot;&gt;What it does&lt;/h1&gt;

&lt;p&gt;mercator has two halves. The first is the &lt;strong&gt;tile service&lt;/strong&gt;: an HTTP endpoint serving the value-encoded tiles plus a &lt;code class=&quot;highlighter-rouge&quot;&gt;metadata.json&lt;/code&gt; that fully documents the encoding, so any developer can decode the pixels without my code. The second is an &lt;strong&gt;open-source SDK&lt;/strong&gt; that ships the shader decoders and ready-made visualisations (colormapped rasters, animated wind and current streamlines, arrows, contours, value labels) for &lt;a href=&quot;https://mercator.blue/quickstart/maplibre/&quot;&gt;MapLibre, Mapbox, Leaflet, OpenLayers, deck.gl and React&lt;/a&gt;. Six lines of JavaScript get you an animated wind field on a map.&lt;/p&gt;

&lt;p&gt;The catalogue spans atmospheric weather, ocean currents and waves, air quality and elevation, and the forecast datasets refresh on a six-hourly cycle. The whole thing follows the same shape as Mapbox GL JS or Deck.gl: the SDK is free and open (Apache-2.0), and the paid part is the data API, with a free tier of 10,000 tiles a month. Because the tile format is documented, you are never locked to my renderer.&lt;/p&gt;

&lt;h1 id=&quot;have-a-look&quot;&gt;Have a look&lt;/h1&gt;

&lt;p&gt;There is a live interactive globe on the &lt;a href=&quot;https://mercator.blue&quot;&gt;homepage&lt;/a&gt; with wind streaming over it, a &lt;a href=&quot;https://mercator.blue/quickstart/maplibre/&quot;&gt;live playground for each framework&lt;/a&gt;, and the full &lt;a href=&quot;https://mercator.blue/docs&quot;&gt;tile-encoding and API docs&lt;/a&gt; if you want to decode the tiles yourself. The free tier needs no credit card.&lt;/p&gt;

&lt;p&gt;It started as a tile-animation hack in a C# project, and it has grown into a proper gridded-earth-data service. If you build maps and have ever wanted real weather or ocean data on them without wrestling a point API, I would love for you to &lt;a href=&quot;https://mercator.blue&quot;&gt;try it&lt;/a&gt; and tell me what you think.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">A few years ago I wrote here about generating current-flow animations on map tiles from sparse vector data. That little tile-by-tile animation experiment never quite left me alone. I have spent the last while turning the idea into a real product, and it is now live: mercator, a gridded earth data API that serves weather, ocean, air quality and elevation as map tiles.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://www.independent-software.com/assets/svg/currents.svg" /></entry><entry><title type="html">Getting your PHP backend to finally send email</title><link href="http://www.independent-software.com/getting-backend-to-finally-send-email.html" rel="alternate" type="text/html" title="Getting your PHP backend to finally send email" /><published>2024-04-11T10:11:00+00:00</published><updated>2024-04-11T10:11:00+00:00</updated><id>http://www.independent-software.com/getting-backend-to-finally-send-email</id><content type="html" xml:base="http://www.independent-software.com/getting-backend-to-finally-send-email.html">&lt;p&gt;You’re developing a back-end in PHP (Laravel, Lumen, or just freewheeling it)
and you want it to send out email when users use your “forgot password” 
functionality. Getting everything configured just right can be a headache
and this article lists all the things you need to do. You could also reach
for a third-party solution, but then you’d have to have your credit card handy.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h1 id=&quot;using-a-3rd-party-service&quot;&gt;Using a 3rd-party service?&lt;/h1&gt;

&lt;p&gt;If you don’t want to code the email sending yourself, you can reach for a 
third-party solution. &lt;a href=&quot;https://www.mailgun.com/&quot;&gt;Mailgun&lt;/a&gt;, &lt;a href=&quot;https://sendgrid.com/&quot;&gt;Sendgrid&lt;/a&gt; and &lt;a href=&quot;https://mailchimp.com/&quot;&gt;Mailchimp&lt;/a&gt; come to mind, but they
all cost money. Mailgun has a free tier, but it’ll only work for sending out
email to up to 5 known email addresses, and that’s not what you want - you
want to send email out into the world (but only one email at a time). Even if 
you did pay for a third-party solution, it may have a free tier of up to, say, 
1,000 emails per month, after which you start paying. God forbid that your API 
key falls into the wrong hands and someone sends out a million emails with it!&lt;/p&gt;

&lt;h1 id=&quot;using-your-own-server&quot;&gt;Using your own server&lt;/h1&gt;

&lt;p&gt;In my case, I have a shared-hosting server that runs PHP. Through CPanel, I
am able to create email addresses, so I can go ahead and create 
&lt;code class=&quot;highlighter-rouge&quot;&gt;info@myserver.org&lt;/code&gt; and use that to send email from.&lt;/p&gt;

&lt;h2 id=&quot;problem-1-email-sent-manually-from-my-server-does-not-arrive&quot;&gt;Problem 1: Email sent manually from my server does not arrive&lt;/h2&gt;

&lt;p&gt;With so many spammers around, email has become something like the Wild West. 
Anyone can send out emails, and users are bombarded with spam. To fight some 
of this, email providers try to block emails where it can’t be determined where
the email came from - in which case it could be a spoofed address.&lt;/p&gt;

&lt;p&gt;Sending out a simple email manually from my CPanel email client to a GMail 
address will result in this (I’ll get an email back from CPanel or from Gmail):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;550-5.7.26 This message does not pass authentication checks (SPF and DKIM both 
550-5.7.26 do not pass).
550-5.7.26 This mail is unauthenticated, which poses a security risk to the 
550-5.7.26 sender and Gmail users, and has been blocked. The sender must 
550-5.7.26 authenticate with at least one of SPF or DKIM. For this message, 
550-5.7.26 DKIM checks did not pass and SPF check for [example.com] 
550-5.7.26 did not pass with ip: [x.y.z.n]. The sender should visit 
550-5.7.26 https://support.google.com/mail/answer/81126#authentication for 
550 5.7.26 instructions on setting up authentication.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In other words, if your domain doesn’t have &lt;a href=&quot;https://postmarkapp.com/guides/spf&quot;&gt;SPF&lt;/a&gt; and &lt;a href=&quot;https://postmarkapp.com/guides/dkim&quot;&gt;DKIM&lt;/a&gt; records, GMail (and
likely others) will reject your mails straight out of the gate.&lt;/p&gt;

&lt;p&gt;A solution is brought by CPanel itself: the &lt;strong&gt;Email deliverability&lt;/strong&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.greengeeks.com/support/wp-content/uploads/2019/04/cPanel-select-section-EMAIL-deliverability-01.png&quot; alt=&quot;Accessing Email Deliverability on CPanel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you have no DKIM or SPF records setup, then the Email Deliverabilty screen 
will report that there is a problem and offer to repair it:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.greengeeks.com/support/wp-content/uploads/2019/04/cPanel-email-deliverability-01.png&quot; alt=&quot;Repaint DKIM problem&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If your DNS is actually under CPanel’s control, you can CPanel create SPF
and DKIM records automatically. If not, and like me, you have your domain
at GoDaddy while you’re hosting somewhere else, it’s not going to be automatic.
But never fear, CPanel can still help. If you choose the &lt;strong&gt;Manage&lt;/strong&gt; option,
CPanel will tell you that no DKIM record exists, and provide you with a suggested
record:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This system does not control DNS for the “myserver.org” domain and the system 
did not find any authoritative nameservers for this domain. You can install the 
suggested “DKIM” record locally. However, this server is not the authoritative 
nameserver. If you install this record, this change will not be effective. 
Contact your domain registrar to verify this domain’s registration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Suggested DKIM (TXT) record:
Name = default._domainkey.www.myserver.org.
Value = v=DKIM1; k=rsa; p=a-long-encrypted-value;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Suggested SPF (TXT) record:
Name = www.myserver.org.
Value = v=spf1 +mx +a +ip4:(ip number) ~all&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can actually take these values to GoDaddy and create the DNS records
yourself. Note that both need to be &lt;strong&gt;TXT&lt;/strong&gt; records. Create these and save
them, wait a few minutes, and then manually send an email again. It should
now arrive without issue into a GMail inbox.&lt;/p&gt;

&lt;h2 id=&quot;getting-laravels-mailer-to-behave&quot;&gt;Getting Laravel’s mailer to behave&lt;/h2&gt;

&lt;p&gt;With the TXT records configured, I found that while I could send emails
manually through the email web client and receive them, emails from PHP
would not be received.&lt;/p&gt;

&lt;p&gt;It turns out that for Lumen, after configuring &lt;a href=&quot;https://lumen.laravel.com/docs/10.x/mail&quot;&gt;all that’s necessary&lt;/a&gt; for &lt;code class=&quot;highlighter-rouge&quot;&gt;Illuminate/mail&lt;/code&gt;, no email would be sent. I also found
that the email sending route returns rather quickly; ordinarily it would be
processing a little while before returning.&lt;/p&gt;

&lt;p&gt;I there checked my STMP settings using the &lt;a href=&quot;https://www.gmass.co/smtp-test&quot;&gt;GMass SMTP Test Tool&lt;/a&gt;
which came in handy. I found that I was able to send email email through this
and receive it in a GMail inbox, so my SMTP settings were correct. I also
noted that sending the email took a few seconds, so it was suspicious that
the Laravel code returned immediately.&lt;/p&gt;

&lt;p&gt;Finding no way to get the Laravel code to tell me why it failed, I installed
the venerable &lt;a href=&quot;https://github.com/PHPMailer/PHPMailer&quot;&gt;PHPMailer&lt;/a&gt; instead. Testing
it out by pasting its sample code into my back-end implementation, it immediately worked.&lt;/p&gt;

&lt;p&gt;Stepping away from Laravel’s SwiftMailer was made easier by using Laravel’s &lt;code class=&quot;highlighter-rouge&quot;&gt;ENV&lt;/code&gt;
variables in PHPMailer instead of using hardcoded values (these are the settings 
from the &lt;code class=&quot;highlighter-rouge&quot;&gt;.env&lt;/code&gt; file):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'MAIL_HOST'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// Set the SMTP server to send through&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SMTPAuth&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                        &lt;span class=&quot;c1&quot;&gt;// Enable SMTP authentication&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Username&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'MAIL_USERNAME'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// SMTP username&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Password&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'MAIL_PASSWORD'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// SMTP password&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SMTPSecure&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PHPMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ENCRYPTION_SMTPS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Enable implicit TLS encryption&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Port&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'MAIL_PORT'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2525&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// TCP port&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Further, it’s still possible to use Laravel’s Blade templates by rendering them
to string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Subject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Database password reset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Body&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'reset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;compact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'user'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$mail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I know I’ve had Laravel’s SwiftMailer work for me in the past, but PHPMailer
does me the courtesy of letting me put a &lt;code class=&quot;highlighter-rouge&quot;&gt;try&lt;/code&gt;…&lt;code class=&quot;highlighter-rouge&quot;&gt;catch&lt;/code&gt; around the mail sending
process so that I’ll know when it’s failed. Also, a full SMTP debug can be 
echoed to the output to see precisely what went wrong.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">You’re developing a back-end in PHP (Laravel, Lumen, or just freewheeling it) and you want it to send out email when users use your “forgot password” functionality. Getting everything configured just right can be a headache and this article lists all the things you need to do. You could also reach for a third-party solution, but then you’d have to have your credit card handy.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Texture mapping</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-21-texture-mapping.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Texture mapping" /><published>2023-02-06T16:32:00+00:00</published><updated>2023-02-06T16:32:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-21-texture-mapping</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-21-texture-mapping.html">&lt;p&gt;This trainer is on texture mapping. I know, I know, I said light sourcing, then 
Gouraud, then texture mapping, but I got enough mail (a deluge in fact ;) 
telling me to do texture mapping.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;free-direction-texture-mapping&quot;&gt;Free Direction Texture Mapping&lt;/h2&gt;

&lt;p&gt;There are two things you should know before we begin.&lt;/p&gt;

&lt;p&gt;Firstly, I am cheating. The texture mapping I am going to show you is not
perspective-correct, with clever divides for z-placement etc. This method
looks almost as good and is quite a bit faster too.&lt;/p&gt;

&lt;p&gt;Secondly, you will find it all rather easy. The reason for this is that it’s
all rather simple. I first made the routine by sitting down with some paper
and a pencil and had it on the machine in a few hours. A while later when
people on the net started discussing their methods, they were remarkably
similar.&lt;/p&gt;

&lt;p&gt;Let me show you what I mean.&lt;/p&gt;

&lt;p&gt;Let us assume you have a texture of 128x128 (a straight array of bytes
&lt;code class=&quot;highlighter-rouge&quot;&gt;[0..127, 0..127]&lt;/code&gt;) which you want to map onto the side of a polygon. The
problem of course being that the polygon can be all over the place, with
one side longer then the other etc.&lt;/p&gt;

&lt;p&gt;Our first step is to make sure we know which end is up. Let me
demonstrate:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                      1
                    +
                 /    \
              /         \
          4 +            +  2
              \        /
                \   /
                  +
                  3&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let us say that the above is the chosen polygon. We have decided that point
1 is the top left, point 3 is bottom right. This means that&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;1 - 2   is the top of the texture&lt;/li&gt;
  &lt;li&gt;2 - 3   is the right of the texture&lt;/li&gt;
  &lt;li&gt;3 - 4   is the bottom of the texture&lt;/li&gt;
  &lt;li&gt;4 - 1   is the left of the texture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same polygon, but rotated:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                      3
                    +
                 /    \
              /         \
          2 +            +  4
              \        /
                \   /
                  +
                  1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Although the positions of the points are different, point 1 is still the
top-left of our texture.&lt;/p&gt;

&lt;h2 id=&quot;how-to-put-it-to-screen&quot;&gt;How to put it to screen&lt;/h2&gt;

&lt;p&gt;Okay, so now you have four points and know which one of them is also the 
top-left of our texture. What next?&lt;/p&gt;

&lt;p&gt;If you think back to our tutorial on polygons, you will remember we draw it
scanline by scanline. We do texture mapping the same way.&lt;/p&gt;

&lt;p&gt;Let’s look at that picture again:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                      1
                    +
               a /    \  b
              /         \
          4 +            +  2
              \        /
                \   /
                  +
                  3&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We know that point 1 is at &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,0]&lt;/code&gt; in our texture. Point 2 is at &lt;code class=&quot;highlighter-rouge&quot;&gt;[127,0]&lt;/code&gt;,
Point 3 is at &lt;code class=&quot;highlighter-rouge&quot;&gt;[127,127]&lt;/code&gt;, and point 4 is at &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,127]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The clever bit, and the entire key to texture mapping, is making the
logical leap that precisely half way between Point 1 and Point 2 (b), we are at
&lt;code class=&quot;highlighter-rouge&quot;&gt;[64,0]&lt;/code&gt; in our texture. (a) is in the same manner at &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,64]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s it. All we need to know per y scanline is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The starting position on the x axis of the polygon line&lt;/li&gt;
  &lt;li&gt;The position on the x in the texture map referenced by that point&lt;/li&gt;
  &lt;li&gt;The position on the y in the texture map referenced by that point&lt;/li&gt;
  &lt;li&gt;The ending position on the x axis of the polygon line&lt;/li&gt;
  &lt;li&gt;The position on the x in the texture map referenced by that point&lt;/li&gt;
  &lt;li&gt;The position on the y in the texture map referenced by that point&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me give you an example. Let’s say that (a) and (b) from the above
picture are on the same y scanline. We know that the x of that scanline is
(say) 100 pixels at the start and 200 pixels at the end, making it’s width
100 pixels.&lt;/p&gt;

&lt;p&gt;We know that on the left hand side, the texture is at &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,64]&lt;/code&gt;, and at the
right hand side, the texture is at &lt;code class=&quot;highlighter-rouge&quot;&gt;[64,0]&lt;/code&gt;. In 100 pixels we have to
traverse our texture from &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,64]&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;[64,0]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Assume at the start we have figured out the starting and ending points in
the texture:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;  &lt;span class=&quot;n&quot;&gt;textureX&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;textureY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;textureEndX&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;textureEndY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextureEndX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextureX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)/(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextureEndY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextureY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)/(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;minx&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxx&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PutPixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ypos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texture&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VGA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;textureX&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureX&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;textureY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureY&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Do the above for all the scanlines, and you have a texture mapped polygon!
It’s that simple.&lt;/p&gt;

&lt;p&gt;We find our beginning and ending positions in the usual fashion. We know
that Point 1 is &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,0]&lt;/code&gt;. We know that Point 2 is &lt;code class=&quot;highlighter-rouge&quot;&gt;[127,0]&lt;/code&gt;. We know the number
of scanlines on the y axis between Point 1 and Point 2.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  textureDX = 127/abs (point2.y - point1.y)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We run though all the y scanlines, starting from &lt;code class=&quot;highlighter-rouge&quot;&gt;[0,0]&lt;/code&gt; and adding the above
formula to the X every time. When we hit the last scanline, we will be at
point &lt;code class=&quot;highlighter-rouge&quot;&gt;[127,0]&lt;/code&gt; in the texture.&lt;/p&gt;

&lt;p&gt;Repeat for all four sides, and you have the six needed variables per
scanline.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;As you can see, texture mapping (this type at least) is quite easy, and
produces quite a good result. You will however notice a bit of distortion
if you bring the polygon too close. This can be fixed by a) Subdividing the
polygon, so the one is made up of four or more smaller polygons. Much
bigger, but works; b) Using more accurate fixed point; or c) Figuring out
perspective correct texture mapping, mapping along constant-z lines etc.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">This trainer is on texture mapping. I know, I know, I said light sourcing, then Gouraud, then texture mapping, but I got enough mail (a deluge in fact ;) telling me to do texture mapping.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Hidden face removal</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-20-hidden-face-removal.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Hidden face removal" /><published>2023-02-06T16:27:00+00:00</published><updated>2023-02-06T16:27:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-20-hidden-face-removal</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-20-hidden-face-removal.html">&lt;p&gt;This trainer is on 3D hidden face removal and face sorting. I was going to
add shading, but that can wait until a later trainer. For convenience I
will build on the 3D code from &lt;a href=&quot;/denthor-asphyxia-vga-trainer-8-3d-visualization.html&quot;&gt;Part 8&lt;/a&gt;. The maths for 
face removal is a bit tricky, but just think back to your old high school 
trigonometry classes.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;face-sorting&quot;&gt;Face Sorting&lt;/h2&gt;

&lt;p&gt;There are many ways to sort faces in a 3D object. For now, I will show you
just about the easiest one of the lot.&lt;/p&gt;

&lt;p&gt;Say you have two polygons….&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                ------P1

           ------------------P2

                   Eye&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, &lt;code class=&quot;highlighter-rouge&quot;&gt;P1&lt;/code&gt; has to be drawn before &lt;code class=&quot;highlighter-rouge&quot;&gt;P2&lt;/code&gt;. The easiest way to do this is
as follows:&lt;/p&gt;

&lt;p&gt;On startup, find the midpoint of each of the polys, through the easy
equations:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;x = (P2.1.x + P2.2.x + P2.3.x + p2.4.x)/4
y = (P2.1.y + P2.2.y + P2.3.y + p2.4.y)/4
z = (P2.1.z + P2.2.z + P2.3.z + p2.4.z)/4&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;NOTE: For a triangle you would obviously only use three points and divide
by three.&lt;/p&gt;

&lt;p&gt;Anyway, now you have the X,Y,Z of the midpoint of the polygon. You can then
rotate this point with the others. When it is time to draw, you can
compare the resulting Z of the midpoint, sort all of the Z items, and then
draw them from back to front.&lt;/p&gt;

&lt;p&gt;In the sample program I use a simple bubble sort… basically, I check the
first two values against each other, and swap them if the first is bigger
than the second. I continue doing this to all the numbers until I run
through the entire list without swapping once. Bubble sorts are standard
computer science topics… perhaps borrow a text book to find out
more about them and other (better) sorting methods.&lt;/p&gt;

&lt;p&gt;The above isn’t perfect, but it should work 90% of the time. But it still
means that when you are drawing a cube, you have to draw all 6 sides every
frame, even though only three or so are visible. That is where hidden face
removal comes in…&lt;/p&gt;

&lt;h2 id=&quot;hidden-face-removal&quot;&gt;Hidden Face Removal&lt;/h2&gt;

&lt;p&gt;Pick up something square. A stiffy disk will do fine. Face it towards you,
and number all the corners from one to four in a clockwise direction.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                1 +-------------+ 2
                  |             |
                  |             |
                  |             |
                  |             |
                4 +-------------+ 3&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now rotate the stiffy disk on all three axes, making sure that you can
still see the front of the disk. You will notice that whenever you can see
the front of the disk, the four points are still in alphabetical order. Now
rotate it so that you can see the back of the stiffy. Your points will now
be:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                2 +-------------+ 1
                  |             |
                  |             |
                  |             |
                  |             |
                3 +-------------+ 4&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The points are now anti-clockwise! This means, in its simplest form, that
if you define all your polygon points in a clockwise order, when drawing you
ignore the polys that are anticlockwise. (Obviously when you define the 3D
object, you define the polygons facing away from you in an anticlockwise
order.)&lt;/p&gt;

&lt;p&gt;To find out whether a poly’s points are clockwise or not, we need to find
its normal. Here is where things start getting fun.&lt;/p&gt;

&lt;p&gt;In school, you are told that a normal is perpendicular to the plane. In
ASCII:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                      | Normal
                      |
                      |
        --------------------------- Polygon&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, the normal is at 90 degrees to the surface of the poly. We
must extend this to three dimensions for our polygons. You’ll have to trust
me on that, I can’t draw it in ASCII :)&lt;/p&gt;

&lt;p&gt;To find a normal, you only need three points from your poly (ABC):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;A(x0,y0,z0), B(X1,Y1,Z1), C(X2,Y2,Z2)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then the vector normal = AB^AC = (Xn,Yn,Zn) with&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Xn=(y1-y0)(z0-z2)-(z1-z0)(y0-y2)
Yn=(z1-z0)(x0-x2)-(x1-x0)(z0-z2)
Zn=(x1-x0)(y0-y2)-(y1-y0)(x0-x2)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We are interested in the Z normal, so we will use the function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;normal:=(x1-x0)(y0-y2)-(y1-y0)(x0-x2);&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The result is something of a sine wave when you rotate the poly in three
dimensions. A negative value means that the poly is facing you, a positive
value means that it is pointing away.&lt;/p&gt;

&lt;p&gt;The above means that with a mere two MULs you can discount an entire poly
and not draw it. This method is perfect for “closed” objects such as cubes
etc.&lt;/p&gt;

&lt;p&gt;I am anything but a maths teacher, so go borrow someone’s math book to find
out more about surface normals. Trust me, there is a lot more written about
them than you think.&lt;/p&gt;

&lt;p&gt;An extension of calculating your normal is finding out about light-sourcing
your polygons. Watch for more information in one of the next few trainers.&lt;/p&gt;

&lt;p&gt;A combination of the above two routines should work quite nicely in
creating 3d objects with little or no overlapping.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">This trainer is on 3D hidden face removal and face sorting. I was going to add shading, but that can wait until a later trainer. For convenience I will build on the 3D code from Part 8. The maths for face removal is a bit tricky, but just think back to your old high school trigonometry classes.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Flame effect</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-19-flame-effect.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Flame effect" /><published>2023-02-06T16:11:00+00:00</published><updated>2023-02-06T16:11:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-19-flame-effect</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-19-flame-effect.html">&lt;p&gt;This trainer is on assembler. For those people who already know assembler 
quite well, this tutorial is also on the flame effect.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;assembler---the-short-version&quot;&gt;Assembler - the short version&lt;/h2&gt;

&lt;p&gt;Okay, there are many assembler trainers out there, many of which are
probably better than this one. I will focus on the areas of assembler that
I find important… if you want more, go buy a book (go for the Michael
Abrash ones), or scour the ‘net for others.&lt;/p&gt;

&lt;p&gt;First, let us start off with the basic set up of an assembler program.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;DOSSEG&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This tells your assembler program to order your segments in the same manner
that high level languages do.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;.MODEL &amp;lt;MODEL&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;MODEL&amp;gt;&lt;/code&gt; can be:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Tiny       Code + Data &amp;lt; 64k   (Can be made a COM file)
Small      Code &amp;lt; 64k          Data &amp;lt; 64k
Medium     Code &amp;gt; 64k          Data &amp;lt; 64k
Compact    Code &amp;lt; 64k          Data &amp;gt; 64k
Large      Code &amp;gt; 64k          Data &amp;gt; 64k
Huge       Arrays &amp;gt; 64k&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Enable 286 instructions … can be &lt;code class=&quot;highlighter-rouge&quot;&gt;.386&lt;/code&gt; ; &lt;code class=&quot;highlighter-rouge&quot;&gt;.386P&lt;/code&gt; etc.:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;.286&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Set the stack. &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;size&amp;gt;&lt;/code&gt; will be the size of your stack. I usually use &lt;code class=&quot;highlighter-rouge&quot;&gt;200h&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;.STACK &amp;lt;size&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Tells the program that the data is about to follow. (Everything after this
will be placed in the data segment):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;.DATA&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Tells the program that the code is about to follow. (Everything after this
will be placed in the code segment)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;.CODE&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Tells the program that this is where the code begins:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;START:&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Tells the program that this is where the code ends:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;END START&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To compile and run an assembler file, we run:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;tasm bob
tlink bob&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I personally use &lt;code class=&quot;highlighter-rouge&quot;&gt;tasm&lt;/code&gt;; you will have to find out how your assembler works.&lt;/p&gt;

&lt;p&gt;Now, if we ran the above file as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;DOSSEG
.MODEL SMALL
.286
.STACK 200h
.DATA
.CODE

START
END START&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You would think that is would just exit to DOS immediately, right? Wrong.
You have to specifically give DOS back control, by doing the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;START
        mov     ax,4c00h
        int     21h
END START&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now if you compiled it, it would run and do nothing.&lt;/p&gt;

&lt;p&gt;Okay, let us kick off with registers.&lt;/p&gt;

&lt;p&gt;Firstly: A bit is a value that is either 1 or 0.&lt;/p&gt;

&lt;p&gt;This is obviously quite limited, but if we start counting in them, we can
get larger numbers. Counting with ones and zeros is known as binary, and we
call it base 2. Counting in normal decimal is known as base 10, and
counting in hexadecimal is known as base 16.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;    Base 2 (Binary)     Base 10 (Decimal)    Base 16 (Hexadecimal)
         0                      0                       0
         1                      1                       1
         10                     2                       2
         11                     3                       3
         100                    4                       4
         101                    5                       5
         110                    6                       6
         111                    7                       7
         1000                   8                       8
         1001                   9                       9
         1010                   10                      A
         1011                   11                      B
         1100                   12                      C
         1101                   13                      D
         1110                   14                      E
         1111                   15                      F&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, you need four bits to count up to 15, and we call this a
&lt;em&gt;nibble&lt;/em&gt;. With eight bits, we can count up to 255, and we call this a &lt;em&gt;byte&lt;/em&gt;.
With sixteen bits, we can count up to 65535, and we call this a &lt;em&gt;word&lt;/em&gt;. With
thirty-two bits, we can count up to lots, and we call this a &lt;em&gt;double word&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A quick note: Converting from binary to hexadecimal is actually quite easy. You
break up the binary into groups of four bits, starting on the right, and
convert these groups of four to hex.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;      1010 0010 1111 0001
  =      A    2    F    1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Converting to decimal is a bit more difficult. What you do, is you multiply
each number by its base to the power of its index…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  A2F1 hex
= (A*16^3) + (2*16^2) + (F*16^1) + (1*16^0)
= (10*4096) + (2*256) + (15*16) + (1)
= 40960 + 512 + 240 + 1
= 41713 decimal&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The same system can be used for binary.&lt;/p&gt;

&lt;p&gt;To convert from decimal to another base, you divide the decimal value by the
desired base, keeping a note of the remainders, and then read the results
backwards.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;               16   |   41713
               16   |   2607    r   1       (41713 / 16 = 2607 r 1)
               16   |   162     r   F       (2607 / 16 = 162 r 15)
               16   |   10      r   2       (162 / 16 = 10 r 2)
                    |   0       r   A       (10 / 16 = 0 r 10)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Read the remainders backwards, our number is &lt;code class=&quot;highlighter-rouge&quot;&gt;A2F1&lt;/code&gt; hex. Again, the same
method can be used for binary.&lt;/p&gt;

&lt;p&gt;The reason why hex is popular is obvious: using bits, it is impossible
to get a reasonable base 10 (decimal) system going, and binary gets unwieldly
at high values. Don’t worry too much though: most assemblers (like &lt;code class=&quot;highlighter-rouge&quot;&gt;tasm&lt;/code&gt;)
will convert all your decimal values to hex for you.&lt;/p&gt;

&lt;p&gt;You have four general purpose registers: &lt;code class=&quot;highlighter-rouge&quot;&gt;AX&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;BX&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;CX&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;DX&lt;/code&gt;.
Think of them as variables that you will always have. On a 286, these
registers are 16 bytes long, or one &lt;em&gt;word&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As you know, a &lt;em&gt;word&lt;/em&gt; consists of two bytes, and in assembler you can access
these bytes individually. They are separated into high bytes and low bytes per
word.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;   High byte | Low byte
   0000 0000 | 0000 0000  bits
   [--------Word-------]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The method of access is easy. The high byte of &lt;code class=&quot;highlighter-rouge&quot;&gt;AX&lt;/code&gt; is &lt;code class=&quot;highlighter-rouge&quot;&gt;AH&lt;/code&gt;, and the low byte is
&lt;code class=&quot;highlighter-rouge&quot;&gt;AL&lt;/code&gt;. You can also access &lt;code class=&quot;highlighter-rouge&quot;&gt;BH&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;BL&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;CH&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;CL&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;DH&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;DL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A 386 has extended registers: &lt;code class=&quot;highlighter-rouge&quot;&gt;EAX&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;EBX&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ECX&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;EDX&lt;/code&gt;… you can access the
lower word normally (as &lt;code class=&quot;highlighter-rouge&quot;&gt;AX&lt;/code&gt;, with bytes &lt;code class=&quot;highlighter-rouge&quot;&gt;AH&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;AL&lt;/code&gt;), but you cannot access the
high word directly … you must &lt;code class=&quot;highlighter-rouge&quot;&gt;ror EAX,16&lt;/code&gt; (rotate the binary value through
16 bits), after which the high word and low word swap … do it again to
return them. Acessing &lt;code class=&quot;highlighter-rouge&quot;&gt;EAX&lt;/code&gt; as a whole is no problem: 
&lt;code class=&quot;highlighter-rouge&quot;&gt;mov eax, 10; add eax,ebx&lt;/code&gt; … these are all valid.&lt;/p&gt;

&lt;p&gt;Next come segments. As you have probably heard, computer memory is divided
into various 64k segments (note: 64k = 65,536 bytes, sound familiar?) A
segment register points to which segment you are looking at. An offset
register points to how far into that segment you are looking. One way
of looking at it is like looking at a 2D array… the segments are your
columns and your offsets are your rows. Segments and offsets are displayed
as Segment:Offset … so &lt;code class=&quot;highlighter-rouge&quot;&gt;$a000:50&lt;/code&gt; would mean the fiftieth byte in segment
&lt;code class=&quot;highlighter-rouge&quot;&gt;$a000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The segment registers are &lt;code class=&quot;highlighter-rouge&quot;&gt;ES&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;DS&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;SS&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;CS&lt;/code&gt;. A 386 also has &lt;code class=&quot;highlighter-rouge&quot;&gt;FS&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;GS&lt;/code&gt;.
These values are words (0-65,535), and you cannot access the high or low bytes
separately. &lt;code class=&quot;highlighter-rouge&quot;&gt;CS&lt;/code&gt; points to your code segment, and usually if you touch this
your program will explode. &lt;code class=&quot;highlighter-rouge&quot;&gt;SS&lt;/code&gt; points to your stack segment, again, this
baby is dangerous. &lt;code class=&quot;highlighter-rouge&quot;&gt;DS&lt;/code&gt; points to your data segment, and can be altered, if
you put it back after you use it, and don’t use any global variables while
it is altered. &lt;code class=&quot;highlighter-rouge&quot;&gt;ES&lt;/code&gt; is your extra segment, and you can do what you want with
it.&lt;/p&gt;

&lt;p&gt;The offset registers are &lt;code class=&quot;highlighter-rouge&quot;&gt;DI&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;SI&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;IP&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;SP&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;BP&lt;/code&gt;. Offset registers are generally
associated with specific segment registers, as follows:
&lt;code class=&quot;highlighter-rouge&quot;&gt;ES:DI&lt;/code&gt;  &lt;code class=&quot;highlighter-rouge&quot;&gt;DS:SI&lt;/code&gt;  &lt;code class=&quot;highlighter-rouge&quot;&gt;CS:IP&lt;/code&gt;  &lt;code class=&quot;highlighter-rouge&quot;&gt;SS:SP&lt;/code&gt; … On a 286, &lt;code class=&quot;highlighter-rouge&quot;&gt;BX&lt;/code&gt; can be used instead of the above
offset registers, and on a 386, any register may be used. &lt;code class=&quot;highlighter-rouge&quot;&gt;DS:BX&lt;/code&gt; is therefore
valid.&lt;/p&gt;

&lt;p&gt;If you create a global variable (let’s say &lt;code class=&quot;highlighter-rouge&quot;&gt;bob&lt;/code&gt;), when you access that
variable, the compiler will actually look for it in the data segment.
This means that the statement:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ax = bob&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;could be&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ax = ds:[15]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A quick note: A value may be signed or unsigned. An unsigned word has a
range from 0 to 65,535. A signed word is called an &lt;em&gt;integer&lt;/em&gt; and has a range
-32,768 to 32,767. With a signed value, if the leftmost bit is equal to 1,
the value is in the negative.&lt;/p&gt;

&lt;p&gt;Next, let us have a look at the stack. Let us say that you want to save the
value in &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt;, use &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt; to do other things, then restore it to its origional
value afterwards. This is done by utilizing the stack. Have a look at the
following code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;mov   ax, 50      ; ax is equal to 50
push  ax          ; push ax onto the stack
mov   ax, 27      ; ax is equal to 27
pop   ax          ; pop ax off the stack&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;At this point, &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt; is equal to 50.&lt;/p&gt;

&lt;p&gt;Remember we defined the stack to be &lt;code class=&quot;highlighter-rouge&quot;&gt;200h&lt;/code&gt; further up? This is part of the
reason we have it. When you push a value onto the stack, that value is
recorded on the stack heap (referenced by &lt;code class=&quot;highlighter-rouge&quot;&gt;SS:SP&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;SP&lt;/code&gt; is incremented) When you
pop a value off the stack, the value is placed into the variable you are
popping it back in to, &lt;code class=&quot;highlighter-rouge&quot;&gt;SP&lt;/code&gt; is decremented and so forth. Note that the computer
does not care what you pop the value back into.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;mov   ax, 50
push  ax
pop   bx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This would set the values of both &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;bx&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;50&lt;/code&gt;. (There are faster ways 
of doing this, pushing and popping are fairly fast though).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;push ax
push bx
pop  ax
pop  bx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This would swap the values of &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;bx&lt;/code&gt;. As you can see, to pop the values back
in to the original variables, you must pop them back in the opposite
direction to which you pushed them.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;push ax
push bx
push cx

pop cx
pop bx
pop ax&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;would result in no change for any of the registers.&lt;/p&gt;

&lt;p&gt;When a procedure is called, all the parameters for that procedure are pushed
onto the stack. These can actually be read right off the stack, if you want
to.&lt;/p&gt;

&lt;p&gt;As you have already seen, the &lt;code class=&quot;highlighter-rouge&quot;&gt;mov&lt;/code&gt; command moves a value…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;mov  &amp;lt;dest&amp;gt;, &amp;lt;source&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that &lt;code class=&quot;highlighter-rouge&quot;&gt;dest&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;source&lt;/code&gt; must be the same number of bits long.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;mov  ax, dl&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;would not work, and neither would&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;mov  cl,bx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;mov  cx,dx
mov  ax,50
mov  es,ax&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;are all valid.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;shl&lt;/code&gt; I have explained before, it is where all the bits in a register are
shifted one to the left and a zero added on to the right. This is the
equivalent of multiplying the value by two. &lt;code class=&quot;highlighter-rouge&quot;&gt;shr&lt;/code&gt; works in the opposite
direction.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;rol&lt;/code&gt; does the same, except that the bit that is removed from the left is
replaced on the right hand side. &lt;code class=&quot;highlighter-rouge&quot;&gt;ror&lt;/code&gt; works in the opposite direction.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;div &amp;lt;value&amp;gt;&lt;/code&gt; divides the value in &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt; by value and returns the result in
&lt;code class=&quot;highlighter-rouge&quot;&gt;al&lt;/code&gt; if value is a byte, placing the remainder in &lt;code class=&quot;highlighter-rouge&quot;&gt;ah&lt;/code&gt;. If value is a word,
the double word &lt;code class=&quot;highlighter-rouge&quot;&gt;DX:AX&lt;/code&gt; is divided by value, the result being placed in &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt;
and the remainder in &lt;code class=&quot;highlighter-rouge&quot;&gt;dx&lt;/code&gt;. Note that this only works for unsigned values.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;idiv &amp;lt;value&amp;gt;&lt;/code&gt; does the same as above, but for signed variables.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;mul &amp;lt;value&amp;gt;&lt;/code&gt;  If value is a byte, &lt;code class=&quot;highlighter-rouge&quot;&gt;al&lt;/code&gt; is multiplied by value and the result
is stored in &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt;. If value is a word, &lt;code class=&quot;highlighter-rouge&quot;&gt;ax&lt;/code&gt; is multiplied by value and the
result is stored in the double word &lt;code class=&quot;highlighter-rouge&quot;&gt;DX:AX&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;imul &amp;lt;value&amp;gt;&lt;/code&gt; does the same as above, but for signed variables.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;j*&lt;/code&gt; commands are fairly simple: if a condition is met, jump to a certain
label.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;jz  &amp;lt;label&amp;gt;   Jump if zero
ja  &amp;lt;label&amp;gt;   Jump above     (unsigned)
jg  &amp;lt;label&amp;gt;   Jump greater   (signed)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and so forth.&lt;/p&gt;

&lt;p&gt;An example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;cmp  ax,50    ; Compare ax to 50
je   @Equal   ; If they are equal, jump to label @equal
call MyProc   ; Runs procedure MyProc and then returns to the next line of code.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Procedures are declared as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;MyProc   proc near
         ret    ; Must be here to return from where it was called
MyProc   endp&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Variables are also easy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;bob  db 50&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;creates a variable &lt;code class=&quot;highlighter-rouge&quot;&gt;bob&lt;/code&gt;, a byte, with an initial value of 50.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;bob2 dw 50&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;creates a variable &lt;code class=&quot;highlighter-rouge&quot;&gt;bob2&lt;/code&gt;, a word, with an initial value of 50.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;bob3 db 1,2,3,4,5,65,23&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;creates &lt;code class=&quot;highlighter-rouge&quot;&gt;bob3&lt;/code&gt;, an array of 7 bytes.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;bob4 db 100 dup (?)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;creates &lt;code class=&quot;highlighter-rouge&quot;&gt;bob4&lt;/code&gt;, an array of 100 bytes, with no starting value.&lt;/p&gt;

&lt;p&gt;Go back and look at &lt;a href=&quot;/denthor-asphyxia-vga-trainer-7-animation.html&quot;&gt;Part 7&lt;/a&gt; for a whole lot more assembler commands, and get
some sort of reference guide to help you out with others. I personally use
the Norton Guides help file to program assembler.&lt;/p&gt;

&lt;h2 id=&quot;fire-routines&quot;&gt;Fire Routines&lt;/h2&gt;

&lt;p&gt;To demonstrate how to write an assembler program, we will write a fire
routine in 100% assembler. The theory is simple.&lt;/p&gt;

&lt;p&gt;Set the palette to go from white to yellow to red to blue to black.
Create a 2D array representing the screen on the computer.
Place high values at the bottom of the array (screen)
for each element, do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Take the average of the four elements under it:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                         * Current element
                        123
                         4  Other elements&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Get the average of the four elements, and place the result in the current element.&lt;/li&gt;
  &lt;li&gt;Repeat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Easy, no? I first saw a fire routine in the Iguana demo, and I just had to
do one ;) … it looks very effective.&lt;/p&gt;

&lt;p&gt;With the sample file, I have created a batch file, &lt;code class=&quot;highlighter-rouge&quot;&gt;make.bat&lt;/code&gt;. It basically
says:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;tasm fire
tlink fire&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So to build and run the fire program, type:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;make
fire&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The source file is commented quite well, so there shouldn’t be any problems.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;As you can see, the sample program is in 100% assembler. For the next tutorial
I will return to Pascal, and hopefully your newfound assembler skills will
help you there too.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">This trainer is on assembler. For those people who already know assembler quite well, this tutorial is also on the flame effect.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: File packing</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-18-file-packing.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: File packing" /><published>2023-02-06T15:22:00+00:00</published><updated>2023-02-06T15:22:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-18-file-packing</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-18-file-packing.html">&lt;p&gt;This trainer is about reading PCX files, file packing, and putting everything 
into one executable file.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;loading-a-pcx-file&quot;&gt;Loading a PCX file&lt;/h2&gt;

&lt;p&gt;This is actually quite easy. The PCX file is divided into three sections,
namely a 128 byte header, a data section, and a 768 byte palette.&lt;/p&gt;

&lt;p&gt;You can usually ignore the 128 byte header, but here it is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;0  Manufacturer     10 = ZSoft .PCX file
1  Version
2  Encoding
3  Bits Per Pixel
4  XMin, Ymin, XMax, YMax  (2 bytes each)
12 Horizontal Resolution (2 bytes)
14 Vertical Resolution (2 bytes)
16 Color palette setting (48 bytes)
64 Reserved
65 Number of color planes
66 Bytes per line (2 bytes)
68 1 = Color    2 = Grayscale  (2 bytes)
70 Blank (58 bytes)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That makes 128 bytes.&lt;/p&gt;

&lt;p&gt;The palette file, which is 768 bytes, is situated at the very end of the
PCX file. The 769’th byte back should be the decimal 12, which indicates
that a VGA color palette is to follow.&lt;/p&gt;

&lt;p&gt;There is one thing that we have to do to get the palette correct in VGA…
the PCX palette values for R,G,B are 0 to 255 respectively. To convert this
to our standard (VGA) palette, we must divide the R,G,B values by 4, to get
them into a range of 0 to 63.&lt;/p&gt;

&lt;p&gt;Actually decoding the image is very simple. Starting after the 128 byte
header, we read a byte.&lt;/p&gt;

&lt;p&gt;If the top two bits of this byte are not set, we dump the value to the screen.&lt;/p&gt;

&lt;p&gt;We check bits as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;if ((temp and $c0) = $c0) then ...(bits are set)... else ...(bits are not set)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;C0 in hex = 11000000 in binary = 192 in decimal&lt;/p&gt;

&lt;p&gt;Let’s look at that more closely…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  temp  and  c0h
  temp  and  11000000b&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That means, when represented in bit format, both corresponding bits have
to be set to one for the result to be one.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;0 and 0 = 0     1 and 0 = 0    0 and 1 = 0    1 and 1 = 1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the above case then, both of the top two bits of temp have to be set for
the result to equal &lt;code class=&quot;highlighter-rouge&quot;&gt;11000000b&lt;/code&gt;. If it does not equal that, the top two bits
are not both set, and we can put the pixel.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;putpixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;inc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If the top two bits &lt;em&gt;are&lt;/em&gt; set, things change. The bottom six bits become
a loop counter, which the next byte is repeated.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;{ Read in next byte, temp2 here.}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;putpixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;inc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;putpixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;inc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There is our PCX loader. You will note that by and’ing &lt;code class=&quot;highlighter-rouge&quot;&gt;temp&lt;/code&gt; by &lt;code class=&quot;highlighter-rouge&quot;&gt;$3f&lt;/code&gt;; I am
and’ing it by &lt;code class=&quot;highlighter-rouge&quot;&gt;00111111b&lt;/code&gt;… in other words, clearing the top two bits.&lt;/p&gt;

&lt;p&gt;The sample program has the above in assembler, but it is the same procedure…
and you can read the next tutorial for more info on how to code in assembler.&lt;/p&gt;

&lt;p&gt;In the sample I assume that the pic is 320x200, with a maximum size of 66,432
bytes.&lt;/p&gt;

&lt;h2 id=&quot;file-packing&quot;&gt;File packing&lt;/h2&gt;

&lt;p&gt;The question is simple: how do I get all my files into one executable?
Having many small data files can start to look unprofessional.&lt;/p&gt;

&lt;p&gt;An easy way to have one .exe and one .dat file when dealing with many
cels etc. is easy… you would alter your load procedure, which looks
as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1..5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1..256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Procedure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic1.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic2.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic3.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic4.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic5.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For one compile you would do this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1..5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1..256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Procedure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic1.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic2.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic3.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic4.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic5.cel'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic.dat'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rewrite&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;blockwrite&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;From then on, you would do:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1..5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1..256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Procedure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pic.dat'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;blockread&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This means that instead of five data files, you now have one! You have also
stripped the 800 byte cel header too. Note that this will work for any
form of data, not just cel files.&lt;/p&gt;

&lt;p&gt;The next logical step is to include this data in the .exe file, but the
question is how?  In an earlier tutorial, I converted my data file to
constants and placed it inside my main program. This is not good mainly
because of space restrictions … you can only have so many constants, and
what if your data file is two megs big?&lt;/p&gt;

&lt;p&gt;Attached with this tutorial is a solution. I have written a program that
combines your data files with your executable file, no matter how big
the data is. The only thing you have to worry about is a small change in
your data loading methods. Let’s find out what.&lt;/p&gt;

&lt;h2 id=&quot;using-the-file-packer&quot;&gt;Using the file packer&lt;/h2&gt;

&lt;p&gt;Normally you would load your data as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;Procedure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'bob.bob'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadpcx&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'den.pcx'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VGA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;cm&quot;&gt;{ Load a PCX file }&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loaddat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'data.dat'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;    &lt;span class=&quot;cm&quot;&gt;{ Load raw data into lookup }&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Easy, hey? Now, using the file packer, you would change this to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;USES&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;Procedure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;infodat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'bob.bob'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;infodat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'den.pcx'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;infodat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'data.dat'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadcel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loadpcx&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VGA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;loaddat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Not too difficult? Now, this is still using the normal data files on your
hard drive. You would then run PACK.EXE, select the program’s .exe as the
base, then select “bob.bob”, “den.pcx” and “data.dat”, in order (1, 2, 3).
Hit “c” to contine, and it will combine the files. Your programs .exe file
will be able to run independently of the separate data files on disk,
because the data files are imbedded with the .exe.&lt;/p&gt;

&lt;p&gt;Let us take a closer look at the load procedures. Normally a load procedure
would look as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;Procedure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoadData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;blockread&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;^,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filesize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In FPack.pas, we do the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;&lt;span class=&quot;k&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoadData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pack&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paramstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;seek&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;infopos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blockread&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;^,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;infopos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;infopos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;infodat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;blockread&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;^,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filesize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we just have two special cases depending on whether or not
the .exe file has been packed yet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: After you have packed the file, you CAN NOT pklite it. You can
       however pklite the .exe_before you run pack.exe … in other
       words, you cannot use pklite to try pack your data files.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PACK.EXE does have a limitation … you can only pack 24 data files together.
If you would like it to do more, mail me … It should be easy to increase the
number.&lt;/p&gt;

&lt;p&gt;In the sample program, FINAL.EXE is the same as temp.pas, except it has
its PCX embedded inside it. I ran pack2.exe, selected final.exe and
eye.pcx, hit “C”, and there it was. You will notice that eye.pcx is not
included in the directory … it is now part of the exe!&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;Well, that’s about it for this trainer… next one (as I have mentioned
twice already ;) will be on assembler, with a flame routine thrown in.&lt;/p&gt;

&lt;p&gt;This tut has been a bit of a departure from normal tuts … aside from the
PCX loading routines, the rest has been “non programming” oriented …
don’t worry, next week’s one will be back to normal.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">This trainer is about reading PCX files, file packing, and putting everything into one executable file.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Pixel morphing</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-17-pixel-morphing.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Pixel morphing" /><published>2023-02-06T15:16:00+00:00</published><updated>2023-02-06T15:16:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-17-pixel-morphing</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-17-pixel-morphing.html">&lt;p&gt;This trainer is on a few demo effects (pixel morphs and static).&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;pixel-morphing&quot;&gt;Pixel Morphing&lt;/h2&gt;

&lt;p&gt;Have you ever lain down on your back in the grass and looked up at the
cloudy sky? If you have, you have probably seen the clouds move together
and create wonderful shapes… that cloud plus that cloud together make a
whale… a ship… a face etc.&lt;/p&gt;

&lt;p&gt;We can’t quite outdo Mother Nature, but we can sure give it a shot. The
effect I am going to show you is where various pixels at different starting
points move together and create an overall picture.&lt;/p&gt;

&lt;p&gt;The theory behind it is simple: each pixel has bits of data associated
with it, most important of which is as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;This is my color
This is where I am
This is where I want to be.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The pixel, keeping its color, goes from where it is to where it wants to
be. Our main problem is &lt;em&gt;how&lt;/em&gt; it moves from where it is to where it wants
to be. A obvious approach would be to say “If its destination is above it,
decrement its &lt;code class=&quot;highlighter-rouge&quot;&gt;y&lt;/code&gt; value, if the destination is to the left, decrement its &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt;
value and so on.”&lt;/p&gt;

&lt;p&gt;This would be bad. The pixel would only ever move at set angles, as you can
see below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                Dest   O-----------------\
                                           \  &amp;lt;--- Path
                                             \
                                               \
                                                O Source&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Doesn’t look very nice, does it? The pixels would also take different times
to get to their destination, whereas we want them to reach their points at
the same time, i.e.:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;     Dest 1   O-------------------------------O Source 1
     Dest 2   O-----------------O Source 2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Pixels 1 and 2 must get to their destinations at the same time for the best
effect. The way this is done by defining the number of frames or “hops”
needed to get from source to destination. For example, we could tell pixel
one it is allowed 64 hops to get to its destination, and the same for
point 2, and they would both arrive at the same time, even though pixel 2
is closer.&lt;/p&gt;

&lt;p&gt;The next question, it how do we move the pixels in a straight line? This is
easier than you think…&lt;/p&gt;

&lt;p&gt;Let us assume that for each pixel, &lt;code class=&quot;highlighter-rouge&quot;&gt;x1,y1&lt;/code&gt; is where it is, and &lt;code class=&quot;highlighter-rouge&quot;&gt;x2,y2&lt;/code&gt; is where
it wants to be.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;   (x2-x1) = The distance on the X axis between the two points
   (y2-y1) = The distance on the Y axis between the two points&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we do the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  dx := (x2-x1)/64;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;we come out with a value in &lt;code class=&quot;highlighter-rouge&quot;&gt;dx&lt;/code&gt; which is very useful. If we added &lt;code class=&quot;highlighter-rouge&quot;&gt;dx&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;x1&lt;/code&gt; 64
times, the result would be &lt;code class=&quot;highlighter-rouge&quot;&gt;x2&lt;/code&gt;! Let us check…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  dx = (x2-x1)/64
  dx*64 = x2-x1         { Multiply both sides by 64 }
  dx*64+x1 = x2         { Add x1 to both sides }&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is high school math stuff, and is pretty self explanatory. So what we
have is the x movement for every frame that the pixel has to undergo. We
find the y movement in the same manner.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  dy := (y2-y1)/64;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So our program is as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;  &lt;span class=&quot;cm&quot;&gt;{ Set x1,y1 and x2,y2 values }&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;putpixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If there was a compiler that could use the above pseudocode, it would move
the pixel from x1,y1 to x2,y2 in 64 steps.&lt;/p&gt;

&lt;p&gt;So, what we do is set up an array of many pixels with this information, and
move them all at once… voilá, we have pixel morphing! It is usually best
to use a bitmap which defines the color and destination of the pixels, then
randomly scatter them around the screen.&lt;/p&gt;

&lt;p&gt;Why not use pixel morphing on a base object in 3d? It would be the work of
a moment to add in a Z axis to the above.&lt;/p&gt;

&lt;p&gt;The sample program uses fixed point math in order to achieve high speeds,
but it is basically the above algorithm.&lt;/p&gt;

&lt;h2 id=&quot;static&quot;&gt;Static&lt;/h2&gt;

&lt;p&gt;A static screen was one of the first effects Asphyxia ever did. We never
actually released it because we couldn’t find anywhere it would fit. Maybe
you can.&lt;/p&gt;

&lt;p&gt;The easiest way to get a screen of static is to tune your TV into an unused
station … you even get the cool noise effect too. Those people who build
TVs really know how to code ;-)&lt;/p&gt;

&lt;p&gt;For us on a PC however, it is not as easy to generate a screen full of
static (unless you desperately need a new monitor)&lt;/p&gt;

&lt;p&gt;What we do is this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Set colors 1-16 to various shades of grey.&lt;/li&gt;
  &lt;li&gt;Fill the screen up with random pixels between colors 1 and 16&lt;/li&gt;
  &lt;li&gt;Rotate the palette of colors 1 to 16.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it! You have a screenful of static! To get two images in one static
screen, all you need to do is fade up/down the specific colors you are
using for static in one of the images.&lt;/p&gt;

&lt;p&gt;A nice thing about a static screen is that it is just palette rotations
… you can do lots of things in the foreground at the same time (such as a
scroller).&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;Well, that is about it … as I say, I will be doing more theory stuff in
future, as individual demo effects can be thought up if you know the base
stuff.&lt;/p&gt;

&lt;p&gt;Note the putpixel in this GFX3.PAS unit … it is &lt;em&gt;very&lt;/em&gt; fast .. but
remember, just calling a procedure eats clock ticks… so embed putpixels
in your code if you need them. Most of the time a putpixel is not needed
though.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">This trainer is on a few demo effects (pixel morphs and static).</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Bitmap scaling</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-16-bitmap-scaling.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Bitmap scaling" /><published>2023-02-06T15:06:00+00:00</published><updated>2023-02-06T15:06:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-16-bitmap-scaling</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-16-bitmap-scaling.html">&lt;p&gt;This trainer is on the scaling of an arbitrary sized bitmap to
screen in two dimensions. The sample program seems to work quite quickly,
and the code is documented. The scaling procedure is however totally in
assembler… hopefully this won’t cause too many problems.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;what-is-scaling&quot;&gt;What is scaling?&lt;/h2&gt;

&lt;p&gt;I think that most of you know this one already, but here goes. Let us say
you have a picture (10x10 pixels) and you want to draw it to a different
size (say 5x7 pixel), the process of altering the picture to fit into the
new size is called scaling. Scaling only works on rectangular areas.&lt;/p&gt;

&lt;p&gt;With scaling to can easily stretch and shrink your bitmaps.&lt;/p&gt;

&lt;h2 id=&quot;okay-so-how-do-we-code-it&quot;&gt;Okay, so how do we code it?&lt;/h2&gt;

&lt;p&gt;Right. The way I am going to do scaling is as follows:&lt;/p&gt;

&lt;p&gt;For the horizontal area, I am going to calculate a certain step value. I
will then trace along the bitmap, adding this step to my position, and
place the nearest pixel on to the screen. Let me explain this simpler…&lt;/p&gt;

&lt;p&gt;Let us say I have a 10 pixel wide bitmap. I want to squish it into 5 pixels.
Along the bitmap, I would draw every second pixel to screen. In ASCII:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  1234567890   13579
  +--------+   +---+
  |        |   |   |
  | bitmap |   |   |dest
  |        |   |   |
  +--------+   +---+&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, by stepping through every second pixel, I have shrunk the
bitmap to a width of 5 pixels.&lt;/p&gt;

&lt;p&gt;The equation is as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;step = origionalwidth / wantedwidth;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let us say we have a 100 pixel wide bitmap, which we want to get to 20 pixels.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;step = 100 / 20
step = 5&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we draw every fifth pixel from the original bitmap, we have scaled it down
correctly! This also works for all values, if step is of type &lt;code class=&quot;highlighter-rouge&quot;&gt;real&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also find the step for the height in the same way.&lt;/p&gt;

&lt;p&gt;Our horizontal loop is as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;       &lt;span class=&quot;k&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wantedwidth&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;putpixel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bitmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;round&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;curpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;curpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;curpos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xstep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And the vertical loop is much the same. Easy huh? So east in fact, I wrote the
procedure in pure assembler for you ;-) … don’t worry, it’s commented.&lt;/p&gt;

&lt;p&gt;In the sample program, instead of using reals I have used fixed point math.
Refer to &lt;a href=&quot;/denthor-asphyxia-vga-trainer-14-glenz.html&quot;&gt;Part 14&lt;/a&gt; if you have any hassles with fixed point, it is fairly straightforward.&lt;/p&gt;

&lt;p&gt;I also use psuedo 3-d perspective transforms to get the positions smooth…
after &lt;a href=&quot;/denthor-asphyxia-vga-trainer-8-3d-visualization.html&quot;&gt;Part 8&lt;/a&gt;, this should be a breeze.&lt;/p&gt;

&lt;p&gt;There are no new commands in the assembler for you, so you should get by with what 
you learned in tut7/8 … whew! A lot of back referencing there ;) We really are 
building on our knowledge :)&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;Well, that is about it. As you can see the concept is easy, and in fact
fairly obvious, but that didn’t stop me from having to sit down with a
pencil and a piece of paper a few months ago and puzzle it out ;-)&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">This trainer is on the scaling of an arbitrary sized bitmap to screen in two dimensions. The sample program seems to work quite quickly, and the code is documented. The scaling procedure is however totally in assembler… hopefully this won’t cause too many problems.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Plasmas</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-15-plasma.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Plasmas" /><published>2023-02-06T15:06:00+00:00</published><updated>2023-02-06T15:06:00+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-15-plasma</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-15-plasma.html">&lt;p&gt;Plasmas are a great way to wow your friends by their weird shapes and forms.
I was at one stage going to write a game where the bad guy just had two
circular plasmas instead of eyes… I am sure you will find creative and
inventive new ways of doing and using plasmas.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;how-do-plasmas-work&quot;&gt;How do plasmas work?&lt;/h2&gt;

&lt;p&gt;I will only cover one type of plasma here: a realtime plasma of course.
Other types of plasmas include a static picture with a pallette rotation.&lt;/p&gt;

&lt;p&gt;When you get right down to it, this method of realtime plasmas is merely an
intersection of four COS waves. We get our color at a particular point by
saying:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; 
      col := costbl[one]+costbl[two]+costbl[three]+costbl[four];&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The trick is getting the four indexes of that cos table array to create
something that looks nice. This is how we organize it: have two of them
being indexes for vertical movement and two of them being indexes for
horizontal movement.&lt;/p&gt;

&lt;p&gt;This means that by changing these values we can move along the plasma. To
draw an individual screen, we pass the values of the four to another four
so that we do not disturb the original values. For every pixel across, we
add values to the first two indexes, then display the next pixel. For
every row down, we add values to the second two indexes. Sound complex
enough? Good, because that what we want, a complex shape on the screen.&lt;/p&gt;

&lt;p&gt;By altering the original four values, we can get all sorts of cool movement
and cycling of the plasma. The reason we use a cos table is as follows:
a cos table has a nice curve in the value of the numbers… when you
put two or more together, it is possible to get circular pictures…
circles are hard to do on a computer, so this makes it a lot easier…&lt;/p&gt;

&lt;p&gt;Okay, now you can have a look at the source file, all I do is put the above
into practice. I did add one or two things though…&lt;/p&gt;

&lt;p&gt;Background: This is just a large array, with the values in the array being
added to the plasma at that pixel.&lt;/p&gt;

&lt;p&gt;Psychedelic: This cycles through about 7000 colors instead of just rotating
through the base 256.&lt;/p&gt;

&lt;h2 id=&quot;clever-fading&quot;&gt;Clever fading&lt;/h2&gt;

&lt;p&gt;You will notice when the sample program fades in and out that the colors
all reach their destination at the same time … in other words, they don’t
all increment by one until they hit the right color then stop. When done
in that way the fading does not look as professional.&lt;/p&gt;

&lt;p&gt;Here is how we do a step-crossfade:&lt;/p&gt;

&lt;p&gt;Each r,g,b value can be between 0 and 64. Have the palette we want to get
to in &lt;code class=&quot;highlighter-rouge&quot;&gt;bob&lt;/code&gt; and the temporary pallette in &lt;code class=&quot;highlighter-rouge&quot;&gt;bob2&lt;/code&gt;. For each step, from 0 to 63
do the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt; 
     &lt;span class=&quot;n&quot;&gt;bob2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That means if we are halfway through the crossfade (step=32) and the red
value is meant to get to 16, our equation looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt; 
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;64&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Which is half of the way to where it wants to be. This means all colors will
fade in/out with the same ratios… and look nicer.&lt;/p&gt;

&lt;h2 id=&quot;rotating-the-pallette&quot;&gt;Rotating the pallette&lt;/h2&gt;

&lt;p&gt;I have done this one before, I think. Here it is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; 
move color 0 into temp

move color 1 into color 0
move color 2 into color 1
move color 3 into color 2
and so on till color 255

move temp into color 255&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And your palette is rotating. Easy huh? Recheck &lt;a href=&quot;/denthor-asphyxia-vga-trainer-2-palette.html&quot;&gt;Part 2&lt;/a&gt; for more info on
palette rotation.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;The tutorial was a bit short this time, but that is mostly because the
sample file is self-explanatory. The file can however be speeded up, and
of course you can add certain things which will totally change the look
of the plasma.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">Plasmas are a great way to wow your friends by their weird shapes and forms. I was at one stage going to write a game where the bad guy just had two circular plasmas instead of eyes… I am sure you will find creative and inventive new ways of doing and using plasmas.</summary></entry><entry><title type="html">Denthor/Asphyxia’s VGA trainers: Glenzing, Faster polygons, fixed-point math</title><link href="http://www.independent-software.com/denthor-asphyxia-vga-trainer-14-glenz.html" rel="alternate" type="text/html" title="Denthor/Asphyxia's VGA trainers: Glenzing, Faster polygons, fixed-point math" /><published>2023-02-06T14:56:09+00:00</published><updated>2023-02-06T14:56:09+00:00</updated><id>http://www.independent-software.com/denthor-asphyxia-vga-trainer-14-glenz</id><content type="html" xml:base="http://www.independent-software.com/denthor-asphyxia-vga-trainer-14-glenz.html">&lt;p&gt;Well, this trainer is mainly on four things: glenzing, faster polygons,
fixed-point math and assembler. The sample program is basically 
&lt;a href=&quot;/denthor-asphyxia-vga-trainer-9-3d-solids.html&quot;&gt;Part 9&lt;/a&gt;
rewritten to include the above. I’ll go through them in order, and hopefully you won’t have any hassles
grasping the concepts.&lt;/p&gt;

&lt;!--more--&gt;

&lt;div style=&quot;background:steelblue; color: white; padding-top: 15px; border-top: solid 1px #333; border-bottom: solid 1px #333; margin-bottom: 32px;&quot;&gt;

  &lt;pre style=&quot;background: none; text-align: center&quot;&gt;
DENTHOR, coder for ...
_____   _____   ____   __   __  ___  ___ ___  ___  __   _____
/  _  \ /  ___&amp;gt; |  _ \ |  |_|  | \  \/  / \  \/  / |  | /  _  \
|  _  | \___  \ |  __/ |   _   |  \    /   &amp;gt;    &amp;lt;  |  | |  _  |
\_/ \_/ &amp;lt;_____/ |__|   |__| |__|   |__|   /__/\__\ |__| \_/ \_/
smith9@batis.bis.und.ac.za
The great South African Demo Team! Contact us for info/code exchange!  
&lt;/pre&gt;

  &lt;p style=&quot;text-align:center; font-weight: bold&quot;&gt;Grant Smith, alias Denthor of Asphyxia, wrote up several articles on the 
creation of demo effects in the 90s. I reproduce them here, as they offer
so much insight into the demo scene of the time.
&lt;/p&gt;

  &lt;p style=&quot;text-align: center&quot;&gt;
These articles apply some formatting to Denthor's original ASCII files, plus
a few typo fixes.
&lt;/p&gt;

&lt;/div&gt;

&lt;h2 id=&quot;what-is-glenzing&quot;&gt;What is glenzing?&lt;/h2&gt;

&lt;p&gt;This is an easy one. Imagine, in a 3D object, that all the sides are
made out of colored glass. That means that every time you look through
a side, everything behind it is tinged in a certain color.&lt;/p&gt;

&lt;p&gt;In ASCII:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;          +---------+
          |      &amp;lt;--|---Light blue
          |         |
     +--------+     |
     |    | &amp;lt;-|-----|---Dark blue
     |    +---|-----+
     |     &amp;lt;--|---------Light blue
     +--------+&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So where the two sides overlap, the color values of the two sides are 
added. Easy huh? It is also easy to code. This is how you do it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Set up your palette to be a nice run of colors.&lt;/li&gt;
  &lt;li&gt;Draw your first poly.&lt;/li&gt;
  &lt;li&gt;While drawing poly 1, instead of plonking down a set pixel color, grab the background pixel, add 1 to it, then put the result down.&lt;/li&gt;
  &lt;li&gt;Draw your second poly.&lt;/li&gt;
  &lt;li&gt;While drawing poly 2, instead of plonking down a set pixel color, grab the background pixel, add 2 to it, then put the result down.&lt;/li&gt;
  &lt;li&gt;and so forth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if the color behind poly 1 was 5, you would place pixel 6 down instead.&lt;/p&gt;

&lt;p&gt;If you do this for every single pixel of every single side of your 3D 
object, you then have glenzing going. This is obviously slightly slower
than just drawing an item straight, but in the sample program it goes
quite quickly. This is because of the following sections.&lt;/p&gt;

&lt;h2 id=&quot;faster-polygons&quot;&gt;Faster polygons&lt;/h2&gt;

&lt;p&gt;In &lt;a href=&quot;/denthor-asphyxia-vga-trainer-9-3d-solids.html&quot;&gt;Part 9&lt;/a&gt;, you probably noticed that we were using a multiply for every
single line of the poly that we drew. This is not good. Let’s find out
how to speed it up, shall we?&lt;/p&gt;

&lt;p&gt;With the multiply method, we went through every line, to find out the
minimum x and maximum x value for that line.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                           +
                   ------/---\------- Find min x and max x, draw a line
                       /       \        between them.
                     +           +
                       \       /
                         \   /
                           +&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;How about if we found out all the min and max x’s for every line first, 
then just went through an array drawing them. We could do it by 
“scanning” each side in turn. Here is how we do it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                          + 1
                        /
                      /
                  2 +&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We go from point one to point two. For every single y we go down, we 
move a constant x value. This value is found like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;xchange := (x1-x2)/(y1-y2)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Remember gradients? This is how you calculated the slope of a line &lt;em&gt;waaay&lt;/em&gt;
back in school. You never thought it would be any use, didn’t you?&lt;/p&gt;

&lt;p&gt;Anyway, with this value, we can do the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;    &lt;span class=&quot;k&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Put&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clever&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stuff&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;here&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xchange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and we will go through all the x-values we need for that line. Clever, 
huh?&lt;/p&gt;

&lt;p&gt;Now for the clever bit. You have an array, from 0 to 199 (which is all
the possible y-values your onscreen poly can have). Inside this is two 
values, which will be your min x and your max x. You start off with the 
min x being a huge number, and the max x being a low number. Then you 
scan a side. For each y, check to see if one of the following has 
happened:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If the x value is smaller than the xmin value in your array, make the xmin value equal to the x value&lt;/li&gt;
  &lt;li&gt;If the x value is larger than the xmax value in your array, make the xmax value equal to the x value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The loop now looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-pascal&quot; data-lang=&quot;pascal&quot;&gt;    &lt;span class=&quot;k&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xchange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Easy? Do this for all four sides (you can change this for polys with 
different numbers of sides), and then you have all the x min and x max
values you need to draw your polygon.&lt;/p&gt;

&lt;p&gt;In the sample program, if you replaced the &lt;code class=&quot;highlighter-rouge&quot;&gt;Hline&lt;/code&gt; procedure with one that
draws solid lines, you could use the given drawpoly for solids.&lt;/p&gt;

&lt;p&gt;Even this procedure is sped up by the next section, on fixed point.&lt;/p&gt;

&lt;h2 id=&quot;what-is-fixed-point&quot;&gt;What is fixed point?&lt;/h2&gt;

&lt;p&gt;Have you ever noticed how slow reals are? I mean &lt;em&gt;slooooow&lt;/em&gt;. You can get a
massive speed increase in most programs by replacing your reals with 
integers, words etc. But, I hear you cry, what happens to the much 
needed fraction bit after the decimal point? The answer? You keep it. 
Here’s how.&lt;/p&gt;

&lt;p&gt;Let us say you have a word, which is 16 bits. If you want to use it as a
fixed point value, you can separate it into 2 sections, one of which 
holds the whole value, and one which holds the fraction.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;00000000  00000000   &amp;lt;-Bits
Whole     Fraction&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The number 6.5 would therefore be shown as follows:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; 
Top byte    :  6
Bottom byte :  128&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;128 is half (or .5) of 256, and in the case of the fraction section, 256
would equal one whole number.&lt;/p&gt;

&lt;p&gt;So let us say we had &lt;code class=&quot;highlighter-rouge&quot;&gt;6.5 * 2&lt;/code&gt;. Using reals this would be a slow &lt;code class=&quot;highlighter-rouge&quot;&gt;mul&lt;/code&gt;, but 
with fixed point …&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; 
Top Byte    :  6     
Bottom Byte :  128
Value       :  1664   &amp;lt;-This is the true value of the word
                         ie. (top byte*256)+bottom byte).
                         this is how the computer sees the 
                         word.
 1664 shl 1 = 3328    &amp;lt;-shl 1 is the same as *2, just faster.
Top byte    :  13
Bottom byte :  0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we got the correct result! And in a fraction of the time
that a multiplication of a real would have taken us. You can add and
subtract fixed point values with no hassles, and multiply and divide 
them by normal values too. When you need the whole value section, you 
can just read the high byte, or do the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; 
             whole = word shr 8
         eg  1664 shr 8 = 6&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, the fraction is truncated. Obviously, the more bits you 
set aside for the fraction section, the more accurate your calculation 
is, but the lesser the maximum whole number you can have. For example, 
in the above numbers, the maximum value of your whole number was 256, a
far cry from the 65,535 a normal (non fixed point) word’s maximum.&lt;/p&gt;

&lt;p&gt;There are a lot of hassles using fixed point (go on, try shift a
negative value), most of which have to do with the fact that you have 
severely decreased the maximum number you may have, but trust me, the 
speed increase is worth it (With long integers, and/or extended 386
registers, you can even have 16x16 fixed point, which means high
accuracy and high maximum values)&lt;/p&gt;

&lt;p&gt;Try write a program using fixed point. It is not difficult and you will
get it perfect easily. Trust me, I’m a democoder ;-)&lt;/p&gt;

&lt;h2 id=&quot;assembler&quot;&gt;Assembler&lt;/h2&gt;

&lt;p&gt;In the sample program I used one or two assembler commands that I havent
discussed with you. Here they are:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt; 
  imul  value           This is the same as mul, but for integer values. It
                        multiplies ax by the value. If the value is a word,
                        it returns the result in DX:AX

  sal  register,value   This is the same as shl, but it is arithmetic,
                        in other words it works on integers. If you
                        had to shl a negative value, the result would
                        mean nothing to you.

  rcl  register,value   This is the same as shl, but after you have
                        shifted, the value in the carry flag is placed
                        in the now-vacated rightmost bit. The carry
                        flag is set when you do an operation where the
                        result is greater than the upmost possible
                        value of the variable (usually 65535 or 32767)
                        eg mov ax,64000
                             shl ax,1     {&amp;lt;- Carry flag now = 1}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For more info on shifting etc, re-read 
&lt;a href=&quot;/denthor-asphyxia-vga-trainer-7-animation.html&quot;&gt;Part 7&lt;/a&gt;, it goes into the concept
in detail.&lt;/p&gt;

&lt;p&gt;The sample program is basically 
&lt;a href=&quot;/denthor-asphyxia-vga-trainer-9-3d-solids.html&quot;&gt;Part 9&lt;/a&gt; rewritten. To see how the
assembler stuff is working, do the following … Go into 50 line mode
(-Much- easier to debug), then hit [Alt - D] then R. A little box with
all your registers, segments etc and their values will pop up. Move it
down to where you want it, then go back to the program screen (Hit Alt
and its number together), and resize it so that you have both it and
the register box onscreen at once (Alt - 5 to resize) … then use F4,
F7 and F8 to trace though the program (you know how). The current value
of the registers will always be in that box.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;Well, that is about it. The sample program may start as being a little 
intimidating to some when they first look at it, just remember to read 
it with &lt;a href=&quot;/denthor-asphyxia-vga-trainer-9-3d-solids.html&quot;&gt;Part 9&lt;/a&gt;, very little is different, it’s just with fixed point and 
a bit of assembler.&lt;/p&gt;</content><author><name>Alexander van Oostenrijk</name></author><summary type="html">Well, this trainer is mainly on four things: glenzing, faster polygons, fixed-point math and assembler. The sample program is basically Part 9 rewritten to include the above. I’ll go through them in order, and hopefully you won’t have any hassles grasping the concepts.</summary></entry></feed>