added dos timer and double-esc to quit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 3 Jul 2023 10:44:40 +0000 (13:44 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 3 Jul 2023 10:44:40 +0000 (13:44 +0300)
Makefile
src/app.c
src/app.h
src/dos/main.c
src/dos/pit8254.h
src/dos/timer.c [new file with mode: 0644]
src/modern/main.c
src/scr_mod.c
src/timer.h [new file with mode: 0644]

index ada31b2..634f40a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
 !ifdef __UNIX__
-dosobj = src/dos/main.obj src/dos/keyb.obj src/dos/mouse.obj src/dos/cdpmi.obj &
-       src/dos/vidsys.obj src/dos/drv_vga.obj src/dos/drv_vbe.obj src/dos/drv_s3.obj
+dosobj = src/dos/main.obj src/dos/keyb.obj src/dos/mouse.obj src/dos/timer.obj &
+       src/dos/cdpmi.obj src/dos/vidsys.obj src/dos/drv_vga.obj src/dos/drv_vbe.obj &
+       src/dos/drv_s3.obj
 appobj = src/app.obj src/cmesh.obj src/darray.obj src/font.obj src/logger.obj &
        src/meshgen.obj src/meshload.obj src/options.obj src/rbtree.obj src/geom.obj &
        src/rend.obj src/rtk.obj src/scene.obj src/scr_mod.obj src/scr_rend.obj &
@@ -11,8 +12,9 @@ gawobj = src/gaw/gaw_sw.obj src/gaw/gawswtnl.obj src/gaw/polyclip.obj src/gaw/po
 incpath = -Isrc -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/treestor/include -Ilibs/drawtext
 libpath = libpath libs/dos
 !else
-dosobj = src\dos\main.obj src\dos\keyb.obj src\dos\mouse.obj src\dos\cdpmi.obj &
-       src\dos\vidsys.obj src\dos\drv_vga.obj src\dos\drv_vbe.obj src\dos\drv_s3.obj
+dosobj = src\dos\main.obj src\dos\keyb.obj src\dos\mouse.obj src\dos\timer.obj &
+       src\dos\cdpmi.obj src\dos\vidsys.obj src\dos\drv_vga.obj src\dos\drv_vbe.obj &
+       src\dos\drv_s3.obj
 appobj = src\app.obj src\cmesh.obj src\darray.obj src\font.obj src\logger.obj &
        src\meshgen.obj src\meshload.obj src\options.obj src\rbtree.obj src\geom.obj &
        src\rend.obj src\rtk.obj src\scene.obj src\scr_mod.obj src\scr_rend.obj &
index 25baebb..b0fc2e8 100644 (file)
--- a/src/app.c
+++ b/src/app.c
@@ -23,6 +23,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <time.h>
 #include "gaw/gaw.h"
 #include "app.h"
+#include "timer.h"
 #include "rend.h"
 #include "options.h"
 #include "font.h"
@@ -111,7 +112,7 @@ int app_init(void)
                }
        }
 
-       time_msec = app_getmsec();
+       time_msec = get_msec();
 
        for(i=0; i<num_screens; i++) {
                if(screens[i]->name && start_scr_name && strcmp(screens[i]->name, start_scr_name) == 0) {
@@ -154,7 +155,7 @@ void app_shutdown(void)
 
 void app_display(void)
 {
-       time_msec = app_getmsec();
+       time_msec = get_msec();
 
        cur_scr->display();
 }
@@ -191,11 +192,18 @@ void app_reshape(int x, int y)
 
 void app_keyboard(int key, int press)
 {
+       long msec;
+       static long prev_esc;
+
        if(press) {
                switch(key) {
 #ifdef DBG_ESCQUIT
                case 27:
-                       app_quit();
+                       msec = get_msec();
+                       if(msec - prev_esc < 1000) {
+                               app_quit();
+                       }
+                       prev_esc = msec;
                        return;
 #endif
 
index b2a3b82..6073261 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -105,7 +105,6 @@ void app_sball_button(int bn, int st);
 void app_chscr(struct app_screen *scr);
 
 /* defined in main.c */
-long app_getmsec(void);
 void app_redisplay(int x, int y, int w, int h);
 void app_swap_buffers(void);
 void app_quit(void);
index e7aae2c..e26d2b6 100644 (file)
@@ -21,6 +21,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <ctype.h>
 #include <time.h>
 #include "app.h"
+#include "timer.h"
 #include "keyb.h"
 #include "vidsys.h"
 #include "cdpmi.h"
@@ -66,6 +67,7 @@ int main(int argc, char **argv)
                print_cpuid(&cpuid);
        }
 
+       init_timer(0);
        kb_init();
 
        if(!have_mouse()) {
@@ -159,11 +161,6 @@ break_evloop:
        return 0;
 }
 
-long app_getmsec(void)
-{
-       return time(0) * 1000;  /* TODO */
-}
-
 void app_redisplay(int x, int y, int w, int h)
 {
        rtk_rect r;
index 4389883..5d45f55 100644 (file)
@@ -1,20 +1,3 @@
-/*
-colcycle - color cycling image viewer
-Copyright (C) 2016  John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
 #ifndef PIT8254_H_
 #define PIT8254_H_
 
diff --git a/src/dos/timer.c b/src/dos/timer.c
new file mode 100644 (file)
index 0000000..b7cd6a2
--- /dev/null
@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <conio.h>
+#include <dos.h>
+
+#ifdef __WATCOMC__
+#include <i86.h>
+#endif
+
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <go32.h>
+#include <pc.h>
+#endif
+
+#include "pit8254.h"
+#include "inttypes.h"
+#include "util.h"
+#include "dosutil.h"
+
+#define PIT_TIMER_INTR 8
+#define DOS_TIMER_INTR 0x1c
+
+/* macro to divide and round to the nearest integer */
+#define DIV_ROUND(a, b) \
+       ((a) / (b) + ((a) % (b)) / ((b) / 2))
+
+static void set_timer_reload(int reload_val);
+static void cleanup(void);
+
+#ifdef __WATCOMC__
+#define INTERRUPT      __interrupt __far
+
+static void INTERRUPT dos_timer_intr();
+
+static void (INTERRUPT *prev_timer_intr)();
+#endif
+
+#ifdef __DJGPP__
+#define INTERRUPT
+
+static _go32_dpmi_seginfo intr, prev_intr;
+#endif
+
+static void INTERRUPT timer_irq();
+
+static volatile unsigned long ticks;
+static unsigned long tick_interval, ticks_per_dos_intr;
+static int inum;
+
+void init_timer(int res_hz)
+{
+       _disable();
+
+       if(res_hz > 0) {
+               int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
+               set_timer_reload(reload_val);
+
+               tick_interval = DIV_ROUND(1000, res_hz);
+               ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
+
+               inum = PIT_TIMER_INTR;
+#ifdef __WATCOMC__
+               prev_timer_intr = _dos_getvect(inum);
+               _dos_setvect(inum, timer_irq);
+#endif
+#ifdef __DJGPP__
+               _go32_dpmi_get_protected_mode_interrupt_vector(inum, &prev_intr);
+               intr.pm_offset = (intptr_t)timer_irq;
+               intr.pm_selector = _go32_my_cs();
+               _go32_dpmi_allocate_iret_wrapper(&intr);
+               _go32_dpmi_set_protected_mode_interrupt_vector(inum, &intr);
+#endif
+       } else {
+               tick_interval = 55;
+
+               inum = DOS_TIMER_INTR;
+#ifdef __WATCOMC__
+               prev_timer_intr = _dos_getvect(inum);
+               _dos_setvect(inum, dos_timer_intr);
+#endif
+#ifdef __DJGPP__
+               assert(0);
+#endif
+       }
+       _enable();
+
+       atexit(cleanup);
+}
+
+static void cleanup(void)
+{
+       if(!inum) {
+               return; /* init hasn't ran, there's nothing to cleanup */
+       }
+
+       _disable();
+       if(inum == PIT_TIMER_INTR) {
+               /* restore the original timer frequency */
+               set_timer_reload(65535);
+       }
+
+       /* restore the original interrupt handler */
+#ifdef __WATCOMC__
+       _dos_setvect(inum, prev_timer_intr);
+#endif
+#ifdef __DJGPP__
+       _go32_dpmi_set_protected_mode_interrupt_vector(inum, &prev_intr);
+       _go32_dpmi_free_iret_wrapper(&intr);
+#endif
+
+       _enable();
+}
+
+void reset_timer(void)
+{
+       ticks = 0;
+}
+
+unsigned long get_msec(void)
+{
+       return ticks * tick_interval;
+}
+
+void sleep_msec(unsigned long msec)
+{
+       unsigned long wakeup_time = ticks + msec / tick_interval;
+       while(ticks < wakeup_time) {
+#ifdef USE_HLT
+               halt();
+#endif
+       }
+}
+
+static void set_timer_reload(int reload_val)
+{
+       outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
+       outp(PORT_DATA0, reload_val & 0xff);
+       outp(PORT_DATA0, (reload_val >> 8) & 0xff);
+}
+
+#ifdef __WATCOMC__
+static void INTERRUPT dos_timer_intr()
+{
+       ticks++;
+       _chain_intr(prev_timer_intr);   /* DOES NOT RETURN */
+}
+#endif
+
+/* first PIC command port */
+#define PIC1_CMD       0x20
+/* end of interrupt control word */
+#define OCW2_EOI       (1 << 5)
+
+static void INTERRUPT timer_irq()
+{
+       static unsigned long dos_ticks;
+
+       ticks++;
+
+#ifdef __WATCOMC__
+       if(++dos_ticks >= ticks_per_dos_intr) {
+               /* I suppose the dos irq handler does the EOI so I shouldn't
+                * do it if I am to call the previous function
+                */
+               dos_ticks = 0;
+               _chain_intr(prev_timer_intr);   /* XXX DOES NOT RETURN */
+               return; /* just for clarity */
+       }
+#endif
+
+       /* send EOI to the PIC */
+       outp(PIC1_CMD, OCW2_EOI);
+}
index 5c90787..601b2ef 100644 (file)
@@ -96,9 +96,9 @@ int main(int argc, char **argv)
        return 0;
 }
 
-long app_getmsec(void)
+unsigned long get_msec(void)
 {
-       return glutGet(GLUT_ELAPSED_TIME);
+       return (unsigned long)glutGet(GLUT_ELAPSED_TIME);
 }
 
 void app_redisplay(int x, int y, int w, int h)
index efa4cb0..b1cbc1d 100644 (file)
@@ -69,6 +69,7 @@ enum {
 static rtk_widget *tools[NUM_TOOLS];
 
 static int vpdirty;
+static rtk_rect totalrend;
 
 
 static int mdl_init(void);
@@ -388,15 +389,20 @@ static void mdl_mouse(int bn, int press, int x, int y)
                        app_rband(0, 0, 0, 0);
 
                        if(cur_tool == TOOL_REND_AREA) {
-                               if(prev_tool >= 0) {
-                                       act_settool(prev_tool);
+                               if(rband.width && rband.height) {
+                                       rendering = 1;
+                                       rend_size(win_width, win_height);
+                                       rtk_fix_rect(&rband);
+                                       rendrect = rband;
+                                       rend_begin(rband.x, rband.y, rband.width, rband.height);
+                                       app_redisplay(rband.x, rband.y, rband.width, rband.height);
+
+                                       if(totalrend.width) {
+                                               rtk_rect_union(&totalrend, &rband);
+                                       } else {
+                                               totalrend = rband;
+                                       }
                                }
-                               rendering = 1;
-                               rend_size(win_width, win_height);
-                               rtk_fix_rect(&rband);
-                               rendrect = rband;
-                               rend_begin(rband.x, rband.y, rband.width, rband.height);
-                               app_redisplay(rband.x, rband.y, rband.width, rband.height);
                        }
 
                } else if(bn == 0 && x == rband.x && y == rband.y) {
@@ -518,6 +524,13 @@ static void act_settool(int tidx)
        int i;
        rtk_rect r;
 
+       if(tidx == prev_tool) return;
+
+       if(prev_tool == TOOL_REND_AREA) {
+               app_redisplay(totalrend.x, totalrend.y, totalrend.width, totalrend.height);
+               totalrend.width = 0;
+       }
+
        prev_tool = cur_tool;
        cur_tool = tidx;
        for(i=0; i<NUM_TOOLS; i++) {
diff --git a/src/timer.h b/src/timer.h
new file mode 100644 (file)
index 0000000..395381c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* expects the required timer resolution in hertz
+ * if res_hz is 0, the current resolution is retained
+ */
+void init_timer(int res_hz);
+
+void reset_timer(void);
+unsigned long get_msec(void);
+
+void sleep_msec(unsigned long msec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TIMER_H_ */