void operator()( const blocked_range2d<size_t>& r ) const { ContextPtr context = new Context( *m_parentContext ); const Box2i operationWindow( V2i( r.rows().begin()+m_dataWindow.min.x, r.cols().begin()+m_dataWindow.min.y ), V2i( r.rows().end()+m_dataWindow.min.x-1, r.cols().end()+m_dataWindow.min.y-1 ) ); V2i minTileOrigin = ImagePlug::tileOrigin( operationWindow.min ); V2i maxTileOrigin = ImagePlug::tileOrigin( operationWindow.max ); size_t imageStride = m_dataWindow.size().x + 1; for( int tileOriginY = minTileOrigin.y; tileOriginY <= maxTileOrigin.y; tileOriginY += m_tileSize ) { for( int tileOriginX = minTileOrigin.x; tileOriginX <= maxTileOrigin.x; tileOriginX += m_tileSize ) { for( vector<string>::const_iterator it = m_channelNames.begin(), eIt = m_channelNames.end(); it != eIt; it++ ) { context->set( ImagePlug::channelNameContextName, *it ); context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) ); Context::Scope scope( context.get() ); Box2i tileBound( V2i( tileOriginX, tileOriginY ), V2i( tileOriginX + m_tileSize - 1, tileOriginY + m_tileSize - 1 ) ); Box2i b = boxIntersection( tileBound, operationWindow ); ConstFloatVectorDataPtr tileData = m_channelDataPlug->getValue(); for( int y = b.min.y; y<=b.max.y; y++ ) { const float *tilePtr = &(tileData->readable()[0]) + (y - tileOriginY) * m_tileSize + (b.min.x - tileOriginX); float *channelPtr = m_imageChannelData[it-m_channelNames.begin()] + ( m_dataWindow.size().y - ( y - m_dataWindow.min.y ) ) * imageStride + (b.min.x - m_dataWindow.min.x); for( int x = b.min.x; x <= b.max.x; x++ ) { *channelPtr++ = *tilePtr++; } } } } } }
Box2i scale( const Box2i& b, float sx, float sy, int xcenter, int ycenter) { Box2i box = offsetBy( b, V2i( -xcenter, -ycenter)); box = scale( box, sx, sy); box = offsetBy( box, V2i( xcenter, ycenter)); return box; }
V2i Application::normaliseTouch(SDL_TouchID device_id, V2i touch) { // There's only 1 touch device: memorise itss resolution upon initial call static V2i device_resolution = V2i(SDL_GetTouch(device_id)->xres, SDL_GetTouch(device_id)->yres); static V2i default_window_size = V2i(WINDOW_DEFAULT_W, WINDOW_DEFAULT_H); // Normalise the touch position return touch * default_window_size / device_resolution; }
Game::Game() ://mapGraph(NULL), mapPath(NULL), selected(NULL), selectedNode(NULL), delauny(NULL), drawDebug(true), objectMap(AABBf(V2f(-50,-50),V2f(50,50)), V2i(7,7)) { gameLoopRunning = true; paused = false; V2f min(-10, -10), max(10, 10); }
BlackDogState::BlackDogState(bool _tutorial) : GameState(), parallax(), obstacle(BASE_DIFFICULTY), player_progress(STARTING_PROGRESS), difficulty(BASE_DIFFICULTY), victory(false), tutorial(_tutorial ? TUT_FLAPPING : 0) { // add the player character addThing(new AngelThing(V2i(player_progress, WINDOW_DEFAULT_H/2))); // add the dog addThing(new DogThing(V2i(0, WINDOW_DEFAULT_H/2), BASE_DIFFICULTY)); // add the progress-mesure pixie addThing(new PixieThing(V2i(WINDOW_DEFAULT_W/2, WINDOW_DEFAULT_H/2))); }
void Game::init() { objectMap.addLayer(Obstacle::STATIC, AABBf(V2f(-60, -60), V2f(60, 60)), V2i(16, 16)); addObstacle(new CircleObject(Circf(V2f(-4, -4), 2), Obstacle::STATIC)); addObstacle(new AABBObject(AABBf(V2f(-4, 1), V2f(-2, 5)), Obstacle::STATIC)); addObstacle(new BoxObject(Boxf(V2f(4, 0), V2f(2, 5), V2f(1)), Obstacle::STATIC)); addObstacle(new ConeObject(Conef(V2f(0, 1), 1.5f, (float)V_2PI * 1 / 8, (float)V_2PI * 3 / 8), Obstacle::STATIC)); // make the radius of the cone correct based on the calculated center V2f trapezoid[] = { V2f(-.5f, .5f), V2f(.5f, 1.2f), V2f(.5f, -1.5f), V2f(-.5f, -.8f) }; int trapezoidCount = sizeof(trapezoid) / sizeof(trapezoid[0]); addObstacle(new PolygonObject(Polygon2f(V2f(5, -7), V2f((float)V_2PI*0.0f/6), trapezoid, trapezoidCount), Obstacle::STATIC)); // TODO raycast does not always hit the shape correctly from all sides V2f a(-2, -2), b(5, -4); addObstacle(new LineObject(Linef(&a, &b), Obstacle::STATIC)); addObstacle(new PointObject(V2f(7, 7), Obstacle::STATIC)); delaunyBoundary = new CircleObject(Circf(V2f::ZERO(), 100), Obstacle::EVERYTHING); delauny = new DelaunySet(delaunyBoundary); //delauny->addNode(V2f(3, 4)); //delauny->addNode(V2f(-3, 4)); //delauny->addNode(V2f(-3, -4)); //delauny->addNode(V2f(0, -1)); // for (int i = 0; i < 10; ++i) { // delauny->addNode(V2f::randomUnitVector() * Random::PRNGf() * 100); // } delauny->makeRandom(6); delauny->calculateAllTriangles(); }
V2i Pixel_Data::proxy_scale(const V2i & in, Pixel_Data_Info::PROXY proxy) { const int scale = proxy_scale(proxy); return V2i( Math::ceil(in.x / static_cast<double>(scale)), Math::ceil(in.y / static_cast<double>(scale))); }
//---------------------------------------- CState::CState(CWorld const* _pWorld) : m_pWorld(_pWorld),m_vGrid(_pWorld->GetGridSize().x() * _pWorld->GetGridSize().y()) { for (unsigned uGridPos = 0; uGridPos < m_vGrid.size(); ++uGridPos) { m_vGrid[uGridPos] = uGridPos; } m_v2EmptySpacePos = V2i(0, 0); }
void Widget::draw() { Gl_Widget::draw(); //DJV_DEBUG("Widget::draw"); const Box2i & geom = this->geom(); //DJV_DEBUG_PRINT("geom = " << geom); Gl_Util::ortho(V2i(geom.w, geom.h)); DJV_DEBUG_GL(glViewport(0, 0, geom.w, geom.h)); //DJV_DEBUG_GL(glClearColor(0.0, 0.0, 1.0, 0.0)); DJV_DEBUG_GL(glClear(GL_COLOR_BUFFER_BIT)); if (_image) { const Pixel_Data_Info & info = _image->info(); //DJV_DEBUG_PRINT("info = " << info); try { _image->bind(); } catch (Error error) { DJV_APP->error(error); } DJV_DEBUG_GL(glPushMatrix()); double u [] = { 0, 0 }, v [] = { 0, 0 }; u[! info.mirror.x] = info.size.x / static_cast<double>(info.size.x); v[! info.mirror.y] = info.size.y / static_cast<double>(info.size.y); const V2f uv [] = { V2f(u[0], v[0]), V2f(u[0], v[1]), V2f(u[1], v[1]), V2f(u[1], v[0]) }; DJV_DEBUG_GL(glBegin(GL_QUADS)); Gl_Util::draw_box(info.size, uv); DJV_DEBUG_GL(glEnd()); DJV_DEBUG_GL(glPopMatrix()); } }
Box2i dataWindowForTile (const TileDescription &tileDesc, int minX, int maxX, int minY, int maxY, int dx, int dy, int lx, int ly) { V2i tileMin = V2i (minX + dx * tileDesc.xSize, minY + dy * tileDesc.ySize); V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1); V2i levelMax = dataWindowForLevel (tileDesc, minX, maxX, minY, maxY, lx, ly).max; tileMax = V2i (std::min (tileMax[0], levelMax[0]), std::min (tileMax[1], levelMax[1])); return Box2i (tileMin, tileMax); }
void operator()( const blocked_range3d<size_t>& r ) const { ContextPtr context = new Context( *m_parentContext, Context::Borrowed ); Context::Scope scope( context.get() ); const Box2i operationWindow( V2i( r.rows().begin()+m_dataWindow.min.x, r.cols().begin()+m_dataWindow.min.y ), V2i( r.rows().end()+m_dataWindow.min.x-1, r.cols().end()+m_dataWindow.min.y-1 ) ); V2i minTileOrigin = ImagePlug::tileOrigin( operationWindow.min ); V2i maxTileOrigin = ImagePlug::tileOrigin( operationWindow.max ); size_t imageStride = m_dataWindow.size().x + 1; for( size_t channelIndex = r.pages().begin(); channelIndex < r.pages().end(); ++channelIndex ) { context->set( ImagePlug::channelNameContextName, m_channelNames[channelIndex] ); float *channelBegin = m_imageChannelData[channelIndex]; for( int tileOriginY = minTileOrigin.y; tileOriginY <= maxTileOrigin.y; tileOriginY += m_tileSize ) { for( int tileOriginX = minTileOrigin.x; tileOriginX <= maxTileOrigin.x; tileOriginX += m_tileSize ) { context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) ); Box2i tileBound( V2i( tileOriginX, tileOriginY ), V2i( tileOriginX + m_tileSize - 1, tileOriginY + m_tileSize - 1 ) ); Box2i b = boxIntersection( tileBound, operationWindow ); size_t tileStrideSize = sizeof(float) * ( b.size().x + 1 ); ConstFloatVectorDataPtr tileData = m_channelDataPlug->getValue(); const float *tileDataBegin = &(tileData->readable()[0]); for( int y = b.min.y; y<=b.max.y; y++ ) { const float *tilePtr = tileDataBegin + (y - tileOriginY) * m_tileSize + (b.min.x - tileOriginX); float *channelPtr = channelBegin + ( m_dataWindow.size().y - ( y - m_dataWindow.min.y ) ) * imageStride + (b.min.x - m_dataWindow.min.x); std::memcpy( channelPtr, tilePtr, tileStrideSize ); } } } } }
Window::Window(const String & in) : _play(false), _frame(0), _idle_init(false), _idle_frame(0) { DJV_DEBUG(String_Format("Window::Window(%%)").arg(int64_t(this))); // Initialize. try { _movie.init(in); } catch (Error in) { DJV_AUDIO_APP->error(in); } _widget = new Image_View; _play_widget = new Tool_Button("playback_forward"); _play_widget->type(Tool_Button::TOGGLE); _slider = new Int_Slider; Layout_V * layout = new Layout_V(this); layout->margin(0); layout->spacing(0); layout->add(_widget); layout->stretch(_widget); Layout_H * layout_h = new Layout_H(layout); layout_h->margin(0); layout_h->add(_play_widget); layout_h->add(_slider); layout_h->stretch(_slider); _slider->range(0, static_cast<int>(_movie.info_time().list.size()) - 1); dirty(); size(_movie.info().size + V2i(0, size_min().y)); frame_update(); play_update(); _play_widget->signal.set(this, play_callback); _slider->signal.set(this, frame_callback); close_signal.set(this, close_callback); show(); }
Magnify_Dialog::Magnify_Dialog() : Dialog("Magnify"), _view (0), _zoom (ZOOM_200), _widget (0), _zoom_widget (0), _close_widget(0) { // Create widgets. _widget = new Magnify_Widget; _zoom_widget = new Choice_Widget(label_zoom()); _close_widget = new Push_Button(label_close); // Layout. Vertical_Layout * layout = new Vertical_Layout(this); layout->add(_widget); layout->stretch(_widget); Horizontal_Layout * layout_h = new Horizontal_Layout(layout); layout_h->margin(0); layout_h->add(_zoom_widget); layout_h->add_spacer(-1, true); layout_h->add(_close_widget); layout_h->add_spacer(Layout::window_handle_size()); // Preferences. Prefs prefs(Prefs::prefs(), "magnify_dialog"); Prefs::get_(&prefs, "zoom", &_zoom); // Initialize. widget_update(); size(Vector_Util::max(size_hint(), V2i(300, 300))); // Callbacks. _zoom_widget->signal.set(this, zoom_callback); _close_widget->signal.set(this, close_callback); }
void Text_Display::dirty() { Abstract_Text_Widget::dirty(); _widget->textfont(text_font()); _widget->textsize(Style::global()->font_size()); _widget->textcolor(text_color()); size_hint( V2i( //Math::max( // Style::global()->size_button(), // base::string_size(_size_string) //), Font::string_width(_size_string), fl_height() ) + Style::global()->margin_text() * 2 + frame_size() * 2); }
Box2i scale( const Box2i& b, float sx, float sy) { return Box2i( V2i( Math<float>::floor( b.min.x * sx), Math<float>::floor( b.min.y * sy)), V2i( Math<float>::ceil( b.max.x * sx), Math<float>::ceil( b.max.y * sy))); }
void Scale_Op::render(const Image & in) throw (Error) { //DJV_DEBUG("Scale_Op::render"); //DJV_DEBUG_PRINT("in = " << in); //DJV_DEBUG_PRINT("size = " << _value.size); //DJV_DEBUG_PRINT("type = " << _value.type); // Initialize. Pixel_Data_Info info = in.info(); begin(); if (DEFAULT == _value.type) { _texture.init( info, filter_to_gl(_value.default_min), filter_to_gl(_value.default_mag)); const State_Default state(_value); if (_state_default != state) { //DJV_DEBUG_PRINT("init"); _render.shader.init(src_default); _state_default = state; } } else { _texture.init(info); _render.texture_tmp.init( Pixel_Data_Info(V2i(_value.size.x, in.h()), info.pixel)); const State_Custom state(_value); if (_state_custom != state) { //DJV_DEBUG_PRINT("init"); _render.offscreen.init(); Pixel_Data contrib; contrib_fnc( in.w(), _value.size.x, _value.custom_min, _value.custom_mag, &contrib); _render.contrib_x.init(contrib); _render.shader_x.init(String_Format(src_custom). arg(contrib.h()). arg(src_x)); contrib_fnc( in.h(), _value.size.y, _value.custom_min, _value.custom_mag, &contrib); _render.contrib_y.init(contrib); _render.shader_y.init(String_Format(src_custom). arg(contrib.h()). arg(src_y)); _state_custom = state; } } // Render. if (DEFAULT == _value.type) { _render.shader.bind(); const GLuint program = _render.shader.program(); glUniform2f(glGetUniformLocation(program, "scale_input"), static_cast<GLfloat>(in.w()), static_cast<GLfloat>(in.h())); glUniform2f(glGetUniformLocation(program, "scale_output"), static_cast<GLfloat>(_value.size.x), static_cast<GLfloat>(_value.size.y)); glActiveTexture(GL_TEXTURE0); glUniform1i(glGetUniformLocation(program, "texture"), 0); _texture.bind(); _texture.copy(in); info = in.info(); info.size = _value.size; Gl_Util::ortho(_value.size); glViewport(0, 0, _value.size.x, _value.size.y); glClear(GL_COLOR_BUFFER_BIT); Util::quad(info); } else { // Horizontal. _render.offscreen.bind(); _render.offscreen.set(_render.texture_tmp); _render.shader_x.bind(); glActiveTexture(GL_TEXTURE0); glUniform1i( glGetUniformLocation(_render.shader_x.program(), "texture"), 0); _texture.bind(); _texture.copy(in); glActiveTexture(GL_TEXTURE1); glUniform1i( glGetUniformLocation(_render.shader_x.program(), "contrib"), 1); _render.contrib_x.bind(); info = in.info(); info.size.x = _value.size.x; Gl_Util::ortho(info.size); glViewport(0, 0, info.size.x, info.size.y); glClear(GL_COLOR_BUFFER_BIT); Util::quad(info); _render.offscreen.unbind(); // Vertical. _render.shader_y.bind(); glActiveTexture(GL_TEXTURE0); glUniform1i( glGetUniformLocation(_render.shader_y.program(), "texture"), 0); _render.texture_tmp.bind(); glActiveTexture(GL_TEXTURE1); glUniform1i( glGetUniformLocation(_render.shader_y.program(), "contrib"), 1); _render.contrib_y.bind(); Gl_Util::ortho(_value.size); glViewport(0, 0, _value.size.x, _value.size.y); glClear(GL_COLOR_BUFFER_BIT); Util::quad(Pixel_Data_Info(_value.size, in.pixel())); } end(); }
// deal with input messages, return BACK, EXIT or CONTINUE int Application::treatEvents() { // local variables static V2i cursor(0,0); static bool clicking(false); // static to avoid reallocating it ever time we run the function static SDL_Event event; // write each event to our static variable while (SDL_PollEvent(&event)) { switch (event.type) { // exit if the window is closed (ex: pressing the cross) case SDL_QUIT: return Application::EXIT; break; // check for keypresses case SDL_KEYDOWN: switch (event.key.keysym.sym) { case KEY_BACK: return Application::BACK; case KEY_EXIT: return Application::EXIT; case KEY_VOLUME_UP: AudioManager::getInstance()->volume_up(); break; case KEY_VOLUME_DOWN: AudioManager::getInstance()->volume_down(); break; default: // here we DO want a default break, as not all keys are needed break; } break; #if USE_TOUCH // touch events case SDL_FINGERDOWN: cursor = normaliseTouch(event.tfinger.touchId, V2i(event.tfinger.x, event.tfinger.y)); clicking = true; break; case SDL_FINGERUP: clicking = false; break; case SDL_FINGERMOTION: cursor = normaliseTouch(event.tfinger.touchId, V2i(event.tfinger.x, event.tfinger.y)); break; #endif // USE_TOUCH #if USE_MOUSE // mouse events case SDL_MOUSEBUTTONDOWN: if(event.button.button == SDL_BUTTON_RIGHT) return Application::BACK; clicking = true; break; case SDL_MOUSEBUTTONUP: if(event.button.button == SDL_BUTTON_LEFT) clicking = false; break; case SDL_MOUSEMOTION: cursor = V2f(event.motion.x, event.motion.y) / global::scale; break; #endif // USE_MOUSE default: // not all possible inputs are needed, so we DO want a default break break; } } // Update the scene with the new input scene->getState()->setCursor(cursor, clicking); // No exit events encountered, we can continue return Application::CONTINUE; }
void Shuttle::dirty() { Frame::dirty(); size_hint(V2i(_icon[0]->w(), _icon[0]->h()) + 3 * 2); }
void Load::open(const File & in, Image_Io_Info & info) throw (Error) { //DJV_DEBUG("Load::open"); //DJV_DEBUG_PRINT("in = " << in); _close(); // Open the file. CFStringRef cf_string_ref(File_Util::path_absolute(in)); qt::QTNewMoviePropertyElement prop_list [10]; qt::ItemCount prop_size = 0; prop_list[prop_size].propClass = qt::kQTPropertyClass_DataLocation; prop_list[prop_size].propID = qt::kQTDataLocationPropertyID_CFStringNativePath; //qt::kQTDataLocationPropertyID_CFStringPosixPath; prop_list[prop_size].propValueSize = sizeof(cf_string_ref.p); prop_list[prop_size].propValueAddress = (void *)&cf_string_ref.p; prop_list[prop_size].propStatus = 0; ++prop_size; qt::Boolean unresolved = true; prop_list[prop_size].propClass = qt::kQTPropertyClass_MovieInstantiation; prop_list[prop_size].propID = qt::kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs; prop_list[prop_size].propValueSize = sizeof(unresolved); prop_list[prop_size].propValueAddress = &unresolved; prop_list[prop_size].propStatus = 0; ++prop_size; qt::Boolean active = true; prop_list[prop_size].propClass = qt::kQTPropertyClass_NewMovieProperty; prop_list[prop_size].propID = qt::kQTNewMoviePropertyID_Active; prop_list[prop_size].propValueSize = sizeof(active); prop_list[prop_size].propValueAddress = &active; prop_list[prop_size].propStatus = 0; ++prop_size; qt::Boolean no_interact = true; prop_list[prop_size].propClass = qt::kQTPropertyClass_NewMovieProperty; prop_list[prop_size].propID = qt::kQTNewMoviePropertyID_DontInteractWithUser; prop_list[prop_size].propValueSize = sizeof(no_interact); prop_list[prop_size].propValueAddress = &no_interact; prop_list[prop_size].propStatus = 0; ++prop_size; qt::QTVisualContextRef visual = 0; prop_list[prop_size].propClass = qt::kQTPropertyClass_Context; prop_list[prop_size].propID = qt::kQTContextPropertyID_VisualContext; prop_list[prop_size].propValueSize = sizeof(qt::QTVisualContextRef); prop_list[prop_size].propValueAddress = &visual; prop_list[prop_size].propStatus = 0; ++prop_size; qt::QTAudioContextRef audio = 0; prop_list[prop_size].propClass = qt::kQTPropertyClass_Context; prop_list[prop_size].propID = qt::kQTContextPropertyID_AudioContext; prop_list[prop_size].propValueSize = sizeof(qt::QTAudioContextRef); prop_list[prop_size].propValueAddress = &audio; prop_list[prop_size].propStatus = 0; ++prop_size; qt::OSErr err = qt::NewMovieFromProperties( prop_size, prop_list, 0, 0, &_movie); if (err != qt::noErr) { throw_error(name(), String_Format(error_open).arg(in).arg(err)); } // Get the file information. _info.file_name = in; qt::Rect rect; qt::GetMovieBox(_movie, &rect); _info.size = V2i(rect.right - rect.left, rect.bottom - rect.top); _info.mirror.y = true; _info.pixel = Pixel::RGBA_U8; //_info.bgr = true; const qt::TimeScale time_scale = qt::GetMovieTimeScale(_movie); const qt::TimeValue time_duration = qt::GetMovieDuration(_movie); //const long frame_count = _frame_count(_movie); const qt::TimeValue frame_duration = _frame_duration(_movie); //const TimeValue frame_duration = time_duration / frame_count; _start_frame = _options.start_frame; //DJV_DEBUG_PRINT("time scale = " << static_cast<int>(time_scale)); //DJV_DEBUG_PRINT("time duration = " << static_cast<int>(time_duration)); //DJV_DEBUG_PRINT("frame count = " << static_cast<int>(frame_count)); //DJV_DEBUG_PRINT("frame duration = " << static_cast<int>(frame_duration)); //DJV_DEBUG_PRINT("start frame = " << _start_frame); _info.seq = Seq( _start_frame, frame_duration ? (_start_frame + (time_duration / frame_duration - 1)) : _start_frame, 0, Speed(time_scale, frame_duration)); //DJV_DEBUG_PRINT("time = " << _info.seq); info = _info; //! Allocate the temporary buffer. _tmp.set(_info); //! \todo Is this still necessary? unsigned long qt_format = # if defined(DJV_OSX) qt::k32ARGBPixelFormat; # else qt::k32RGBAPixelFormat; # endif err = qt::NewGWorldFromPtr( &_gworld, qt_format, &rect, 0, 0, 0, (char *)_tmp.data(0, 0), _info.size.x * 4); if (err != qt::noErr) { throw_error(name(), String_Format(error_gworld).arg(in).arg(err)); } qt::SetMovieGWorld(_movie, _gworld, 0); }
INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) { GameWorldState *world = GET_STATE_DATA(state, &state->persistentArena, GameWorldState); if (!common_isSet(world->flags, gameworldstateflags_init)) { #ifdef DENGINE_DEBUG { u8 *data = (u8 *)world; for (i32 i = 0; i < sizeof(GameWorldState); i++) ASSERT(data[i] == 0); } #endif world->pixelsPerMeter = 70.0f; MemoryIndex entityArenaSize = (MemoryIndex)((f32)memory->transientSize * 0.5f); u8 *arenaBase = state->transientArena.base + state->transientArena.size; memory_arenaInit(&world->entityArena, arenaBase, entityArenaSize); world->camera.min = V2(0, 0); world->camera.max = state->renderer.size; world->size = state->renderer.size; world->entityListSize = 1024; world->entityList = MEMORY_PUSH_ARRAY(&world->entityArena, world->entityListSize, Entity); { // Init null entity Entity *nullEntity = &world->entityList[world->entityIndex++]; nullEntity->id = world->entityIdCounter++; } { // Init asteroid entities world->numAsteroids = 15; } { // Init audio renderer world->numAudioRenderers = 8; world->audioRenderer = MEMORY_PUSH_ARRAY( &world->entityArena, world->numAudioRenderers, AudioRenderer); } { // Global Collision Rules setCollisionRule(world, entitytype_ship, entitytype_asteroid_small, TRUE); setCollisionRule(world, entitytype_ship, entitytype_asteroid_medium, TRUE); setCollisionRule(world, entitytype_ship, entitytype_asteroid_large, TRUE); setCollisionRule(world, entitytype_bullet, entitytype_asteroid_small, TRUE); setCollisionRule(world, entitytype_bullet, entitytype_asteroid_medium, TRUE); setCollisionRule(world, entitytype_bullet, entitytype_asteroid_large, TRUE); } world->numStarP = 100; world->starPList = MEMORY_PUSH_ARRAY(&world->entityArena, world->numStarP, v2); world->starMinOpacity = 0.25f; for (i32 i = 0; i < world->numStarP; i++) { i32 randX = rand() % (i32)world->size.x; i32 randY = rand() % (i32)world->size.y; world->starPList[i] = V2i(randX, randY); } world->flags |= gameworldstateflags_init; world->scoreMultiplier = 5; world->scoreMultiplierBarTimer = 0.0f; world->scoreMultiplierBarThresholdInS = 2.0f; } if (common_isSet(world->flags, gameworldstateflags_level_started)) { Font *arial40 = asset_fontGet(&state->assetManager, "Arial", 40); Renderer *renderer = &state->renderer; /* Render scores onto screen */ v2 stringP = V2((renderer->size.w * 0.5f), renderer->size.h - arial40->size); char gamePointsString[COMMON_ITOA_MAX_BUFFER_32BIT] = {0}; common_itoa(world->score, gamePointsString, ARRAY_COUNT(gamePointsString)); renderer_stringFixedCentered(renderer, &state->transientArena, arial40, gamePointsString, stringP, V2(0, 0), 0, V4(1.0f, 1.0f, 1.0f, 1.0f), 1, 0); /* Render multiplier accumulator bar onto screen */ v2 stringDim = asset_fontStringDimInPixels(arial40, gamePointsString); v2 multiplierOutlineSize = V2(renderer->size.w * 0.5f, stringDim.h * 0.25f); v2 multiplierOutlineP = V2(renderer->size.w * 0.5f, stringP.h); multiplierOutlineP.x -= (multiplierOutlineSize.w * 0.5f); multiplierOutlineP.y -= stringDim.h * 1.5f; renderer_rectFixedOutline( renderer, multiplierOutlineP, multiplierOutlineSize, V2(0, 0), 2, 0, NULL, V4(0.2f, 0.3f, 0.8f, 1.0f), 2, renderflag_no_texture); f32 progressNormalised = world->scoreMultiplierBarTimer / world->scoreMultiplierBarThresholdInS; renderer_rectFixed(renderer, multiplierOutlineP, V2(multiplierOutlineSize.w * progressNormalised, multiplierOutlineSize.h), V2(0, 0), 0, NULL, V4(0.2f, 0.3f, 0.8f, 1.0f), 1, renderflag_no_texture); /* Render multiplier counter hud onto screen */ v2 multiplierHudP = V2(0, 0.05f * renderer->size.h); v2 multiplierHudSize = V2((arial40->maxSize.w * 3.5f), arial40->fontHeight * 1.2f); renderer_rectFixed(renderer, multiplierHudP, multiplierHudSize, V2(0, 0), 0, NULL, V4(1, 1, 1, 0.1f), 2, renderflag_no_texture); /* Render multiplier counter string to hud */ char multiplierToString[COMMON_ITOA_MAX_BUFFER_32BIT + 1] = {0}; common_itoa(world->scoreMultiplier, multiplierToString + 1, ARRAY_COUNT(multiplierToString) - 1); multiplierToString[0] = 'x'; v2 multiplierToStringP = multiplierHudP; multiplierToStringP = v2_add(multiplierToStringP, v2_scale(multiplierHudSize, 0.5f)); renderer_stringFixedCentered( renderer, &state->transientArena, arial40, multiplierToString, multiplierToStringP, V2(0, 0), 0, V4(1.0f, 1.0f, 1.0f, 1.0f), 3, 0); /* Process multiplier bar updates */ if (!common_isSet(world->flags, gameworldstateflags_player_lost)) { f32 barTimerPenalty = 1.0f; if (world->timeSinceLastShot < 1.5f) { barTimerPenalty = 0.1f; } world->scoreMultiplierBarTimer += (barTimerPenalty * dt); world->timeSinceLastShot += dt; if (world->scoreMultiplierBarTimer > world->scoreMultiplierBarThresholdInS) { world->scoreMultiplierBarTimer = 0; world->scoreMultiplier++; if (world->scoreMultiplier > 9999) world->scoreMultiplier = 9999; } } } if (common_isSet(world->flags, gameworldstateflags_player_lost)) { Font *arial40 = asset_fontGet(&state->assetManager, "Arial", 40); char *gameOver = "Game Over"; v2 gameOverP = v2_scale(state->renderer.size, 0.5f); renderer_stringFixedCentered( &state->renderer, &state->transientArena, arial40, "Game Over", gameOverP, V2(0, 0), 0, V4(1, 1, 1, 1), 0, 0); v2 gameOverSize = asset_fontStringDimInPixels(arial40, gameOver); v2 replayP = V2(gameOverP.x, gameOverP.y - (gameOverSize.h * 1.2f)); renderer_stringFixedCentered( &state->renderer, &state->transientArena, arial40, "Press enter to play again or backspace to return to menu", replayP, V2(0, 0), 0, V4(1, 1, 1, 1), 0, 0); if (platform_queryKey(&state->input.keys[keycode_enter], readkeytype_one_shot, 0.0f)) { // TODO(doyle): Extract score init default values to some game // definitions file world->score = 0; world->scoreMultiplier = 5; world->scoreMultiplierBarTimer = 0.0f; world->scoreMultiplierBarThresholdInS = 2.0f; addPlayer(world); world->flags ^= gameworldstateflags_player_lost; } else if (platform_queryKey(&state->input.keys[keycode_backspace], readkeytype_one_shot, 0.0f)) { common_memset((u8 *)world, 0, sizeof(*world)); state->currState = appstate_StartMenuState; return; } } for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++) addAsteroid(world, (rand() % asteroidsize_count)); Radians starRotation = DEGREES_TO_RADIANS(45.0f); v2 starSize = V2(2, 2); ASSERT(world->starMinOpacity >= 0.0f && world->starMinOpacity <= 1.0f); f32 opacityFadeRateInS = 0.5f; if (world->starFadeAway) { opacityFadeRateInS *= -1.0f; } if (world->starOpacity > 1.0f) { world->starOpacity = 1.0f; world->starFadeAway = TRUE; } else if (world->starOpacity < world->starMinOpacity) { world->starOpacity = world->starMinOpacity; world->starFadeAway = FALSE; } world->starOpacity += (opacityFadeRateInS * dt); DEBUG_PUSH_VAR("Star Opacity: %5.2f", world->starOpacity, "f32"); for (i32 i = 0; i < world->numStarP; i++) { world->starPList[i] = v2_add(world->starPList[i], V2(4.0f * dt, 0)); world->starPList[i] = wrapPAroundBounds( world->starPList[i], math_rectCreate(V2(0, 0), world->size)); renderer_rect(&state->renderer, world->camera, world->starPList[i], starSize, V2(0, 0), starRotation, NULL, V4(0.8f, 0.8f, 0.8f, world->starOpacity), 0, renderflag_no_texture | renderflag_wireframe); } #ifdef DENGINE_DEBUG if (platform_queryKey(&state->input.keys[keycode_left_square_bracket], readkeytype_repeat, 0.2f)) { addAsteroid(world, (rand() % asteroidsize_count)); } #endif ASSERT(world->entityList[0].id == NULL_ENTITY_ID); for (i32 i = 1; i < world->entityIndex; i++) { Entity *entity = &world->entityList[i]; ASSERT(entity->type != entitytype_invalid); v2 pivotPoint = {0}; f32 ddPSpeedInMs = 0; v2 ddP = {0}; if (entity->type == entitytype_ship) { if (platform_queryKey(&state->input.keys[keycode_up], readkeytype_repeat, 0.0f)) { // TODO(doyle): Renderer creates upfacing triangles by default, // but we need to offset rotation so that our base "0 degrees" // is right facing for trig to work Radians rotation = DEGREES_TO_RADIANS((entity->rotation + 90.0f)); v2 direction = V2(math_cosf(rotation), math_sinf(rotation)); ddP = direction; AudioVorbis *thrust = asset_vorbisGet(&state->assetManager, "thrust"); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, thrust, 3); if (audioRenderer) { audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, thrust, 1); } } if (platform_queryKey(&state->input.keys[keycode_space], readkeytype_one_shot, KEY_DELAY_NONE)) { addBullet(world, entity); if (world->timeSinceLastShot >= 0) { world->timeSinceLastShot = 0; f32 multiplierPenalty = -2.0f; world->timeSinceLastShot += multiplierPenalty; } AudioVorbis *fire = asset_vorbisGet(&state->assetManager, "fire"); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, fire, 2); if (audioRenderer) { // TODO(doyle): Atm transient arena is not used, this is // just to fill out the arguments audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, fire, 1); } } Degrees rotationsPerSecond = 180.0f; if (platform_queryKey(&state->input.keys[keycode_left], readkeytype_repeat, 0.0f)) { entity->rotation += (rotationsPerSecond)*dt; } if (platform_queryKey(&state->input.keys[keycode_right], readkeytype_repeat, 0.0f)) { entity->rotation -= (rotationsPerSecond)*dt; } entity->rotation = (f32)((i32)entity->rotation); ddPSpeedInMs = 25; DEBUG_PUSH_VAR("Pos: %5.2f, %5.2f", entity->pos, "v2"); DEBUG_PUSH_VAR("Velocity: %5.2f, %5.2f", entity->dP, "v2"); DEBUG_PUSH_VAR("Rotation: %5.2f", entity->rotation, "f32"); DEBUG_PUSH_VAR("TimeSinceLastShot: %5.2f", world->timeSinceLastShot, "f32"); renderer_rect(&state->renderer, world->camera, entity->pos, V2(5, 5), V2(0, 0), DEGREES_TO_RADIANS(entity->rotation), NULL, V4(1.0f, 1.0f, 1.0f, 1.0f), 0, renderflag_no_texture); } else if (entity->type >= entitytype_asteroid_small && entity->type <= entitytype_asteroid_large) { i32 randValue = rand(); // NOTE(doyle): If it is a new asteroid with no dp set, we need to // set a initial dp for it to move from. v2 localDp = {0}; if ((i32)entity->dP.x == 0 && (i32)entity->dP.y == 0) { enum Direction direction = randValue % direction_count; switch (direction) { case direction_north: case direction_northwest: { localDp.x = 1.0f; localDp.y = 1.0f; } break; case direction_west: case direction_southwest: { localDp.x = -1.0f; localDp.y = -1.0f; } break; case direction_south: case direction_southeast: { localDp.x = 1.0f; localDp.y = -1.0f; } break; case direction_east: case direction_northeast: { localDp.x = 1.0f; localDp.y = 1.0f; } break; default: { ASSERT(INVALID_CODE_PATH); } break; } } // NOTE(doyle): Otherwise, if it has pre-existing dp, maintain our // direction by extrapolating from it's current dp else { if (entity->dP.x >= 0) localDp.x = 1.0f; else localDp.x = -1.0f; if (entity->dP.y >= 0) localDp.y = 1.0f; else localDp.y = -1.0f; } /* NOTE(doyle): We compare current dP with the calculated dP. In the event we want to artificially boost the asteroid, we set a higher dP on creation, which will have a higher dP than the default dP we calculate. So here we choose to keep it until it decays enough that the default dP of the asteroid is accepted. */ v2 newDp = v2_scale(localDp, world->pixelsPerMeter * 1.5f); f32 newDpSum = ABS(newDp.x) + ABS(newDp.y); f32 oldDpSum = ABS(entity->dP.x) + ABS(entity->dP.y); if (newDpSum > oldDpSum) { entity->dP = newDp; } } else if (entity->type == entitytype_bullet) { if (!math_rectContainsP(world->camera, entity->pos)) { deleteEntity(world, i--); continue; } Radians rotation = DEGREES_TO_RADIANS((entity->rotation + 90.0f)); v2 localDp = V2(math_cosf(rotation), math_sinf(rotation)); entity->dP = v2_scale(localDp, world->pixelsPerMeter * 5); } else if (entity->type == entitytype_particle) { f32 diff = entity->color.a - 0.1f; if (diff < 0.01f) { deleteEntity(world, i--); continue; } f32 divisor = MAX(entity->particleInitDp.x, entity->particleInitDp.y); f32 maxDp = MAX(entity->dP.x, entity->dP.y); entity->color.a = maxDp / divisor; } entity->pos = wrapPAroundBounds(entity->pos, math_rectCreate(V2(0, 0), world->size)); /* Loop entity around world */ i32 collisionIndex = moveEntity(world, &state->transientArena, entity, i, ddP, dt, ddPSpeedInMs); v4 collideColor = {0}; if (collisionIndex != -1) { ASSERT(collisionIndex < world->entityIndex); Entity *collideEntity = &world->entityList[collisionIndex]; Entity *colliderA; Entity *colliderB; if (collideEntity->type < entity->type) { colliderA = collideEntity; colliderB = entity; } else { colliderA = entity; colliderB = collideEntity; } // Assumptions made that the collision detect system relies on ASSERT(entitytype_ship < entitytype_asteroid_small); ASSERT(entitytype_asteroid_small < entitytype_asteroid_medium); ASSERT(entitytype_asteroid_medium < entitytype_asteroid_large); ASSERT(entitytype_asteroid_large < entitytype_bullet); ASSERT(entitytype_asteroid_small + 1 == entitytype_asteroid_medium); ASSERT(entitytype_asteroid_medium + 1 == entitytype_asteroid_large); if (colliderA->type >= entitytype_asteroid_small && colliderA->type <= entitytype_asteroid_large) { f32 numParticles = 4; if (colliderA->type == entitytype_asteroid_medium) { AsteroidSpec spec = {0}; spec.pos = colliderA->pos; spec.dP = v2_scale(colliderA->dP, -2.0f); addAsteroidWithSpec(world, asteroidsize_small, &spec); numParticles = 8; world->score += (10 * world->scoreMultiplier); } else if (colliderA->type == entitytype_asteroid_large) { AsteroidSpec spec = {0}; spec.pos = colliderA->pos; spec.dP = v2_scale(colliderA->dP, -4.0f); addAsteroidWithSpec(world, asteroidsize_medium, &spec); spec.dP = v2_perpendicular(spec.dP); addAsteroidWithSpec(world, asteroidsize_small, &spec); spec.dP = v2_perpendicular(colliderA->dP); addAsteroidWithSpec(world, asteroidsize_small, &spec); numParticles = 16; world->score += (20 * world->scoreMultiplier); } else { world->score += (5 * world->scoreMultiplier); } for (i32 i = 0; i < numParticles; i++) { { // Add particles Entity *particle = &world->entityList[world->entityIndex++]; particle->id = world->entityIdCounter++; particle->pos = colliderA->pos; particle->size = V2(4.0f, 4.0f); i32 randValue = rand(); Radians rotation = DEGREES_TO_RADIANS((randValue % 360)); v2 randDirectionVec = V2(math_cosf(rotation), math_sinf(rotation)); i32 particleDpLimit = 8; f32 randDpMultiplier = (f32)(randValue % particleDpLimit) + 1; v2 newDp = v2_scale(colliderA->dP, randDpMultiplier); newDp = v2_hadamard(newDp, randDirectionVec); particle->dP = newDp; particle->particleInitDp = newDp; particle->offset = v2_scale(particle->size, -0.5f); particle->hitbox = particle->size; particle->rotation = 0; particle->renderMode = rendermode_polygon; if (!world->particleVertexCache) { world->particleVertexCache = MEMORY_PUSH_ARRAY(&world->entityArena, 4, v2); world->particleVertexCache[0] = V2(0, particle->size.h); world->particleVertexCache[1] = V2(0, 0); world->particleVertexCache[2] = V2(particle->size.w, 0); world->particleVertexCache[3] = particle->size; } particle->vertexPoints = world->particleVertexCache; particle->numVertexPoints = 4; particle->type = entitytype_particle; particle->color = V4(1.0f, 0.0f, 0, 1.0f); } } ASSERT(colliderB->type == entitytype_bullet); deleteEntity(world, collisionIndex); deleteEntity(world, i--); world->asteroidCounter--; ASSERT(world->asteroidCounter >= 0); char *sound; i32 choice = rand() % 3; if (choice == 0) { sound = "bang_small"; } else if (choice == 1) { sound = "bang_medium"; } else { sound = "bang_large"; } AudioVorbis *explode = asset_vorbisGet(&state->assetManager, sound); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, explode, 3); if (audioRenderer) { audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, explode, 1); } continue; } else if (colliderA->type == entitytype_ship) { if (colliderB->type >= entitytype_asteroid_small && colliderB->type <= entitytype_asteroid_large) { world->flags |= gameworldstateflags_player_lost; if (collideEntity->type == entitytype_ship) { deleteEntity(world, collisionIndex); } else { deleteEntity(world, i--); } AudioVorbis *explode = asset_vorbisGet(&state->assetManager, "bang_large"); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, explode, 3); if (audioRenderer) { audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, explode, 1); } continue; } } } RenderFlags flags = renderflag_wireframe | renderflag_no_texture; renderer_entity(&state->renderer, &state->transientArena, world->camera, entity, V2(0, 0), 0, collideColor, 0, flags); } for (i32 i = 0; i < world->numAudioRenderers; i++) { AudioRenderer *audioRenderer = &world->audioRenderer[i]; audio_updateAndPlay(&state->transientArena, &state->audioManager, audioRenderer); } }
void Application_Message_Dialog::dirty() { Dialog::dirty(); _size_min = Vector_Util::max(Dialog::size_min(), V2i(400, 200)); }
INTERNAL void addAsteroidWithSpec(GameWorldState *world, enum AsteroidSize asteroidSize, AsteroidSpec *spec) { world->asteroidCounter++; enum EntityType type; v2 size; v2 **vertexCache = NULL; if (asteroidSize == asteroidsize_small) { size = V2i(25, 25); type = entitytype_asteroid_small; vertexCache = world->asteroidSmallVertexCache; } else if (asteroidSize == asteroidsize_medium) { size = V2i(50, 50); type = entitytype_asteroid_medium; vertexCache = world->asteroidMediumVertexCache; } else if (asteroidSize == asteroidsize_large) { type = entitytype_asteroid_large; size = V2i(100, 100); vertexCache = world->asteroidLargeVertexCache; } else { ASSERT(INVALID_CODE_PATH); } Entity *asteroid = &world->entityList[world->entityIndex++]; asteroid->id = world->entityIdCounter++; i32 randValue = rand(); if (!spec) { i32 randX = (randValue % (i32)world->size.w); i32 randY = (randValue % (i32)world->size.h); v2 midpoint = v2_scale(world->size, 0.5f); Rect topLeftQuadrant = {V2(0, midpoint.y), V2(midpoint.x, world->size.y)}; Rect botLeftQuadrant = {V2(0, 0), midpoint}; Rect topRightQuadrant = {midpoint, world->size}; Rect botRightQuadrant = {V2(midpoint.x, 0), V2(world->size.x, midpoint.y)}; // NOTE(doyle): Off-screen so asteroids "float" into view. There's no // particular order, just pushing things offscreen when they get // generated // to float back into game space v2 newP = V2i(randX, randY); if (math_rectContainsP(topLeftQuadrant, newP)) { newP.y += midpoint.y; } else if (math_rectContainsP(botLeftQuadrant, newP)) { newP.x -= midpoint.x; } else if (math_rectContainsP(topRightQuadrant, newP)) { newP.y -= midpoint.y; } else if (math_rectContainsP(botRightQuadrant, newP)) { newP.x += midpoint.x; } else { ASSERT(INVALID_CODE_PATH); } asteroid->pos = newP; } else { asteroid->pos = spec->pos; asteroid->dP = spec->dP; } asteroid->size = size; asteroid->hitbox = asteroid->size; asteroid->offset = v2_scale(asteroid->size, -0.5f); asteroid->type = type; asteroid->renderMode = rendermode_polygon; asteroid->numVertexPoints = 10; i32 cacheIndex = randValue % ARRAY_COUNT(world->asteroidSmallVertexCache); ASSERT(ARRAY_COUNT(world->asteroidSmallVertexCache) == ARRAY_COUNT(world->asteroidMediumVertexCache)); ASSERT(ARRAY_COUNT(world->asteroidSmallVertexCache) == ARRAY_COUNT(world->asteroidLargeVertexCache)); if (!vertexCache[cacheIndex]) { vertexCache[cacheIndex] = createAsteroidVertexList( &world->entityArena, asteroid->numVertexPoints, (i32)(asteroid->size.w * 0.5f)); } asteroid->vertexPoints = vertexCache[cacheIndex]; asteroid->color = V4(1.0f, 1.0f, 1.0f, 1.0f); }