void OnShown(object sender, EventArgs ee) { // Note: Events are fired in the order (Load, Activated, Shown), // It is said that using a MessageBox() can perturb the order of these events, // causing Shown to occur before Load. // http://stackoverflow.com/questions/3070163/order-of-form-load-form-shown-and-form-activated-events // It is also said that "depending on the order of events fired" is undesirable / bad style; // so perhaps once I understand what the idiomatic alternative would be, // this should be changed. // // To call any GL methods (such as setting the GL Viewport, or loading textures) // the OpenGL system must be initialized, which occurs upon the 'Load' event // firing for a Form which contains a GLControl. // http://www.opentk.com/doc/chapter/2/glcontrol // See also, regarding OpenTK.Graphics.GraphicsContext: // http://www.opentk.com/book/export/html/140 // // For this reason, the GL setup, and GL texture loading (via TileSheet constructor calls) // code has been moved here, in a method we set up to be called upon the 'Shown' event // (which is fired upon the first display of this Form). ts = new TileSheet(16, 16, NEW_OBJID, @"media/tiles/U4.B_enhanced-32x32.png"); f1234 = new TileSheet(4, 9, 32, 32, 1, 1, 1, 1, NEW_OBJID, @"media/tiles/example_all_facings.4_frames.intra_1.png"); f1234_stack = new TileSheet(1, 9, 32, 32, 1, 1, 1, 1, NEW_OBJID, @"media/tiles/example_all_facings.stacked/example_all_facings.intra_1.frame_1.png", @"media/tiles/example_all_facings.stacked/example_all_facings.intra_1.frame_2.png", @"media/tiles/example_all_facings.stacked/example_all_facings.intra_1.frame_3.png", @"media/tiles/example_all_facings.stacked/example_all_facings.intra_1.frame_4.png"); wp_ts = new TileSheet(4, 1, NEW_OBJID, @"media/tiles/whirlpool_bright.png"); wp_stack_ts = new TileSheet(1, 1, NEW_OBJID, @"media/tiles/whirlpool.stacked/whirlpool_1.png", @"media/tiles/whirlpool.stacked/whirlpool_2.png", @"media/tiles/whirlpool.stacked/whirlpool_3.png", @"media/tiles/whirlpool.stacked/whirlpool_4.png"); creatures_stack = new TileSheet(4, 7, NEW_OBJID, @"media/tiles/creatures.stacked/creatures.frame_1.png", @"media/tiles/creatures.stacked/creatures.frame_2.png", @"media/tiles/creatures.stacked/creatures.frame_3.png", @"media/tiles/creatures.stacked/creatures.frame_4.png"); //string[] empty_file_names_list = { }; //TileSheet null_filenames_ts = new TileSheet(4, 4, NEW_OBJID, null ); // Will throw an exception //TileSheet empty_filenames_list_ts = new TileSheet(4, 4, NEW_OBJID, empty_file_names_list); // Will throw an exception TileSprite anim_blue_wiz = new TileSprite(ts, NEW_OBJID, 32, 33); TileSprite anim_red_wiz = new TileSprite(ts, NEW_OBJID, 224, 225, 226, 227); // Counters for 3 frames (A,B,C) and for 4 frames (1,2,3,4) // This illustrates why the master frame cycle need be the Least Common Multiple of (3,4) // (or whatever other set of ITileSprite.num_frames values). TileSprite count_ABC = new TileSprite(ts, NEW_OBJID, 96, 97, 98); //ts[0, 6], ts[1, 6], ts[2, 6]); TileSprite count_1234 = new TileSprite(f1234_stack, NEW_OBJID, 0, 9 + 0, 18 + 0, 27 + 0); // Same as count_1234, but frames from 4 files // TileSprite whirlpool = new TileSprite(wp_ts, NEW_OBJID, 0, 1, 2, 3); TileSprite whirlpool = new TileSprite(wp_stack_ts, NEW_OBJID, 0, 1, 2, 3); // Save as from wp_ts, but using 4 image files in a stack TileSprite bat = new TileSprite(creatures_stack, NEW_OBJID, (0 * 28) + 1, (1 * 28) + 1, (2 * 28) + 1, (3 * 28) + 1); TileSprite skel_mage = new TileSprite(creatures_stack, NEW_OBJID, (0 * 28) + 21, (1 * 28) + 21, (2 * 28) + 21, (3 * 28) + 21); LF = new TileSheet(8, 1, NEW_OBJID, @"media/tiles/lava.wave_down.speed_4.frames_8.png"); // LF == LavaFlow TileSprite lava_flow = new TileSprite(LF, NEW_OBJID, 0, 1, 2, 3, 4, 5, 6, 7); // TODO: Support some manner of ITileSprite for "wave" sprites // TileSheet TW = new TileSheet(1, 9, NEW_OBJID, @"media/tiles/example_wave_test.intra_1.png"); // Will need WaveTileSprite to support this... TileSprite grass = new TileSprite(ts, NEW_OBJID, 4); TileSprite trees = new TileSprite(ts, NEW_OBJID, 6); TileSprite boulder = new TileSprite(ts, NEW_OBJID, 57); int[] path_rect_5x4 = new int[] { // 5 = grass, 7 = trees, 58 = boulder boulder.ID, grass.ID, grass.ID, trees.ID, grass.ID, grass.ID, grass.ID, grass.ID, trees.ID, trees.ID, trees.ID, trees.ID, trees.ID, trees.ID, 0, // 0 is a "hole in the map" for blitting / map composition purposes grass.ID, grass.ID, trees.ID, grass.ID, grass.ID, }; DenseGrid map_16x64 = new DenseGrid(16, 64, lava_flow.ID); // Blit a non-square grid onto the map, demonstrating the various possible rotations and flips: DenseGrid flip_none = new DenseGrid(5, 4, path_rect_5x4); DenseGrid flip_we = flip_none.Flip_WE(); DenseGrid flip_ns = flip_none.Flip_NS(); DenseGrid flip_wens = flip_we.Flip_NS(); DenseGrid.BlitFromAOntoB(flip_none, map_16x64, 1, 1); DenseGrid.BlitFromAOntoB(flip_we, map_16x64, 7, 1); DenseGrid.BlitFromAOntoB(flip_ns, map_16x64, 1, 7); DenseGrid.BlitFromAOntoB(flip_wens, map_16x64, 7, 7); DenseGrid flip_none_rot090 = flip_none.Rotate090(); DenseGrid flip_we_rot090 = flip_we.Rotate090(); DenseGrid flip_ns_rot090 = flip_ns.Rotate090(); DenseGrid flip_wens_rot090 = flip_wens.Rotate090(); DenseGrid.BlitFromAOntoB(flip_none_rot090, map_16x64, 1, 52); DenseGrid.BlitFromAOntoB(flip_we_rot090, map_16x64, 7, 52); DenseGrid.BlitFromAOntoB(flip_ns_rot090, map_16x64, 1, 58); DenseGrid.BlitFromAOntoB(flip_wens_rot090, map_16x64, 7, 58); map = new SimpleMapV1(16, 64); map.AddTerrainRegion(map_16x64, 0, 0); tvpc.scroll_constraint = ScrollConstraint.CenterTile; tvpc.set_center(map, 2, 2); // Add some elements to the Beings layer of the Map: // BUG: (in demo data) // The below are bare integers which do not correspond // to a constructed TileSprite; those display wrongly (confusion between object ID and OpenGL texture ID or somesuch?) // The fix is merely to create TileSprite objects and use their .ID // (This fossil is due to the TileSheet + TileSprite refactor; // the sprites are no longer implicitly created and stored within the TileSheet) /* map.layers[MapLayers.Beings].set_contents_at_XY( 8, 7, 256+21); // Horse map.layers[MapLayers.Beings].set_contents_at_XY( 4, 15, 256+21); // Horse map.layers[MapLayers.Beings].set_contents_at_XY( 8, 20, 33); // Wizard map.layers[MapLayers.Beings].set_contents_at_XY( 3, 25, 70); // Force field map.layers[MapLayers.Beings].set_contents_at_XY(10, 30, 29); // Stair down map.layers[MapLayers.Beings].set_contents_at_XY( 9, 35, 30); // Ruin map.layers[MapLayers.Beings].set_contents_at_XY( 6, 40, 45); // Archer map.layers[MapLayers.Beings].set_contents_at_XY(12, 45, 23); // Purple tiles map.layers[MapLayers.Beings].set_contents_at_XY( 5, 50, 19); // Ship */ map.layers[MapLayers.Beings].set_contents_at_XY(2, 1, anim_blue_wiz.ID); // Blue Wizard, animated (2 frames) map.layers[MapLayers.Beings].set_contents_at_XY(3, 3, anim_red_wiz.ID); // Red Wizard, animated (4 frames) map.layers[MapLayers.Beings].set_contents_at_XY(4, 1, count_ABC.ID); // 3 frames (A,B,C) map.layers[MapLayers.Beings].set_contents_at_XY(5, 1, count_1234.ID); // 4 frames (1,2,3,4) map.layers[MapLayers.Beings].set_contents_at_XY(6, 6, bat.ID); map.layers[MapLayers.Beings].set_contents_at_XY(4, 7, skel_mage.ID); map.layers[MapLayers.Beings].set_contents_at_XY(0, 0, whirlpool.ID); // Add some elements to the UI_elements layer of the TileViewPort: // Over-sized cursor // Drawback: outside of tile bounds // is off-viewport for edge-of-viewport sides of cursor on edge-of-viewport tiles. // Also, the "quanta" animation rate for the cursor blinking is too fast, as in "pokemon epilepsy warning" too-fast. // (Blinking at "frame" rate seems OK...may want a modestly faster rate.) // // This cursor _does_ look a lot better, other than for edge-of-viewport tiles. // One possible solution to that issue would be for the "rest" state of the viewport // to have an n-pixel border along all edges, showing partial tiles. // Will need to coordinate all this with smooth-scrolling, too... ts_cursor_blink_40x40 = new TileSheet(1, 1, 40, 40, 0, 0, 0, 0, NEW_OBJID, @"media/cursors/cursor_40x40_blink.stacked/cursor_40x40.frame_1.png", @"media/cursors/cursor_40x40_blink.stacked/cursor_40x40.frame_2.png"); TileSprite large_cursor = new TileSprite(ts_cursor_blink_40x40, NEW_OBJID, 0, 1); int LC = large_cursor.ID; tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(tvpc.center_x, tvpc.center_y, LC); // Center tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(0, 0, LC); // NW tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(tvpc.max_x, 0, LC); // NE tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(0, tvpc.max_y, LC); // SW tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(tvpc.max_x, tvpc.max_y, LC); // SE // // "Marquee" cursor // // Drawback: cursor itself is entirely within tile bounds, thus clips edge pixels of the under-cursor tile... // // //reticle_single_file_ts = new TileSheet(4, 1, NEW_OBJID, @"media/tiles/bright_marquee.frame_1234.png"); reticle_four_files_ts = new TileSheet(4, 4, NEW_OBJID, @"media/tiles/bright_marquee.frame_1.png", @"media/tiles/bright_marquee.frame_2.png", @"media/tiles/bright_marquee.frame_3.png", @"media/tiles/bright_marquee.frame_4.png"); // Also used in Form1.OnPaint() //TileSprite anim_reticle = new TileSprite(reticle_four_files_ts, 15, 31, 47, 63); // Bottom right tile in each image file //int reticle = anim_reticle.ID; //tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(tvpc.center_x, tvpc.center_y, reticle); // Center //tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(0, 0, reticle); // NW //tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(tvpc.max_x, 0, reticle); // NE //tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(0, tvpc.max_y, reticle); // SW //tvpc.layers[ViewPortLayers.UI_Elements].set_contents_at_XY(tvpc.max_x, tvpc.max_y, reticle); // SE // A few method calls to demonstrate that Archetype and Obj are working: Archetype aa = new Archetype("first_test_archetype", 0); aa.add_field("int_2a", FieldType.INT); aa.add_field("string_2a", FieldType.STRING); aa.add_field("decimal_2a", FieldType.DECIMAL); aa.add_field("ID_2a", FieldType.ID); aa.add_field("int_list", FieldType.LIST_INT); aa.add_field("string_list", FieldType.LIST_STRING); aa.add_field("decimal_list", FieldType.LIST_DECIMAL); aa.add_field("ID_list", FieldType.LIST_ID); Obj obj1 = new Obj(aa, "first_test_obj", 0); stdout.print("archetype.serialize()\n"); stdout.print("{0}", aa.serialize() ); stdout.print("\n"); stdout.print("obj.serialize()\n"); stdout.print("{0}", obj1.serialize() ); stdout.print("\n"); }