Войти
Life Engine

Мой эмулятор NES:: что-то уже получается : )

Итак, прошло 18 дней с момента, когда я решил написать свой первый эмулятор :3

Так как он первый у меня - решил начать с наиболее простого, но интересного устройства ) И выбрал DENDY (NES).

Сначала это был ацкий дремучий лес! Что как работает - непонятно! С чего начать - непонятно! Вообще ничего непонятно >_<  ААА!

Но, как говорится, глаза боятся, а руки делают ) Сел и просто начал писать. Что непонятно - не пишу. Потихоньку читаю доки, начинаю вкуривать всяческие аспекты работы железа и дописывать их : )

Через 6 дней разработки у меня игра SuperMarioBrothers перешла в играбельное состояние! Т.е. было корректное изображение, управление. О звуке тогда было страшно подумать :D


Дальше приходило всё больше понимания и ранее непонятные вещи становились очевидными )  Так потихоньку я дошёл до сегодняшнего дня - у меня в эмуляторе появился звук ^_________________^

Звук жестоко выпилил мозг..  не совсем было понятно значение слов Envelope, decay, sweep,  и т.п. в контексте  APU.  Что они делают? АА!  В доках всё сложно описано : \  Но таки "врагу не сдаётся наш гордый Варяг"(с), поэтому заготовив 2 литра пепси и 2 кружки годного залёного чая решил раскурить основалтельно, что и получилось )

На данный момент эмулируются все 5 каналов APU (2 из них Square):  Square, Noise, Triangle, DMC.  Есть в них некоторые баги, однако это же только начало : )

Для вывода звука использую OpenAL и 3 буфера внутри по 735 семплов каждый.


К сожалению у меня не 10 рук и я не успел ещё прикрутить различные мапперы (микросхемы на картриджах, переключающие банки памяти), поэтому "крутые" игры просто не запустятся!  Зато игры с 0 маппером поидее должны работать (большинство).

Скачать:  http://l-proger.narod.ru/LifeNes_0_3f.rar

Скрины (дада, маленькие )

Ссылка | Комментарии [65]
3 окт 2011

Hardcore wanted::Начал писать эмулятор Famicom (DENDY)

Софтрендеры, рейтрейсеры и прочее раньше казались весьма хардкорными!  Казались.. до того, пока в них не разобрался и не написал.  После написания  они стали казаться весьма и весьма простыми : \ 

Подумал я, что надо написать что-то чуть более хардкорное : )  Да не просто потратить на это время, а выучить что-то новое. В этот момент пришла в голову безуслоооовно гениальная идея - написать эмулятор NES (DENDY).    Я не застал ZxSpectrum и подобные "компьютеры" - поэтому NES для меня была самой первой и самой "слабой" игровой приставкой.  Вот и решил, что надо начинать с простого, с денди )

С простого.. ага, щас.  Железо.. процессор.. какието прерывания.. страницы памяти.. memory mapping, memory mirroring, какието опкоды, циклы, PPU, APU  и прочая куча всяких мтерных слов.  ЧТОЭТО!?  ААА!! - такое было первое впечатление.  Начал писать я позавчера ^^

Но не всё так плохо ) То, что я чего-то не знаю - вообще ничего не решает, ведь под рукой есть инет и теперь книги Владислава Пирогова :D  Узнать можно что угодно в считанные секунды/минуты. С пониманием информации вроде всё ок.  Так, понемногу раскуриваю ассемблер, принципы работы железа и саму игровую приставку : ) Раскуривание пошло весьма удачно, надо отметить )

Сегодня в голове собрался весь паззл (асм, железо, устройство денди) и, придя под вечер домой начал писать )

Сейчас есть загрузка ROM-а игры. Есть базовая структура классов. Накидал работу с памятью (scratch ram, save ram, prg_rom, chr_rom) , работу со стеком (кстати он зачемто развёрнут в денди! Ну тоесть push в стек  сопровождается _декрементом указателя на память стека, а pop инкрементом >_<), написал пустые функции обработки опкодов, заполнил массив lookup-а функций обработки опкодов (самое мозговыносящее блин), написал обработку некоторых опкодов и прерываний!


функция апдейта процессора выглядит сейчас так:

void CPU::Update()
{
  //store previous opcode
  opcode_previous = opcode_current;
  //read next opcode
  opcode_current = pNes->ReadMemory8(reg_pc);
  //execute opcode
  (this->*opcodes[opcode_current])();

  //count cycles
  cycle_total += cycle_local;

  if(cycle_local >= pNes->cyclesPerScanline)
  {
    //render scan line HERE
    //push PC register to stack
    //push state register to stack

    //process NMI interrupt
    reg_pc = pNes->ReadMemory16(0xFFFA);

    cycle_local -= pNes->cyclesPerScanline;
  }
}


Я обязательно допилю этот эмулятор : )  Не знаю насколько он будет совместим с большинством игр, но в марио на нём точно можно будет играть ))

Ладно, сейчас надо идти спать, а завтра если будет время - описать работу почти 150 опкодов  : ((((

Ссылка | Комментарии [249]
17 сен 2011

DirectX10_1 Sample 1

Всем привет.

Понадобился DX10 но годных туториалов по нему в инете не нашёл (для SlimDX).

Методом научного тыка таки разобрался сам с DX10, собсно выкладываю сюда исходники в помощь начинающим прогерам. В дальнейшем буду выкладывать новый усложнённый код по мере моего самообучения : )

В данном примере:
1. Создаётся фабрика и девайс
2. создаётся SwapChain и бэкбуфер
3. Очищается бэкбуфер и выводится на экран
+ ещё мелочи

Для работы примера нужен установленный SlimDX 2010 (June)

using System;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D10;
using SlimDX.DXGI;

namespace DX10_Test
{
    public partial class Form1 : Form
    {
        private SlimDX.Direct3D10_1.Device1 g_device;
        private Factory g_factory;
        private SwapChain g_primarySC;
        private SwapChainDescription g_scDesc;
        private RenderTargetView g_backBuffer;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //creating DXGI factory
            g_factory = new Factory();

            //i dunno what's that, LOL
            g_factory.SetWindowAssociation(this.Handle, WindowAssociationFlags.None);

            //creating device
            g_device = new SlimDX.Direct3D10_1.Device1(g_factory.GetAdapter(0), DriverType.Hardware, DeviceCreationFlags.None, SlimDX.Direct3D10_1.FeatureLevel.Level_9_3);

            //filling mode description
            ModeDescription mode = new ModeDescription();
            mode.Format = Format.R8G8B8A8_UNorm;
            mode.Height = this.Height;
            mode.Width = this.Width;
            mode.ScanlineOrdering = DisplayModeScanlineOrdering.Unspecified;
            mode.Scaling = DisplayModeScaling.Unspecified;
            mode.RefreshRate = new Rational(60, 1);

            //filling sample descriptrion
            SampleDescription sample = new SampleDescription();
            sample.Count = 1;
            sample.Quality = 0;

            //filling swap chain description
            g_scDesc = new SwapChainDescription();
            g_scDesc.BufferCount = 1;
            g_scDesc.Flags = SwapChainFlags.None;
            g_scDesc.IsWindowed = true;
            g_scDesc.ModeDescription = mode;
            g_scDesc.OutputHandle = this.Handle;
            g_scDesc.SampleDescription = sample;
            g_scDesc.SwapEffect = SwapEffect.Discard;
            g_scDesc.Usage = Usage.RenderTargetOutput;

            //creating swap chain
            g_primarySC = new SwapChain(g_factory, g_device, g_scDesc);

            //creating render target holder (view)
            g_backBuffer = new RenderTargetView(g_device, SlimDX.Direct3D10.Resource.FromSwapChain<Texture2D>(g_primarySC, 0));

            //we should manually set up viewports
            g_device.Rasterizer.SetViewports(new Viewport(0, 0, this.Width, this.Height, 0, 1));

            this.Show();

            //main loop ^____^
            while (this.Created)
            {
                //clear render target
                g_device.ClearRenderTargetView(g_backBuffer, new Color4(0xffff00));

                //presenting out back buffer to the monitor
                g_primarySC.Present(0, PresentFlags.None);

                Application.DoEvents();
            }

            //disposing resources
            {
                g_backBuffer.Resource.Dispose(); // This is important thing!
                g_device.ClearState();
                g_backBuffer.Dispose();
                g_device.Dispose();
                g_primarySC.Dispose();
                g_factory.Dispose();
            }
        }
    }
}

Ну и собсно EXE (скомпилированный пример):  Скачать (10kb)

Ссылка | Комментарии [4]
11 окт 2010

Update 2

Во, сделал наконецто асинхронную подгрузку ресурсов - подгружаются в отдельном потоке в то время, как ига уже началась ^^  Значительно ускорился перезод от скрина загрузки к игре. Ура.

Ссылка
27 июня 2010

Update 1

Както заффтыкал обновлять и тут блог...хмм. )

Собсно добавил PSSM тени. Работает всё чётко. Оптимизировал максимально. Рендерятся тени в одну одноканальную текстуру формата R32F чтобы техника была более кеш-френдли. Фильтрация для PSSM юзается ТОЛЬКО PCF так как VSM был поспешно уддалён после его подключения к PSSM.  На моей видяхе летает PSSM со следующими параметрами: количество сплитов - 3, размер общей текстуры глубины 4096x4096  - это 2 сплита по 2048x2048 и один 4096x2048 для ближнего сплита. ФПС жжот НО(!) если делать VSM и блурить текстуру минимум в 1 проход,то, собсно, необходима вторая текстура в котору и будет записываться результат блура. Для VSM нужно 2 канала.  Собсно 2-х канальная текстура формата G32R32F размера 4096x4096 будет весить 128 МБ и нужна ещё одна копия на 128 МБ для блура. В итоге для качественных теней надо 256(!!!!!!!!) МБ видео. Ненене, нафиг!  Заюзал PCF 4x4 и доволен. Тень мягкая, скорость высокая, памяти хаваецо мало ^^

Какбы скрин.  Чел и небо сильно зачвечены - не подкрутил HDR но я  ТЕНИ показываю, так что не плеваться : ))

Изображение


Сейчас займусь фоновой подгрузкой ресурсов ^^

Ссылка
26 июня 2010

Первый шаг: концепт-документ

Концепт-документ к первой игре, которую буду делать на своём движке:

"Дверь" Концепт-документ

Писал: Wolshebnik
Надзор: Я

Ссылка | Комментарии [11]
15 мая 2010

Архив 

Следующие записи