<commit_before>/* JCHOR - random-wait chorus instrument based on Paul Lansky's chor
           and Doug Scott's trans code

   p0  = output start time
   p1  = input start time
   p2  = output duration
   p3  = input duration (not input end time)
   p4  = maintain input duration, regardless of transposition (1: yes, 0: no)
   p5  = transposition (8ve.pc)
   p6  = number of voices (minimum of 1)
   p7  = minimum grain amplitude
   p8  = maximum grain amplitude
   p9  = minimum grain wait (seconds)
   p10 = maximum grain wait (seconds)
   p11 = seed (0 - 1)
   p12 = input channel [optional]
         (If p12 is missing and input has > 1 chan, input channels averaged.)

   Assumes function table 1 is amplitude curve for the note. (Try gen 18.)
   Or you can just call setline. If no setline or function table 1, uses
   flat amplitude curve. By default, the amplitude envelope is updated 1000
   times per second, but this can be changed by calling reset() with a
   different value.

   Assumes function table 2 is grain window function. (Try gen 25.)

   Output can be either mono or stereo. If it's stereo, the program randomly
   distributes the voices across the stereo field.

   Notes on p4 (maintain input duration)...

      Because the transposition method doesn't try to maintain duration -- it
      works like the speed control on a tape deck -- you have an option about
      the way to handle the duration of the input read:

      - If p4 is 1, the grain length after transposition will be the same as
        that given by p3 (input duration). This means that the amount actually
        read from the input file will be shorter or longer than p3, depending
        on the transposition.

      - If p4 is 0, the segment of sound specified by p3 will be read, and the
        grain length will be shorter or longer than p3, depending on the
        transposition.

   Differences between JCHOR and chor (besides RT ability):
      - No limit on input duration or number of voices
      - Transpose the input signal
      - Specify the input channel to use (or an average of them)
      - Specify overall amplitude curve and grain window function via makegens

   John Gibson (jgg9c@virginia.edu), 9/20/98, RT'd 6/24/99.
*/

#include <stdio.h>
#include <stdlib.h>
#include <mixerr.h>
#include <Instrument.h>
#include "JCHOR.h"
#include <rt.h>
#include <rtdefs.h>

extern "C" {
   #include <ugens.h>
   extern int resetval;
   extern double m_DUR(float [], int);     /* in sys/minc_info.c */
}

//#define DEBUG

#define ENVELOPE_TABLE_SLOT  1
#define WINDOW_FUNC_SLOT    2
#define AVERAGE_CHANS        -1           /* average input chans flag value */
#define WINDOW_CONTROL_RATE  22051.       /* don't skimp on this */

/* local functions */
static double interp(double, double, double, double);

JCHOR::JCHOR() : Instrument()
{
   in = new float[MAXBUF];
   voices = NULL;
   grain = NULL;
   grain_done = 0;
}

JCHOR::~JCHOR()
{
   delete [] in;
   delete [] voices;
   delete [] grain;
}

int JCHOR::init(float p[], short n_args)
{
   float outskip, outdur, maxamp, maxwait;

   outskip = p[0];
   inskip = p[1];
   outdur = p[2];
   indur = p[3];
   maintain_indur = (int)p[4];
   transpose = p[5];
   nvoices = (int)p[6];
   minamp = p[7];
   maxamp = p[8];
   minwait = p[9];
   maxwait = p[10];
   seed = p[11];
   inchan = (n_args > 12) ? (int)p[12] : AVERAGE_CHANS;

   if (n_args < 12) {
      fprintf(stderr, "JCHOR: Not enough pfields.\n");
      exit(1);
   }

   rtsetinput(inskip, this);
   nsamps = rtsetoutput(outskip, outdur, this);

   if (outputchans > 2) {
      fprintf(stderr, "JCHOR: Output must have no more than two channels.\n");
      exit(1);
   }

   if (nvoices < 1) {
      fprintf(stderr, "JCHOR: Must have at least one voice.\n");
      exit(1);
   }

   if (minamp < 0.0 || maxamp <= 0.0 || minamp > maxamp) {
      fprintf(stderr, "JCHOR: Grain amplitude range confused.\n");
      exit(1);
   }
   ampdiff = maxamp - minamp;

   if (minwait < 0.0 || maxwait < 0.0 || minwait > maxwait) {
      fprintf(stderr, "JCHOR: Grain wait range confused.\n");
      exit(1);
   }
   waitdiff = (maxwait - minwait) * SR;
   minwait *= SR;

   if (seed < 0.0 || seed > 1.0) {
      fprintf(stderr, "JCHOR: Seed must be between 0 and 1 inclusive.\n");
      exit(1);
   }

   amparray = floc(ENVELOPE_TABLE_SLOT);
   if (amparray) {
      int len = fsize(ENVELOPE_TABLE_SLOT);
      tableset(outdur, len, amptabs);
   }
   else
      printf("JCHOR: Setting phrase curve to all 1's\n");

   /* MUST do this here, rather than in grain_input_and_transpose,
      because by the time that is called, the makegen for this slot
      may have changed.
   */
   winarray = floc(WINDOW_FUNC_SLOT);   /* NB: floc aborts if slot empty */
   winarraylen = fsize(WINDOW_FUNC_SLOT);

   skip = (int)(SR / (float)resetval);

   return nsamps;
}

int JCHOR::run()
{
   int   i, j, branch;
   float amp;
   float out[2];
   Voice *v;

   Instrument::run();

   if (!grain_done) {
      grain_input_and_transpose();
      setup_voices();
   }

   amp = 1.0;                   /* in case amparray == NULL */

   branch = 0;
   for (i = 0; i < chunksamps; i++) {
      if (--branch < 0) {
         if (amparray)
            amp = tablei(cursamp, amparray, amptabs);
         branch = skip;
      }

      out[0] = out[1] = 0.0;
      for (j = 0, v = voices; j < nvoices; j++, v++) {
         if (v->index++ < 0)
            continue;
         if (v->index >= grainsamps) {
            seed = crandom(seed);
            v->index = (int)(-((seed * waitdiff) + minwait));
            if (outputchans > 1) {
               seed = crandom(seed);
               v->left_amp = seed;
               v->right_amp = 1.0 - v->left_amp;
            }
            seed = crandom(seed);
            v->overall_amp = (seed * ampdiff) + minamp;
         }
         else {
            float sig = grain[v->index] * v->overall_amp;
            if (outputchans > 1) {
               out[0] += sig * v->left_amp;
               out[1] += sig * v->right_amp;
            }
            else
               out[0] += sig;
         }
      }
      out[0] *= amp;
      out[1] *= amp;

      rtaddout(out);
      cursamp++;
   }

   return i;
}

/* --------------------------------------------------------------- interp --- */
/* Cubic spline interpolation.
   Nabbed from Doug Scott's trans.
*/
static double
interp(double y0, double y1, double y2, double t)
{
   register double hy2, hy0, a, b, c;

   a = y0;
   hy0 = y0 / 2.0;
   hy2 =  y2 / 2.0;
   b = (-3.0 * hy0) + (2.0 * y1) - hy2;
   c = hy0 - y1 + hy2;

   return (a + b*t + c*t*t);
}

/* -------------------------------------------- grain_input_and_transpose --- */
int JCHOR::setup_voices()
{
   int   i;
   Voice *v;

   voices = new Voice[nvoices];

   for (i = 0, v = voices; i < nvoices; i++, v++) {
      seed = crandom(seed);
      v->index = (int)(-seed * (grainsamps - 1));
      if (outputchans > 1) {
         seed = crandom(seed);
         v->left_amp = seed;
         v->right_amp = 1.0 - v->left_amp;
      }
      seed = crandom(seed);
      v->overall_amp = (seed * ampdiff) + minamp;
   }
#ifdef DEBUG
   printf("\n%d grainsamps\n", grainsamps);
   printf("Voices:\n");
   for (i = 0, v = voices; i < nvoices; i++, v++)
      printf("%6d: index=%d, left=%g, right=%g, amp=%g\n",
             i, v->index, v->left_amp, v->right_amp, v->overall_amp);
#endif
   return 0;
}

/* -------------------------------------------- grain_input_and_transpose --- */
/* Reads part of a soundfile into a newly allocated array <grain>, transposing
   the signal as it's read, and shaping its amplitude with a window function.

   The method of transposition (adapted from the trans instrument) doesn't
   try to preserve duration. So we have a potential discrepancy between the
   input duration <indur> and the duration of that segment of sound after
   transposition. (For example, if transposition is down an octave, the
   length of the input segment after transposition will be <indur> * 2.)
   There are two ways to handle the discrepancy. Since both ways are useful,
   the caller can choose between them:
      - If <maintain_indur> is true, the grain length after transposition
        will be the same as that given by <indur>. This means that the amount
        actually read from the input file will be shorter or longer than
        <indur>, depending on the transposition.
      - If <maintain_indur> is false, the segment of sound specified by
        <indur> will be read, and the grain length will be shorter or longer
        than <indur>, depending on the transposition.

   <inchan> gives the input channel number to read, or if it's -1, specifies
   that all input channels will be averaged when read into the 1-channel array
   returned by the function. If the input file is mono, <inchan> is ignored.

   <WINDOW_FUNC_SLOT> is the makegen slot of a function used as an amplitude
   curve for the grain. Use gen 25 for a Hanning or Hamming window, or try
   gens 5 or 7 to make other envelope shapes.
*/
int JCHOR::grain_input_and_transpose()
{
   int     i, j, k, n, reset_count, inframes, bufframes;
   int     getflag, incount;
   float   read_indur, store_indur, total_indur, interval, amp;
   double  increment, newsig, oldsig, oldersig, frac, counter;

   if (inputchans == 1)
      inchan = 0;

   interval = octpch(transpose);
   increment = cpsoct(10.0 + interval) / cpsoct(10.0);
   if (maintain_indur) {
      read_indur = (double)indur / increment;
      store_indur = indur;
   }
   else {
      read_indur = indur;
      store_indur = (double)indur / increment;
   }
#ifdef DEBUG
   printf("increment=%g, read_indur=%g, store_indur=%g\n",
           increment, read_indur, store_indur);
#endif
#ifdef NOT_YET
   total_indur = (float)m_DUR(NULL, 0);
   if (inskip < 0.0 || read_indur <= 0.0 || inskip + read_indur > total_indur) {
      fprintf(stderr, "Input file segment out of range.\n");
      exit(1);
   }
#endif

   grainsamps = (int)(store_indur * SR + 0.5);

   grain = new float[grainsamps];

   tableset(store_indur, winarraylen, wintabs);

   inframes = (int)(SR / read_indur);
   bufframes = RTBUFSAMPS;

   reset_count = (int)(SR / WINDOW_CONTROL_RATE);

   getflag = 1;
   incount = 0;            /* frames */
   counter = 0.0;
   oldersig = oldsig = newsig = 0.0;

   k = bufframes;
   for (i = j = 0; i < grainsamps; i++) {
      if (--j < 0) {
         amp = tablei(i, winarray, wintabs);
         j = reset_count;
      }
      while (getflag) {
         int index;
         if (k == bufframes) {              /* time for an input buffer */
            rtgetin(in, this, inputchans * bufframes);
            k = 0;
         }
         index = k * inputchans;
         oldersig = oldsig;
         oldsig = newsig;
         if (inchan == AVERAGE_CHANS) {
            newsig = 0.0;
            for (n = 0; n < inputchans; n++)
               newsig += (double)in[index + n];
            newsig /= (double)inputchans;
         }
         else
            newsig = (double)in[index + inchan];
         incount++;
         k++;
         if (counter - (float)incount < 0.5)
            getflag = 0;
      }
      frac = counter - (double)incount + 2.0;
      grain[i] = (float)interp(oldersig, oldsig, newsig, frac) * amp;
      counter += increment;
      if (counter - (float)incount >= -0.5)
         getflag = 1;
   }

   grain_done = 1;

   return 0;
}

Instrument *makeJCHOR()
{
   JCHOR *inst;

   inst = new JCHOR();
   inst->set_bus_config("JCHOR");

   return inst;
}

void rtprofile()
{
   RT_INTRO("JCHOR", makeJCHOR);
}

<commit_msg>Allocate input buffer in run method, to reduce memory footprint.<commit_after>/* JCHOR - random-wait chorus instrument based on Paul Lansky's chor
           and Doug Scott's trans code

   p0  = output start time
   p1  = input start time
   p2  = output duration
   p3  = input duration (not input end time)
   p4  = maintain input duration, regardless of transposition (1: yes, 0: no)
   p5  = transposition (8ve.pc)
   p6  = number of voices (minimum of 1)
   p7  = minimum grain amplitude
   p8  = maximum grain amplitude
   p9  = minimum grain wait (seconds)
   p10 = maximum grain wait (seconds)
   p11 = seed (0 - 1)
   p12 = input channel [optional]
         (If p12 is missing and input has > 1 chan, input channels averaged.)

   Assumes function table 1 is amplitude curve for the note. (Try gen 18.)
   Or you can just call setline. If no setline or function table 1, uses
   flat amplitude curve. By default, the amplitude envelope is updated 1000
   times per second, but this can be changed by calling reset() with a
   different value.

   Assumes function table 2 is grain window function. (Try gen 25.)

   Output can be either mono or stereo. If it's stereo, the program randomly
   distributes the voices across the stereo field.

   Notes on p4 (maintain input duration)...

      Because the transposition method doesn't try to maintain duration -- it
      works like the speed control on a tape deck -- you have an option about
      the way to handle the duration of the input read:

      - If p4 is 1, the grain length after transposition will be the same as
        that given by p3 (input duration). This means that the amount actually
        read from the input file will be shorter or longer than p3, depending
        on the transposition.

      - If p4 is 0, the segment of sound specified by p3 will be read, and the
        grain length will be shorter or longer than p3, depending on the
        transposition.

   Differences between JCHOR and chor (besides RT ability):
      - No limit on input duration or number of voices
      - Transpose the input signal
      - Specify the input channel to use (or an average of them)
      - Specify overall amplitude curve and grain window function via makegens

   John Gibson (jgg9c@virginia.edu), 9/20/98, RT'd 6/24/99.
*/

#include <stdio.h>
#include <stdlib.h>
#include <mixerr.h>
#include <Instrument.h>
#include "JCHOR.h"
#include <rt.h>
#include <rtdefs.h>

extern "C" {
   #include <ugens.h>
   extern int resetval;
   extern double m_DUR(float [], int);     /* in sys/minc_info.c */
}

//#define DEBUG

#define ENVELOPE_TABLE_SLOT  1
#define WINDOW_FUNC_SLOT    2
#define AVERAGE_CHANS        -1           /* average input chans flag value */
#define WINDOW_CONTROL_RATE  22051.       /* don't skimp on this */

/* local functions */
static double interp(double, double, double, double);

JCHOR::JCHOR() : Instrument()
{
   in = NULL;
   voices = NULL;
   grain = NULL;
   grain_done = 0;
}

JCHOR::~JCHOR()
{
   delete [] in;
   delete [] voices;
   delete [] grain;
}

int JCHOR::init(float p[], short n_args)
{
   float outskip, outdur, maxamp, maxwait;

   outskip = p[0];
   inskip = p[1];
   outdur = p[2];
   indur = p[3];
   maintain_indur = (int)p[4];
   transpose = p[5];
   nvoices = (int)p[6];
   minamp = p[7];
   maxamp = p[8];
   minwait = p[9];
   maxwait = p[10];
   seed = p[11];
   inchan = (n_args > 12) ? (int)p[12] : AVERAGE_CHANS;

   if (n_args < 12) {
      fprintf(stderr, "JCHOR: Not enough pfields.\n");
      exit(1);
   }

   rtsetinput(inskip, this);
   nsamps = rtsetoutput(outskip, outdur, this);

   if (outputchans > 2) {
      fprintf(stderr, "JCHOR: Output must have no more than two channels.\n");
      exit(1);
   }

   if (nvoices < 1) {
      fprintf(stderr, "JCHOR: Must have at least one voice.\n");
      exit(1);
   }

   if (minamp < 0.0 || maxamp <= 0.0 || minamp > maxamp) {
      fprintf(stderr, "JCHOR: Grain amplitude range confused.\n");
      exit(1);
   }
   ampdiff = maxamp - minamp;

   if (minwait < 0.0 || maxwait < 0.0 || minwait > maxwait) {
      fprintf(stderr, "JCHOR: Grain wait range confused.\n");
      exit(1);
   }
   waitdiff = (maxwait - minwait) * SR;
   minwait *= SR;

   if (seed < 0.0 || seed > 1.0) {
      fprintf(stderr, "JCHOR: Seed must be between 0 and 1 inclusive.\n");
      exit(1);
   }

   amparray = floc(ENVELOPE_TABLE_SLOT);
   if (amparray) {
      int len = fsize(ENVELOPE_TABLE_SLOT);
      tableset(outdur, len, amptabs);
   }
   else
      printf("JCHOR: Setting phrase curve to all 1's\n");

   /* MUST do this here, rather than in grain_input_and_transpose,
      because by the time that is called, the makegen for this slot
      may have changed.
   */
   winarray = floc(WINDOW_FUNC_SLOT);   /* NB: floc aborts if slot empty */
   winarraylen = fsize(WINDOW_FUNC_SLOT);

   skip = (int)(SR / (float)resetval);

   return nsamps;
}

int JCHOR::run()
{
   int   i, j, branch;
   float amp;
   float out[2];
   Voice *v;

   Instrument::run();

   if (!grain_done) {
      in = new float [RTBUFSAMPS * inputchans];
      grain_input_and_transpose();
      setup_voices();
   }

   amp = 1.0;                   /* in case amparray == NULL */

   branch = 0;
   for (i = 0; i < chunksamps; i++) {
      if (--branch < 0) {
         if (amparray)
            amp = tablei(cursamp, amparray, amptabs);
         branch = skip;
      }

      out[0] = out[1] = 0.0;
      for (j = 0, v = voices; j < nvoices; j++, v++) {
         if (v->index++ < 0)
            continue;
         if (v->index >= grainsamps) {
            seed = crandom(seed);
            v->index = (int)(-((seed * waitdiff) + minwait));
            if (outputchans > 1) {
               seed = crandom(seed);
               v->left_amp = seed;
               v->right_amp = 1.0 - v->left_amp;
            }
            seed = crandom(seed);
            v->overall_amp = (seed * ampdiff) + minamp;
         }
         else {
            float sig = grain[v->index] * v->overall_amp;
            if (outputchans > 1) {
               out[0] += sig * v->left_amp;
               out[1] += sig * v->right_amp;
            }
            else
               out[0] += sig;
         }
      }
      out[0] *= amp;
      out[1] *= amp;

      rtaddout(out);
      cursamp++;
   }

   return i;
}

/* --------------------------------------------------------------- interp --- */
/* Cubic spline interpolation.
   Nabbed from Doug Scott's trans.
*/
static double
interp(double y0, double y1, double y2, double t)
{
   register double hy2, hy0, a, b, c;

   a = y0;
   hy0 = y0 / 2.0;
   hy2 =  y2 / 2.0;
   b = (-3.0 * hy0) + (2.0 * y1) - hy2;
   c = hy0 - y1 + hy2;

   return (a + b*t + c*t*t);
}

/* -------------------------------------------- grain_input_and_transpose --- */
int JCHOR::setup_voices()
{
   int   i;
   Voice *v;

   voices = new Voice[nvoices];

   for (i = 0, v = voices; i < nvoices; i++, v++) {
      seed = crandom(seed);
      v->index = (int)(-seed * (grainsamps - 1));
      if (outputchans > 1) {
         seed = crandom(seed);
         v->left_amp = seed;
         v->right_amp = 1.0 - v->left_amp;
      }
      seed = crandom(seed);
      v->overall_amp = (seed * ampdiff) + minamp;
   }
#ifdef DEBUG
   printf("\n%d grainsamps\n", grainsamps);
   printf("Voices:\n");
   for (i = 0, v = voices; i < nvoices; i++, v++)
      printf("%6d: index=%d, left=%g, right=%g, amp=%g\n",
             i, v->index, v->left_amp, v->right_amp, v->overall_amp);
#endif
   return 0;
}

/* -------------------------------------------- grain_input_and_transpose --- */
/* Reads part of a soundfile into a newly allocated array <grain>, transposing
   the signal as it's read, and shaping its amplitude with a window function.

   The method of transposition (adapted from the trans instrument) doesn't
   try to preserve duration. So we have a potential discrepancy between the
   input duration <indur> and the duration of that segment of sound after
   transposition. (For example, if transposition is down an octave, the
   length of the input segment after transposition will be <indur> * 2.)
   There are two ways to handle the discrepancy. Since both ways are useful,
   the caller can choose between them:
      - If <maintain_indur> is true, the grain length after transposition
        will be the same as that given by <indur>. This means that the amount
        actually read from the input file will be shorter or longer than
        <indur>, depending on the transposition.
      - If <maintain_indur> is false, the segment of sound specified by
        <indur> will be read, and the grain length will be shorter or longer
        than <indur>, depending on the transposition.

   <inchan> gives the input channel number to read, or if it's -1, specifies
   that all input channels will be averaged when read into the 1-channel array
   returned by the function. If the input file is mono, <inchan> is ignored.

   <WINDOW_FUNC_SLOT> is the makegen slot of a function used as an amplitude
   curve for the grain. Use gen 25 for a Hanning or Hamming window, or try
   gens 5 or 7 to make other envelope shapes.
*/
int JCHOR::grain_input_and_transpose()
{
   int     i, j, k, n, reset_count, inframes, bufframes;
   int     getflag, incount;
   float   read_indur, store_indur, total_indur, interval, amp;
   double  increment, newsig, oldsig, oldersig, frac, counter;

   if (inputchans == 1)
      inchan = 0;

   interval = octpch(transpose);
   increment = cpsoct(10.0 + interval) / cpsoct(10.0);
   if (maintain_indur) {
      read_indur = (double)indur / increment;
      store_indur = indur;
   }
   else {
      read_indur = indur;
      store_indur = (double)indur / increment;
   }
#ifdef DEBUG
   printf("increment=%g, read_indur=%g, store_indur=%g\n",
           increment, read_indur, store_indur);
#endif
#ifdef NOT_YET
   total_indur = (float)m_DUR(NULL, 0);
   if (inskip < 0.0 || read_indur <= 0.0 || inskip + read_indur > total_indur) {
      fprintf(stderr, "Input file segment out of range.\n");
      exit(1);
   }
#endif

   grainsamps = (int)(store_indur * SR + 0.5);

   grain = new float[grainsamps];

   tableset(store_indur, winarraylen, wintabs);

   inframes = (int)(SR / read_indur);
   bufframes = RTBUFSAMPS;

   reset_count = (int)(SR / WINDOW_CONTROL_RATE);

   getflag = 1;
   incount = 0;            /* frames */
   counter = 0.0;
   oldersig = oldsig = newsig = 0.0;

   k = bufframes;
   for (i = j = 0; i < grainsamps; i++) {
      if (--j < 0) {
         amp = tablei(i, winarray, wintabs);
         j = reset_count;
      }
      while (getflag) {
         int index;
         if (k == bufframes) {              /* time for an input buffer */
            rtgetin(in, this, inputchans * bufframes);
            k = 0;
         }
         index = k * inputchans;
         oldersig = oldsig;
         oldsig = newsig;
         if (inchan == AVERAGE_CHANS) {
            newsig = 0.0;
            for (n = 0; n < inputchans; n++)
               newsig += (double)in[index + n];
            newsig /= (double)inputchans;
         }
         else
            newsig = (double)in[index + inchan];
         incount++;
         k++;
         if (counter - (float)incount < 0.5)
            getflag = 0;
      }
      frac = counter - (double)incount + 2.0;
      grain[i] = (float)interp(oldersig, oldsig, newsig, frac) * amp;
      counter += increment;
      if (counter - (float)incount >= -0.5)
         getflag = 1;
   }

   grain_done = 1;

   return 0;
}

Instrument *makeJCHOR()
{
   JCHOR *inst;

   inst = new JCHOR();
   inst->set_bus_config("JCHOR");

   return inst;
}

void rtprofile()
{
   RT_INTRO("JCHOR", makeJCHOR);
}

<|endoftext|>


<commit_before>#include <cassert>

#include "sam_shared.hpp"
#include "interactives.hpp"

#include "level1.h"

const unsigned int TPlayer::frames[eNUM_PLAYER_ANIMATIONS][eFRAMES_PER_ANIMATION] =
{
    { 389, 390, 391, 392 },
    { 366, 367, 368, 369 },
    { 436, 436, 436, 436 },
    { 435, 435, 435, 435 },
    { 413, 415, 415, 413 },
    { 412, 414, 414, 412 }
};

const signed int TPlayer::widths[eNUM_PLAYER_ANIMATIONS][eFRAMES_PER_ANIMATION] =
{
    { 22, 22, 22, 22 }, /* standing left  */
    { 22, 22, 22, 22 }, /* standing right */

    { 22, 22, 22, 22 }, /* standing left  */
    { 22, 22, 22, 22 }, /* standing right */
    //{ 28, 28, 28, 28 }, /* jumping left   */
    //{ 28, 28, 28, 28 }, /* jumping right  */

    { 20, 32, 32, 20 }, /* shooting left  */
    { 20, 32, 32, 20 }  /* shooting right */
};

void TPlayer::Tick(double delta_seconds)
{
    m_seconds_since_last_frame_change += delta_seconds;

    if (m_seconds_since_last_frame_change >= ANIMATION_RATE)
    {
        m_frameIndex = (m_frameIndex + 1) % eFRAMES_PER_ANIMATION;
        m_seconds_since_last_frame_change = 0.0;
    }

    /* select the current animation */
    if (m_facing == eFACING_RIGHT)
    {
        if (m_jumping || !OnSolidGround())
        	m_animation = eANIM_JUMPING_RIGHT;
        // else if (m_shooting)
        //  m_animation = eANIM_SHOOTING_RIGHT;
        else
        	m_animation = eANIM_STANDING_RIGHT;
	}
    else if (m_facing == eFACING_LEFT)
    {
        if (m_jumping || !OnSolidGround())
        	m_animation = eANIM_JUMPING_LEFT;
        // else if (m_shooting)
        //  m_animation = eANIM_SHOOTING_LEFT;
        else
        	m_animation = eANIM_STANDING_LEFT;
    }
}

unsigned int TPlayer::TileID() const
{
    return frames[m_animation][m_frameIndex];
}

signed int TPlayer::DrawWidth() const
{
    return widths[m_animation][m_frameIndex];
}

bool TGlasses::CollidedWith(TObject &obj)
{
    if (&obj == &GLOBALS::player)
    {
        const unsigned int atlasWidth_tiles = al_get_bitmap_width(GLOBALS::tileAtlas_unscaled) / TILE_WIDTH_PIXELS_UNSCALED;
        unsigned int tileY, tileX;
        signed int tileID, tileIndex;

        al_set_target_bitmap(GLOBALS::background_scaled);

        // turn on the invisible platforms
        for (tileIndex = 0; tileIndex < (LEVEL_HEIGHT_TILES * LEVEL_WIDTH_TILES); ++tileIndex)
        {
            if (level1MapData.codes[tileIndex] == eCODE_INVISIBLE_PLATFORM)
            {
                level1MapData.codes[tileIndex] = 0;

                tileID = 53;

                level1MapData.bounds[tileIndex] = SOLID_TOP;
                level1MapData.midTiles[tileIndex] = tileID;

                tileY = tileIndex / LEVEL_WIDTH_TILES;
                tileX = tileIndex % LEVEL_WIDTH_TILES;
                al_draw_scaled_bitmap(GLOBALS::tileAtlas_unscaled,
                                      (tileID % atlasWidth_tiles) * TILE_WIDTH_PIXELS_UNSCALED, (tileID / atlasWidth_tiles) * TILE_HEIGHT_PIXELS_UNSCALED,
                                      TILE_WIDTH_PIXELS_UNSCALED, TILE_HEIGHT_PIXELS_UNSCALED,
                                      (TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR) * tileX, (TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR) * tileY,
                                      TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR, TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR,
                                      0);
            }
        }
        // paint over glasses graphic in background image
        tileY = m_y/TILE_HEIGHT_PIXELS_UNSCALED;
        tileX = m_x/TILE_WIDTH_PIXELS_UNSCALED;

/*
        tileID = level1MapData.backTiles[(tileY*LEVEL_WIDTH_TILES)+tileX];

        al_draw_scaled_bitmap(GLOBALS::tileAtlas_unscaled,
                              (tileID % atlasWidth_tiles) * TILE_WIDTH_PIXELS_UNSCALED, (tileID / atlasWidth_tiles) * TILE_HEIGHT_PIXELS_UNSCALED,
                              TILE_WIDTH_PIXELS_UNSCALED, TILE_HEIGHT_PIXELS_UNSCALED,
                              (TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR) * tileX, (TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR) * tileY,
                              TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR, TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR,
                              0);
*/
        return true;
    }

    return false;
}

const unsigned int TSatelliteDish::frames[eFRAMES_PER_ANIMATION] = {357, 358, 357, 359}; /* center, right, center, left */
const   signed int TSatelliteDish::widths[eFRAMES_PER_ANIMATION] = {TILE_WIDTH_PIXELS_UNSCALED, TILE_WIDTH_PIXELS_UNSCALED, TILE_WIDTH_PIXELS_UNSCALED, TILE_WIDTH_PIXELS_UNSCALED};

void TSatelliteDish::Tick(double delta_seconds)
{
	m_seconds_since_last_frame_change += delta_seconds;

	if (m_seconds_since_last_frame_change >= 0.33)
	{
		m_frameIndex = (m_frameIndex + 1) % eFRAMES_PER_ANIMATION;
		m_seconds_since_last_frame_change = 0.0;
	}
}

bool TSatelliteDish::CollidedWith(TObject &obj)
{
	/*
	if (obj == player's bullet)
		++m_timeShot;

		if (m_timesShot >= hit points)
			remove from level
			give player points
			record that dish is destroyed, so player is allowed to exit
			return true;
	*/

	return false;
}

unsigned int TSatelliteDish::TileID() const
{
    return frames[m_frameIndex];
}

signed int TSatelliteDish::DrawWidth() const
{
    return widths[m_frameIndex];
}

bool TAmmo::CollidedWith(TObject &obj)
{
    if (&obj == &GLOBALS::player)
    {
        GLOBALS::player.AddAmmo(5); // 5 = number of shots awarded for each ammo collected
        return true;
    }

    return false;
}

TPushable::TPushable(unsigned int tileID, signed int x, signed int y) : TObject(tileID, x, y)
{
	int tileX = x / TILE_WIDTH_PIXELS_UNSCALED;
    int tileXright = (x + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
    int tileY = y / TILE_HEIGHT_PIXELS_UNSCALED;

    // save the existing bounding solids details of the tiles where the pushable is being placed
    // so that when the pushable is moved from these tiles into different ones, the original
    // solids can be set back to the correct values.
    m_boundsLeft = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX];
    m_boundsRight = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright];
};

bool TPushable::CollidedWith(TObject &obj)
{
    int oldX = m_x;
    int oldY = m_y;
	int tileX = oldX / TILE_WIDTH_PIXELS_UNSCALED;
    int tileXright = (oldX + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
    int tileY = oldY / TILE_HEIGHT_PIXELS_UNSCALED;

    if (&obj == &GLOBALS::player)
    {
        bool moved = false;

        if (GLOBALS::player.m_x < m_x) // player is on left, trying to push right
        {
        	tileXright = (oldX + DrawWidth()) / TILE_WIDTH_PIXELS_UNSCALED;
        	if (!(level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright] & SOLID_LEFT))
        	{
        		m_x = GLOBALS::player.m_x + GLOBALS::player.DrawWidth() + 1;
        		moved = true;
        	}
        }
        else if (GLOBALS::player.m_x > m_x) // player is on right, trying to push left
        {
        	tileX = (oldX-1) / TILE_WIDTH_PIXELS_UNSCALED;
            if (!(level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX] & SOLID_RIGHT))
            {
            	m_x = GLOBALS::player.m_x - DrawWidth();
            	moved = true;
            }
        }

        if (moved)
        {
            // compute tileX and tileY for oldX and oldY
        	tileX = oldX / TILE_WIDTH_PIXELS_UNSCALED;
            tileXright = (oldX + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
            tileY = oldY / TILE_HEIGHT_PIXELS_UNSCALED;

            // put boundaries for the old tiles back to their original values
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX]      = m_boundsLeft;
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright] = m_boundsRight;

            // compute tileX and tileY for m_x and m_y
        	tileX = m_x / TILE_WIDTH_PIXELS_UNSCALED;
            tileXright = (m_x + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
            tileY = m_y / TILE_HEIGHT_PIXELS_UNSCALED;

            // save the boundaries for the new tiles before modifying them
            m_boundsLeft  = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX];
            m_boundsRight = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright];

            // set SOLID_TOP bounds in those tiles
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX]      |= SOLID_TOP;
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright] |= SOLID_TOP;
        }
    }

    // always returns false because pushables are never removed, even when touched
    return false;
}
<commit_msg>Correct some indentations (tabs -> spaces) introduced by Eclipse.<commit_after>#include <cassert>

#include "sam_shared.hpp"
#include "interactives.hpp"

#include "level1.h"

const unsigned int TPlayer::frames[eNUM_PLAYER_ANIMATIONS][eFRAMES_PER_ANIMATION] =
{
    { 389, 390, 391, 392 },
    { 366, 367, 368, 369 },
    { 436, 436, 436, 436 },
    { 435, 435, 435, 435 },
    { 413, 415, 415, 413 },
    { 412, 414, 414, 412 }
};

const signed int TPlayer::widths[eNUM_PLAYER_ANIMATIONS][eFRAMES_PER_ANIMATION] =
{
    { 22, 22, 22, 22 }, /* standing left  */
    { 22, 22, 22, 22 }, /* standing right */

    { 22, 22, 22, 22 }, /* standing left  */
    { 22, 22, 22, 22 }, /* standing right */
    //{ 28, 28, 28, 28 }, /* jumping left   */
    //{ 28, 28, 28, 28 }, /* jumping right  */

    { 20, 32, 32, 20 }, /* shooting left  */
    { 20, 32, 32, 20 }  /* shooting right */
};

void TPlayer::Tick(double delta_seconds)
{
    m_seconds_since_last_frame_change += delta_seconds;

    if (m_seconds_since_last_frame_change >= ANIMATION_RATE)
    {
        m_frameIndex = (m_frameIndex + 1) % eFRAMES_PER_ANIMATION;
        m_seconds_since_last_frame_change = 0.0;
    }

    /* select the current animation */
    if (m_facing == eFACING_RIGHT)
    {
        if (m_jumping || !OnSolidGround())
        	m_animation = eANIM_JUMPING_RIGHT;
        // else if (m_shooting)
        //  m_animation = eANIM_SHOOTING_RIGHT;
        else
        	m_animation = eANIM_STANDING_RIGHT;
	}
    else if (m_facing == eFACING_LEFT)
    {
        if (m_jumping || !OnSolidGround())
        	m_animation = eANIM_JUMPING_LEFT;
        // else if (m_shooting)
        //  m_animation = eANIM_SHOOTING_LEFT;
        else
        	m_animation = eANIM_STANDING_LEFT;
    }
}

unsigned int TPlayer::TileID() const
{
    return frames[m_animation][m_frameIndex];
}

signed int TPlayer::DrawWidth() const
{
    return widths[m_animation][m_frameIndex];
}

bool TGlasses::CollidedWith(TObject &obj)
{
    if (&obj == &GLOBALS::player)
    {
        const unsigned int atlasWidth_tiles = al_get_bitmap_width(GLOBALS::tileAtlas_unscaled) / TILE_WIDTH_PIXELS_UNSCALED;
        unsigned int tileY, tileX;
        signed int tileID, tileIndex;

        al_set_target_bitmap(GLOBALS::background_scaled);

        // turn on the invisible platforms
        for (tileIndex = 0; tileIndex < (LEVEL_HEIGHT_TILES * LEVEL_WIDTH_TILES); ++tileIndex)
        {
            if (level1MapData.codes[tileIndex] == eCODE_INVISIBLE_PLATFORM)
            {
                level1MapData.codes[tileIndex] = 0;

                tileID = 53;

                level1MapData.bounds[tileIndex] = SOLID_TOP;
                level1MapData.midTiles[tileIndex] = tileID;

                tileY = tileIndex / LEVEL_WIDTH_TILES;
                tileX = tileIndex % LEVEL_WIDTH_TILES;
                al_draw_scaled_bitmap(GLOBALS::tileAtlas_unscaled,
                                      (tileID % atlasWidth_tiles) * TILE_WIDTH_PIXELS_UNSCALED, (tileID / atlasWidth_tiles) * TILE_HEIGHT_PIXELS_UNSCALED,
                                      TILE_WIDTH_PIXELS_UNSCALED, TILE_HEIGHT_PIXELS_UNSCALED,
                                      (TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR) * tileX, (TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR) * tileY,
                                      TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR, TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR,
                                      0);
            }
        }
        // paint over glasses graphic in background image
        tileY = m_y/TILE_HEIGHT_PIXELS_UNSCALED;
        tileX = m_x/TILE_WIDTH_PIXELS_UNSCALED;

/*
        tileID = level1MapData.backTiles[(tileY*LEVEL_WIDTH_TILES)+tileX];

        al_draw_scaled_bitmap(GLOBALS::tileAtlas_unscaled,
                              (tileID % atlasWidth_tiles) * TILE_WIDTH_PIXELS_UNSCALED, (tileID / atlasWidth_tiles) * TILE_HEIGHT_PIXELS_UNSCALED,
                              TILE_WIDTH_PIXELS_UNSCALED, TILE_HEIGHT_PIXELS_UNSCALED,
                              (TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR) * tileX, (TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR) * tileY,
                              TILE_WIDTH_PIXELS_UNSCALED * SCALE_FACTOR, TILE_HEIGHT_PIXELS_UNSCALED * SCALE_FACTOR,
                              0);
*/
        return true;
    }

    return false;
}

const unsigned int TSatelliteDish::frames[eFRAMES_PER_ANIMATION] = {357, 358, 357, 359}; /* center, right, center, left */
const   signed int TSatelliteDish::widths[eFRAMES_PER_ANIMATION] = {TILE_WIDTH_PIXELS_UNSCALED, TILE_WIDTH_PIXELS_UNSCALED, TILE_WIDTH_PIXELS_UNSCALED, TILE_WIDTH_PIXELS_UNSCALED};

void TSatelliteDish::Tick(double delta_seconds)
{
	m_seconds_since_last_frame_change += delta_seconds;

	if (m_seconds_since_last_frame_change >= 0.33)
	{
		m_frameIndex = (m_frameIndex + 1) % eFRAMES_PER_ANIMATION;
		m_seconds_since_last_frame_change = 0.0;
	}
}

bool TSatelliteDish::CollidedWith(TObject &obj)
{
	/*
	if (obj == player's bullet)
		++m_timeShot;

		if (m_timesShot >= hit points)
			remove from level
			give player points
			record that dish is destroyed, so player is allowed to exit
			return true;
	*/

	return false;
}

unsigned int TSatelliteDish::TileID() const
{
    return frames[m_frameIndex];
}

signed int TSatelliteDish::DrawWidth() const
{
    return widths[m_frameIndex];
}

bool TAmmo::CollidedWith(TObject &obj)
{
    if (&obj == &GLOBALS::player)
    {
        GLOBALS::player.AddAmmo(5); // 5 = number of shots awarded for each ammo collected
        return true;
    }

    return false;
}

TPushable::TPushable(unsigned int tileID, signed int x, signed int y) : TObject(tileID, x, y)
{
	int tileX = x / TILE_WIDTH_PIXELS_UNSCALED;
    int tileXright = (x + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
    int tileY = y / TILE_HEIGHT_PIXELS_UNSCALED;

    // save the existing bounding solids details of the tiles where the pushable is being placed
    // so that when the pushable is moved from these tiles into different ones, the original
    // solids can be set back to the correct values.
    m_boundsLeft = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX];
    m_boundsRight = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright];
};

bool TPushable::CollidedWith(TObject &obj)
{
    int oldX = m_x;
    int oldY = m_y;
	int tileX = oldX / TILE_WIDTH_PIXELS_UNSCALED;
    int tileXright = (oldX + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
    int tileY = oldY / TILE_HEIGHT_PIXELS_UNSCALED;

    if (&obj == &GLOBALS::player)
    {
        bool moved = false;

        if (GLOBALS::player.m_x < m_x) // player is on left, trying to push right
        {
        	tileXright = (oldX + DrawWidth()) / TILE_WIDTH_PIXELS_UNSCALED;
        	if (!(level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright] & SOLID_LEFT))
        	{
        		m_x = GLOBALS::player.m_x + GLOBALS::player.DrawWidth() + 1;
        		moved = true;
        	}
        }
        else if (GLOBALS::player.m_x > m_x) // player is on right, trying to push left
        {
        	tileX = (oldX-1) / TILE_WIDTH_PIXELS_UNSCALED;
            if (!(level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX] & SOLID_RIGHT))
            {
            	m_x = GLOBALS::player.m_x - DrawWidth();
            	moved = true;
            }
        }

        if (moved)
        {
            // compute tileX and tileY for oldX and oldY
            tileX = oldX / TILE_WIDTH_PIXELS_UNSCALED;
            tileXright = (oldX + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
            tileY = oldY / TILE_HEIGHT_PIXELS_UNSCALED;

            // put boundaries for the old tiles back to their original values
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX]      = m_boundsLeft;
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright] = m_boundsRight;

            // compute tileX and tileY for m_x and m_y
            tileX = m_x / TILE_WIDTH_PIXELS_UNSCALED;
            tileXright = (m_x + DrawWidth() - 1) / TILE_WIDTH_PIXELS_UNSCALED;
            tileY = m_y / TILE_HEIGHT_PIXELS_UNSCALED;

            // save the boundaries for the new tiles before modifying them
            m_boundsLeft  = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX];
            m_boundsRight = level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright];

            // set SOLID_TOP bounds in those tiles
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileX]      |= SOLID_TOP;
            level1MapData.bounds[tileY * LEVEL_WIDTH_TILES + tileXright] |= SOLID_TOP;
        }
    }

    // always returns false because pushables are never removed, even when touched
    return false;
}
<|endoftext|>


<commit_before>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Symbol table is a bag of all known symbols. We put all symbols of
// all input files to the symbol table. The symbol Table is basically
// a hash table with the logic to resolve symbol name conflicts using
// the symbol types.
//
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;

using namespace lld;
using namespace lld::elf2;

template <class ELFT> SymbolTable<ELFT>::SymbolTable() {}

template <class ELFT> bool SymbolTable<ELFT>::shouldUseRela() const {
  ELFKind K = cast<ELFFileBase<ELFT>>(Config->FirstElf)->getELFKind();
  return K == ELF64LEKind || K == ELF64BEKind;
}

template <class ELFT>
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
  checkCompatibility(File);

  if (auto *AF = dyn_cast<ArchiveFile>(File.get())) {
    ArchiveFiles.emplace_back(std::move(File));
    AF->parse();
    for (Lazy &Sym : AF->getLazySymbols())
      addLazy(&Sym);
    return;
  }

  if (auto *S = dyn_cast<SharedFile<ELFT>>(File.get())) {
    S->parseSoName();
    if (!IncludedSoNames.insert(S->getSoName()).second)
      return;
    S->parse();
  } else {
    cast<ObjectFile<ELFT>>(File.get())->parse(Comdats);
  }
  addELFFile(cast<ELFFileBase<ELFT>>(File.release()));
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
  auto *Sym = new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Required);
  resolve(Sym);
  return Sym;
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
  auto *Sym = new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Optional);
  resolve(Sym);
  return Sym;
}

template <class ELFT>
void SymbolTable<ELFT>::addAbsoluteSym(StringRef Name,
                                       typename ELFFile<ELFT>::Elf_Sym &ESym) {
  resolve(new (Alloc) DefinedAbsolute<ELFT>(Name, ESym));
}

template <class ELFT>
void SymbolTable<ELFT>::addSyntheticSym(StringRef Name,
                                        OutputSectionBase<ELFT> &Section,
                                        typename ELFFile<ELFT>::uintX_t Value) {
  typedef typename DefinedSynthetic<ELFT>::Elf_Sym Elf_Sym;
  auto ESym = new (Alloc) Elf_Sym;
  memset(ESym, 0, sizeof(Elf_Sym));
  ESym->st_value = Value;
  auto Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, *ESym, Section);
  resolve(Sym);
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addIgnoredSym(StringRef Name) {
  auto Sym = new (Alloc)
      DefinedAbsolute<ELFT>(Name, DefinedAbsolute<ELFT>::IgnoreUndef);
  resolve(Sym);
  return Sym;
}

template <class ELFT> bool SymbolTable<ELFT>::isUndefined(StringRef Name) {
  if (SymbolBody *Sym = find(Name))
    return Sym->isUndefined();
  return false;
}

template <class ELFT>
void SymbolTable<ELFT>::addELFFile(ELFFileBase<ELFT> *File) {
  if (auto *O = dyn_cast<ObjectFile<ELFT>>(File))
    ObjectFiles.emplace_back(O);
  else if (auto *S = dyn_cast<SharedFile<ELFT>>(File))
    SharedFiles.emplace_back(S);

  if (auto *O = dyn_cast<ObjectFile<ELFT>>(File)) {
    for (SymbolBody *Body : O->getSymbols())
      resolve(Body);
  }

  if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
    for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
      resolve(&Body);
  }
}

template <class ELFT>
std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
  typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
  typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;

  const Elf_Sym &OldE = cast<ELFSymbolBody<ELFT>>(*Old).Sym;
  const Elf_Sym &NewE = cast<ELFSymbolBody<ELFT>>(*New).Sym;
  ELFFileBase<ELFT> *OldFile = nullptr;
  ELFFileBase<ELFT> *NewFile = nullptr;

  for (const std::unique_ptr<ObjectFile<ELFT>> &File : ObjectFiles) {
    Elf_Sym_Range Syms = File->getObj().symbols(File->getSymbolTable());
    if (&OldE > Syms.begin() && &OldE < Syms.end())
      OldFile = File.get();
    if (&NewE > Syms.begin() && &NewE < Syms.end())
      NewFile = File.get();
  }

  StringRef Sym = Old->getName();
  StringRef F1 = OldFile ? OldFile->getName() : "(internal)";
  StringRef F2 = NewFile ? NewFile->getName() : "(internal)";
  return (Sym + " in " + F1 + " and " + F2).str();
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;

  SymbolBody *Existing = Sym->Body;

  if (Lazy *L = dyn_cast<Lazy>(Existing)) {
    if (New->isUndefined()) {
      if (New->isWeak()) {
        // See the explanation in SymbolTable::addLazy
        L->setUsedInRegularObj();
        L->setWeak();
        return;
      }
      addMemberFile(L);
      return;
    }

    // Found a definition for something also in an archive. Ignore the archive
    // definition.
    Sym->Body = New;
    return;
  }

  if (New->isTLS() != Existing->isTLS())
    error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  int comp = Existing->compare<ELFT>(New);
  if (comp == 0) {
    std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
    if (!Config->AllowMultipleDefinition)
      error(S);
    warning(S);
    return;
  }
  if (comp < 0)
    Sym->Body = New;
}

template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym) {
    Sym = new (Alloc) Symbol(New);
    New->setBackref(Sym);
    return Sym;
  }
  New->setBackref(Sym);
  return Sym;
}

template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return nullptr;
  return It->second->Body;
}

template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;
  SymbolBody *Existing = Sym->Body;
  if (Existing->isDefined() || Existing->isLazy())
    return;
  Sym->Body = New;
  assert(Existing->isUndefined() && "Unexpected symbol kind.");

  // Weak undefined symbols should not fetch members from archives.
  // If we were to keep old symbol we would not know that an archive member was
  // available if a strong undefined symbol shows up afterwards in the link.
  // If a strong undefined symbol never shows up, this lazy symbol will
  // get to the end of the link and must be treated as the weak undefined one.
  // We set UsedInRegularObj in a similar way to what is done with shared
  // symbols and mark it as weak to reduce how many special cases are needed.
  if (Existing->isWeak()) {
    New->setUsedInRegularObj();
    New->setWeak();
    return;
  }
  addMemberFile(New);
}

template <class ELFT>
void SymbolTable<ELFT>::checkCompatibility(std::unique_ptr<InputFile> &File) {
  auto *E = dyn_cast<ELFFileBase<ELFT>>(File.get());
  if (!E)
    return;
  if (E->getELFKind() == Config->EKind && E->getEMachine() == Config->EMachine)
    return;
  StringRef A = E->getName();
  StringRef B = Config->Emulation;
  if (B.empty())
    B = Config->FirstElf->getName();
  error(A + " is incompatible with " + B);
}

template <class ELFT> void SymbolTable<ELFT>::addMemberFile(Lazy *Body) {
  // getMember returns nullptr if the member was already read from the library.
  if (std::unique_ptr<InputFile> File = Body->getMember())
    addFile(std::move(File));
}

// This function takes care of the case in which shared libraries depend on
// the user program (not the other way, which is usual). Shared libraries
// may have undefined symbols, expecting that the user program provides
// the definitions for them. An example is BSD's __progname symbol.
// We need to put such symbols to the main program's .dynsym so that
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
  for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles)
    for (StringRef U : File->getUndefinedSymbols())
      if (SymbolBody *Sym = find(U))
        if (Sym->isDefined())
          Sym->setUsedInDynamicReloc();
}

template class lld::elf2::SymbolTable<ELF32LE>;
template class lld::elf2::SymbolTable<ELF32BE>;
template class lld::elf2::SymbolTable<ELF64LE>;
template class lld::elf2::SymbolTable<ELF64BE>;
<commit_msg>ELF: Factor out common code. NFC.<commit_after>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Symbol table is a bag of all known symbols. We put all symbols of
// all input files to the symbol table. The symbol Table is basically
// a hash table with the logic to resolve symbol name conflicts using
// the symbol types.
//
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;

using namespace lld;
using namespace lld::elf2;

template <class ELFT> SymbolTable<ELFT>::SymbolTable() {}

template <class ELFT> bool SymbolTable<ELFT>::shouldUseRela() const {
  ELFKind K = cast<ELFFileBase<ELFT>>(Config->FirstElf)->getELFKind();
  return K == ELF64LEKind || K == ELF64BEKind;
}

template <class ELFT>
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
  checkCompatibility(File);

  if (auto *AF = dyn_cast<ArchiveFile>(File.get())) {
    ArchiveFiles.emplace_back(std::move(File));
    AF->parse();
    for (Lazy &Sym : AF->getLazySymbols())
      addLazy(&Sym);
    return;
  }

  if (auto *S = dyn_cast<SharedFile<ELFT>>(File.get())) {
    S->parseSoName();
    if (!IncludedSoNames.insert(S->getSoName()).second)
      return;
    S->parse();
  } else {
    cast<ObjectFile<ELFT>>(File.get())->parse(Comdats);
  }
  addELFFile(cast<ELFFileBase<ELFT>>(File.release()));
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
  auto *Sym = new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Required);
  resolve(Sym);
  return Sym;
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
  auto *Sym = new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Optional);
  resolve(Sym);
  return Sym;
}

template <class ELFT>
void SymbolTable<ELFT>::addAbsoluteSym(StringRef Name,
                                       typename ELFFile<ELFT>::Elf_Sym &ESym) {
  resolve(new (Alloc) DefinedAbsolute<ELFT>(Name, ESym));
}

template <class ELFT>
void SymbolTable<ELFT>::addSyntheticSym(StringRef Name,
                                        OutputSectionBase<ELFT> &Section,
                                        typename ELFFile<ELFT>::uintX_t Value) {
  typedef typename DefinedSynthetic<ELFT>::Elf_Sym Elf_Sym;
  auto ESym = new (Alloc) Elf_Sym;
  memset(ESym, 0, sizeof(Elf_Sym));
  ESym->st_value = Value;
  auto Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, *ESym, Section);
  resolve(Sym);
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addIgnoredSym(StringRef Name) {
  auto Sym = new (Alloc)
      DefinedAbsolute<ELFT>(Name, DefinedAbsolute<ELFT>::IgnoreUndef);
  resolve(Sym);
  return Sym;
}

template <class ELFT> bool SymbolTable<ELFT>::isUndefined(StringRef Name) {
  if (SymbolBody *Sym = find(Name))
    return Sym->isUndefined();
  return false;
}

template <class ELFT>
void SymbolTable<ELFT>::addELFFile(ELFFileBase<ELFT> *File) {
  if (auto *O = dyn_cast<ObjectFile<ELFT>>(File))
    ObjectFiles.emplace_back(O);
  else if (auto *S = dyn_cast<SharedFile<ELFT>>(File))
    SharedFiles.emplace_back(S);

  if (auto *O = dyn_cast<ObjectFile<ELFT>>(File)) {
    for (SymbolBody *Body : O->getSymbols())
      resolve(Body);
  }

  if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
    for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
      resolve(&Body);
  }
}

// Returns a file from which symbol B was created.
// If B does not belong to any file in ObjectFiles, returns a nullptr.
template <class ELFT>
static ELFFileBase<ELFT> *
findFile(std::vector<std::unique_ptr<ObjectFile<ELFT>>> &ObjectFiles,
         SymbolBody *B) {
  typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
  typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;

  const Elf_Sym *Sym = &cast<ELFSymbolBody<ELFT>>(*B).Sym;
  for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) {
    Elf_Sym_Range R = F->getObj().symbols(F->getSymbolTable());
    if (R.begin() <= Sym && Sym < R.end())
      return F.get();
  }
  return nullptr;
}

template <class ELFT>
std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
  ELFFileBase<ELFT> *OldFile = findFile(ObjectFiles, Old);
  ELFFileBase<ELFT> *NewFile = findFile(ObjectFiles, New);

  StringRef Sym = Old->getName();
  StringRef F1 = OldFile ? OldFile->getName() : "(internal)";
  StringRef F2 = NewFile ? NewFile->getName() : "(internal)";
  return (Sym + " in " + F1 + " and " + F2).str();
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;

  SymbolBody *Existing = Sym->Body;

  if (Lazy *L = dyn_cast<Lazy>(Existing)) {
    if (New->isUndefined()) {
      if (New->isWeak()) {
        // See the explanation in SymbolTable::addLazy
        L->setUsedInRegularObj();
        L->setWeak();
        return;
      }
      addMemberFile(L);
      return;
    }

    // Found a definition for something also in an archive. Ignore the archive
    // definition.
    Sym->Body = New;
    return;
  }

  if (New->isTLS() != Existing->isTLS())
    error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  int comp = Existing->compare<ELFT>(New);
  if (comp == 0) {
    std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
    if (!Config->AllowMultipleDefinition)
      error(S);
    warning(S);
    return;
  }
  if (comp < 0)
    Sym->Body = New;
}

template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym) {
    Sym = new (Alloc) Symbol(New);
    New->setBackref(Sym);
    return Sym;
  }
  New->setBackref(Sym);
  return Sym;
}

template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return nullptr;
  return It->second->Body;
}

template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;
  SymbolBody *Existing = Sym->Body;
  if (Existing->isDefined() || Existing->isLazy())
    return;
  Sym->Body = New;
  assert(Existing->isUndefined() && "Unexpected symbol kind.");

  // Weak undefined symbols should not fetch members from archives.
  // If we were to keep old symbol we would not know that an archive member was
  // available if a strong undefined symbol shows up afterwards in the link.
  // If a strong undefined symbol never shows up, this lazy symbol will
  // get to the end of the link and must be treated as the weak undefined one.
  // We set UsedInRegularObj in a similar way to what is done with shared
  // symbols and mark it as weak to reduce how many special cases are needed.
  if (Existing->isWeak()) {
    New->setUsedInRegularObj();
    New->setWeak();
    return;
  }
  addMemberFile(New);
}

template <class ELFT>
void SymbolTable<ELFT>::checkCompatibility(std::unique_ptr<InputFile> &File) {
  auto *E = dyn_cast<ELFFileBase<ELFT>>(File.get());
  if (!E)
    return;
  if (E->getELFKind() == Config->EKind && E->getEMachine() == Config->EMachine)
    return;
  StringRef A = E->getName();
  StringRef B = Config->Emulation;
  if (B.empty())
    B = Config->FirstElf->getName();
  error(A + " is incompatible with " + B);
}

template <class ELFT> void SymbolTable<ELFT>::addMemberFile(Lazy *Body) {
  // getMember returns nullptr if the member was already read from the library.
  if (std::unique_ptr<InputFile> File = Body->getMember())
    addFile(std::move(File));
}

// This function takes care of the case in which shared libraries depend on
// the user program (not the other way, which is usual). Shared libraries
// may have undefined symbols, expecting that the user program provides
// the definitions for them. An example is BSD's __progname symbol.
// We need to put such symbols to the main program's .dynsym so that
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
  for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles)
    for (StringRef U : File->getUndefinedSymbols())
      if (SymbolBody *Sym = find(U))
        if (Sym->isDefined())
          Sym->setUsedInDynamicReloc();
}

template class lld::elf2::SymbolTable<ELF32LE>;
template class lld::elf2::SymbolTable<ELF32BE>;
template class lld::elf2::SymbolTable<ELF64LE>;
template class lld::elf2::SymbolTable<ELF64BE>;
<|endoftext|>


<commit_before>#include "bochs.h"

bx_iodebug_c bx_iodebug;

// Constructor
bx_iodebug_c::bx_iodebug_c( void )
{
  put("IODEBUG");
  settype(IODEBUGLOG);
  memset(&s, 0, sizeof(s));
}

// Destructor
bx_iodebug_c::~bx_iodebug_c( void )
{
}

int bx_iodebug_c::init( bx_devices_c *d )
{
  int i;

  BX_IODEBUG_THIS devices = d;
  BX_IODEBUG_THIS devices->register_io_read_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG");
  BX_IODEBUG_THIS devices->register_io_read_handler(this, read_handler, 0x8A01,"BOCHS IODEBUG");

  BX_IODEBUG_THIS devices->register_io_write_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG");
  BX_IODEBUG_THIS devices->register_io_write_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG");
  fprintf( stderr, "IODEBUG initialized\n");

  BX_IODEBUG_THIS s.enabled = 0;
  BX_IODEBUG_THIS s.register_select = 0;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
    BX_IODEBUG_THIS s.monitored_mem_areas_start[i] = 0;
    BX_IODEBUG_THIS s.monitored_mem_areas_end[i] = 0;
  }

  return(1);
}

Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
  bx_iodebug_c *class_ptr = (bx_iodebug_c *) this_ptr;
  return( class_ptr->read(addr, io_len) );
}

Bit32u bx_iodebug_c::read( Bit32u addr, unsigned io_len )
{

  if(BX_IODEBUG_THIS s.enabled) return(0x8A00);
  return(0);
}

void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
  bx_iodebug_c *class_ptr = (bx_iodebug_c *) this_ptr;
  class_ptr->write( addr, dvalue, io_len );
}

void bx_iodebug_c::write( Bit32u addr, Bit32u dvalue, unsigned int io_len )
{

  fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned int)addr, (unsigned int)dvalue, io_len);

  if( addr == 0x8A00 && dvalue == 0x8A00 )
  {
    if( BX_IODEBUG_THIS s.enabled )
      fprintf( stderr, "IODEBUG device already activated\n");
    else
    {
      BX_IODEBUG_THIS s.enabled=1;
      fprintf( stderr, "IODEBUG device activated\n");
    }
  }

  else if ( BX_IODEBUG_THIS s.enabled )
  {

    // Register Select port
    if( addr == 0x8A00 )
    {
      if( dvalue == 0x8AFF )
      {
        BX_IODEBUG_THIS s.enabled = 0;
	fprintf( stderr, "IODEBUG device deactivated\n");
      }
      fprintf( stderr, "IODEBUG register selected: %8x\n", dvalue);
      BX_IODEBUG_THIS s.register_select = dvalue;
    }

    // Data port
    else
    {
      fprintf( stderr, "IODEBUG value written to register %2x: %8x\n", BX_IODEBUG_THIS s.register_select, dvalue);
    }
  }
}

void bx_iodebug_c::mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  Bit32u data32;
  Bit16u data16;
  Bit8u  data8;

  int area;
  if( !BX_IODEBUG_THIS s.enabled ) return;

  // Device is enabled, testing address ranges
  if( area = BX_IODEBUG_THIS range_test( addr, len ) )
  {
    area--;
    fprintf( stderr,
             "IODEBUG write to monitored memory area %i\n\trange start: %8x\trange end: %8x\n\taddress accessed: %8x\tdata written: ",
	     area,
	     BX_IODEBUG_THIS s.monitored_mem_areas_start[area],
	     BX_IODEBUG_THIS s.monitored_mem_areas_end[area],
	     (unsigned int)addr);
    data32 = * (Bit32u *)data;
    data16 = (Bit16u)data32;
    data8  = (Bit8u)data32;

    switch(len)
    {
      case(1):
        fprintf(stderr,"%2x\n", (unsigned int)data8);
	break;

      case(2):
        fprintf(stderr,"%4x\n", (unsigned int)data16);
	break;

      case(4):
        fprintf(stderr,"%8x\n", (unsigned int)data32);
	break;

      default:
        fprintf(stderr, "unsupported write size\n");
    }
  }
}

void bx_iodebug_c::mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  if( !BX_IODEBUG_THIS s.enabled ) return;

  // Device is enabled, testing address range
}

unsigned int bx_iodebug_c::range_test( Bit32u addr, unsigned int len )
{
  int i;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( BX_IODEBUG_THIS s.monitored_mem_areas_start[i] ||
        BX_IODEBUG_THIS s.monitored_mem_areas_end[i] )
    {
      if( (addr+len-1) < BX_IODEBUG_THIS s.monitored_mem_areas_start[i] )
        continue;
      if( addr > BX_IODEBUG_THIS s.monitored_mem_areas_end[i] )
        return(++i);
    }
  }
}
<commit_msg>final revision of the memory protection material<commit_after>#include "bochs.h"

bx_iodebug_c bx_iodebug;
bx_iodebug_c *bx_iodebug_ptr;

  struct bx_iodebug_s_type {
    Boolean enabled;
    unsigned int register_select;
    Bit32u registers[2];
    Bit32u monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
    Bit32u monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
  } bx_iodebug_s;

// Constructor
bx_iodebug_c::bx_iodebug_c( void )
{
  put("IODEBUG");
  settype(IODEBUGLOG);

}

// Destructor
bx_iodebug_c::~bx_iodebug_c( void )
{
}

int bx_iodebug_c::init( bx_devices_c *d )
{
  int i;

  BX_IODEBUG_THIS devices = d;
  BX_IODEBUG_THIS devices->register_io_read_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG");
  BX_IODEBUG_THIS devices->register_io_write_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG");
  BX_IODEBUG_THIS devices->register_io_write_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG");
  fprintf( stderr, "IODEBUG initialized\n");

  bx_iodebug_s.enabled = 0;
  bx_iodebug_s.register_select = 0;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
    bx_iodebug_s.monitored_mem_areas_start[i] = 0;
    bx_iodebug_s.monitored_mem_areas_end[i] = 0;
  }

  return(1);
}

Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
  bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  return( bx_iodebug_ptr->read(addr, io_len) );
}

Bit32u bx_iodebug_c::read( Bit32u addr, unsigned io_len )
{

  if(bx_iodebug_s.enabled) return(0x8A00);
  return(0);
}

void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
  bx_iodebug_c *class_ptr = (bx_iodebug_c *) this_ptr;
  class_ptr->write( addr, dvalue, io_len );
}

void bx_iodebug_c::write( Bit32u addr, Bit32u dvalue, unsigned int io_len )
{

  fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned int)addr, (unsigned int)dvalue, io_len);

  if( addr == 0x8A01 && io_len == 2 )
  {
      bx_iodebug_s.registers[bx_iodebug_s.register_select] =
        (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
	(dvalue & 0x0000FFFF );
  }

  if( (addr != 0x8A00) || (io_len != 2) ) return;

  if( !bx_iodebug_s.enabled )
  {
    if( dvalue == 0x8A00 )
    {
      bx_iodebug_s.enabled = 1;
      fprintf(stderr, "IODEBUG enabled\n");
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
    }
    return;
  }

  switch( dvalue )
  {
    case( 0x8A01 ):
      bx_iodebug_s.register_select = 0;
      fprintf( stderr, "IODEBUG register 0 selected\n");
      break;

    case( 0x8A02 ):
      bx_iodebug_s.register_select = 1;
      fprintf( stderr, "IODEBUG register 1 selected\n");
      break;

    case( 0x8A80 ):
      bx_iodebug_s.register_select = 0;
      bx_iodebug_c::add_range(
          bx_iodebug_s.registers[0],
	  bx_iodebug_s.registers[1]);
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
      break;

    case( 0x8AFF ):
      bx_iodebug_s.enabled = 0;
      fprintf( stderr, "IODEBUG device deactivated\n");
      break;

    default:
      fprintf(stderr,"IODEBUG unsupported register code\n");
  }
}

// Static function
void bx_iodebug_c::mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  Bit32u data32;
  Bit16u data16;
  Bit8u  data8;

  unsigned int area;
  if( !bx_iodebug_s.enabled ) return;

  area = bx_iodebug_c::range_test( addr, len );
  // Device is enabled, testing address ranges
  if( area )
  {
    area--;
    fprintf( stderr,
             "IODEBUG write to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     area,
	     bx_cpu.eip,
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned int)addr);
    data32 = * (Bit32u *)data;
    data16 = (Bit16u)data32;
    data8  = (Bit8u)data32;

    switch(len)
    {
      case(1):
        fprintf(stderr,"%02X\n", (unsigned int)data8);
	break;

      case(2):
        fprintf(stderr,"%04X\n", (unsigned int)data16);
	break;

      case(4):
        fprintf(stderr,"%08X\n", (unsigned int)data32);
	break;

      default:
        fprintf(stderr, "unsupported write size\n");
    }
  }
}

void bx_iodebug_c::mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  if( !bx_iodebug_s.enabled ) return;

  // Device is enabled, testing address range
}

unsigned int bx_iodebug_c::range_test( Bit32u addr, unsigned int len )
{
  unsigned int i;

  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( (bx_iodebug_s.monitored_mem_areas_start[i]!=0) ||
        (bx_iodebug_s.monitored_mem_areas_end[i]!=0) )
    {
      if( (Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i] )
        continue;
      if( addr < bx_iodebug_s.monitored_mem_areas_end[i] )
      {
        return(++i);
      }
    }
  }
  return(0);
}

void bx_iodebug_c::add_range( Bit32u addr_start, Bit32u addr_end )
{
  unsigned int i;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( !bx_iodebug_s.monitored_mem_areas_start[i] &&
        !bx_iodebug_s.monitored_mem_areas_end[i] )
    {
	bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
	bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
	fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
	return;
    }
  }
  fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
}
<|endoftext|>


<commit_before>#ifndef VAST_CONCEPT_PARSEABLE_CORE_REPEAT_HPP
#define VAST_CONCEPT_PARSEABLE_CORE_REPEAT_HPP

#include <vector>

#include "vast/concept/parseable/core/parser.hpp"
#include "vast/concept/parseable/detail/container.hpp"

#include "vast/detail/assert.hpp"

namespace vast {
namespace detail {

template <class Parser, class Iterator, class Attribute>
bool parse_repeat(Parser& p, Iterator& f, Iterator const& l, Attribute& a,
                  int min, int max) {
  if (max == 0)
    return true; // If we have nothing todo, we're succeeding.
  auto save = f;
  auto i = 0;
  while (i < max) {
    if (!container<typename Parser::attribute>::parse(p, f, l, a))
      break;
    ++i;
  }
  if (i >= min)
    return true;
  f = save;
  return false;
}

} // namespace detail

template <class Parser, int Min, int Max = Min>
class static_repeat_parser
  : public parser<static_repeat_parser<Parser, Min, Max>> {
  static_assert(Min <= Max, "minimum must be smaller than maximum");

public:
  using container = detail::container<typename Parser::attribute>;
  using attribute = typename container::attribute;

  explicit static_repeat_parser(Parser p) : parser_{std::move(p)} {
  }

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, Iterator const& l, Attribute& a) const {
    return detail::parse_repeat(parser_, f, l, a, Min, Max);
  }

private:
  Parser parser_;
};

template <class Parser>
class dynamic_repeat_parser : public parser<dynamic_repeat_parser<Parser>> {
public:
  using container = detail::container<typename Parser::attribute>;
  using attribute = typename container::attribute;

  dynamic_repeat_parser(Parser p, const int& min, const int& max)
    : parser_{std::move(p)},
      min_{min},
      max_{max} {
    VAST_ASSERT(min <= max);
  }

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, Iterator const& l, Attribute& a) const {
    return detail::parse_repeat(parser_, f, l, a, min_, max_);
  }

private:
  Parser parser_;
  const int& min_;
  const int& max_;
};

template <int Min, int Max = Min, class Parser>
auto repeat(Parser const& p) {
  return static_repeat_parser<Parser, Min, Max>{p};
}

template <class Parser>
auto repeat(Parser const& p, int n) {
  return dynamic_repeat_parser<Parser>{p, n, n};
}

template <class Parser>
auto repeat(Parser const& p, int min, int max) {
  return dynamic_repeat_parser<Parser>{p, min, max};
}

namespace parsers {

template <int Min, int Max = Min, class Parser>
auto rep(Parser const& p) {
  return repeat<Min, Max>(p);
}

template <class Parser>
auto rep(Parser const& p, const int& n) {
  return repeat(p, n);
}

template <class Parser>
auto rep(Parser const& p, const int& min, const int& max) {
  return repeat(p, min, max);
}

} // namespace parsers
} // namespace vast

#endif
<commit_msg>Fix bug in repeat parser<commit_after>#ifndef VAST_CONCEPT_PARSEABLE_CORE_REPEAT_HPP
#define VAST_CONCEPT_PARSEABLE_CORE_REPEAT_HPP

#include <vector>

#include "vast/concept/parseable/core/parser.hpp"
#include "vast/concept/parseable/detail/container.hpp"

#include "vast/detail/assert.hpp"

namespace vast {
namespace detail {

template <class Parser, class Iterator, class Attribute>
bool parse_repeat(Parser& p, Iterator& f, Iterator const& l, Attribute& a,
                  int min, int max) {
  if (max == 0)
    return true; // If we have nothing todo, we're succeeding.
  auto save = f;
  auto i = 0;
  while (i < max) {
    if (!container<typename Parser::attribute>::parse(p, f, l, a))
      break;
    ++i;
  }
  if (i >= min)
    return true;
  f = save;
  return false;
}

} // namespace detail

template <class Parser, int Min, int Max = Min>
class static_repeat_parser
  : public parser<static_repeat_parser<Parser, Min, Max>> {
  static_assert(Min <= Max, "minimum must be smaller than maximum");

public:
  using container = detail::container<typename Parser::attribute>;
  using attribute = typename container::attribute;

  explicit static_repeat_parser(Parser p) : parser_{std::move(p)} {
  }

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, Iterator const& l, Attribute& a) const {
    return detail::parse_repeat(parser_, f, l, a, Min, Max);
  }

private:
  Parser parser_;
};

template <class Parser, class T>
class dynamic_repeat_parser : public parser<dynamic_repeat_parser<Parser, T>> {
  static_assert(std::is_integral<T>::value, "T must be an an integral type");

public:
  using container = detail::container<typename Parser::attribute>;
  using attribute = typename container::attribute;

  dynamic_repeat_parser(Parser p, const T& min, const T& max)
    : parser_{std::move(p)},
      min_{min},
      max_{max} {
    VAST_ASSERT(min <= max);
  }

  template <class Iterator, class Attribute>
  bool parse(Iterator& f, Iterator const& l, Attribute& a) const {
    return detail::parse_repeat(parser_, f, l, a, min_, max_);
  }

private:
  Parser parser_;
  const T& min_;
  const T& max_;
};

template <int Min, int Max = Min, class Parser>
auto repeat(Parser const& p) {
  return static_repeat_parser<Parser, Min, Max>{p};
}

template <class Parser, class T>
auto repeat(Parser const& p, const T& n) {
  return dynamic_repeat_parser<Parser, T>{p, n, n};
}

template <class Parser, class T>
auto repeat(Parser const& p, const T& min, const T& max) {
  return dynamic_repeat_parser<Parser, T>{p, min, max};
}

namespace parsers {

template <int Min, int Max = Min, class Parser>
auto rep(Parser const& p) {
  return repeat<Min, Max>(p);
}

template <class Parser, class T>
auto rep(Parser const& p, const T& n) {
  return repeat(p, n);
}

template <class Parser, class T>
auto rep(Parser const& p, const T& min, const T& max) {
  return repeat(p, min, max);
}

} // namespace parsers
} // namespace vast

#endif
<|endoftext|>


<commit_before>/********************************************************************************
    LibVideoGfx - video processing library
    Copyright (C) 2002  Dirk Farin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ********************************************************************************/

#include "libvideogfx/graphics/fileio/ppm.hh"
#include "libvideogfx/error.hh"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

namespace videogfx {
  using namespace std;

  // --- low-level PPM writers

  void WritePPM5(const Bitmap<Pixel>& pm, ostream& ostr)
  {
    const int w = pm.AskWidth();
    const int h = pm.AskHeight();

    ostr << "P5\n" << w << ' ' << h << "\n255\n";

    const Pixel*const* Y = pm.AskFrame();

    for (int y=0;y<h;y++)
      ostr.write((char*)Y[y],w);
  }

  void WritePPM6(const Bitmap<Pixel>& r, const Bitmap<Pixel>& g, const Bitmap<Pixel>& b, ostream& ostr)
  {
    const int w = r.AskWidth();
    const int h = r.AskHeight();

    Assert(w==g.AskWidth() && h==g.AskHeight());
    Assert(w==b.AskWidth() && h==b.AskHeight());

    ostr << "P6\n" << w << ' ' << h << "\n255\n";

    uint8* linebuf = new uint8[w*3];

    const Pixel*const* R = r.AskFrame();
    const Pixel*const* G = g.AskFrame();
    const Pixel*const* B = b.AskFrame();

    for (int y=0;y<h;y++)
      {
	uint8* p = linebuf;

	for (int x=0;x<w;x++)
	  {
	    *p++ = R[y][x];
	    *p++ = G[y][x];
	    *p++ = B[y][x];
	  }

	ostr.write((char*)linebuf,w*3);
      }

    delete[] linebuf;
  }

  // --- high-level PPM-writer class

  FileWriter_PPM::FileWriter_PPM()
    : d_yuv_as_grey(false),
      d_rgb_as_grey(false),
      d_grey_as_rgb(false)
  {
  }

  void FileWriter_PPM::Write(const Image<Pixel>& img,const char* filename)
  {
    ofstream ostr(filename);
    Write(img,ostr);
  }

  void FileWriter_PPM::Write(const Image<Pixel>& img,ostream& ostr)
  {
    ImageParam param = img.AskParam();

    if (param.colorspace == Colorspace_RGB)
      {
	if (d_rgb_as_grey)
	  WritePPM5(img.AskBitmapG(),ostr);
	else
	  WritePPM6(img.AskBitmapR(),img.AskBitmapG(),img.AskBitmapB(),ostr);
      }
    else if (param.colorspace == Colorspace_Greyscale)
      {
	if (d_grey_as_rgb)
	  WritePPM6(img.AskBitmapY(),img.AskBitmapY(),img.AskBitmapY(),ostr);
	else
	  WritePPM5(img.AskBitmapY(),ostr);
      }
    else if (param.colorspace == Colorspace_YUV)
      {
	if (d_yuv_as_grey)
	  WritePPM5(img.AskBitmapY(),ostr);
	else
	  {
	    AssertDescr(false,"cannot save YUV as PPM in RGB colorspace");
	  }
      }
    else
      {
	AssertDescr(false,"cannot save this colorspace as PPM file");
      }
  }

  // --- convenience function for PPM writing

  void WriteImage_PPM(const Image<Pixel>& img,ostream& stream)
  {
    FileWriter_PPM writer;
    writer.Write(img,stream);
  }

  void WriteImage_PPM(const Image<Pixel>& img,const char* filename)
  {
    FileWriter_PPM writer;
    writer.Write(img,filename);
  }

  // --- PPM reading functions

  static bool is_whiteline(const char* b)
  {
    for (int i=0; b[i]; i++)
      if (!isspace(b[i]))
	return false;

    return true;
  }

  void ReadImage_PPM(Image<Pixel>& dest,const char* filename)
  {
    ifstream istr(filename);
    ReadImage_PPM(dest,istr);
  }

  void ReadImage_PPM(Image<Pixel>& dest,istream& stream)
  {
    char buffer[100+1];
    stream.getline(buffer,100);

    if (strlen(buffer)!=2 || buffer[0]!='P')
      { throw Excpt_Text(ErrSev_Error,"input is not a PPM format file"); }

    bool greyscale;
    if (buffer[1]=='5')
      greyscale=true;
    else if (buffer[1]=='6')
      greyscale=false;
    else
      { throw Excpt_Text(ErrSev_Error,"input is not a type 5 or type 6 PPM format file"); }

    int width,height,maxval;

    do
      {
	stream.getline(buffer,100);
      } while(buffer[0] == '#' || is_whiteline(buffer));
    sscanf(buffer,"%d %d",&width,&height);
    do
      {
	stream.getline(buffer,100);
      } while(buffer[0] == '#' || is_whiteline(buffer));
    maxval=atoi(buffer);

    if (maxval != 255)
      { throw Excpt_Text(ErrSev_Error,"cannot read PPM file with maximum pixel-value != 255"); }

    ImageParam param = dest.AskParam();
    param.width  = width;
    param.height = height;

    if (greyscale)
      {
	param.colorspace = Colorspace_Greyscale;
	dest.Create(param);

	Pixel*const* Y = dest.AskFrameY();

	for (int y=0;y<height;y++)
	  stream.read((char*)Y[y],width);
      }
    else
      {
	param.colorspace = Colorspace_RGB;
	dest.Create(param);

	uint8* linebuf = new uint8[width * 3];

	Pixel*const* r = dest.AskFrameR();
	Pixel*const* g = dest.AskFrameG();
	Pixel*const* b = dest.AskFrameB();

	for (int y=0;y<height;y++)
	  {
	    stream.read((char*)linebuf,width*3);

	    uint8* p = linebuf;
	    uint8* rp = r[y];
	    uint8* gp = g[y];
	    uint8* bp = b[y];

	    for (int x=0;x<width;x++)
	      {
		*rp++ = *p++;
		*gp++ = *p++;
		*bp++ = *p++;
	      }
	  }

	delete[] linebuf;
      }
  }

}
<commit_msg>save YUV images as greyscale by default (instead of printing error)<commit_after>/********************************************************************************
    LibVideoGfx - video processing library
    Copyright (C) 2002  Dirk Farin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ********************************************************************************/

#include "libvideogfx/graphics/fileio/ppm.hh"
#include "libvideogfx/error.hh"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

namespace videogfx {
  using namespace std;

  // --- low-level PPM writers

  void WritePPM5(const Bitmap<Pixel>& pm, ostream& ostr)
  {
    const int w = pm.AskWidth();
    const int h = pm.AskHeight();

    ostr << "P5\n" << w << ' ' << h << "\n255\n";

    const Pixel*const* Y = pm.AskFrame();

    for (int y=0;y<h;y++)
      ostr.write((char*)Y[y],w);
  }

  void WritePPM6(const Bitmap<Pixel>& r, const Bitmap<Pixel>& g, const Bitmap<Pixel>& b, ostream& ostr)
  {
    const int w = r.AskWidth();
    const int h = r.AskHeight();

    Assert(w==g.AskWidth() && h==g.AskHeight());
    Assert(w==b.AskWidth() && h==b.AskHeight());

    ostr << "P6\n" << w << ' ' << h << "\n255\n";

    uint8* linebuf = new uint8[w*3];

    const Pixel*const* R = r.AskFrame();
    const Pixel*const* G = g.AskFrame();
    const Pixel*const* B = b.AskFrame();

    for (int y=0;y<h;y++)
      {
	uint8* p = linebuf;

	for (int x=0;x<w;x++)
	  {
	    *p++ = R[y][x];
	    *p++ = G[y][x];
	    *p++ = B[y][x];
	  }

	ostr.write((char*)linebuf,w*3);
      }

    delete[] linebuf;
  }

  // --- high-level PPM-writer class

  FileWriter_PPM::FileWriter_PPM()
    : d_yuv_as_grey(false),
      d_rgb_as_grey(false),
      d_grey_as_rgb(false)
  {
  }

  void FileWriter_PPM::Write(const Image<Pixel>& img,const char* filename)
  {
    ofstream ostr(filename);
    Write(img,ostr);
  }

  void FileWriter_PPM::Write(const Image<Pixel>& img,ostream& ostr)
  {
    ImageParam param = img.AskParam();

    if (param.colorspace == Colorspace_RGB)
      {
	if (d_rgb_as_grey)
	  WritePPM5(img.AskBitmapG(),ostr);
	else
	  WritePPM6(img.AskBitmapR(),img.AskBitmapG(),img.AskBitmapB(),ostr);
      }
    else if (param.colorspace == Colorspace_Greyscale)
      {
	if (d_grey_as_rgb)
	  WritePPM6(img.AskBitmapY(),img.AskBitmapY(),img.AskBitmapY(),ostr);
	else
	  WritePPM5(img.AskBitmapY(),ostr);
      }
    else if (param.colorspace == Colorspace_YUV)
      {
	if (d_yuv_as_grey)
	  WritePPM5(img.AskBitmapY(),ostr);
	else
	  {
	    AssertDescr(false,"cannot save YUV as PPM in RGB colorspace");
	  }
      }
    else
      {
	AssertDescr(false,"cannot save this colorspace as PPM file");
      }
  }

  // --- convenience function for PPM writing

  void WriteImage_PPM(const Image<Pixel>& img,ostream& stream)
  {
    FileWriter_PPM writer;
    writer.Write(img,stream);
  }

  void WriteImage_PPM(const Image<Pixel>& img,const char* filename)
  {
    FileWriter_PPM writer;
    writer.WriteYUVAsGreyscale(true);
    writer.Write(img,filename);
  }

  // --- PPM reading functions

  static bool is_whiteline(const char* b)
  {
    for (int i=0; b[i]; i++)
      if (!isspace(b[i]))
	return false;

    return true;
  }

  void ReadImage_PPM(Image<Pixel>& dest,const char* filename)
  {
    ifstream istr(filename);
    ReadImage_PPM(dest,istr);
  }

  void ReadImage_PPM(Image<Pixel>& dest,istream& stream)
  {
    char buffer[100+1];
    stream.getline(buffer,100);

    if (strlen(buffer)!=2 || buffer[0]!='P')
      { throw Excpt_Text(ErrSev_Error,"input is not a PPM format file"); }

    bool greyscale;
    if (buffer[1]=='5')
      greyscale=true;
    else if (buffer[1]=='6')
      greyscale=false;
    else
      { throw Excpt_Text(ErrSev_Error,"input is not a type 5 or type 6 PPM format file"); }

    int width,height,maxval;

    do
      {
	stream.getline(buffer,100);
      } while(buffer[0] == '#' || is_whiteline(buffer));
    sscanf(buffer,"%d %d",&width,&height);
    do
      {
	stream.getline(buffer,100);
      } while(buffer[0] == '#' || is_whiteline(buffer));
    maxval=atoi(buffer);

    if (maxval != 255)
      { throw Excpt_Text(ErrSev_Error,"cannot read PPM file with maximum pixel-value != 255"); }

    ImageParam param = dest.AskParam();
    param.width  = width;
    param.height = height;

    if (greyscale)
      {
	param.colorspace = Colorspace_Greyscale;
	dest.Create(param);

	Pixel*const* Y = dest.AskFrameY();

	for (int y=0;y<height;y++)
	  stream.read((char*)Y[y],width);
      }
    else
      {
	param.colorspace = Colorspace_RGB;
	dest.Create(param);

	uint8* linebuf = new uint8[width * 3];

	Pixel*const* r = dest.AskFrameR();
	Pixel*const* g = dest.AskFrameG();
	Pixel*const* b = dest.AskFrameB();

	for (int y=0;y<height;y++)
	  {
	    stream.read((char*)linebuf,width*3);

	    uint8* p = linebuf;
	    uint8* rp = r[y];
	    uint8* gp = g[y];
	    uint8* bp = b[y];

	    for (int x=0;x<width;x++)
	      {
		*rp++ = *p++;
		*gp++ = *p++;
		*bp++ = *p++;
	      }
	  }

	delete[] linebuf;
      }
  }

}
<|endoftext|>


<commit_before>#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_mixer.h>
#include "ScreenSystem/ScreenManager.h"
#include "Screens/ScreenBackgroundImage.h"
#include "Screens/ScreenMenu.h"
#include "Screens/ScreenTest.h"
#include "global.h"

bool SDLInited = false;
SDL_Window *win = NULL;
SDL_Renderer *ren = NULL;

ScreenManager screenManager;

int _resetFrameSkip = 0;

bool debugViewBounds = false;

bool initializeSDL()
{
	if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
	{
		std::cout << "SDL_Init error: " << SDL_GetError() << std::endl;
		return false;
	}
	SDLInited = true;

	win = SDL_CreateWindow("ExLauncher", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320, 240, SDL_WINDOW_SHOWN);
	if (win == NULL)
	{
		std::cout << SDL_GetError() << std::endl;
		return false;
	}

	ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
	if (ren == NULL)
	{
		std::cout << SDL_GetError() << std::endl;
		return false;
	}

	SDL_RendererInfo renInfo;
	if (SDL_GetRendererInfo(ren, &renInfo) < 0)
	{
		std::cout << "Unable to query renderer" << std::endl;
		return false;
	}

	/*if ((renInfo.flags & SDL_RENDERER_TARGETTEXTURE) == 0)
	{
		std::cout << "Renderer does not support render targets" << std::endl;
		return false;
	}*/

	if (TTF_Init() != 0)
	{
		std::cout << TTF_GetError() << std::endl;
		return false;
	}

	int mixFlags = MIX_INIT_OGG;
	if ((Mix_Init(mixFlags) & mixFlags) != mixFlags)
	{
		std::cout << Mix_GetError() << std::endl;
		return false;
	}

	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) == -1)
	{
		std::cout << Mix_GetError() << std::endl;
		return false;
	}

	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");

	return true;
}

void terminateSDL()
{
	int audioTimesOpened, frequency, channels;
	Uint16 format;
	audioTimesOpened = Mix_QuerySpec(&frequency, &format, &channels);

	while (audioTimesOpened > 0)
	{
		Mix_CloseAudio();
		audioTimesOpened--;
	}

	while (Mix_Init(0))
		Mix_Quit();

	if (TTF_WasInit())
	{
		TTF_Quit();
	}

	if (ren != NULL)
	{
		SDL_DestroyRenderer(ren);
		ren = NULL;
	}

	if (win != NULL)
	{
		SDL_DestroyWindow(win);
		win = NULL;
	}

	//if (SDL_WasInit(0) > 0) // FIXME TEST
	if (SDLInited)
	{
		SDL_Quit();
		SDLInited = false;
	}
}

void setKeyBindings()
{
	int gameKeys[GAMEKEY_MAX];
	gameKeys[GAMEKEY_UP] = SDL_SCANCODE_UP;
	gameKeys[GAMEKEY_LEFT] = SDL_SCANCODE_LEFT;
	gameKeys[GAMEKEY_RIGHT] = SDL_SCANCODE_RIGHT;
	gameKeys[GAMEKEY_DOWN] = SDL_SCANCODE_DOWN;
	gameKeys[GAMEKEY_A] = SDL_SCANCODE_Z;
	gameKeys[GAMEKEY_B] = SDL_SCANCODE_X;
	gameKeys[GAMEKEY_X] = SDL_SCANCODE_C;
	gameKeys[GAMEKEY_Y] = SDL_SCANCODE_V;
	gameKeys[GAMEKEY_START] = SDL_SCANCODE_RETURN;
	gameKeys[GAMEKEY_SELECT] = SDL_SCANCODE_BACKSPACE;
	gameKeys[GAMEKEY_TRIGGER_L] = SDL_SCANCODE_Q;
	gameKeys[GAMEKEY_TRIGGER_R] = SDL_SCANCODE_W;

	screenManager.SetGameKeyBindings(gameKeys, GAMEKEY_MAX);
}

int main(int argc, char **argv)
{
	std::cout << "main()" << std::endl;
	std::cout << "Initializing SDL... " << std::endl;
	if (!initializeSDL())
	{
		terminateSDL();
		return 1;
	}
	std::cout << "SDL is init!!" << std::endl;

	std::cout << "Initializing ScreenManager... ";
	if (!screenManager.Init())
	{
		std::cout << "FAILED" << std::endl;
		terminateSDL();
		return 1;
	}
	std::cout << "OK" << std::endl;

	screenManager.SetRenderer(ren);
	std::cout << "Loading resources... ";
	if (!screenManager.LoadGlobalResources())
	{
		std::cout << "FAILED" << std::endl;
		std::cout << screenManager.GetLastError() << std::endl;
		terminateSDL();
		return 1;
	}
	std::cout << "OK" << std::endl;

	setKeyBindings();

	std::cout << "APP IS START" << std::endl;

	// TEMP TEMP TEMP!
	screenManager.GetResourceManager()->LoadImage("SnowCloseUp", "data/wallpapers/SnowCloseUp.jpg");
	screenManager.GetResourceManager()->LoadImage("GothenburgNight", "data/wallpapers/GothenburgNight.jpg");
	screenManager.GetResourceManager()->LoadImage("Bug", "data/wallpapers/Bug.jpg");
	screenManager.GetResourceManager()->LoadImage("Circuit", "data/wallpapers/Circuit.jpg");
	screenManager.GetResourceManager()->LoadImage("Leaves", "data/wallpapers/Leaves.jpg");

	screenManager.GetResourceManager()->LoadImage("IconApplications", "data/graphics/icon_applications.png");
	screenManager.GetResourceManager()->LoadImage("IconEmulators", "data/graphics/icon_emulators.png");
	screenManager.GetResourceManager()->LoadImage("IconGames", "data/graphics/icon_games.png");
	screenManager.GetResourceManager()->LoadImage("IconSettings", "data/graphics/icon_settings.png");

	ScreenBackgroundImage* bgScreen = new ScreenBackgroundImage();
	screenManager.AddScreen(bgScreen);
	screenManager.AddScreen(new ScreenMenu("@theme/testaction.xml"));
	//screenManager.AddScreen(new ScreenTest());

	bgScreen->AddImage("Circuit");
	bgScreen->AddImage("Bug");
	bgScreen->AddImage("SnowCloseUp");
	bgScreen->AddImage("GothenburgNight");
	bgScreen->AddImage("Leaves");

	int currentTime = SDL_GetTicks();
	double accumulator = 0;
	double frameTime = 1000.0/(double)FPS;
	int newTime;
	int deltaTime;
	int shouldDraw = 0;

	while(!screenManager.HasExit())
	{
		newTime = SDL_GetTicks();
		deltaTime = newTime - currentTime;
		currentTime = newTime;
		accumulator += deltaTime;

#if defined(NO_FPS_LIMIT)
		accumulator = frameTime;
#endif
		if(_resetFrameSkip)
		{
			accumulator = frameTime;
			_resetFrameSkip = 0;
		}

		while (accumulator >= frameTime)
		{
			accumulator -= frameTime;

			screenManager.Update();
			shouldDraw = 1;
		}

		if (shouldDraw)
		{
			screenManager.Draw();
			shouldDraw = 0;
		}
		else
		{
			SDL_Delay(1);
		}
	}

	terminateSDL();
	return 0;
}
<commit_msg>Fix keybindings for GCW Zero<commit_after>#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_mixer.h>
#include "ScreenSystem/ScreenManager.h"
#include "Screens/ScreenBackgroundImage.h"
#include "Screens/ScreenMenu.h"
#include "Screens/ScreenTest.h"
#include "global.h"

bool SDLInited = false;
SDL_Window *win = NULL;
SDL_Renderer *ren = NULL;

ScreenManager screenManager;

int _resetFrameSkip = 0;

bool debugViewBounds = false;

bool initializeSDL()
{
	if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
	{
		std::cout << "SDL_Init error: " << SDL_GetError() << std::endl;
		return false;
	}
	SDLInited = true;

	win = SDL_CreateWindow("ExLauncher", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320, 240, SDL_WINDOW_SHOWN);
	if (win == NULL)
	{
		std::cout << SDL_GetError() << std::endl;
		return false;
	}

	ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
	if (ren == NULL)
	{
		std::cout << SDL_GetError() << std::endl;
		return false;
	}

	SDL_RendererInfo renInfo;
	if (SDL_GetRendererInfo(ren, &renInfo) < 0)
	{
		std::cout << "Unable to query renderer" << std::endl;
		return false;
	}

	/*if ((renInfo.flags & SDL_RENDERER_TARGETTEXTURE) == 0)
	{
		std::cout << "Renderer does not support render targets" << std::endl;
		return false;
	}*/

	if (TTF_Init() != 0)
	{
		std::cout << TTF_GetError() << std::endl;
		return false;
	}

	int mixFlags = MIX_INIT_OGG;
	if ((Mix_Init(mixFlags) & mixFlags) != mixFlags)
	{
		std::cout << Mix_GetError() << std::endl;
		return false;
	}

	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) == -1)
	{
		std::cout << Mix_GetError() << std::endl;
		return false;
	}

	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");

	return true;
}

void terminateSDL()
{
	int audioTimesOpened, frequency, channels;
	Uint16 format;
	audioTimesOpened = Mix_QuerySpec(&frequency, &format, &channels);

	while (audioTimesOpened > 0)
	{
		Mix_CloseAudio();
		audioTimesOpened--;
	}

	while (Mix_Init(0))
		Mix_Quit();

	if (TTF_WasInit())
	{
		TTF_Quit();
	}

	if (ren != NULL)
	{
		SDL_DestroyRenderer(ren);
		ren = NULL;
	}

	if (win != NULL)
	{
		SDL_DestroyWindow(win);
		win = NULL;
	}

	//if (SDL_WasInit(0) > 0) // FIXME TEST
	if (SDLInited)
	{
		SDL_Quit();
		SDLInited = false;
	}
}

void setKeyBindings()
{
	int gameKeys[GAMEKEY_MAX];
	gameKeys[GAMEKEY_UP] = SDL_SCANCODE_UP;
	gameKeys[GAMEKEY_LEFT] = SDL_SCANCODE_LEFT;
	gameKeys[GAMEKEY_RIGHT] = SDL_SCANCODE_RIGHT;
	gameKeys[GAMEKEY_DOWN] = SDL_SCANCODE_DOWN;
	gameKeys[GAMEKEY_A] = SDL_SCANCODE_LCTRL;
	gameKeys[GAMEKEY_B] = SDL_SCANCODE_LALT;
	gameKeys[GAMEKEY_X] = SDL_SCANCODE_SPACE;
	gameKeys[GAMEKEY_Y] = SDL_SCANCODE_LSHIFT;
	gameKeys[GAMEKEY_START] = SDL_SCANCODE_RETURN;
	gameKeys[GAMEKEY_SELECT] = SDL_SCANCODE_ESCAPE;
	gameKeys[GAMEKEY_TRIGGER_L] = SDL_SCANCODE_TAB;
	gameKeys[GAMEKEY_TRIGGER_R] = SDL_SCANCODE_BACKSPACE;

	screenManager.SetGameKeyBindings(gameKeys, GAMEKEY_MAX);
}

int main(int argc, char **argv)
{
	std::cout << "main()" << std::endl;
	std::cout << "Initializing SDL... " << std::endl;
	if (!initializeSDL())
	{
		terminateSDL();
		return 1;
	}
	std::cout << "SDL is init!!" << std::endl;

	std::cout << "Initializing ScreenManager... ";
	if (!screenManager.Init())
	{
		std::cout << "FAILED" << std::endl;
		terminateSDL();
		return 1;
	}
	std::cout << "OK" << std::endl;

	screenManager.SetRenderer(ren);
	std::cout << "Loading resources... ";
	if (!screenManager.LoadGlobalResources())
	{
		std::cout << "FAILED" << std::endl;
		std::cout << screenManager.GetLastError() << std::endl;
		terminateSDL();
		return 1;
	}
	std::cout << "OK" << std::endl;

	setKeyBindings();

	std::cout << "APP IS START" << std::endl;

	// TEMP TEMP TEMP!
	screenManager.GetResourceManager()->LoadImage("SnowCloseUp", "data/wallpapers/SnowCloseUp.jpg");
	screenManager.GetResourceManager()->LoadImage("GothenburgNight", "data/wallpapers/GothenburgNight.jpg");
	screenManager.GetResourceManager()->LoadImage("Bug", "data/wallpapers/Bug.jpg");
	screenManager.GetResourceManager()->LoadImage("Circuit", "data/wallpapers/Circuit.jpg");
	screenManager.GetResourceManager()->LoadImage("Leaves", "data/wallpapers/Leaves.jpg");

	screenManager.GetResourceManager()->LoadImage("IconApplications", "data/graphics/icon_applications.png");
	screenManager.GetResourceManager()->LoadImage("IconEmulators", "data/graphics/icon_emulators.png");
	screenManager.GetResourceManager()->LoadImage("IconGames", "data/graphics/icon_games.png");
	screenManager.GetResourceManager()->LoadImage("IconSettings", "data/graphics/icon_settings.png");

	ScreenBackgroundImage* bgScreen = new ScreenBackgroundImage();
	screenManager.AddScreen(bgScreen);
	screenManager.AddScreen(new ScreenMenu("@theme/testaction.xml"));
	//screenManager.AddScreen(new ScreenTest());

	bgScreen->AddImage("Circuit");
	bgScreen->AddImage("Bug");
	bgScreen->AddImage("SnowCloseUp");
	bgScreen->AddImage("GothenburgNight");
	bgScreen->AddImage("Leaves");

	int currentTime = SDL_GetTicks();
	double accumulator = 0;
	double frameTime = 1000.0/(double)FPS;
	int newTime;
	int deltaTime;
	int shouldDraw = 0;

	while(!screenManager.HasExit())
	{
		newTime = SDL_GetTicks();
		deltaTime = newTime - currentTime;
		currentTime = newTime;
		accumulator += deltaTime;

#if defined(NO_FPS_LIMIT)
		accumulator = frameTime;
#endif
		if(_resetFrameSkip)
		{
			accumulator = frameTime;
			_resetFrameSkip = 0;
		}

		while (accumulator >= frameTime)
		{
			accumulator -= frameTime;

			screenManager.Update();
			shouldDraw = 1;
		}

		if (shouldDraw)
		{
			screenManager.Draw();
			shouldDraw = 0;
		}
		else
		{
			SDL_Delay(1);
		}
	}

	terminateSDL();
	return 0;
}
<|endoftext|>