Skip to content

Instantly share code, notes, and snippets.

@hakelimopu
Last active January 11, 2017 11:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakelimopu/ac636231098104cb5a6b5d9e132d7e50 to your computer and use it in GitHub Desktop.
Save hakelimopu/ac636231098104cb5a6b5d9e132d7e50 to your computer and use it in GitHub Desktop.
Gotta get an asset loader and color cache going, but these are the bones of an SDL Runner.
using System;
using SDL2;
using PixelVisionSDK.Engine;
using PixelVisionSDK.Engine.Chips.Graphics.Sprites;
using PixelVisionSDK.Engine.Chips.Graphics.Colors;
using PixelVisionSDK.Engine.Chips.Graphics.Display;
using PixelVisionSDK.Engine.Chips.IO.Controller;
using PixelVisionSDK.Engine.Chips.Game;
using PixelVisionSDK.Engine.Utils;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace SDLRunner
{
class Program
{
[STAThread]
static void Main(string[] args)
{
SDL.SDL_Init(SDL.SDL_INIT_VIDEO);
SDL_image.IMG_Init(SDL_image.IMG_InitFlags.IMG_INIT_PNG);
IntPtr window = IntPtr.Zero;
IntPtr renderer = IntPtr.Zero;
SDL.SDL_CreateWindowAndRenderer(1280, 720, 0, out window, out renderer);
//TODO: put [ChipDependency] attribute on DrawSpriteDemo, and augment engine.LoadGame to automagically pull them in.
string[] chips =
{
typeof(ColorChip).FullName,
typeof(SpriteChip).FullName,
typeof(ScreenBufferChip).FullName,
typeof(TileMapChip).FullName,
typeof(FontChip).FullName,
typeof(ControllerChip).FullName,
typeof(DisplayChip).FullName
};
IEngine engine = new PixelVisionEngine(chips);
#region Load Colors From colors.png
IntPtr surface = SDL_image.IMG_Load("colors.png");
SDL.SDL_Surface surfaceStruct = (SDL.SDL_Surface)Marshal.PtrToStructure(surface, typeof(SDL.SDL_Surface));
const int bitsPerPixel = 32;
const int bytesPerPixel = 32 / 8;
const int redOffset = 0;
const int greenOffset = 1;
const int blueOffset = 2;
var pixels = new byte[surfaceStruct.w * surfaceStruct.h * bytesPerPixel];
var handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
var tempSurface = SDL.SDL_CreateRGBSurfaceFrom(handle.AddrOfPinnedObject(), surfaceStruct.w, surfaceStruct.h, bitsPerPixel, surfaceStruct.w * bytesPerPixel, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
SDL.SDL_BlitSurface(surface, IntPtr.Zero, tempSurface, IntPtr.Zero);
SDL.SDL_FreeSurface(tempSurface);
tempSurface = IntPtr.Zero;
handle.Free();
SDL.SDL_FreeSurface(surface);
surface = IntPtr.Zero;
engine.colorChip.Clear();
engine.colorChip.RebuildColorPages(pixels.Length / bytesPerPixel);
Dictionary<string, int> lookUp = new Dictionary<string, int>();
Dictionary<int, byte> lookUpRed = new Dictionary<int, byte>();
Dictionary<int, byte> lookUpGreen = new Dictionary<int, byte>();
Dictionary<int, byte> lookUpBlue = new Dictionary<int, byte>();
for (int index=0;index<pixels.Length;index+=bytesPerPixel)
{
byte redValue = pixels[index + redOffset];
byte greenValue = pixels[index + greenOffset];
byte blueValue = pixels[index + blueOffset];
int colorIndex = index / bytesPerPixel;
string colorValue = string.Format("#{0:X2}{1:X2}{2:X2}", redValue, greenValue, blueValue);
lookUp[colorValue] = colorIndex;
lookUpRed[colorIndex] = redValue;
lookUpGreen[colorIndex] = greenValue;
lookUpBlue[colorIndex] = blueValue;
engine.colorChip.UpdateColorAt(colorIndex, colorValue);
}
#endregion
#region Import Sprites from sprites.png
var spriteChip = engine.spriteChip;
surface = SDL_image.IMG_Load("sprites.png");
surfaceStruct = (SDL.SDL_Surface)Marshal.PtrToStructure(surface, typeof(SDL.SDL_Surface));
pixels = new byte[surfaceStruct.w * surfaceStruct.h * bytesPerPixel];
handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
tempSurface = SDL.SDL_CreateRGBSurfaceFrom(handle.AddrOfPinnedObject(), surfaceStruct.w, surfaceStruct.h, bitsPerPixel, surfaceStruct.w * bytesPerPixel, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
SDL.SDL_BlitSurface(surface, IntPtr.Zero, tempSurface, IntPtr.Zero);
SDL.SDL_FreeSurface(tempSurface);
tempSurface = IntPtr.Zero;
SDL.SDL_FreeSurface(surface);
surface = IntPtr.Zero;
handle.Free();
var spritesPerRow = surfaceStruct.w / spriteChip.width;
var totalSprites = SpriteChipUtil.CalculateTotalSprites(surfaceStruct.w, surfaceStruct.h, spriteChip.width, spriteChip.height);
var maxSprites = SpriteChipUtil.CalculateTotalSprites(spriteChip.textureWidth, spriteChip.textureHeight,
spriteChip.width, spriteChip.height);
for(int index=0;index<totalSprites && index<maxSprites;++index)
{
int spriteRow = (surfaceStruct.h / spriteChip.height) - 1 - index / spritesPerRow;
int spriteColumn = index % spritesPerRow;
var spriteData = new int[spriteChip.width * spriteChip.height];
for(int spriteX = 0;spriteX<spriteChip.width;++spriteX)
{
for(int spriteY=0;spriteY<spriteChip.height;++spriteY)
{
int pixelIndex = ((spriteY + spriteRow * spriteChip.height) * surfaceStruct.w + (spriteX + spriteColumn * spriteChip.width)) * bytesPerPixel;
byte red = pixels[pixelIndex + redOffset];
byte green = pixels[pixelIndex + greenOffset];
byte blue = pixels[pixelIndex + blueOffset];
string hex = string.Format("#{0:X2}{1:X2}{2:X2}", red, green, blue);
int paletteIndex = lookUp[hex];
spriteData[spriteX + spriteY * spriteChip.width] = paletteIndex;
}
}
spriteChip.UpdateSpriteAt(index, spriteData);
}
#endregion
GameChip gameChip = new DrawSpriteDemo();
SDL.SDL_RenderSetLogicalSize(renderer, 256, 240);
engine.LoadGame(gameChip);
engine.RunGame();
SDL.SDL_Event evt;
bool done = false;
DateTimeOffset clock = DateTimeOffset.Now;
while(!done)
{
while (SDL.SDL_PollEvent(out evt) > 0)
{
if (evt.type == SDL.SDL_EventType.SDL_QUIT)
{
done = true;
break;
}
}
DateTimeOffset oldClock = clock;
clock = DateTimeOffset.Now;
var elapsed = clock - oldClock;
engine.Update((float)elapsed.TotalSeconds);
engine.Draw();
//more or less taken wholecloth from MonoGameRunner's Draw function.
var pixelData = engine.displayChip.displayPixelData;
var total = pixelData.Length;
SDL.SDL_Rect rect = new SDL.SDL_Rect() { x = 0, y = 0, w = 1, h = 1 };
// Now it's time to loop through all of the DisplayChip's pixel data.
for (var i = 0; i < total; i++)
{
int x, y;
PosUtil.CalculatePosition(i, 256, out x, out y);
int j;
PosUtil.CalculateIndex(x, 240 - y - 1, 256, out j);
// Here we get a reference to the color we are trying to look up from the pixelData array. Then we compare that ID to what we
// have in the cachedPixels. If the color is out of range, we use the cachedTransparentColor. If the color exists in the cache we use that.
var colorRef = pixelData[i];
//TODO: get the actual color, and set it for the renderer
//cachedPixels[j] = colorRef < 0 || colorRef >= totalCachedColors ? cacheTransparentColor : cachedColors[colorRef];
if (colorRef < 0)
{
SDL.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
}
else
{
SDL.SDL_SetRenderDrawColor(renderer, lookUpRed[colorRef], lookUpGreen[colorRef], lookUpBlue[colorRef], 255);
}
rect.x = x;
rect.y = y;
SDL.SDL_RenderFillRect(renderer, ref rect);
// As you can see, we are using a protected field called cachedPixels. When we call ResetResolution, we resize this array to make sure that
// it matches the length of the DisplayChip's pixel data. By keeping a reference to this Array and updating each color instead of rebuilding
// it, we can significantly increase the render performance of the Runner.
}
SDL.SDL_RenderPresent(renderer);
}
SDL.SDL_DestroyRenderer(renderer);
SDL.SDL_DestroyWindow(window);
SDL_image.IMG_Quit();
SDL.SDL_Quit();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment