Sourcecode for Carrot Man: https://www.yousry.de/?p=8395&preview=true
// | |
// Carrot.mm | |
// | |
// Created by Yousry Abdallah. | |
// Copyright 2016 yousry.de. All rights reserved. | |
#include <string> | |
#import "YATextureArray.h" | |
#import "YATextureManager.h" | |
#import "YAImpersonatorInstanced.h" | |
#import "YAProbability.h" | |
#import "YAPreferences.h" | |
#import "YAEXRImageLoader.h" | |
#import "YASoundCollector.h" | |
#import "YAOpenAL.h" | |
#ifdef __linux__ | |
#import "HIDReader.h" | |
#endif | |
#import "YASpotLight.h" | |
#import "YAGouradLight.h" | |
#import "YAQuaternion.h" | |
#import "YATransformator.h" | |
#import "YAMaterial.h" | |
#import "YAImpersonatorInstanced.h" | |
#import "YAIngredient.h" | |
#import "YAPerspectiveProjectionInfo.h" | |
#import "YAQuaternion.h" | |
#import "YAVector4f.h" | |
#import "YAVector3f.h" | |
#import "YAVector2f.h" | |
#import "YAVector2i.h" | |
#import "YATransformator.h" | |
#import "YARenderLoop.h" | |
#import "YALog.h" | |
#import "YADefenderUtils.h" | |
#import "BlenderSceneImporter.h" | |
#import "YAOpenAL.h" | |
#import "Carrot.h" | |
static const NSString* TAG = @"Carrot"; | |
static const double ZFAR = 100.0f; | |
using namespace defender; | |
#define clamp(x,y,z) fminf(fmaxf(x,y),z) | |
@interface Carrot () | |
{ | |
YADefenderUtils* defenderUtils; | |
BlenderSceneImporter *blenderSceneImporter; | |
__block NSArray *carrotImps; | |
__block YAImpersonator *carrotSphere; | |
__block YAVector3f* lookAt; | |
YAOpenAL *openAL; | |
} | |
@end | |
@implementation Carrot : NSObject | |
- (id) initIn: (YARenderLoop*) loop | |
{ | |
[YALog debug:TAG message:@"initIn"]; | |
self = [super init]; | |
if(self) { | |
renderLoop = loop; | |
defenderUtils = [[YADefenderUtils alloc] initIn: renderLoop]; | |
} | |
return self; | |
} | |
- (void) setup | |
{ | |
[YALog debug:TAG message:@"setup scene"]; | |
// Load lively music and place it direct between the ears. | |
openAL = [[YAOpenAL alloc] initInWorld: renderLoop]; | |
openAL.baseVolume = 100; | |
int srcB = [openAL loadOgg: @"pianoRoll.ogg"]; | |
int srcID = [openAL setupSound:srcB atPosition: [[YAVector3f alloc] init] loop:NO]; | |
[openAL playSound: srcID]; | |
// Import Blender Scene | |
blenderSceneImporter = [[BlenderSceneImporter alloc] initIn:renderLoop]; | |
[blenderSceneImporter load:@"carrot"]; | |
// The Brown thingies are badly modelled (not cloesed). | |
carrotImps = [defenderUtils getImpsForIngredient:@"carrotCarrot"]; | |
for(YAImpersonator* imp in carrotImps) { | |
imp.backfaceCulling = false; | |
} | |
// find the clump in the scene graph | |
carrotSphere = [defenderUtils getImpForIngredient:@"carrotSphere"]; | |
[self interactiveSetup]; | |
[self thingySetup]; | |
[self ballSetup]; | |
[self rotateTree]; | |
renderLoop.transformer.projectionInfo.zNear = 0.1; | |
renderLoop.transformer.projectionInfo.zFar = ZFAR; | |
[[renderLoop transformer] recalcCam]; | |
// save shadowbuffer memory by updating the spotlight frustum. | |
renderLoop.shadowTransformer.projectionInfo.zNear = 0.1f; | |
renderLoop.shadowTransformer.projectionInfo.zFar = 10.0f; | |
[[renderLoop shadowTransformer] recalcCam]; | |
[defenderUtils showFPSandFrame]; | |
// Activation FXAA for Screen Recording. | |
renderLoop.deferred = YES; | |
renderLoop.bloom = NO; | |
// Loading HDR Background. | |
[renderLoop setSkyMap:@"IMG_0741_Panorama_sphere"]; | |
[renderLoop createLightProbe:@"IMG_0741_Panorama_sphere" Position: [[YAVector3f alloc] init]]; | |
renderLoop.showSkyMap = YES; | |
[renderLoop setTraceMouseMove:YES]; | |
[renderLoop changeImpsSortOrder:SORT_IDENTITY_ALPHA]; | |
[renderLoop resetAnimators]; | |
[renderLoop setMultiSampling:YES]; | |
[renderLoop setActiveAnimation:true]; | |
renderLoop.drawScene = YES; | |
} | |
- (void) rotateTree | |
{ | |
// The blender importer uses quats. Therefore I cannot use a sinple parameter modifier. | |
YAImpersonator* crTB = [defenderUtils getImpForIngredient:@"CarrotTreeB"]; | |
__block YAQuaternion *qTB = crTB.rotationQuaternion.copy; | |
YABlockAnimator *aTB = [renderLoop createBlockAnimator]; | |
aTB.progress = harmonic; | |
aTB.interval = 7.0f; | |
[aTB addListener:^(float spanPos, NSNumber* event, int message) { | |
YAQuaternion *rot = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0 roll: spanPos * 360.0f * 2]; | |
[crTB.rotationQuaternion setQuat: [qTB mulQuaternion: rot]]; | |
}]; | |
YAImpersonator* crTC = [defenderUtils getImpForIngredient:@"CarrotTreeC"]; | |
__block YAQuaternion *qTC = crTC.rotationQuaternion.copy; | |
YABlockAnimator *aTC = [renderLoop createBlockAnimator]; | |
aTC.progress = harmonic; | |
aTC.interval = 7.25f; | |
[aTC addListener:^(float spanPos, NSNumber* event, int message) { | |
YAQuaternion *rot = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0 roll: spanPos * 360.0f * 2]; | |
[crTC.rotationQuaternion setQuat: [qTC mulQuaternion: rot]]; | |
}]; | |
} | |
-(void) ballSetup | |
{ | |
__block YAQuaternion *orgRot = carrotSphere.rotationQuaternion.copy; | |
__block YAVector3f* orgPos = carrotSphere.translation.copy; | |
YABlockAnimator *anim = [renderLoop createBlockAnimator]; | |
anim.asyncProcessing = false; | |
anim.delay = 1.8f; | |
__block float start = -1.0f; | |
__block float last = start; | |
[anim addListener:^(float spanPos, NSNumber* event, int message) | |
{ | |
// Alternatively setup timeline scheduler | |
if(start < 0) { | |
start = YALog.glfwGetTime; | |
last = start; | |
return; | |
} | |
float now = YALog.glfwGetTime; | |
float duration = now - start; | |
// 1/50 Steps | |
float r = duration * 50.0f; | |
YAQuaternion *rot = [[YAQuaternion alloc] initEulerDeg: r pitch: 0 roll: 0 ]; | |
// Rotation around center. | |
YAVector3f* newPos = [rot rotate: orgPos]; | |
[carrotSphere.translation setVector: newPos]; | |
// This is the rotation during straight movement 0.595 it the sphere radius. | |
YAQuaternion *rotU = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0.595 * 2.0f * M_PI * r roll: 0 ]; | |
// The sphere heading is identical to its z rotation | |
YAQuaternion *rotUU = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0 roll: r ]; | |
// Apply heading to the sphere rotation | |
YAQuaternion *rotUUU =[rotUU mulQuaternion: rotU]; | |
// Update the orientation | |
[carrotSphere.rotationQuaternion setQuat: [orgRot mulQuaternion: rotUUU] ]; | |
}]; | |
} | |
-(void) thingySetup | |
{ | |
for(int i = 0; i < 4; i++) { | |
YABlockAnimator *animA = [renderLoop createBlockAnimator]; | |
animA.asyncProcessing = false; | |
animA.progress = cyclic; | |
animA.delay = (3 - i) * 1.8; | |
animA.interval = 7.2f; | |
// Accordion calculation. rotations adds up. No need for a Subspace or Armature. | |
__block YAImpersonator* impB = carrotImps[1 + i * 4]; | |
YAQuaternion *orgRotB = impB.rotationQuaternion.copy; | |
__block YAImpersonator* impC = carrotImps[2 + i * 4]; | |
YAQuaternion *orgRotC = impC.rotationQuaternion.copy; | |
__block YAImpersonator* impD = carrotImps[3 + i * 4]; | |
YAQuaternion *orgRotD = impD.rotationQuaternion.copy; | |
[animA addListener:^(float spanPos, NSNumber* event, int message) | |
{ | |
// acelleration and decelleration . | |
float d = sin(spanPos * M_PI); | |
// addin to a nearly 90 degree rotation. | |
YAQuaternion *rotB = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0 roll: d * 45.0f]; | |
YAQuaternion *rotC = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0 roll: d * 45.0f * 2]; | |
YAQuaternion *rotD = [[YAQuaternion alloc] initEulerDeg: 0 pitch: 0 roll: d * 45.0f * 2.98]; | |
// Update Rotation | |
[impB.rotationQuaternion setQuat: [orgRotB.copy mulQuaternion: rotB]]; | |
[impC.rotationQuaternion setQuat: [orgRotC.copy mulQuaternion: rotC]]; | |
[impD.rotationQuaternion setQuat: [orgRotD.copy mulQuaternion: rotD]]; | |
}]; | |
} | |
} | |
- (void) interactiveSetup | |
{ | |
// Update the View according to mousemovement | |
__block YAVector2i* mouseVector = nil; | |
__block YAVector2f* force = [[YAVector2f alloc] init]; | |
__block float actHead = 0; | |
__block float actPitch = 0; | |
__block float distance = 1.2 * [defenderUtils.avatar.position distanceTo: lookAt]; | |
__block float actDistance = distance; | |
const float defaultDistance = distance; | |
const float reducedDistance = distance / 1.5f; | |
YABlockAnimator* mausi = [renderLoop createBlockAnimator]; | |
// HID recording (Mouse) > 400HZ | |
mausi.asyncProcessing = YES; | |
[mausi addListener:^(float spanPos, NSNumber* event, int message) | |
{ | |
event_keyPressed ev = (event_keyPressed)event.intValue; | |
if(ev == MOUSE_VECTOR) { | |
// Mouse inpulses are bit encoded. | |
mouseVector = [[YAVector2i alloc] initVals:(message >> 16) :message & 511]; | |
const float x = ((mouseVector.x / 512.0f) - 0.5f) * 1.0f; | |
const float y = ((mouseVector.y / 512.0f) - 0.5f) * 1.0f; | |
force.x = x; | |
force.y = y; | |
// SPACE changes the distance. | |
} else if(ev == SPACE) { | |
if(message != 0) { | |
distance = distance < defaultDistance ? defaultDistance : reducedDistance; | |
} | |
} | |
}]; | |
YABlockAnimator* looki = [renderLoop createBlockAnimator]; | |
looki.asyncProcessing = false; | |
looki.progress = harmonic; | |
looki.interval = 2.5f; | |
[looki addListener:^(float spanPos, NSNumber* event, int message) | |
{ | |
actHead += force.x * 1.6; | |
actPitch -= force.y; | |
// limit the movements to avoid ugly perspectives. | |
actPitch = clamp(actPitch, 10.0f, 45.0f); | |
actHead = fmodf(actHead + 360.0f, 360.0f); | |
YAQuaternion* rot = [[YAQuaternion alloc] initEulerDeg: actHead pitch: actPitch roll: 0]; | |
YAVector3f* pos = [[YAVector3f alloc] initZAxis]; | |
// set the position step size. | |
if(actDistance < distance) | |
actDistance += 0.05f; | |
else if(actDistance > distance) | |
actDistance -= 0.05f; | |
// set the distance step size. | |
if(actDistance < reducedDistance) | |
actDistance = reducedDistance; | |
else if(actDistance > defaultDistance) | |
actDistance = defaultDistance; | |
// pos is already normailzed | |
[pos mulScalar: -actDistance]; | |
// Update View and frustum. | |
[[defenderUtils.avatar position] setVector: [rot rotate: pos]]; | |
[defenderUtils.avatar lookAt: carrotSphere.translation]; | |
}]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment