// BlockyFroggy
// Copyright © 2017 John Ryland.
// All rights reserved.
#import "GameViewController.h"
#import <OpenGLES/ES2/glext.h>
#include "Log.h"
#include "Debug.h"
#include "GameScreen.h"
#include "GameAudio.h"
#include "SystemInformation.h"
#include "TargetConditionals.h"
#include <fstream>
void loadPlatformFile(const char* filename, std::vector<uint8_t>& data)
{
data.clear();
NSString *fname = [NSString stringWithUTF8String:filename];
NSString* fileName = [fname stringByDeletingPathExtension];
NSString* extension = [fname pathExtension];
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
#if 1
NSData *nsData = [NSData dataWithContentsOfFile:filePath];
if (nsData) {
const uint8_t* d = (const uint8_t*)[nsData bytes];
data.assign(d, d + [nsData length]);
#else
//NSData *nsData = [NSData dataWithContentsOfFile:filePath];
//int len = [nsData length];
const char* fileStr = [filePath UTF8String];
std::ifstream file(fileStr, std::ios::binary);
if (!file.fail()) {
file.seekg(0, std::ios::end);
data.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read((char*)data.data(), data.size());
file.close();
LogTag(LL_Error, "LDR", "lens: %lu", data.size());
#endif
} else {
LogTag(LL_Error, "LDR", "Couldn't load %s file", filename);
}
}
DECLARE_LOG_CONTEXT(CTX)
@interface GameViewController ()
{
SystemInformation m_sysInfo;
GameScreen m_screen;
BOOL _bannerIsVisible;
//ADBannerView *bannerView;
GameAudioRenderer m_audio;
}
@property (nonatomic, assign) BOOL bannerIsVisible;
@property (strong, nonatomic) EAGLContext *context;
- (void)close;
@end
class EAGLContextWrapper
{
public:
EAGLContextWrapper();
private:
EAGLContext *m_context;
};
@implementation GameViewController
- (void)viewDidLoad
{
#if 0
if ([ADBannerView instancesRespondToSelector:@selector(initWithAdType:)]) {
bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
} else {
bannerView = [[ADBannerView alloc] init];
}
/*
//bannerView = [[ADBannerView alloc] initWithFrame:CGRectZero];
bannerView.frame = CGRectOffset(adView.frame, 0, -50);
bannerView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifierPortrait];
bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
*/
const bool showAds = true;
if (showAds)
{
bannerView.delegate=self;
//[self.view addSubview:bannerView];
//bannerView.bottomAnchor
//bannerView.centerXAnchor
CGRect adFrame = bannerView.frame;
adFrame.origin.y = self.view.frame.size.height - bannerView.frame.size.height;
adFrame.origin.x = (self.view.frame.size.width - bannerView.frame.size.width) / 2;
bannerView.frame = adFrame;
[self.view addSubview:bannerView];
self.bannerIsVisible=NO;
}
#endif
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
Log(LL_Error, "Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
//view.preferredFramesPerSecond = 60.0;
self.preferredFramesPerSecond = 60.0;//62;
Log(LL_Info, "setupGL");
[EAGLContext setCurrentContext:self.context];
m_screen.initialize();
#if !TARGET_IPHONE_SIMULATOR
m_audio.initialize(SampleRate_44100Hz, Bits_16, Stereo);//Mono);
m_audio.start();
#endif
self.context.multiThreaded = TRUE;
}
- (void)dealloc
{
[self close];
}
- (void)close
{
Log(LL_Info, "tearDownGL");
[EAGLContext setCurrentContext:self.context];
m_screen.shutdown();
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if ([self isViewLoaded] && ([[self view] window] == nil)) {
self.view = nil;
[self close];
self.context = nil;
}
// Dispose of any resources that can be recreated.
m_screen.freeSpace();
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (void)update
{
AllocationTracking::g_enableAllocTracing = true;
//! @todo remove the time scaling
m_screen.update(5.0f * self.timeSinceLastUpdate, fabs(self.view.bounds.size.width / self.view.bounds.size.height));
}
#include <malloc/malloc.h>
#include "Utilities.h"
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
AllocationTracking::g_enableAllocTracing = true;
/*
malloc_zone_t *zone = malloc_default_zone();
malloc_statistics_t stats;
malloc_zone_statistics(zone, &stats);
setDebugValue("AllocBlkIU:", std::to_string(stats.blocks_in_use).c_str());
setDebugValue("AllocSizeA:", std::to_string(stats.size_allocated).c_str());
setDebugValue("AllocInUse:", std::to_string(stats.size_in_use).c_str());
setDebugValue("AllocMaxIU:", std::to_string(stats.max_size_in_use).c_str());
*/
setDebugValue("AllocFrame:", std::to_string(AllocationTracking::frameAllocations).c_str());
setDebugValue("AllocSet:", std::to_string(AllocationTracking::allocationCount - AllocationTracking::deallocationCount).c_str());
setDebugValue("AllocTotal:", std::to_string(AllocationTracking::allocationCount).c_str());
setDebugValue("AllocFrees:", std::to_string(AllocationTracking::deallocationCount).c_str());
AllocationTracking::frameAllocations = 0;
setDebugValue("CPU Usage:", m_sysInfo.getCpuUsage());
setDebugValue("Memory Usage:", std::string(std::to_string(m_sysInfo.getMemoryUsage()) + " bytes").c_str());
setDebugValue("Frame time:", std::string(std::to_string(m_sysInfo.getFrameTime() * 1000.0) + " ms").c_str());
setDebugValue("Draw time:", std::string(std::to_string(m_sysInfo.getDrawTime() * 1000.0) + " ms").c_str());
setDebugValue("FPS:", m_sysInfo.getFps());
setDebugValue("Average FPS:", m_sysInfo.getAverageFps());
setDebugValue("W:", int(self.view.frame.size.width * self.view.contentScaleFactor));
setDebugValue("H:", int(self.view.frame.size.height * self.view.contentScaleFactor));
m_sysInfo.preDraw();
m_screen.draw();
m_sysInfo.frameDrawn();
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
float s = touch.view.contentScaleFactor;
//! @todo remove the need for these constants
// What this is doing is treating the screen as some fixed size, but scaling the actual values to
// this arbitary resolution that everything has been hard-coded to. Will be hard to undo this. Perhaps
// make the arbitary resolution be 1.0 x 1.0 and then scale everything else accordingly and call it
// normalized coordinates. Then it won't be biased to portrait / landscape.
float xs = 2*640.0 / (self.view.frame.size.width * s); // iPhone 5s res is 640 x 1136
float ys = 2*960.0 / (self.view.frame.size.height * s);
m_screen.touchDown(touchLocation.x*xs, touchLocation.y*ys);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
float s = touch.view.contentScaleFactor;
float xs = 2*640.0 / (self.view.frame.size.width * s);
float ys = 2*960.0 / (self.view.frame.size.height * s);
m_screen.touchUp(touchLocation.x*xs, touchLocation.y*ys);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
float s = touch.view.contentScaleFactor;
float xs = 2*640.0 / (self.view.frame.size.width * s);
float ys = 2*960.0 / (self.view.frame.size.height * s);
m_screen.touchMove(touchLocation.x*xs, touchLocation.y*ys);
}
@end